aboutsummaryrefslogtreecommitdiffstats
path: root/linux/net/ipsec
diff options
context:
space:
mode:
Diffstat (limited to 'linux/net/ipsec')
-rw-r--r--linux/net/ipsec/.cvsignore47
-rw-r--r--linux/net/ipsec/Config.in41
-rw-r--r--linux/net/ipsec/Makefile529
-rw-r--r--linux/net/ipsec/Makefile.algtest125
-rw-r--r--linux/net/ipsec/alg/Config.alg_aes.in3
-rw-r--r--linux/net/ipsec/alg/Config.alg_blowfish.in3
-rw-r--r--linux/net/ipsec/alg/Config.alg_cryptoapi.in3
-rw-r--r--linux/net/ipsec/alg/Config.alg_serpent.in3
-rw-r--r--linux/net/ipsec/alg/Config.alg_sha2.in3
-rw-r--r--linux/net/ipsec/alg/Config.alg_twofish.in3
-rw-r--r--linux/net/ipsec/alg/Config.in7
-rw-r--r--linux/net/ipsec/alg/Makefile112
-rw-r--r--linux/net/ipsec/alg/Makefile.alg_aes23
-rw-r--r--linux/net/ipsec/alg/Makefile.alg_blowfish23
-rw-r--r--linux/net/ipsec/alg/Makefile.alg_cryptoapi14
-rw-r--r--linux/net/ipsec/alg/Makefile.alg_serpent21
-rw-r--r--linux/net/ipsec/alg/Makefile.alg_sha222
-rw-r--r--linux/net/ipsec/alg/Makefile.alg_twofish21
-rw-r--r--linux/net/ipsec/alg/ipsec_alg_aes.c253
-rw-r--r--linux/net/ipsec/alg/ipsec_alg_blowfish.c142
-rw-r--r--linux/net/ipsec/alg/ipsec_alg_cryptoapi.c421
-rw-r--r--linux/net/ipsec/alg/ipsec_alg_serpent.c139
-rw-r--r--linux/net/ipsec/alg/ipsec_alg_sha2.c185
-rw-r--r--linux/net/ipsec/alg/ipsec_alg_twofish.c138
-rw-r--r--linux/net/ipsec/alg/scripts/mk-static_init.c.sh18
-rw-r--r--linux/net/ipsec/defconfig140
-rw-r--r--linux/net/ipsec/ipcomp.c725
-rw-r--r--linux/net/ipsec/ipsec_alg.c927
-rw-r--r--linux/net/ipsec/ipsec_init.c755
-rw-r--r--linux/net/ipsec/ipsec_life.c210
-rw-r--r--linux/net/ipsec/ipsec_mast.c1064
-rw-r--r--linux/net/ipsec/ipsec_md5c.c448
-rw-r--r--linux/net/ipsec/ipsec_proc.c1003
-rw-r--r--linux/net/ipsec/ipsec_radij.c550
-rw-r--r--linux/net/ipsec/ipsec_rcv.c2204
-rw-r--r--linux/net/ipsec/ipsec_sa.c1031
-rw-r--r--linux/net/ipsec/ipsec_sha1.c219
-rw-r--r--linux/net/ipsec/ipsec_tunnel.c1671
-rw-r--r--linux/net/ipsec/ipsec_xform.c73
-rw-r--r--linux/net/ipsec/ipsec_xmit.c1782
-rw-r--r--linux/net/ipsec/pfkey_v2.c2125
-rw-r--r--linux/net/ipsec/pfkey_v2_ext_process.c851
-rw-r--r--linux/net/ipsec/pfkey_v2_parser.c3420
-rw-r--r--linux/net/ipsec/radij.c992
-rw-r--r--linux/net/ipsec/sysctl_net_ipsec.c196
-rw-r--r--linux/net/ipsec/tagsfile.mak6
46 files changed, 22691 insertions, 0 deletions
diff --git a/linux/net/ipsec/.cvsignore b/linux/net/ipsec/.cvsignore
new file mode 100644
index 000000000..63cb2042f
--- /dev/null
+++ b/linux/net/ipsec/.cvsignore
@@ -0,0 +1,47 @@
+.addrtoa.o.flags
+.adler32.o.flags
+.cbc_enc.o.flags
+.datatot.o.flags
+.deflate.o.flags
+.des_enc.o.flags
+.ecb_enc.o.flags
+.goodmask.o.flags
+.infblock.o.flags
+.infcodes.o.flags
+.inffast.o.flags
+.inflate.o.flags
+.inftrees.o.flags
+.infutil.o.flags
+.ipcomp.o.flags
+.ipsec.o.flags
+.ipsec_init.o.flags
+.ipsec_life.o.flags
+.ipsec_md5c.o.flags
+.ipsec_proc.o.flags
+.ipsec_radij.o.flags
+.ipsec_rcv.o.flags
+.ipsec_sa.o.flags
+.ipsec_sha1.o.flags
+.ipsec_tunnel.o.flags
+.pfkey_v2.o.flags
+.pfkey_v2_build.o.flags
+.pfkey_v2_debug.o.flags
+.pfkey_v2_ext_bits.o.flags
+.pfkey_v2_ext_process.o.flags
+.pfkey_v2_parse.o.flags
+.pfkey_v2_parser.o.flags
+.prng.o.flags
+.radij.o.flags
+.rangetoa.o.flags
+.satoa.o.flags
+.set_key.o.flags
+.subnetof.o.flags
+.subnettoa.o.flags
+.sysctl_net_ipsec.o.flags
+.trees.o.flags
+.ultoa.o.flags
+.version.o.flags
+.zutil.o.flags
+version.c
+.*.o.flags
+*.o
diff --git a/linux/net/ipsec/Config.in b/linux/net/ipsec/Config.in
new file mode 100644
index 000000000..379738a69
--- /dev/null
+++ b/linux/net/ipsec/Config.in
@@ -0,0 +1,41 @@
+#
+# IPSEC configuration
+# Copyright (C) 1998, 1999, 2000,2001 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: Config.in,v 1.3 2004/03/30 21:11:11 as Exp $
+
+comment 'IPsec options (strongSwan)'
+
+bool ' IPSEC: IP-in-IP encapsulation (tunnel mode)' CONFIG_IPSEC_IPIP
+
+bool ' IPSEC: Authentication Header' CONFIG_IPSEC_AH
+if [ "$CONFIG_IPSEC_AH" = "y" -o "$CONFIG_IPSEC_ESP" = "y" ]; then
+ bool ' HMAC-MD5 authentication algorithm' CONFIG_IPSEC_AUTH_HMAC_MD5
+ bool ' HMAC-SHA1 authentication algorithm' CONFIG_IPSEC_AUTH_HMAC_SHA1
+fi
+
+bool ' IPSEC: Encapsulating Security Payload' CONFIG_IPSEC_ESP
+if [ "$CONFIG_IPSEC_ESP" = "y" ]; then
+ bool ' 3DES encryption algorithm' CONFIG_IPSEC_ENC_3DES
+fi
+
+bool ' IPSEC Modular Extensions' CONFIG_IPSEC_ALG
+if [ "$CONFIG_IPSEC_ALG" != "n" ]; then
+ source net/ipsec/alg/Config.in
+fi
+
+bool ' IPSEC: IP Compression' CONFIG_IPSEC_IPCOMP
+
+bool ' IPSEC Debugging Option' CONFIG_IPSEC_DEBUG
+
+bool ' IPSEC NAT-Traversal' CONFIG_IPSEC_NAT_TRAVERSAL
diff --git a/linux/net/ipsec/Makefile b/linux/net/ipsec/Makefile
new file mode 100644
index 000000000..6d834a067
--- /dev/null
+++ b/linux/net/ipsec/Makefile
@@ -0,0 +1,529 @@
+# Makefile for KLIPS kernel code as a module
+# Copyright (C) 1998, 1999, 2000,2001 Richard Guy Briggs.
+# Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+#
+# 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: Makefile,v 1.2 2004/03/22 21:53:19 as Exp $
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+
+ifeq ($(strip $(KLIPSMODULE)),)
+FREESWANSRCDIR=.
+else
+FREESWANSRCDIR=../../..
+endif
+-include ${FREESWANSRCDIR}/Makefile.ver
+
+ifeq ($(strip $(KLIPS_TOP)),)
+KLIPS_TOP=../..
+endif
+
+ifneq ($(strip $(KLIPSMODULE)),)
+
+ifndef TOPDIR
+TOPDIR:=/usr/src/linux
+endif
+export TOPDIR
+
+endif
+
+#
+# This magic from User-Mode-Linux list. It gets list of -I options, as
+# UML needs some extra, that varry by revision.
+#
+KERNEL_CFLAGS= $(shell $(MAKE) -C $(TOPDIR) --no-print-directory -s -f Makefile ARCH=$(ARCH) MAKEFLAGS= script SCRIPT='@echo $$(CFLAGS)' )
+
+MODULE_CFLAGS= $(shell $(MAKE) -C $(TOPDIR) --no-print-directory -s -f Makefile ARCH=$(ARCH) MAKEFLAGS= script SCRIPT='@echo $$(MODFLAGS)' )
+
+subdir- :=
+subdir-n :=
+subdir-y :=
+subdir-m :=
+
+
+MOD_DESTDIR:=net/ipsec
+
+export TOPDIR
+
+all: ipsec.o
+
+foo:
+ echo KERNEL: ${KERNEL_CFLAGS}
+ echo MODULE: ${MODULE_CFLAGS}
+
+ipsec.o: foo
+
+O_TARGET := ipsec.o
+obj-y := ipsec_init.o ipsec_sa.o ipsec_radij.o radij.o
+obj-y += ipsec_life.o ipsec_proc.o
+obj-y += ipsec_tunnel.o ipsec_xmit.o ipsec_rcv.o
+obj-y += sysctl_net_ipsec.o
+obj-y += pfkey_v2.o pfkey_v2_parser.o pfkey_v2_ext_process.o
+#obj-y += version.o
+
+LIBDESDIR=${KLIPS_TOP}/crypto/ciphers/des
+VPATH+= ${LIBDESDIR}
+
+include ${LIBDESDIR}/Makefile.objs
+
+LIBFREESWANDIR=${KLIPS_TOP}/lib/libfreeswan
+VPATH+=${LIBFREESWANDIR}
+
+include ${LIBFREESWANDIR}/Makefile.objs
+
+# IPcomp stuff
+obj-$(CONFIG_IPSEC_IPCOMP) += ipcomp.o
+
+LIBZLIBSRCDIR=${KLIPS_TOP}/lib/zlib
+VPATH+=${LIBZLIBSRCDIR}
+
+# LIBCRYPTO Will be overriden eg. when doing "make module"
+# from freeswan-2 src root
+# Default value assumes already symlinked libcrypto under $TOPDIR/lib
+LIBCRYPTO=$(TOPDIR)/lib/libcrypto
+VPATH+=${LIBCRYPTO}
+
+alg/static_init_mod.o: dummy
+ $(MAKE) -C alg CC='$(CC)' TOPDIR='$(TOPDIR)' \
+ 'EXTRA_CFLAGS=$(EXTRA_CFLAGS)' \
+ static_init_mod.o
+
+
+alg_modules: dummy
+ $(MAKE) $(MODULE_FLAGS) -C alg CC='$(CC)' TOPDIR='$(TOPDIR)' \
+ 'LIBCRYPTO=$(LIBCRYPTO)' \
+ 'EXTRA_CFLAGS=$(EXTRA_CFLAGS)' \
+ modules
+
+# CFLAGS='$(CFLAGS)' \
+# MODULE_CFLAGS='$(MODULE_CFLAGS)' KERNEL_CFLAGS='$(KERNEL_CFLAGS)' \
+#
+include ${LIBZLIBSRCDIR}/Makefile.objs
+
+export-objs := radij.o
+
+# New handling of KERNEL_CFLAGS and MODULE_CFLAGS introduced in 2.0
+# tosses export-objs logic :(
+CFLAGS_ipsec_alg.o += -DEXPORT_SYMTAB
+obj-$(CONFIG_IPSEC_ALG) +=ipsec_alg.o alg/static_init_mod.o
+export-objs += ipsec_alg.o
+subdir-m += alg
+
+EXTRA_CFLAGS += $(ALGO_FLAGS)
+
+
+# include file with .h-style macros that would otherwise be created by
+# config. Must occur before other includes.
+ifneq ($(strip $(MODULE_DEF_INCLUDE)),)
+EXTRA_CFLAGS += -include ${MODULE_DEF_INCLUDE}
+endif
+
+# 'override CFLAGS' should really be 'EXTRA_CFLAGS'
+#EXTRA_CFLAGS += -nostdinc
+EXTRA_CFLAGS += -I${KLIPS_TOP}/include
+
+EXTRA_CFLAGS += -I${TOPDIR}/include
+EXTRA_CFLAGS += -I${LIBZLIBSRCDIR}
+
+ifeq ($(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION),2.4.2-2)
+EXTRA_CFLAGS += -DREDHAT_BOGOSITY
+endif
+
+ifeq ($(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION),2.4.3-12)
+EXTRA_CFLAGS += -DREDHAT_BOGOSITY
+endif
+
+
+#ifeq ($(CONFIG_IPSEC_DEBUG),y)
+#EXTRA_CFLAGS += -g
+#endif
+
+#ifeq ($(CONFIG_IPSEC_ALG), y)
+EXTRA_CFLAGS += -DCONFIG_IPSEC_ALG
+#endif
+# MOST of these flags are in KERNEL_CFLAGS already!
+
+EXTRA_CFLAGS += $(KLIPSCOMPILE)
+EXTRA_CFLAGS += -Wall
+#EXTRA_CFLAGS += -Werror
+#EXTRA_CFLAGS += -Wconversion
+#EXTRA_CFLAGS += -Wmissing-prototypes
+# cannot use both -Wpointer-arith and -Werror with CONFIG_HIGHMEM
+# include/linux/highmem.h has an inline function definition that uses void* arithmentic.
+ifeq ($(CONFIG_NOHIGHMEM),y)
+EXTRA_CFLAGS += -Wpointer-arith
+endif
+#EXTRA_CFLAGS += -Wcast-qual
+#EXTRA_CFLAGS += -Wmissing-declarations
+#EXTRA_CFLAGS += -Wstrict-prototypes
+#EXTRA_CFLAGS += -pedantic
+#EXTRA_CFLAGS += -O3
+#EXTRA_CFLAGS += -W
+#EXTRA_CFLAGS += -Wwrite-strings
+#EXTRA_CFLAGS += -Wbad-function-cast
+
+ifneq ($(strip $(KLIPSMODULE)),)
+# for when we aren't building in the kernel tree
+EXTRA_CFLAGS += -DARCH=${ARCH}
+EXTRA_CFLAGS += -DMODVERSIONS
+EXTRA_CFLAGS += -include ${TOPDIR}/include/linux/modversions.h
+EXTRA_CFLAGS += ${MODULE_CFLAGS}
+endif
+
+EXTRA_CFLAGS += ${KERNEL_CFLAGS}
+
+
+# GCC 3.2 (and we presume any other 3.x) wants -falign-functions
+# in place of the traditional -malign-functions. Getting this
+# wrong leads to a warning, which is fatal due to our use of -Werror.
+ifeq ($(patsubst 3.%,3,$(shell $(CC) -dumpversion)),3)
+override CFLAGS:=$(subst -malign-functions=,-falign-functions=,$(CFLAGS))
+endif
+
+
+obj-$(CONFIG_IPSEC_AUTH_HMAC_MD5) += ipsec_md5c.o
+obj-$(CONFIG_IPSEC_AUTH_HMAC_SHA1) += ipsec_sha1.o
+
+###
+### Pre Rules.make
+###
+# undo O_TARGET, obj-y if no static
+ifneq ($(CONFIG_IPSEC),y)
+O_TARGET :=
+ipsec_obj-y := $(obj-y)
+obj-y :=
+subdir-y :=
+endif
+
+# Define obj-m if modular ipsec
+ifeq ($(CONFIG_IPSEC),m)
+obj-m += ipsec.o
+endif
+
+
+# These rules translate from new to old makefile rules
+# Translate to Rules.make lists.
+multi-used := $(filter $(list-multi), $(obj-y) $(obj-m))
+multi-objs := $(foreach m, $(multi-used), $($(basename $(m))-objs))
+active-objs := $(sort $(multi-objs) $(obj-y) $(obj-m))
+O_OBJS := $(obj-y)
+M_OBJS := $(obj-m)
+MIX_OBJS := $(filter $(export-objs), $(active-objs))
+OX_OBJS := $(export-objs)
+SUB_DIRS := $(subdir-y)
+ALL_SUB_DIRS := $(subdir-y) $(subdir-m)
+MOD_SUB_DIRS := $(subdir-m)
+
+# dunno why, but some 2.2 setups may need explicit -DEXPORT_SYMTAB
+# uncomment next line if ipsec_alg.c compilation fails with
+# "parse error before `EXPORT_SYMTAB_not_defined'" --Juanjo
+# CFLAGS_ipsec_alg.o += -DEXPORT_SYMTAB
+#
+
+include $(TOPDIR)/Rules.make
+
+###
+### Post Rules.make
+###
+# for modular ipsec, no O_TARGET defined => define ipsec.o creation rules
+ifeq ($(CONFIG_IPSEC),m)
+ipsec.o : $(ipsec_obj-y)
+ rm -f $@
+ $(LD) $(LD_EXTRAFLAGS) -r $(ipsec_obj-y) -o $@
+endif
+
+$(ipsec_obj-y) $(obj-y) $(obj-m): $(TOPDIR)/include/linux/config.h $(TOPDIR)/include/linux/autoconf.h
+
+#$(obj-y) $(obj-m): $(TOPDIR)/include/linux/config.h $(TOPDIR)/include/linux/autoconf.h
+
+USE_STANDARD_AS_RULE=true
+
+clean:
+ $(MAKE) -C alg clean
+ -rm -f *.o
+ -rm -f .*.o.flags
+ -rm version.c
+
+tags TAGS: *.c *.h libfreeswan/*.c libfreeswan/*.h
+ etags *.c ../../include/*.h ../../include/freeswan/*.h
+ ctags *.c ../../include/*.h ../../include/freeswan/*.h
+
+tar:
+ tar -cvf /dev/f1 .
+
+#
+# $Log: Makefile,v $
+# Revision 1.2 2004/03/22 21:53:19 as
+# merged alg-0.8.1 branch with HEAD
+#
+# Revision 1.1.4.1 2004/03/16 09:48:19 as
+# alg-0.8.1rc12 patch merged
+#
+# Revision 1.1 2004/03/15 20:35:26 as
+# added files from freeswan-2.04-x509-1.5.3
+#
+# Revision 1.61 2003/06/22 21:07:46 mcr
+# adjusted TAGS target in makefile to be useful in 2.00 source layout.
+#
+# Revision 1.60 2003/05/03 23:45:23 mcr
+# rm .o.flags and generated version.c file.
+#
+# Revision 1.59 2003/02/12 19:32:47 rgb
+# Added ipsec_xmit to the list of object files.
+#
+# Revision 1.58 2003/01/03 00:36:44 rgb
+#
+# Added emacs compile-command.
+#
+# Revision 1.57 2002/11/08 23:49:53 mcr
+# use KERNEL_CFLAGS and MODULE_CFLAGS to get proper list
+# of include directories.
+# This also eliminates some of the guesswork in the kernel
+# configuration file.
+#
+# Revision 1.56 2002/11/08 23:23:18 mcr
+# attempt to guess kernel compilation flags (i.e. list of -I)
+# by using some magic targets in the kernel makefile.
+#
+# Revision 1.55 2002/11/08 10:13:33 mcr
+# added additional include directories for module builds for 2.4.19.
+#
+# Revision 1.54 2002/10/20 06:10:30 build
+# CONFIG_NOHIGHMEM for -Wpointer-arith RPM building issues.
+#
+# Revision 1.53 2002/10/17 16:32:01 mcr
+# enable standard AS rules.
+#
+# Revision 1.52 2002/10/06 06:13:44 sam
+# Altering order of includes, so that architecture-specific header files,
+# used for building RPM modules specifically, are processed first.
+#
+# Revision 1.51 2002/10/05 15:06:38 dhr
+#
+# - To allow for gcc3.2 (used in Red Hat Linux 8.0): adjust CFLAGS (set
+# by kernel machinery) to use -falign-functions= in place of
+# -malign-functions=. Eliminates a warning (fatal with -Werror).
+#
+# - When CONFIG_HIGHMEM is on, -Wpointer-arith will warn about
+# include/linux/highmem.h. Since this is fatal with -Werror, we
+# suppress -Wpointer-arith if CONFIG_HIGHMEM is set.
+#
+# Revision 1.50 2002/09/16 21:19:45 mcr
+# enable -Werror for production - this helps a lot (found a bug in ipsec_rcv.c)
+#
+# Revision 1.49 2002/07/29 05:12:39 mcr
+# get rid of some extraneous stuff, now handled by a prefix
+# Makefile when building as a module.
+#
+# Revision 1.48 2002/07/28 23:13:49 mcr
+# set KLIPS_TOP and use it instead of ../..
+# if KLIPSMODULE, then include a bunch of stuff defined in Makefile.inc
+# that gets us the "typical" configuration that we want.
+#
+# Revision 1.47 2002/06/02 21:51:41 mcr
+# changed TOPDIR->FREESWANSRCDIR in all Makefiles.
+# (note that linux/net/ipsec/Makefile uses TOPDIR because this is the
+# kernel sense.)
+#
+# Revision 1.46 2002/05/14 02:35:51 rgb
+# Added file pfkey_v2_ext_process.c.
+#
+# Revision 1.45 2002/05/13 17:21:40 mcr
+# mkdep dies when given a -I to a directory that does not exist.
+# arch/${ARCH}/include is for UM arch only, so include it for that
+# ARCH only.
+#
+# Revision 1.44 2002/04/24 20:38:12 mcr
+# moved more stuff behind $KLIPSMODULE=y to get static linking to work.
+#
+# Revision 1.43 2002/04/24 09:16:18 mcr
+# include local Makefile.ver as well as FS_rootdir version.
+#
+# Revision 1.42 2002/04/24 08:50:08 mcr
+# critical patch is to set TOPDIR with :=.
+#
+# Revision 1.40 2002/04/24 00:41:07 mcr
+# Moved from ./klips/net/ipsec/Makefile,v
+#
+# Revision 1.39 2002/01/17 04:39:40 rgb
+# Take compile options from top level Makefile.inc
+#
+# Revision 1.38 2001/11/27 05:28:07 rgb
+# Shut off -Werror until we figure out a graceful way of quieting down the
+# pfkey_ops defined but not used complaint in the case of SMP in
+# pfkey_v2.c.
+#
+# Revision 1.37 2001/11/27 05:10:15 rgb
+# Added -Ilibdes and removed lib/des* symlinks.
+#
+# Revision 1.36 2001/11/26 09:23:47 rgb
+# Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
+#
+# Revision 1.35.2.1 2001/09/25 02:17:50 mcr
+# added ipsec_sa, ipsec_life, ipsec_proc.
+# added -Werror to compile flags (see fix for zlib/zutil.h)
+#
+# Revision 1.3 2001/09/21 04:41:26 mcr
+# actually, ipsec_proc.c and ipsec_life.c were never actually compiled.
+#
+# Revision 1.2 2001/09/21 04:11:33 mcr
+# first compilable version.
+#
+# Revision 1.1.1.2 2001/09/17 01:17:52 mcr
+# snapshot 2001-09-16
+#
+# Revision 1.35 2001/09/07 22:09:12 rgb
+# Quiet down compilation.
+#
+# Revision 1.34 2001/08/11 17:10:23 henry
+# update bogosity stuff to cover RH7.1 update
+#
+# Revision 1.33 2001/06/14 19:35:07 rgb
+# Update copyright date.
+#
+# Revision 1.32 2001/06/13 21:00:50 rgb
+# Added a kludge to get around RedHat kernel version bogosity...
+#
+# Revision 1.31 2001/01/29 22:19:06 rgb
+# Convert to 2.4 new style with back compat.
+#
+# Revision 1.30 2000/09/29 19:51:57 rgb
+# Moved klips/net/ipsec/ipcomp_* to zlib/* (Svenning).
+#
+# Revision 1.29 2000/09/15 11:37:01 rgb
+# Merge in heavily modified Svenning Soerensen's <svenning@post5.tele.dk>
+# IPCOMP zlib deflate code.
+#
+# Revision 1.28 2000/09/15 04:55:25 rgb
+# Clean up pfkey object inclusion into the default object.
+#
+# Revision 1.27 2000/09/12 03:20:47 rgb
+# Cleared out now unused pfkeyv2 switch.
+# Enabled sysctl.
+#
+# Revision 1.26 2000/09/08 19:12:55 rgb
+# Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
+#
+# Revision 1.25 2000/06/16 03:09:16 rgb
+# Shut up cast lost warning due to changes in 2.4.0-test1.
+#
+# Revision 1.24 2000/03/16 06:40:48 rgb
+# Hardcode PF_KEYv2 support.
+#
+# Revision 1.23 2000/02/14 21:10:38 rgb
+# Added gcc debug flag when KLIPS_DEBUG is swtiched on.
+#
+# Revision 1.22 2000/01/21 09:44:29 rgb
+# Added compiler switches to be a lot more fussy.
+#
+# Revision 1.21 1999/11/25 23:35:20 rgb
+# Removed quotes to fix Alpha compile issues.
+#
+# Revision 1.20 1999/11/17 15:49:34 rgb
+# Changed all occurrences of ../../../lib in pathnames to libfreeswan,
+# which refers to the /usr/src/linux/net/ipsec/lib directory setup by the
+# klink target in the top-level Makefile; and libdeslite.o to
+# libdes/libdes.a.
+# Added SUB_DIRS := lib definition for the kernel libraries.
+#
+# Revision 1.19 1999/04/27 19:06:47 rgb
+# dd libs and dependancies to tags generation.
+#
+# Revision 1.18 1999/04/16 16:28:12 rgb
+# Minor bugfix to avoid including DES if only AH is used.
+#
+# Revision 1.17 1999/04/15 15:37:23 rgb
+# Forward check changes from POST1_00 branch.
+#
+# Revision 1.14.2.1 1999/03/30 17:29:17 rgb
+# Add support for pfkey.
+#
+# Revision 1.16 1999/04/11 00:28:56 henry
+# GPL boilerplate
+#
+# Revision 1.15 1999/04/06 04:54:25 rgb
+# Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+# patch shell fixes.
+#
+# Revision 1.14 1999/02/18 16:50:45 henry
+# update for new DES library
+#
+# Revision 1.13 1999/02/12 21:11:45 rgb
+# Prepare for newer LIBDES (patch from P.Onion).
+#
+# Revision 1.12 1999/01/26 02:05:08 rgb
+# Remove references to INET_GET_PROTOCOL.
+# Removed CONFIG_IPSEC_ALGO_SWITCH macro.
+# Change from transform switch to algorithm switch.
+#
+# Revision 1.11 1999/01/22 06:16:09 rgb
+# Added algorithm switch code config option.
+#
+# Revision 1.10 1998/11/08 05:31:21 henry
+# be a little fussier
+#
+# Revision 1.9 1998/11/08 05:29:41 henry
+# revisions for new libdes handling
+#
+# Revision 1.8 1998/08/12 00:05:48 rgb
+# Added new xforms to Makefile (moved des-cbc to des-old).
+#
+# Revision 1.7 1998/07/27 21:48:47 rgb
+# Add libkernel.
+#
+# Revision 1.6 1998/07/14 15:50:47 rgb
+# Add dependancies on linux config files.
+#
+# Revision 1.5 1998/07/09 17:44:06 rgb
+# Added 'clean' and 'tags' targets.
+# Added TOPDIR macro.
+# Change module back from symbol exporting to not.
+#
+# Revision 1.3 1998/06/25 19:25:04 rgb
+# Rearrange to support static linking and objects with exported symbol
+# tables.
+#
+# Revision 1.1 1998/06/18 21:27:42 henry
+# move sources from klips/src to klips/net/ipsec, to keep stupid
+# kernel-build scripts happier in the presence of symlinks
+#
+# Revision 1.3 1998/04/15 23:18:43 rgb
+# Unfixed the ../../libdes fix to avoid messing up Henry's script.
+#
+# Revision 1.2 1998/04/14 17:50:47 rgb
+# Fixed to find the new location of libdes.
+#
+# Revision 1.1 1998/04/09 03:05:22 henry
+# sources moved up from linux/net/ipsec
+# modifications to centralize libdes code
+#
+# Revision 1.1.1.1 1998/04/08 05:35:02 henry
+# RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
+#
+# Revision 0.5 1997/06/03 04:24:48 ji
+# Added ESP-3DES-MD5-96
+#
+# Revision 0.4 1997/01/15 01:32:59 ji
+# Added new transforms.
+#
+# Revision 0.3 1996/11/20 14:22:53 ji
+# *** empty log message ***
+#
+#
+# Local Variables:
+# compile-command: "(cd ../../.. && source umlsetup.sh && make -C ${POOLSPACE} module/ipsec.o)"
+# End Variables:
+#
+
diff --git a/linux/net/ipsec/Makefile.algtest b/linux/net/ipsec/Makefile.algtest
new file mode 100644
index 000000000..e68b4ac77
--- /dev/null
+++ b/linux/net/ipsec/Makefile.algtest
@@ -0,0 +1,125 @@
+IPSECVERSION=2.03
+# vim:aw:ai
+#
+# null-patch, non-root GNUmakefile addon for freeswan modules compilation
+#
+# It will not "affect" normal KLIPS building because this GNUmakefile
+# it's not copied to /usr/src/linux
+#
+# Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+# $Id: Makefile.algtest,v 1.2 2004/03/22 21:53:19 as Exp $
+#
+# 1) Copy me to linux/net/ipsec
+# 2)
+# cd klibs/net/ipsec
+# make prep TOPDIR=/path/to/usr/src/linux \
+# [CONFIG=/path/to/.config | CONFIG=/dev/null]
+# 3)
+# make all TOPDIR=.... CONFIG=....
+#CONFIG_IPSEC_ENC_3DES=y
+#CONFIG_IPSEC_AUTH_HMAC_MD5=y
+#CONFIG_IPSEC_AUTH_HMAC_SHA1=y
+CONFIG_IPSEC_ALG_AES=m
+
+ifndef TOPDIR
+$(error You _must_ pass TOPDIR= and optionally CONFIG=)
+endif
+CONFIG=$(TOPDIR)/.config
+include $(CONFIG)
+
+ifdef CONFIG_USERMODE
+ ARCH=um
+endif
+CONFIG_IPSEC=m
+CONFIG_IPSEC_MODULE=y
+CONFIG_IPSEC_IPIP=y
+CONFIG_IPSEC_AH=y
+CONFIG_IPSEC_ESP=y
+CONFIG_IPSEC_ALG=y
+CONFIG_IPSEC_IPCOMP=y
+
+CONFIG_M586 :=$(shell uname -m | sed -n "s/i586/y/p" )
+CONFIG_M686 :=$(shell uname -m | sed -n "s/i686/y/p" )
+export CONFIG_M586 CONFIG_M686
+cflags-arch-$(CONFIG_M586) += -march=i586
+cflags-arch-$(CONFIG_M586_TSC) += -march=i586
+cflags-arch-$(CONFIG_M686) += -march=i686
+cflags-arch-$(CONFIG_MPENTIUMIII) += -march=i686
+cflags-arch-$(CONFIG_MK7) += -march=i686 -malign-functions=4
+CFLAGS_ARCH := $(cflags-arch-y)
+
+ifndef $(CONFIG_SHELL)
+CONFIG_SHELL=/bin/bash
+endif
+export CONFIG_SHELL TOPDIR
+
+ifdef CONFIG_SMP
+EXTRA_CFLAGS += -D__SMP__
+EXTRA_AFLAGS += -D__SMP__
+endif
+
+CFLAGS_IPSEC:=\
+ -DMODVERSIONS \
+ -DCONFIG_IPSEC_MODULE=1\
+ -DCONFIG_IPSEC_IPIP=1\
+ -DCONFIG_IPSEC_AH=1\
+ -DCONFIG_IPSEC_ESP=1\
+ -DCONFIG_IPSEC_IPCOMP=1\
+ -DCONFIG_IPSEC_DEBUG=1 \
+ -DCONFIG_IPSEC_ALG=1 \
+
+# -DCONFIG_IPSEC_DEBUG=1 \
+#
+cflags-ipsec-$(CONFIG_IPSEC_ENC_3DES) += -DCONFIG_IPSEC_ENC_3DES=1
+cflags-ipsec-$(CONFIG_IPSEC_ALG_AES) += -DCONFIG_IPSEC_ALG_AES=1
+cflags-ipsec-$(CONFIG_IPSEC_AUTH_HMAC_MD5)+= -DCONFIG_IPSEC_AUTH_HMAC_MD5=1
+cflags-ipsec-$(CONFIG_IPSEC_AUTH_HMAC_SHA1)+= -DCONFIG_IPSEC_AUTH_HMAC_SHA1=1
+CFLAGS_IPSEC+=$(cflags-ipsec-y)
+export CONFIG_IPSEC
+export CONFIG_IPSEC_MODULE
+
+
+# last bits over CFLAGS ...
+CFLAGS+=$(KINCLUDE) $(CFLAGS_IPSEC) $(CFLAGS_ARCH) $(CFLAGS_KERNEL)
+EXTRA_CFLAGS:=-I$(LOCALKLIPS) -I$(IPSEC_ROOT)/lib
+# libdes options: OPTS1
+OPTS1:=$(CFLAGS) $(EXTRA_CFLAGS)
+export OPTS1 CFLAGS
+
+#include Makefile
+KERNEL_CFLAGS= $(shell $(MAKE) -C $(TOPDIR) --no-print-directory -s -f Makefile ARCH=$(ARCH) MAKEFLAGS= script SCRIPT='@echo $$(CFLAGS)' )
+
+MODULE_CFLAGS= $(shell $(MAKE) -C $(TOPDIR) --no-print-directory -s -f Makefile ARCH=$(ARCH) MAKEFLAGS= script SCRIPT='@echo $$(MODFLAGS)' )
+
+
+ALGO_FLAGS=$(CFLAGS_IPSEC)
+export ALGO_FLAGS
+all: modules alg_modules
+modules:
+ $(MAKE) -C $(TOPDIR) SUBDIRS=$(PWD) modules
+
+ifdef CONFIG_USERMODE
+local_modversions_h:
+ > local_modversions.h
+else
+local_modversions_h:
+ (echo "#ifndef _LINUX_MODVERSIONS_H";\
+ echo "#define _LINUX_MODVERSIONS_H"; \
+ echo "#include <linux/modsetver.h>"; \
+ cd $(TOPDIR)/include/linux/modules; \
+ perl -ne 'print "#define __ver_$$1\t$$2$$3\n#define $$1\t_set_ver($$1)\n" if (/ (.*)_R(smp)?([a-z0-9]{8})\W/);' /proc/ksyms ;\
+ echo "#endif"; \
+ ) > local_modversions.h
+endif
+un_local_modversions_h:
+ @rm -f local_modversions.h
+
+all_alg_modules:
+ (cd alg && \
+ $(MAKE) CC='$(CC)' CFLAGS='$(CFLAGS) $(EXTRA_CFLAGS)' \
+ LIBCRYPTO=$(LOCALKLIPS)/../../../lib/libcrypto \
+ all_alg_modules;)
+
+.PHONY: local_modversions_h
+
+
diff --git a/linux/net/ipsec/alg/Config.alg_aes.in b/linux/net/ipsec/alg/Config.alg_aes.in
new file mode 100644
index 000000000..4a2f81a0b
--- /dev/null
+++ b/linux/net/ipsec/alg/Config.alg_aes.in
@@ -0,0 +1,3 @@
+if [ "$CONFIG_IPSEC_ALG" = "y" ]; then
+ tristate ' AES encryption algorithm' CONFIG_IPSEC_ALG_AES
+fi
diff --git a/linux/net/ipsec/alg/Config.alg_blowfish.in b/linux/net/ipsec/alg/Config.alg_blowfish.in
new file mode 100644
index 000000000..a4e5709b0
--- /dev/null
+++ b/linux/net/ipsec/alg/Config.alg_blowfish.in
@@ -0,0 +1,3 @@
+if [ "$CONFIG_IPSEC_ALG" = "y" ]; then
+ tristate ' BLOWFISH encryption algorithm' CONFIG_IPSEC_ALG_BLOWFISH
+fi
diff --git a/linux/net/ipsec/alg/Config.alg_cryptoapi.in b/linux/net/ipsec/alg/Config.alg_cryptoapi.in
new file mode 100644
index 000000000..c2c66eed8
--- /dev/null
+++ b/linux/net/ipsec/alg/Config.alg_cryptoapi.in
@@ -0,0 +1,3 @@
+if [ "$CONFIG_IPSEC_ALG" = "y" ]; then
+ dep_tristate ' CRYPTOAPI ciphers support (needs cryptoapi patch)' CONFIG_IPSEC_ALG_CRYPTOAPI $CONFIG_CRYPTO
+fi
diff --git a/linux/net/ipsec/alg/Config.alg_serpent.in b/linux/net/ipsec/alg/Config.alg_serpent.in
new file mode 100644
index 000000000..fb1a88460
--- /dev/null
+++ b/linux/net/ipsec/alg/Config.alg_serpent.in
@@ -0,0 +1,3 @@
+if [ "$CONFIG_IPSEC_ALG" = "y" ]; then
+ tristate ' SERPENT encryption algorithm' CONFIG_IPSEC_ALG_SERPENT
+fi
diff --git a/linux/net/ipsec/alg/Config.alg_sha2.in b/linux/net/ipsec/alg/Config.alg_sha2.in
new file mode 100644
index 000000000..2d26c814b
--- /dev/null
+++ b/linux/net/ipsec/alg/Config.alg_sha2.in
@@ -0,0 +1,3 @@
+if [ "$CONFIG_IPSEC_ALG" = "y" ]; then
+ tristate ' HMAC_SHA2 auth algorithm' CONFIG_IPSEC_ALG_SHA2
+fi
diff --git a/linux/net/ipsec/alg/Config.alg_twofish.in b/linux/net/ipsec/alg/Config.alg_twofish.in
new file mode 100644
index 000000000..13655649d
--- /dev/null
+++ b/linux/net/ipsec/alg/Config.alg_twofish.in
@@ -0,0 +1,3 @@
+if [ "$CONFIG_IPSEC_ALG" = "y" ]; then
+ tristate ' TWOFISH encryption algorithm' CONFIG_IPSEC_ALG_TWOFISH
+fi
diff --git a/linux/net/ipsec/alg/Config.in b/linux/net/ipsec/alg/Config.in
new file mode 100644
index 000000000..be5990e3a
--- /dev/null
+++ b/linux/net/ipsec/alg/Config.in
@@ -0,0 +1,7 @@
+#Placeholder
+source net/ipsec/alg/Config.alg_aes.in
+source net/ipsec/alg/Config.alg_blowfish.in
+source net/ipsec/alg/Config.alg_twofish.in
+source net/ipsec/alg/Config.alg_serpent.in
+source net/ipsec/alg/Config.alg_cryptoapi.in
+source net/ipsec/alg/Config.alg_sha2.in
diff --git a/linux/net/ipsec/alg/Makefile b/linux/net/ipsec/alg/Makefile
new file mode 100644
index 000000000..2249668f5
--- /dev/null
+++ b/linux/net/ipsec/alg/Makefile
@@ -0,0 +1,112 @@
+# $Id: Makefile,v 1.2 2004/03/22 21:53:19 as Exp $
+ifeq ($(strip $(KLIPSMODULE)),)
+FREESWANSRCDIR=.
+else
+FREESWANSRCDIR=../../../..
+endif
+ifeq ($(strip $(KLIPS_TOP)),)
+KLIPS_TOP=../../..
+override EXTRA_CFLAGS += -I$(KLIPS_TOP)/include
+endif
+
+ifeq ($(CONFIG_IPSEC_DEBUG),y)
+override EXTRA_CFLAGS += -g
+endif
+
+# LIBCRYPTO normally comes as an argument from "parent" Makefile
+# (this applies both to FS' "make module" and eg. Linux' "make modules"
+# But make dep doest follow same evaluations, so we need this default:
+LIBCRYPTO=$(TOPDIR)/lib/libcrypto
+
+override EXTRA_CFLAGS += -I$(LIBCRYPTO)/include
+override EXTRA_CFLAGS += -Wall -Wpointer-arith -Wstrict-prototypes
+
+MOD_LIST_NAME := NET_MISC_MODULES
+
+#O_TARGET := static_init.o
+
+subdir- :=
+subdir-n :=
+subdir-y :=
+subdir-m :=
+
+obj-y := static_init.o
+
+ARCH_ASM-y :=
+ARCH_ASM-$(CONFIG_M586) := i586
+ARCH_ASM-$(CONFIG_M586TSC) := i586
+ARCH_ASM-$(CONFIG_M586MMX) := i586
+ARCH_ASM-$(CONFIG_MK6) := i586
+ARCH_ASM-$(CONFIG_M686) := i686
+ARCH_ASM-$(CONFIG_MPENTIUMIII) := i686
+ARCH_ASM-$(CONFIG_MPENTIUM4) := i686
+ARCH_ASM-$(CONFIG_MK7) := i686
+ARCH_ASM-$(CONFIG_MCRUSOE) := i586
+ARCH_ASM-$(CONFIG_MWINCHIPC6) := i586
+ARCH_ASM-$(CONFIG_MWINCHIP2) := i586
+ARCH_ASM-$(CONFIG_MWINCHIP3D) := i586
+ARCH_ASM-$(CONFIG_USERMODE) := i586
+
+ARCH_ASM :=$(ARCH_ASM-y)
+ifdef NO_ASM
+ARCH_ASM :=
+endif
+
+# The algorithm makefiles may put dependences, short-circuit them
+null:
+
+makefiles=$(filter-out %.preipsec, $(wildcard Makefile.alg_*))
+ifneq ($(makefiles),)
+#include Makefile.alg_aes
+#include Makefile.alg_aes-opt
+include $(makefiles)
+endif
+
+# These rules translate from new to old makefile rules
+# Translate to Rules.make lists.
+multi-used := $(filter $(list-multi), $(obj-y) $(obj-m))
+multi-objs := $(foreach m, $(multi-used), $($(basename $(m))-objs))
+active-objs := $(sort $(multi-objs) $(obj-y) $(obj-m))
+O_OBJS := $(obj-y)
+M_OBJS := $(obj-m)
+MIX_OBJS := $(filter $(export-objs), $(active-objs))
+#OX_OBJS := $(export-objs)
+SUB_DIRS := $(subdir-y)
+ALL_SUB_DIRS := $(subdir-y) $(subdir-m)
+MOD_SUB_DIRS := $(subdir-m)
+
+
+static_init_mod.o: $(obj-y)
+ rm -f $@
+ $(LD) $(LD_EXTRAFLAGS) $(obj-y) -r -o $@
+
+perlasm: $(LIBCRYPTO)/perlasm
+ ln -sf $? $@
+
+$(obj-y) $(obj-m): $(TOPDIR)/include/linux/config.h $(TOPDIR)/include/linux/autoconf.h $(KLIPS_TOP)/include/freeswan/ipsec_alg.h
+$(alg_obj-y) $(alg_obj-m): perlasm $(TOPDIR)/include/linux/config.h $(TOPDIR)/include/linux/autoconf.h $(KLIPS_TOP)/include/freeswan/ipsec_alg.h
+
+
+all_alg_modules: perlasm $(ALG_MODULES)
+ @echo "ALG_MODULES=$(ALG_MODULES)"
+
+
+#
+# Construct alg. init. function: call ipsec_ALGO_init() for every static algo
+# Needed when there are static algos (with static or modular ipsec.o)
+#
+static_init.c: $(TOPDIR)/include/linux/autoconf.h Makefile $(makefiles) scripts/mk-static_init.c.sh
+ @echo "Re-creating $@"
+ $(SHELL) scripts/mk-static_init.c.sh $(static_init-func-y) > $@
+
+clean:
+ @for i in $(ALG_SUBDIRS);do test -d $$i && make -C $$i clean;done;exit 0
+ @find . -type l -exec rm -f {} \;
+ -rm -f perlasm
+ -rm -rf $(ALG_SUBDIRS)
+ -rm -f *.o .*.o.flags static_init.c
+
+ifdef TOPDIR
+include $(TOPDIR)/Rules.make
+endif
+
diff --git a/linux/net/ipsec/alg/Makefile.alg_aes b/linux/net/ipsec/alg/Makefile.alg_aes
new file mode 100644
index 000000000..75284c47a
--- /dev/null
+++ b/linux/net/ipsec/alg/Makefile.alg_aes
@@ -0,0 +1,23 @@
+MOD_AES := ipsec_aes.o
+
+ALG_MODULES += $(MOD_AES)
+ALG_SUBDIRS += libaes
+
+obj-$(CONFIG_IPSEC_ALG_AES) += $(MOD_AES)
+static_init-func-$(CONFIG_IPSEC_ALG_AES)+= ipsec_aes_init
+alg_obj-$(CONFIG_IPSEC_ALG_AES) += ipsec_alg_aes.o
+
+AES_OBJS := ipsec_alg_aes.o libaes/libaes.a
+
+$(MOD_AES): libaes $(AES_OBJS)
+ $(LD) $(EXTRA_LDFLAGS) -r $(AES_OBJS) -o $@
+
+libaes: $(LIBCRYPTO)/libaes
+ test -d $@ || mkdir $@ ;exit 0
+ test -d $@/asm || mkdir $@/asm;exit 0
+ cd $@ && ln -sf $?/Makefile $?/*.[chS] .
+ cd $@/asm && ln -sf $?/asm/*.S .
+
+libaes/libaes.a: libaes
+ ( cd libaes && \
+ $(MAKE) CC='$(CC)' 'ARCH_ASM=$(ARCH_ASM)' CFLAGS='$(CFLAGS) $(EXTRA_CFLAGS)' libaes.a ;)
diff --git a/linux/net/ipsec/alg/Makefile.alg_blowfish b/linux/net/ipsec/alg/Makefile.alg_blowfish
new file mode 100644
index 000000000..9413a9f1c
--- /dev/null
+++ b/linux/net/ipsec/alg/Makefile.alg_blowfish
@@ -0,0 +1,23 @@
+MOD_BLOWFISH := ipsec_blowfish.o
+
+ALG_MODULES += $(MOD_BLOWFISH)
+ALG_SUBDIRS += libblowfish
+
+obj-$(CONFIG_IPSEC_ALG_BLOWFISH) += $(MOD_BLOWFISH)
+static_init-func-$(CONFIG_IPSEC_ALG_BLOWFISH)+= ipsec_blowfish_init
+alg_obj-$(CONFIG_IPSEC_ALG_BLOWFISH) += ipsec_alg_blowfish.o
+
+BLOWFISH_OBJS:= ipsec_alg_blowfish.o libblowfish/libblowfish.a
+
+$(MOD_BLOWFISH): libblowfish $(BLOWFISH_OBJS)
+ $(LD) -r $(BLOWFISH_OBJS) -o $@
+
+libblowfish : $(LIBCRYPTO)/libblowfish
+ test -d $@ || mkdir $@ ;exit 0
+ test -d $@/asm || mkdir $@/asm;exit 0
+ cd $@ && ln -sf $?/Makefile $?/*.[chS] .
+ cd $@/asm && ln -sf $?/asm/*.pl .
+
+libblowfish/libblowfish.a:
+ ( cd libblowfish && \
+ $(MAKE) CC='$(CC)' 'ARCH_ASM=$(ARCH_ASM)' CFLAGS='$(CFLAGS) $(EXTRA_CFLAGS)' EXTRA_CFLAGS='$(EXTRA_CFLAGS)' libblowfish.a ;)
diff --git a/linux/net/ipsec/alg/Makefile.alg_cryptoapi b/linux/net/ipsec/alg/Makefile.alg_cryptoapi
new file mode 100644
index 000000000..77ee6481f
--- /dev/null
+++ b/linux/net/ipsec/alg/Makefile.alg_cryptoapi
@@ -0,0 +1,14 @@
+MOD_CRYPTOAPI := ipsec_cryptoapi.o
+
+ifneq ($(wildcard $(TOPDIR)/include/linux/crypto.h),)
+ALG_MODULES += $(MOD_CRYPTOAPI)
+obj-$(CONFIG_IPSEC_ALG_CRYPTOAPI) += $(MOD_CRYPTOAPI)
+static_init-func-$(CONFIG_IPSEC_ALG_CRYPTOAPI)+= ipsec_cryptoapi_init
+alg_obj-$(CONFIG_IPSEC_ALG_CRYPTOAPI) += ipsec_alg_cryptoapi.o
+else
+$(warning "Linux CryptoAPI (2.4.22+ or 2.6.x) not found, not building ipsec_cryptoapi.o")
+endif
+
+CRYPTOAPI_OBJS := ipsec_alg_cryptoapi.o
+$(MOD_CRYPTOAPI): $(CRYPTOAPI_OBJS)
+ $(LD) -r $(CRYPTOAPI_OBJS) -o $@
diff --git a/linux/net/ipsec/alg/Makefile.alg_serpent b/linux/net/ipsec/alg/Makefile.alg_serpent
new file mode 100644
index 000000000..1a2383a6a
--- /dev/null
+++ b/linux/net/ipsec/alg/Makefile.alg_serpent
@@ -0,0 +1,21 @@
+MOD_SERPENT := ipsec_serpent.o
+
+ALG_MODULES += $(MOD_SERPENT)
+ALG_SUBDIRS += libserpent
+
+obj-$(CONFIG_IPSEC_ALG_SERPENT) += $(MOD_SERPENT)
+static_init-func-$(CONFIG_IPSEC_ALG_SERPENT)+= ipsec_serpent_init
+alg_obj-$(CONFIG_IPSEC_ALG_SERPENT) += ipsec_alg_serpent.o
+
+SERPENT_OBJS=ipsec_alg_serpent.o libserpent/libserpent.a
+$(MOD_SERPENT) : libserpent $(SERPENT_OBJS)
+ $(LD) -r $(SERPENT_OBJS) -o $@
+
+libserpent : $(LIBCRYPTO)/libserpent
+ test -d $@ || mkdir $@ ;exit 0
+ test -d $@/asm || mkdir $@/asm;exit 0
+ cd $@ && ln -sf $?/Makefile $?/*.[chS] .
+
+libserpent/libserpent.a:
+ ( cd libserpent && \
+ $(MAKE) CC='$(CC)' CFLAGS='$(CFLAGS) $(EXTRA_CFLAGS)' EXTRA_CFLAGS='$(EXTRA_CFLAGS)' libserpent.a ;)
diff --git a/linux/net/ipsec/alg/Makefile.alg_sha2 b/linux/net/ipsec/alg/Makefile.alg_sha2
new file mode 100644
index 000000000..956a0f1a3
--- /dev/null
+++ b/linux/net/ipsec/alg/Makefile.alg_sha2
@@ -0,0 +1,22 @@
+MOD_SHA2 := ipsec_sha2.o
+
+ALG_MODULES += $(MOD_SHA2)
+ALG_SUBDIRS += libsha2
+
+obj-$(CONFIG_IPSEC_ALG_SHA2) += $(MOD_SHA2)
+static_init-func-$(CONFIG_IPSEC_ALG_SHA2)+= ipsec_sha2_init
+alg_obj-$(CONFIG_IPSEC_ALG_SHA2) += ipsec_alg_sha2.o
+
+SHA2_OBJS := ipsec_alg_sha2.o libsha2/libsha2.a
+
+$(MOD_SHA2): libsha2 $(SHA2_OBJS)
+ $(LD) $(EXTRA_LDFLAGS) -r $(SHA2_OBJS) -o $@
+
+libsha2 : $(LIBCRYPTO)/libsha2
+ test -d $@ || mkdir $@ ;exit 0
+ test -d $@/asm || mkdir $@/asm;exit 0
+ cd $@ && ln -sf $?/Makefile $?/*.[chS] .
+
+libsha2/libsha2.a:
+ ( cd libsha2 && \
+ $(MAKE) CC='$(CC)' CFLAGS='$(CFLAGS) $(EXTRA_CFLAGS)' EXTRA_CFLAGS='$(EXTRA_CFLAGS)' libsha2.a ;)
diff --git a/linux/net/ipsec/alg/Makefile.alg_twofish b/linux/net/ipsec/alg/Makefile.alg_twofish
new file mode 100644
index 000000000..559285ddd
--- /dev/null
+++ b/linux/net/ipsec/alg/Makefile.alg_twofish
@@ -0,0 +1,21 @@
+MOD_TWOFISH := ipsec_twofish.o
+
+ALG_MODULES += $(MOD_TWOFISH)
+ALG_SUBDIRS += libtwofish
+
+obj-$(CONFIG_IPSEC_ALG_TWOFISH) += $(MOD_TWOFISH)
+static_init-func-$(CONFIG_IPSEC_ALG_TWOFISH)+= ipsec_twofish_init
+alg_obj-$(CONFIG_IPSEC_ALG_TWOFISH) += ipsec_alg_twofish.o
+
+TWOFISH_OBJS := ipsec_alg_twofish.o libtwofish/libtwofish.a
+$(MOD_TWOFISH): libtwofish $(TWOFISH_OBJS)
+ $(LD) -r $(TWOFISH_OBJS) -o $@
+
+libtwofish : $(LIBCRYPTO)/libtwofish
+ test -d $@ || mkdir $@ ;exit 0
+ test -d $@/asm || mkdir $@/asm;exit 0
+ cd $@ && ln -sf $?/Makefile $?/*.[chS] .
+
+libtwofish/libtwofish.a:
+ ( cd libtwofish && \
+ $(MAKE) CC='$(CC)' CFLAGS='$(CFLAGS) $(EXTRA_CFLAGS)' EXTRA_CFLAGS='$(EXTRA_CFLAGS)' libtwofish.a ;)
diff --git a/linux/net/ipsec/alg/ipsec_alg_aes.c b/linux/net/ipsec/alg/ipsec_alg_aes.c
new file mode 100644
index 000000000..c6b390281
--- /dev/null
+++ b/linux/net/ipsec/alg/ipsec_alg_aes.c
@@ -0,0 +1,253 @@
+/*
+ * ipsec_alg AES cipher stubs
+ *
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * $Id: ipsec_alg_aes.c,v 1.2 2004/03/22 21:53:19 as Exp $
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * Fixes by:
+ * PK: Pawel Krawczyk <kravietz@aba.krakow.pl>
+ * Fixes list:
+ * PK: make XCBC comply with latest draft (keylength)
+ *
+ */
+#include <linux/config.h>
+#include <linux/version.h>
+
+/*
+ * special case: ipsec core modular with this static algo inside:
+ * must avoid MODULE magic for this file
+ */
+#if CONFIG_IPSEC_MODULE && CONFIG_IPSEC_ALG_AES
+#undef MODULE
+#endif
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h> /* printk() */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/string.h>
+
+/* Check if __exit is defined, if not null it */
+#ifndef __exit
+#define __exit
+#endif
+
+/* Low freeswan header coupling */
+#include "freeswan/ipsec_alg.h"
+#include "libaes/aes_cbc.h"
+
+#define CONFIG_IPSEC_ALG_AES_MAC 1
+
+#define AES_CONTEXT_T aes_context
+MODULE_AUTHOR("JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>");
+static int debug=0;
+MODULE_PARM(debug, "i");
+static int test=0;
+MODULE_PARM(test, "i");
+static int excl=0;
+MODULE_PARM(excl, "i");
+static int keyminbits=0;
+MODULE_PARM(keyminbits, "i");
+static int keymaxbits=0;
+MODULE_PARM(keymaxbits, "i");
+
+#if CONFIG_IPSEC_ALG_AES_MAC
+#include "libaes/aes_xcbc_mac.h"
+
+/*
+ * Not IANA number yet (draft-ietf-ipsec-ciph-aes-xcbc-mac-00.txt).
+ * We use 9 for non-modular algorithm and none for modular, thus
+ * forcing user to specify one on module load. -kravietz
+ */
+#ifdef MODULE
+static int auth_id=0;
+#else
+static int auth_id=9;
+#endif
+MODULE_PARM(auth_id, "i");
+#endif
+
+#define ESP_AES 12 /* truely _constant_ :) */
+
+/* 128, 192 or 256 */
+#define ESP_AES_KEY_SZ_MIN 16 /* 128 bit secret key */
+#define ESP_AES_KEY_SZ_MAX 32 /* 256 bit secret key */
+#define ESP_AES_CBC_BLK_LEN 16 /* AES-CBC block size */
+
+/* Values according to draft-ietf-ipsec-ciph-aes-xcbc-mac-02.txt
+ * -kravietz
+ */
+#define ESP_AES_MAC_KEY_SZ 16 /* 128 bit MAC key */
+#define ESP_AES_MAC_BLK_LEN 16 /* 128 bit block */
+
+static int _aes_set_key(struct ipsec_alg_enc *alg, __u8 * key_e, const __u8 * key, size_t keysize) {
+ int ret;
+ AES_CONTEXT_T *ctx=(AES_CONTEXT_T*)key_e;
+ ret=AES_set_key(ctx, key, keysize)!=0? 0: -EINVAL;
+ if (debug > 0)
+ printk(KERN_DEBUG "klips_debug:_aes_set_key:"
+ "ret=%d key_e=%p key=%p keysize=%d\n",
+ ret, key_e, key, keysize);
+ return ret;
+}
+static int _aes_cbc_encrypt(struct ipsec_alg_enc *alg, __u8 * key_e, __u8 * in, int ilen, const __u8 * iv, int encrypt) {
+ AES_CONTEXT_T *ctx=(AES_CONTEXT_T*)key_e;
+ if (debug > 0)
+ printk(KERN_DEBUG "klips_debug:_aes_cbc_encrypt:"
+ "key_e=%p in=%p ilen=%d iv=%p encrypt=%d\n",
+ key_e, in, ilen, iv, encrypt);
+ return AES_cbc_encrypt(ctx, in, in, ilen, iv, encrypt);
+}
+#if CONFIG_IPSEC_ALG_AES_MAC
+static int _aes_mac_set_key(struct ipsec_alg_auth *alg, __u8 * key_a, const __u8 * key, int keylen) {
+ aes_context_mac *ctxm=(aes_context_mac *)key_a;
+ return AES_xcbc_mac_set_key(ctxm, key, keylen)? 0 : -EINVAL;
+}
+static int _aes_mac_hash(struct ipsec_alg_auth *alg, __u8 * key_a, const __u8 * dat, int len, __u8 * hash, int hashlen) {
+ int ret;
+ char hash_buf[16];
+ aes_context_mac *ctxm=(aes_context_mac *)key_a;
+ ret=AES_xcbc_mac_hash(ctxm, dat, len, hash_buf);
+ memcpy(hash, hash_buf, hashlen);
+ return ret;
+}
+static struct ipsec_alg_auth ipsec_alg_AES_MAC = {
+ ixt_version: IPSEC_ALG_VERSION,
+ ixt_module: THIS_MODULE,
+ ixt_refcnt: ATOMIC_INIT(0),
+ ixt_alg_type: IPSEC_ALG_TYPE_AUTH,
+ ixt_alg_id: 0,
+ ixt_name: "aes_mac",
+ ixt_blocksize: ESP_AES_MAC_BLK_LEN,
+ ixt_keyminbits: ESP_AES_MAC_KEY_SZ*8,
+ ixt_keymaxbits: ESP_AES_MAC_KEY_SZ*8,
+ ixt_a_keylen: ESP_AES_MAC_KEY_SZ,
+ ixt_a_ctx_size: sizeof(aes_context_mac),
+ ixt_a_hmac_set_key: _aes_mac_set_key,
+ ixt_a_hmac_hash:_aes_mac_hash,
+};
+#endif /* CONFIG_IPSEC_ALG_AES_MAC */
+static struct ipsec_alg_enc ipsec_alg_AES = {
+ ixt_version: IPSEC_ALG_VERSION,
+ ixt_module: THIS_MODULE,
+ ixt_refcnt: ATOMIC_INIT(0),
+ ixt_alg_type: IPSEC_ALG_TYPE_ENCRYPT,
+ ixt_alg_id: ESP_AES,
+ ixt_name: "aes",
+ ixt_blocksize: ESP_AES_CBC_BLK_LEN,
+ ixt_keyminbits: ESP_AES_KEY_SZ_MIN*8,
+ ixt_keymaxbits: ESP_AES_KEY_SZ_MAX*8,
+ ixt_e_keylen: ESP_AES_KEY_SZ_MAX,
+ ixt_e_ctx_size: sizeof(AES_CONTEXT_T),
+ ixt_e_set_key: _aes_set_key,
+ ixt_e_cbc_encrypt:_aes_cbc_encrypt,
+};
+
+IPSEC_ALG_MODULE_INIT( ipsec_aes_init )
+{
+ int ret, test_ret;
+ if (keyminbits)
+ ipsec_alg_AES.ixt_keyminbits=keyminbits;
+ if (keymaxbits) {
+ ipsec_alg_AES.ixt_keymaxbits=keymaxbits;
+ if (keymaxbits*8>ipsec_alg_AES.ixt_keymaxbits)
+ ipsec_alg_AES.ixt_e_keylen=keymaxbits*8;
+ }
+ if (excl) ipsec_alg_AES.ixt_state |= IPSEC_ALG_ST_EXCL;
+ ret=register_ipsec_alg_enc(&ipsec_alg_AES);
+ printk("ipsec_aes_init(alg_type=%d alg_id=%d name=%s): ret=%d\n",
+ ipsec_alg_AES.ixt_alg_type,
+ ipsec_alg_AES.ixt_alg_id,
+ ipsec_alg_AES.ixt_name,
+ ret);
+ if (ret==0 && test) {
+ test_ret=ipsec_alg_test(
+ ipsec_alg_AES.ixt_alg_type,
+ ipsec_alg_AES.ixt_alg_id,
+ test);
+ printk("ipsec_aes_init(alg_type=%d alg_id=%d): test_ret=%d\n",
+ ipsec_alg_AES.ixt_alg_type,
+ ipsec_alg_AES.ixt_alg_id,
+ test_ret);
+ }
+#if CONFIG_IPSEC_ALG_AES_MAC
+ if (auth_id!=0){
+ int ret;
+ ipsec_alg_AES_MAC.ixt_alg_id=auth_id;
+ ret=register_ipsec_alg_auth(&ipsec_alg_AES_MAC);
+ printk("ipsec_aes_init(alg_type=%d alg_id=%d name=%s): ret=%d\n",
+ ipsec_alg_AES_MAC.ixt_alg_type,
+ ipsec_alg_AES_MAC.ixt_alg_id,
+ ipsec_alg_AES_MAC.ixt_name,
+ ret);
+ if (ret==0 && test) {
+ test_ret=ipsec_alg_test(
+ ipsec_alg_AES_MAC.ixt_alg_type,
+ ipsec_alg_AES_MAC.ixt_alg_id,
+ test);
+ printk("ipsec_aes_init(alg_type=%d alg_id=%d): test_ret=%d\n",
+ ipsec_alg_AES_MAC.ixt_alg_type,
+ ipsec_alg_AES_MAC.ixt_alg_id,
+ test_ret);
+ }
+ } else {
+ printk(KERN_DEBUG "klips_debug: experimental ipsec_alg_AES_MAC not registered [Ok] (auth_id=%d)\n", auth_id);
+ }
+#endif /* CONFIG_IPSEC_ALG_AES_MAC */
+ return ret;
+}
+IPSEC_ALG_MODULE_EXIT( ipsec_aes_fini )
+{
+#if CONFIG_IPSEC_ALG_AES_MAC
+ if (auth_id) unregister_ipsec_alg_auth(&ipsec_alg_AES_MAC);
+#endif /* CONFIG_IPSEC_ALG_AES_MAC */
+ unregister_ipsec_alg_enc(&ipsec_alg_AES);
+ return;
+}
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+#if 0+NOT_YET
+#ifndef MODULE
+/*
+ * This is intended for static module setups, currently
+ * doesn't work for modular ipsec.o with static algos inside
+ */
+static int setup_keybits(const char *str)
+{
+ unsigned aux;
+ char *end;
+
+ aux = simple_strtoul(str,&end,0);
+ if (aux != 128 && aux != 192 && aux != 256)
+ return 0;
+ keyminbits = aux;
+
+ if (*end == 0 || *end != ',')
+ return 1;
+ str=end+1;
+ aux = simple_strtoul(str, NULL, 0);
+ if (aux != 128 && aux != 192 && aux != 256)
+ return 0;
+ if (aux >= keyminbits)
+ keymaxbits = aux;
+ return 1;
+}
+__setup("ipsec_aes_keybits=", setup_keybits);
+#endif
+#endif
+EXPORT_NO_SYMBOLS;
diff --git a/linux/net/ipsec/alg/ipsec_alg_blowfish.c b/linux/net/ipsec/alg/ipsec_alg_blowfish.c
new file mode 100644
index 000000000..6adc22b22
--- /dev/null
+++ b/linux/net/ipsec/alg/ipsec_alg_blowfish.c
@@ -0,0 +1,142 @@
+/* ipsec_alg BLOWFISH cipher stubs
+ *
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * 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.
+ *
+ * RCS ID $Id: ipsec_alg_blowfish.c,v 1.3 2004/09/17 18:57:30 as Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+
+/*
+ * special case: ipsec core modular with this static algo inside:
+ * must avoid MODULE magic for this file
+ */
+#if CONFIG_IPSEC_MODULE && CONFIG_IPSEC_ALG_BLOWFISH
+#undef MODULE
+#endif
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h> /* printk() */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/string.h>
+
+/* Check if __exit is defined, if not null it */
+#ifndef __exit
+#define __exit
+#endif
+
+/* Low freeswan header coupling */
+#include "freeswan/ipsec_alg.h"
+#include "libblowfish/blowfish.h"
+#define blowfish_context BF_KEY
+
+#define ESP_BLOWFISH 7 /* truly _constant_ :) */
+
+#define ESP_BLOWFISH_KEY_SZ_MIN 16 /* 128 bit secret key min */
+#define ESP_BLOWFISH_KEY_SZ 16 /* 128 bit secret key */
+#define ESP_BLOWFISH_KEY_SZ_MAX 56 /* 448 bit secret key max */
+#define ESP_BLOWFISH_CBC_BLK_LEN 8 /* block size */
+
+MODULE_AUTHOR("JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>");
+static int debug=0;
+MODULE_PARM(debug, "i");
+static int test=0;
+MODULE_PARM(test, "i");
+static int excl=0;
+MODULE_PARM(excl, "i");
+static int keyminbits=0;
+MODULE_PARM(keyminbits, "i");
+static int keymaxbits=0;
+MODULE_PARM(keymaxbits, "i");
+
+static int _blowfish_set_key(struct ipsec_alg_enc *alg, __u8 * key_e, const __u8 * key, size_t keysize) {
+ blowfish_context *ctx=(blowfish_context*)key_e;
+ if (debug > 0)
+ printk(KERN_DEBUG "klips_debug:_blowfish_set_key:"
+ "key_e=%p key=%p keysize=%d\n",
+ key_e, key, keysize);
+ BF_set_key(ctx, keysize, (unsigned char *)key);
+ return 0;
+}
+static int _blowfish_cbc_encrypt(struct ipsec_alg_enc *alg, __u8 * key_e, __u8 * in, int ilen, const __u8 *iv, int encrypt) {
+ /* blowfish toasts passed IV */
+ __u8 iv_buf[ESP_BLOWFISH_CBC_BLK_LEN];
+ blowfish_context *ctx=(blowfish_context*)key_e;
+ *((__u32*)&(iv_buf)) = ((__u32*)(iv))[0];
+ *((__u32*)&(iv_buf)+1) = ((__u32*)(iv))[1];
+ if (debug > 0)
+ printk(KERN_DEBUG "klips_debug:_blowfish_cbc_encrypt:"
+ "key_e=%p in=%p ilen=%d iv=%p encrypt=%d\n",
+ key_e, in, ilen, iv_buf, encrypt);
+ BF_cbc_encrypt(in, in, ilen, ctx, iv_buf, encrypt);
+ return ilen;
+}
+static struct ipsec_alg_enc ipsec_alg_BLOWFISH = {
+ ixt_version: IPSEC_ALG_VERSION,
+ ixt_module: THIS_MODULE,
+ ixt_refcnt: ATOMIC_INIT(0),
+ ixt_alg_type: IPSEC_ALG_TYPE_ENCRYPT,
+ ixt_alg_id: ESP_BLOWFISH,
+ ixt_name: "blowfish",
+ ixt_blocksize: ESP_BLOWFISH_CBC_BLK_LEN,
+ ixt_keyminbits: ESP_BLOWFISH_KEY_SZ_MIN*8,
+ ixt_keymaxbits: ESP_BLOWFISH_KEY_SZ_MAX*8,
+ ixt_e_keylen: ESP_BLOWFISH_KEY_SZ,
+ ixt_e_ctx_size: sizeof(blowfish_context),
+ ixt_e_set_key: _blowfish_set_key,
+ ixt_e_cbc_encrypt:_blowfish_cbc_encrypt,
+};
+
+IPSEC_ALG_MODULE_INIT(ipsec_blowfish_init)
+{
+ int ret, test_ret;
+ if (keyminbits)
+ ipsec_alg_BLOWFISH.ixt_keyminbits=keyminbits;
+ if (keymaxbits) {
+ ipsec_alg_BLOWFISH.ixt_keymaxbits=keymaxbits;
+ if (keymaxbits*8>ipsec_alg_BLOWFISH.ixt_keymaxbits)
+ ipsec_alg_BLOWFISH.ixt_e_keylen=keymaxbits*8;
+ }
+ if (excl) ipsec_alg_BLOWFISH.ixt_state |= IPSEC_ALG_ST_EXCL;
+ ret=register_ipsec_alg_enc(&ipsec_alg_BLOWFISH);
+ printk("ipsec_blowfish_init(alg_type=%d alg_id=%d name=%s): ret=%d\n",
+ ipsec_alg_BLOWFISH.ixt_alg_type,
+ ipsec_alg_BLOWFISH.ixt_alg_id,
+ ipsec_alg_BLOWFISH.ixt_name,
+ ret);
+ if (ret==0 && test) {
+ test_ret=ipsec_alg_test(
+ ipsec_alg_BLOWFISH.ixt_alg_type,
+ ipsec_alg_BLOWFISH.ixt_alg_id,
+ test);
+ printk("ipsec_blowfish_init(alg_type=%d alg_id=%d): test_ret=%d\n",
+ ipsec_alg_BLOWFISH.ixt_alg_type,
+ ipsec_alg_BLOWFISH.ixt_alg_id,
+ test_ret);
+ }
+ return ret;
+}
+IPSEC_ALG_MODULE_EXIT(ipsec_blowfish_fini)
+{
+ unregister_ipsec_alg_enc(&ipsec_alg_BLOWFISH);
+ return;
+}
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+EXPORT_NO_SYMBOLS;
diff --git a/linux/net/ipsec/alg/ipsec_alg_cryptoapi.c b/linux/net/ipsec/alg/ipsec_alg_cryptoapi.c
new file mode 100644
index 000000000..fc68094c2
--- /dev/null
+++ b/linux/net/ipsec/alg/ipsec_alg_cryptoapi.c
@@ -0,0 +1,421 @@
+/*
+ * ipsec_alg to linux cryptoapi GLUE
+ *
+ * Authors: CODE.ar TEAM
+ * Harpo MAxx <harpo@linuxmendoza.org.ar>
+ * JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ * Luciano Ruete <docemeses@softhome.net>
+ *
+ * $Id: ipsec_alg_cryptoapi.c,v 1.3 2004/09/17 18:57:30 as Exp $
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * Example usage:
+ * modinfo -p ipsec_cryptoapi (quite useful info, including supported algos)
+ * modprobe ipsec_cryptoapi
+ * modprobe ipsec_cryptoapi test=1
+ * modprobe ipsec_cryptoapi excl=1 (exclusive cipher/algo)
+ * modprobe ipsec_cryptoapi noauto=1 aes=1 twofish=1 (only these ciphers)
+ * modprobe ipsec_cryptoapi aes=128,128 (force these keylens)
+ * modprobe ipsec_cryptoapi des_ede3=0 (everything but 3DES)
+ */
+#include <linux/config.h>
+#include <linux/version.h>
+
+/*
+ * special case: ipsec core modular with this static algo inside:
+ * must avoid MODULE magic for this file
+ */
+#if CONFIG_IPSEC_MODULE && CONFIG_IPSEC_ALG_CRYPTOAPI
+#undef MODULE
+#endif
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h> /* printk() */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/string.h>
+
+/* Check if __exit is defined, if not null it */
+#ifndef __exit
+#define __exit
+#endif
+
+/* warn the innocent */
+#if !defined (CONFIG_CRYPTO) && !defined (CONFIG_CRYPTO_MODULE)
+#warning "No linux CryptoAPI found, install 2.4.22+ or 2.6.x"
+#define NO_CRYPTOAPI_SUPPORT
+#endif
+/* Low freeswan header coupling */
+#include "freeswan/ipsec_alg.h"
+
+#include <linux/crypto.h>
+#ifdef CRYPTO_API_VERSION_CODE
+#warning "Old CryptoAPI is not supported. Only linux-2.4.22+ or linux-2.6.x are supported"
+#define NO_CRYPTOAPI_SUPPORT
+#endif
+
+#ifdef NO_CRYPTOAPI_SUPPORT
+#warning "Building an unusable module :P"
+/* Catch old CryptoAPI by not allowing module to load */
+IPSEC_ALG_MODULE_INIT( ipsec_cryptoapi_init )
+{
+ printk(KERN_WARNING "ipsec_cryptoapi.o was not built on stock Linux CryptoAPI (2.4.22+ or 2.6.x), not loading.\n");
+ return -EINVAL;
+}
+#else
+#include <asm/scatterlist.h>
+#include <asm/pgtable.h>
+#include <linux/mm.h>
+
+#define CIPHERNAME_AES "aes"
+#define CIPHERNAME_3DES "des3_ede"
+#define CIPHERNAME_BLOWFISH "blowfish"
+#define CIPHERNAME_CAST "cast5"
+#define CIPHERNAME_SERPENT "serpent"
+#define CIPHERNAME_TWOFISH "twofish"
+
+#define ESP_3DES 3
+#define ESP_AES 12
+#define ESP_BLOWFISH 7 /* truly _constant_ :) */
+#define ESP_CAST 6 /* quite constant :) */
+#define ESP_SERPENT 252 /* from ipsec drafts */
+#define ESP_TWOFISH 253 /* from ipsec drafts */
+
+#define AH_MD5 2
+#define AH_SHA 3
+#define DIGESTNAME_MD5 "md5"
+#define DIGESTNAME_SHA1 "sha1"
+
+MODULE_AUTHOR("Juanjo Ciarlante, Harpo MAxx, Luciano Ruete");
+static int debug=0;
+MODULE_PARM(debug, "i");
+static int test=0;
+MODULE_PARM(test, "i");
+static int excl=0;
+MODULE_PARM(excl, "i");
+
+static int noauto = 0;
+MODULE_PARM(noauto,"i");
+MODULE_PARM_DESC(noauto, "Dont try all known algos, just setup enabled ones");
+
+static int des_ede3[] = {-1, -1};
+static int aes[] = {-1, -1};
+static int blowfish[] = {-1, -1};
+static int cast[] = {-1, -1};
+static int serpent[] = {-1, -1};
+static int twofish[] = {-1, -1};
+
+MODULE_PARM(des_ede3,"1-2i");
+MODULE_PARM(aes,"1-2i");
+MODULE_PARM(blowfish,"1-2i");
+MODULE_PARM(cast,"1-2i");
+MODULE_PARM(serpent,"1-2i");
+MODULE_PARM(twofish,"1-2i");
+MODULE_PARM_DESC(des_ede3, "0: disable | 1: force_enable | min,max: dontuse");
+MODULE_PARM_DESC(aes, "0: disable | 1: force_enable | min,max: keybitlens");
+MODULE_PARM_DESC(blowfish, "0: disable | 1: force_enable | min,max: keybitlens");
+MODULE_PARM_DESC(cast, "0: disable | 1: force_enable | min,max: keybitlens");
+MODULE_PARM_DESC(serpent, "0: disable | 1: force_enable | min,max: keybitlens");
+MODULE_PARM_DESC(twofish, "0: disable | 1: force_enable | min,max: keybitlens");
+
+struct ipsec_alg_capi_cipher {
+ const char *ciphername; /* cryptoapi's ciphername */
+ unsigned blocksize;
+ unsigned short minbits;
+ unsigned short maxbits;
+ int *parm; /* lkm param for this cipher */
+ struct ipsec_alg_enc alg; /* note it's not a pointer */
+};
+static struct ipsec_alg_capi_cipher alg_capi_carray[] = {
+ { CIPHERNAME_AES , 16, 128, 256, aes , { ixt_alg_id: ESP_AES, }},
+ { CIPHERNAME_TWOFISH , 16, 128, 256, twofish, { ixt_alg_id: ESP_TWOFISH, }},
+ { CIPHERNAME_SERPENT , 16, 128, 256, serpent, { ixt_alg_id: ESP_SERPENT, }},
+ { CIPHERNAME_CAST , 8, 128, 128, cast , { ixt_alg_id: ESP_CAST, }},
+ { CIPHERNAME_BLOWFISH , 8, 128, 448, blowfish,{ ixt_alg_id: ESP_BLOWFISH, }},
+ { CIPHERNAME_3DES , 8, 192, 192, des_ede3,{ ixt_alg_id: ESP_3DES, }},
+ { NULL, 0, 0, 0, NULL, {} }
+};
+#ifdef NOT_YET
+struct ipsec_alg_capi_digest {
+ const char *digestname; /* cryptoapi's digestname */
+ struct digest_implementation *di;
+ struct ipsec_alg_auth alg; /* note it's not a pointer */
+};
+static struct ipsec_alg_capi_cipher alg_capi_darray[] = {
+ { DIGESTNAME_MD5, NULL, { ixt_alg_id: AH_MD5, }},
+ { DIGESTNAME_SHA1, NULL, { ixt_alg_id: AH_SHA, }},
+ { NULL, NULL, {} }
+};
+#endif
+/*
+ * "generic" linux cryptoapi setup_cipher() function
+ */
+int setup_cipher(const char *ciphername)
+{
+ return crypto_alg_available(ciphername, 0);
+}
+
+/*
+ * setups ipsec_alg_capi_cipher "hyper" struct components, calling
+ * register_ipsec_alg for cointaned ipsec_alg object
+ */
+static void _capi_destroy_key (struct ipsec_alg_enc *alg, __u8 *key_e);
+static __u8 * _capi_new_key (struct ipsec_alg_enc *alg, const __u8 *key, size_t keylen);
+static int _capi_cbc_encrypt(struct ipsec_alg_enc *alg, __u8 * key_e, __u8 * in, int ilen, const __u8 * iv, int encrypt);
+
+static int
+setup_ipsec_alg_capi_cipher(struct ipsec_alg_capi_cipher *cptr)
+{
+ int ret;
+ cptr->alg.ixt_version = IPSEC_ALG_VERSION;
+ cptr->alg.ixt_module = THIS_MODULE;
+ atomic_set (& cptr->alg.ixt_refcnt, 0);
+ strncpy (cptr->alg.ixt_name , cptr->ciphername, sizeof (cptr->alg.ixt_name));
+
+ cptr->alg.ixt_blocksize=cptr->blocksize;
+ cptr->alg.ixt_keyminbits=cptr->minbits;
+ cptr->alg.ixt_keymaxbits=cptr->maxbits;
+ cptr->alg.ixt_state = 0;
+ if (excl) cptr->alg.ixt_state |= IPSEC_ALG_ST_EXCL;
+ cptr->alg.ixt_e_keylen=cptr->alg.ixt_keymaxbits/8;
+ cptr->alg.ixt_e_ctx_size = 0;
+ cptr->alg.ixt_alg_type = IPSEC_ALG_TYPE_ENCRYPT;
+ cptr->alg.ixt_e_new_key = _capi_new_key;
+ cptr->alg.ixt_e_destroy_key = _capi_destroy_key;
+ cptr->alg.ixt_e_cbc_encrypt = _capi_cbc_encrypt;
+ cptr->alg.ixt_data = cptr;
+
+ ret=register_ipsec_alg_enc(&cptr->alg);
+ printk("setup_ipsec_alg_capi_cipher(): "
+ "alg_type=%d alg_id=%d name=%s "
+ "keyminbits=%d keymaxbits=%d, ret=%d\n",
+ cptr->alg.ixt_alg_type,
+ cptr->alg.ixt_alg_id,
+ cptr->alg.ixt_name,
+ cptr->alg.ixt_keyminbits,
+ cptr->alg.ixt_keymaxbits,
+ ret);
+ return ret;
+}
+/*
+ * called in ipsec_sa_wipe() time, will destroy key contexts
+ * and do 1 unbind()
+ */
+static void
+_capi_destroy_key (struct ipsec_alg_enc *alg, __u8 *key_e)
+{
+ struct crypto_tfm *tfm=(struct crypto_tfm*)key_e;
+
+ if (debug > 0)
+ printk(KERN_DEBUG "klips_debug: _capi_destroy_key:"
+ "name=%s key_e=%p \n",
+ alg->ixt_name, key_e);
+ if (!key_e) {
+ printk(KERN_ERR "klips_debug: _capi_destroy_key:"
+ "name=%s NULL key_e!\n",
+ alg->ixt_name);
+ return;
+ }
+ crypto_free_tfm(tfm);
+}
+
+/*
+ * create new key context, need alg->ixt_data to know which
+ * (of many) cipher inside this module is the target
+ */
+static __u8 *
+_capi_new_key (struct ipsec_alg_enc *alg, const __u8 *key, size_t keylen)
+{
+ struct ipsec_alg_capi_cipher *cptr;
+ struct crypto_tfm *tfm=NULL;
+
+ cptr = alg->ixt_data;
+ if (!cptr) {
+ printk(KERN_ERR "_capi_new_key(): "
+ "NULL ixt_data (?!) for \"%s\" algo\n"
+ , alg->ixt_name);
+ goto err;
+ }
+ if (debug > 0)
+ printk(KERN_DEBUG "klips_debug:_capi_new_key:"
+ "name=%s cptr=%p key=%p keysize=%d\n",
+ alg->ixt_name, cptr, key, keylen);
+
+ /*
+ * alloc tfm
+ */
+ tfm = crypto_alloc_tfm(cptr->ciphername, CRYPTO_TFM_MODE_CBC);
+ if (!tfm) {
+ printk(KERN_ERR "_capi_new_key(): "
+ "NULL tfm for \"%s\" cryptoapi (\"%s\") algo\n"
+ , alg->ixt_name, cptr->ciphername);
+ goto err;
+ }
+ if (crypto_cipher_setkey(tfm, key, keylen) < 0) {
+ printk(KERN_ERR "_capi_new_key(): "
+ "failed new_key() for \"%s\" cryptoapi algo (keylen=%d)\n"
+ , alg->ixt_name, keylen);
+ crypto_free_tfm(tfm);
+ tfm=NULL;
+ }
+err:
+ if (debug > 0)
+ printk(KERN_DEBUG "klips_debug:_capi_new_key:"
+ "name=%s key=%p keylen=%d tfm=%p\n",
+ alg->ixt_name, key, keylen, tfm);
+ return (__u8 *) tfm;
+}
+/*
+ * core encryption function: will use cx->ci to call actual cipher's
+ * cbc function
+ */
+static int
+_capi_cbc_encrypt(struct ipsec_alg_enc *alg, __u8 * key_e, __u8 * in, int ilen, const __u8 * iv, int encrypt) {
+ int error =0;
+ struct crypto_tfm *tfm=(struct crypto_tfm *)key_e;
+ struct scatterlist sg = {
+ .page = virt_to_page(in),
+ .offset = (unsigned long)(in) % PAGE_SIZE,
+ .length=ilen,
+ };
+ if (debug > 1)
+ printk(KERN_DEBUG "klips_debug:_capi_cbc_encrypt:"
+ "key_e=%p "
+ "in=%p out=%p ilen=%d iv=%p encrypt=%d\n"
+ , key_e
+ , in, in, ilen, iv, encrypt);
+ crypto_cipher_set_iv(tfm, iv, crypto_tfm_alg_ivsize(tfm));
+ if (encrypt)
+ error = crypto_cipher_encrypt (tfm, &sg, &sg, ilen);
+ else
+ error = crypto_cipher_decrypt (tfm, &sg, &sg, ilen);
+ if (debug > 1)
+ printk(KERN_DEBUG "klips_debug:_capi_cbc_encrypt:"
+ "error=%d\n"
+ , error);
+ return (error<0)? error : ilen;
+}
+/*
+ * main initialization loop: for each cipher in list, do
+ * 1) setup cryptoapi cipher else continue
+ * 2) register ipsec_alg object
+ */
+static int
+setup_cipher_list (struct ipsec_alg_capi_cipher* clist)
+{
+ struct ipsec_alg_capi_cipher *cptr;
+ /* foreach cipher in list ... */
+ for (cptr=clist;cptr->ciphername;cptr++) {
+ /*
+ * see if cipher has been disabled (0) or
+ * if noauto set and not enabled (1)
+ */
+ if (cptr->parm[0] == 0 || (noauto && cptr->parm[0] < 0)) {
+ if (debug>0)
+ printk(KERN_INFO "setup_cipher_list(): "
+ "ciphername=%s skipped at user request: "
+ "noauto=%d parm[0]=%d parm[1]=%d\n"
+ , cptr->ciphername
+ , noauto
+ , cptr->parm[0]
+ , cptr->parm[1]);
+ continue;
+ }
+ /*
+ * use a local ci to avoid touching cptr->ci,
+ * if register ipsec_alg success then bind cipher
+ */
+ if( setup_cipher(cptr->ciphername) ) {
+ if (debug > 0)
+ printk(KERN_DEBUG "klips_debug:"
+ "setup_cipher_list():"
+ "ciphername=%s found\n"
+ , cptr->ciphername);
+ if (setup_ipsec_alg_capi_cipher(cptr) == 0) {
+
+
+ } else {
+ printk(KERN_ERR "klips_debug:"
+ "setup_cipher_list():"
+ "ciphername=%s failed ipsec_alg_register\n"
+ , cptr->ciphername);
+ }
+ } else {
+ if (debug>0)
+ printk(KERN_INFO "setup_cipher_list(): lookup for ciphername=%s: not found \n",
+ cptr->ciphername);
+ }
+ }
+ return 0;
+}
+/*
+ * deregister ipsec_alg objects and unbind ciphers
+ */
+static int
+unsetup_cipher_list (struct ipsec_alg_capi_cipher* clist)
+{
+ struct ipsec_alg_capi_cipher *cptr;
+ /* foreach cipher in list ... */
+ for (cptr=clist;cptr->ciphername;cptr++) {
+ if (cptr->alg.ixt_state & IPSEC_ALG_ST_REGISTERED) {
+ unregister_ipsec_alg_enc(&cptr->alg);
+ }
+ }
+ return 0;
+}
+/*
+ * test loop for registered algos
+ */
+static int
+test_cipher_list (struct ipsec_alg_capi_cipher* clist)
+{
+ int test_ret;
+ struct ipsec_alg_capi_cipher *cptr;
+ /* foreach cipher in list ... */
+ for (cptr=clist;cptr->ciphername;cptr++) {
+ if (cptr->alg.ixt_state & IPSEC_ALG_ST_REGISTERED) {
+ test_ret=ipsec_alg_test(
+ cptr->alg.ixt_alg_type,
+ cptr->alg.ixt_alg_id,
+ test);
+ printk("test_cipher_list(alg_type=%d alg_id=%d): test_ret=%d\n",
+ cptr->alg.ixt_alg_type,
+ cptr->alg.ixt_alg_id,
+ test_ret);
+ }
+ }
+ return 0;
+}
+
+IPSEC_ALG_MODULE_INIT( ipsec_cryptoapi_init )
+{
+ int ret, test_ret;
+ if ((ret=setup_cipher_list(alg_capi_carray)) < 0)
+ return -EPROTONOSUPPORT;
+ if (ret==0 && test) {
+ test_ret=test_cipher_list(alg_capi_carray);
+ }
+ return ret;
+}
+IPSEC_ALG_MODULE_EXIT( ipsec_cryptoapi_fini )
+{
+ unsetup_cipher_list(alg_capi_carray);
+ return;
+}
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+EXPORT_NO_SYMBOLS;
+#endif /* NO_CRYPTOAPI_SUPPORT */
diff --git a/linux/net/ipsec/alg/ipsec_alg_serpent.c b/linux/net/ipsec/alg/ipsec_alg_serpent.c
new file mode 100644
index 000000000..1f26b0b01
--- /dev/null
+++ b/linux/net/ipsec/alg/ipsec_alg_serpent.c
@@ -0,0 +1,139 @@
+/*
+ * ipsec_alg SERPENT cipher stubs
+ *
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * $Id: ipsec_alg_serpent.c,v 1.2 2004/03/22 21:53:19 as Exp $
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ */
+#include <linux/config.h>
+#include <linux/version.h>
+
+/*
+ * special case: ipsec core modular with this static algo inside:
+ * must avoid MODULE magic for this file
+ */
+#if CONFIG_IPSEC_MODULE && CONFIG_IPSEC_ALG_SERPENT
+#undef MODULE
+#endif
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h> /* printk() */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/string.h>
+
+/* Check if __exit is defined, if not null it */
+#ifndef __exit
+#define __exit
+#endif
+
+/* Low freeswan header coupling */
+#include "freeswan/ipsec_alg.h"
+#include "libserpent/serpent.h"
+#include "libserpent/serpent_cbc.h"
+
+#define ESP_SERPENT 252 /* from ipsec drafts */
+
+/* 128, 192 or 256 */
+#define ESP_SERPENT_KEY_SZ_MIN 16 /* 128 bit secret key */
+#define ESP_SERPENT_KEY_SZ_MAX 32 /* 256 bit secret key */
+#define ESP_SERPENT_CBC_BLK_LEN 16 /* SERPENT-CBC block size */
+
+MODULE_AUTHOR("JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>");
+static int debug=0;
+MODULE_PARM(debug, "i");
+static int test=0;
+MODULE_PARM(test, "i");
+static int excl=0;
+MODULE_PARM(excl, "i");
+static int keyminbits=0;
+MODULE_PARM(keyminbits, "i");
+static int keymaxbits=0;
+MODULE_PARM(keymaxbits, "i");
+
+static int _serpent_set_key(struct ipsec_alg_enc *alg, __u8 * key_e, const __u8 * key, size_t keysize) {
+ serpent_context *ctx=(serpent_context *)key_e;
+ if (debug > 0)
+ printk(KERN_DEBUG "klips_debug:_serpent_set_key:"
+ "key_e=%p key=%p keysize=%d\n",
+ key_e, key, keysize);
+ serpent_set_key(ctx, key, keysize);
+ return 0;
+}
+static int _serpent_cbc_encrypt(struct ipsec_alg_enc *alg, __u8 * key_e, __u8 * in, int ilen, const __u8 * iv, int encrypt) {
+ serpent_context *ctx=(serpent_context *)key_e;
+ if (debug > 0)
+ printk(KERN_DEBUG "klips_debug:_serpent_cbc_encrypt:"
+ "key_e=%p in=%p ilen=%d iv=%p encrypt=%d\n",
+ key_e, in, ilen, iv, encrypt);
+ serpent_cbc_encrypt(ctx, in, in, ilen, iv, encrypt);
+ return ilen;
+}
+static struct ipsec_alg_enc ipsec_alg_SERPENT = {
+ ixt_version: IPSEC_ALG_VERSION,
+ ixt_module: THIS_MODULE,
+ ixt_refcnt: ATOMIC_INIT(0),
+ ixt_alg_type: IPSEC_ALG_TYPE_ENCRYPT,
+ ixt_alg_id: ESP_SERPENT,
+ ixt_name: "serpent",
+ ixt_blocksize: ESP_SERPENT_CBC_BLK_LEN,
+ ixt_keyminbits: ESP_SERPENT_KEY_SZ_MIN * 8,
+ ixt_keymaxbits: ESP_SERPENT_KEY_SZ_MAX * 8,
+ ixt_e_keylen: ESP_SERPENT_KEY_SZ_MAX,
+ ixt_e_ctx_size: sizeof(serpent_context),
+ ixt_e_set_key: _serpent_set_key,
+ ixt_e_cbc_encrypt:_serpent_cbc_encrypt,
+};
+
+IPSEC_ALG_MODULE_INIT(ipsec_serpent_init)
+{
+ int ret, test_ret;
+ if (keyminbits)
+ ipsec_alg_SERPENT.ixt_keyminbits=keyminbits;
+ if (keymaxbits) {
+ ipsec_alg_SERPENT.ixt_keymaxbits=keymaxbits;
+ if (keymaxbits*8>ipsec_alg_SERPENT.ixt_keymaxbits)
+ ipsec_alg_SERPENT.ixt_e_keylen=keymaxbits*8;
+ }
+ if (excl) ipsec_alg_SERPENT.ixt_state |= IPSEC_ALG_ST_EXCL;
+ ret=register_ipsec_alg_enc(&ipsec_alg_SERPENT);
+ printk("ipsec_serpent_init(alg_type=%d alg_id=%d name=%s): ret=%d\n",
+ ipsec_alg_SERPENT.ixt_alg_type,
+ ipsec_alg_SERPENT.ixt_alg_id,
+ ipsec_alg_SERPENT.ixt_name,
+ ret);
+ if (ret==0 && test) {
+ test_ret=ipsec_alg_test(
+ ipsec_alg_SERPENT.ixt_alg_type,
+ ipsec_alg_SERPENT.ixt_alg_id,
+ test);
+ printk("ipsec_serpent_init(alg_type=%d alg_id=%d): test_ret=%d\n",
+ ipsec_alg_SERPENT.ixt_alg_type,
+ ipsec_alg_SERPENT.ixt_alg_id,
+ test_ret);
+ }
+ return ret;
+}
+IPSEC_ALG_MODULE_EXIT(ipsec_serpent_fini)
+{
+ unregister_ipsec_alg_enc(&ipsec_alg_SERPENT);
+ return;
+}
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+EXPORT_NO_SYMBOLS;
diff --git a/linux/net/ipsec/alg/ipsec_alg_sha2.c b/linux/net/ipsec/alg/ipsec_alg_sha2.c
new file mode 100644
index 000000000..548585c16
--- /dev/null
+++ b/linux/net/ipsec/alg/ipsec_alg_sha2.c
@@ -0,0 +1,185 @@
+/*
+ * ipsec_alg SHA2 hash stubs
+ *
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * $Id: ipsec_alg_sha2.c,v 1.2 2004/03/22 21:53:19 as Exp $
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ */
+#include <linux/config.h>
+#include <linux/version.h>
+
+/*
+ * special case: ipsec core modular with this static algo inside:
+ * must avoid MODULE magic for this file
+ */
+#if CONFIG_IPSEC_MODULE && CONFIG_IPSEC_ALG_SHA2
+#undef MODULE
+#endif
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h> /* printk() */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/string.h>
+
+/* Check if __exit is defined, if not null it */
+#ifndef __exit
+#define __exit
+#endif
+
+/* Low freeswan header coupling */
+#include "freeswan/ipsec_alg.h"
+#include "libsha2/sha2.h"
+#include "libsha2/hmac_sha2.h"
+
+MODULE_AUTHOR("JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>");
+static int debug=0;
+MODULE_PARM(debug, "i");
+static int test=0;
+MODULE_PARM(test, "i");
+static int excl=0;
+MODULE_PARM(excl, "i");
+
+/* almost constants ...: draft-ietf-ipsec-ciph-aes-cbc-03.txt */
+#define AH_SHA2_256 5
+#define AH_SHA2_384 6
+#define AH_SHA2_512 7
+
+static int _sha256_hmac_set_key(struct ipsec_alg_auth *alg, __u8 * key_a, const __u8 * key, int keylen) {
+ sha256_hmac_context *hctx=(sha256_hmac_context*)(key_a);
+ sha256_hmac_set_key(hctx, key, keylen);
+ if (debug > 0)
+ printk(KERN_DEBUG "klips_debug: _sha256_hmac_set_key(): "
+ "key_a=%p key=%p keysize=%d\n",
+ key_a, key, keylen);
+ return 0;
+}
+static int _sha256_hmac_hash(struct ipsec_alg_auth *alg, __u8 * key_a, const __u8 * dat, int len, __u8 * hash, int hashlen) {
+ sha256_hmac_context *hctx=(sha256_hmac_context*)(key_a);
+ if (debug > 0)
+ printk(KERN_DEBUG "klips_debug: _sha256_hmac_hash(): "
+ "key_a=%p dat=%p len=%d hash=%p hashlen=%d\n",
+ key_a, dat, len, hash, hashlen);
+ sha256_hmac_hash(hctx, dat, len, hash, hashlen);
+ return 0;
+}
+static int _sha512_hmac_set_key(struct ipsec_alg_auth *alg, __u8 * key_a, const __u8 * key, int keylen) {
+ sha512_hmac_context *hctx=(sha512_hmac_context*)(key_a);
+ sha512_hmac_set_key(hctx, key, keylen);
+ if (debug > 0)
+ printk(KERN_DEBUG "klips_debug: _sha512_hmac_set_key(): "
+ "key_a=%p key=%p keysize=%d\n",
+ key_a, key, keylen);
+ return 0;
+}
+static int _sha512_hmac_hash(struct ipsec_alg_auth *alg, __u8 * key_a, const __u8 * dat, int len, __u8 * hash, int hashlen) {
+ sha512_hmac_context *hctx=(sha512_hmac_context*)(key_a);
+ if (debug > 0)
+ printk(KERN_DEBUG "klips_debug: _sha512_hmac_hash(): "
+ "key_a=%p dat=%p len=%d hash=%p hashlen=%d\n",
+ key_a, dat, len, hash, hashlen);
+ sha512_hmac_hash(hctx, dat, len, hash, hashlen);
+ return 0;
+}
+static struct ipsec_alg_auth ipsec_alg_SHA2_256 = {
+ ixt_version: IPSEC_ALG_VERSION,
+ ixt_module: THIS_MODULE,
+ ixt_refcnt: ATOMIC_INIT(0),
+ ixt_alg_type: IPSEC_ALG_TYPE_AUTH,
+ ixt_alg_id: AH_SHA2_256,
+ ixt_name: "sha2_256",
+ ixt_blocksize: SHA256_BLOCKSIZE,
+ ixt_keyminbits: 256,
+ ixt_keymaxbits: 256,
+ ixt_a_keylen: 256/8,
+ ixt_a_ctx_size: sizeof(sha256_hmac_context),
+ ixt_a_hmac_set_key: _sha256_hmac_set_key,
+ ixt_a_hmac_hash: _sha256_hmac_hash,
+};
+static struct ipsec_alg_auth ipsec_alg_SHA2_512 = {
+ ixt_version: IPSEC_ALG_VERSION,
+ ixt_module: THIS_MODULE,
+ ixt_refcnt: ATOMIC_INIT(0),
+ ixt_alg_type: IPSEC_ALG_TYPE_AUTH,
+ ixt_alg_id: AH_SHA2_512,
+ ixt_name: "sha2_512",
+ ixt_blocksize: SHA512_BLOCKSIZE,
+ ixt_keyminbits: 512,
+ ixt_keymaxbits: 512,
+ ixt_a_keylen: 512/8,
+ ixt_a_ctx_size: sizeof(sha512_hmac_context),
+ ixt_a_hmac_set_key: _sha512_hmac_set_key,
+ ixt_a_hmac_hash: _sha512_hmac_hash,
+};
+
+IPSEC_ALG_MODULE_INIT( ipsec_sha2_init )
+{
+ int ret, test_ret;
+ if (excl) ipsec_alg_SHA2_256.ixt_state |= IPSEC_ALG_ST_EXCL;
+ ret=register_ipsec_alg_auth(&ipsec_alg_SHA2_256);
+ printk("ipsec_sha2_init(alg_type=%d alg_id=%d name=%s): ret=%d\n",
+ ipsec_alg_SHA2_256.ixt_alg_type,
+ ipsec_alg_SHA2_256.ixt_alg_id,
+ ipsec_alg_SHA2_256.ixt_name,
+ ret);
+ if (ret != 0)
+ goto out;
+ if (ret==0 && test) {
+ test_ret=ipsec_alg_test(
+ ipsec_alg_SHA2_256.ixt_alg_type,
+ ipsec_alg_SHA2_256.ixt_alg_id,
+ test);
+ printk("ipsec_sha2_init(alg_type=%d alg_id=%d): test_ret=%d\n",
+ ipsec_alg_SHA2_256.ixt_alg_type,
+ ipsec_alg_SHA2_256.ixt_alg_id,
+ test_ret);
+ }
+ if (excl) ipsec_alg_SHA2_512.ixt_state |= IPSEC_ALG_ST_EXCL;
+ ret=register_ipsec_alg_auth(&ipsec_alg_SHA2_512);
+ printk("ipsec_sha2_init(alg_type=%d alg_id=%d name=%s): ret=%d\n",
+ ipsec_alg_SHA2_512.ixt_alg_type,
+ ipsec_alg_SHA2_512.ixt_alg_id,
+ ipsec_alg_SHA2_512.ixt_name,
+ ret);
+ if (ret != 0)
+ goto out_256;
+ if (ret==0 && test) {
+ test_ret=ipsec_alg_test(
+ ipsec_alg_SHA2_512.ixt_alg_type,
+ ipsec_alg_SHA2_512.ixt_alg_id,
+ test);
+ printk("ipsec_sha2_init(alg_type=%d alg_id=%d): test_ret=%d\n",
+ ipsec_alg_SHA2_512.ixt_alg_type,
+ ipsec_alg_SHA2_512.ixt_alg_id,
+ test_ret);
+ }
+ goto out;
+out_256:
+ unregister_ipsec_alg_auth(&ipsec_alg_SHA2_256);
+out:
+ return ret;
+}
+IPSEC_ALG_MODULE_EXIT( ipsec_sha2_fini )
+{
+ unregister_ipsec_alg_auth(&ipsec_alg_SHA2_512);
+ unregister_ipsec_alg_auth(&ipsec_alg_SHA2_256);
+ return;
+}
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+EXPORT_NO_SYMBOLS;
diff --git a/linux/net/ipsec/alg/ipsec_alg_twofish.c b/linux/net/ipsec/alg/ipsec_alg_twofish.c
new file mode 100644
index 000000000..dfeba1f1b
--- /dev/null
+++ b/linux/net/ipsec/alg/ipsec_alg_twofish.c
@@ -0,0 +1,138 @@
+/*
+ * ipsec_alg TWOFISH cipher stubs
+ *
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * $Id: ipsec_alg_twofish.c,v 1.2 2004/03/22 21:53:19 as Exp $
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ */
+#include <linux/config.h>
+#include <linux/version.h>
+
+/*
+ * special case: ipsec core modular with this static algo inside:
+ * must avoid MODULE magic for this file
+ */
+#if CONFIG_IPSEC_MODULE && CONFIG_IPSEC_ALG_TWOFISH
+#undef MODULE
+#endif
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h> /* printk() */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/string.h>
+
+/* Check if __exit is defined, if not null it */
+#ifndef __exit
+#define __exit
+#endif
+
+/* Low freeswan header coupling */
+#include "freeswan/ipsec_alg.h"
+#include "libtwofish/twofish.h"
+#include "libtwofish/twofish_cbc.h"
+
+#define ESP_TWOFISH 253 /* from ipsec drafts */
+
+/* 128, 192 or 256 */
+#define ESP_TWOFISH_KEY_SZ_MIN 16 /* 128 bit secret key */
+#define ESP_TWOFISH_KEY_SZ_MAX 32 /* 256 bit secret key */
+#define ESP_TWOFISH_CBC_BLK_LEN 16 /* TWOFISH-CBC block size */
+
+MODULE_AUTHOR("JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>");
+static int debug=0;
+MODULE_PARM(debug, "i");
+static int test=0;
+MODULE_PARM(test, "i");
+static int excl=0;
+MODULE_PARM(excl, "i");
+static int keyminbits=0;
+MODULE_PARM(keyminbits, "i");
+static int keymaxbits=0;
+MODULE_PARM(keymaxbits, "i");
+
+static int _twofish_set_key(struct ipsec_alg_enc *alg, __u8 * key_e, const __u8 * key, size_t keysize) {
+ twofish_context *ctx=(twofish_context *)key_e;
+ if (debug > 0)
+ printk(KERN_DEBUG "klips_debug:_twofish_set_key:"
+ "key_e=%p key=%p keysize=%d\n",
+ key_e, key, keysize);
+ twofish_set_key(ctx, key, keysize);
+ return 0;
+}
+static int _twofish_cbc_encrypt(struct ipsec_alg_enc *alg, __u8 * key_e, __u8 * in, int ilen, const __u8 * iv, int encrypt) {
+ twofish_context *ctx=(twofish_context *)key_e;
+ if (debug > 0)
+ printk(KERN_DEBUG "klips_debug:_twofish_cbc_encrypt:"
+ "key_e=%p in=%p ilen=%d iv=%p encrypt=%d\n",
+ key_e, in, ilen, iv, encrypt);
+ twofish_cbc_encrypt(ctx, in, in, ilen, iv, encrypt);
+ return ilen;
+}
+static struct ipsec_alg_enc ipsec_alg_TWOFISH = {
+ ixt_version: IPSEC_ALG_VERSION,
+ ixt_module: THIS_MODULE,
+ ixt_refcnt: ATOMIC_INIT(0),
+ ixt_alg_type: IPSEC_ALG_TYPE_ENCRYPT,
+ ixt_alg_id: ESP_TWOFISH,
+ ixt_name: "twofish",
+ ixt_blocksize: ESP_TWOFISH_CBC_BLK_LEN,
+ ixt_keyminbits: ESP_TWOFISH_KEY_SZ_MIN * 8,
+ ixt_keymaxbits: ESP_TWOFISH_KEY_SZ_MAX * 8,
+ ixt_e_keylen: ESP_TWOFISH_KEY_SZ_MAX,
+ ixt_e_ctx_size: sizeof(twofish_context),
+ ixt_e_set_key: _twofish_set_key,
+ ixt_e_cbc_encrypt:_twofish_cbc_encrypt,
+};
+
+IPSEC_ALG_MODULE_INIT( ipsec_twofish_init )
+{
+ int ret, test_ret;
+ if (keyminbits)
+ ipsec_alg_TWOFISH.ixt_keyminbits=keyminbits;
+ if (keymaxbits) {
+ ipsec_alg_TWOFISH.ixt_keymaxbits=keymaxbits;
+ if (keymaxbits*8>ipsec_alg_TWOFISH.ixt_keymaxbits)
+ ipsec_alg_TWOFISH.ixt_e_keylen=keymaxbits*8;
+ }
+ if (excl) ipsec_alg_TWOFISH.ixt_state |= IPSEC_ALG_ST_EXCL;
+ ret=register_ipsec_alg_enc(&ipsec_alg_TWOFISH);
+ printk("ipsec_twofish_init(alg_type=%d alg_id=%d name=%s): ret=%d\n",
+ ipsec_alg_TWOFISH.ixt_alg_type,
+ ipsec_alg_TWOFISH.ixt_alg_id,
+ ipsec_alg_TWOFISH.ixt_name, ret);
+ if (ret==0 && test) {
+ test_ret=ipsec_alg_test(
+ ipsec_alg_TWOFISH.ixt_alg_type,
+ ipsec_alg_TWOFISH.ixt_alg_id,
+ test);
+ printk("ipsec_twofish_init(alg_type=%d alg_id=%d): test_ret=%d\n",
+ ipsec_alg_TWOFISH.ixt_alg_type,
+ ipsec_alg_TWOFISH.ixt_alg_id,
+ ret);
+ }
+ return ret;
+}
+IPSEC_ALG_MODULE_EXIT( ipsec_twofish_fini )
+{
+ unregister_ipsec_alg_enc(&ipsec_alg_TWOFISH);
+ return;
+}
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
+#endif
diff --git a/linux/net/ipsec/alg/scripts/mk-static_init.c.sh b/linux/net/ipsec/alg/scripts/mk-static_init.c.sh
new file mode 100644
index 000000000..8a17c670e
--- /dev/null
+++ b/linux/net/ipsec/alg/scripts/mk-static_init.c.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+cat << EOF
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include "freeswan/ipsec_alg.h"
+$(for i in $*; do
+ test -z "$i" && continue
+ echo "extern int $i(void);"
+done)
+void ipsec_alg_static_init(void){
+ int __attribute__ ((unused)) err=0;
+$(for i in $*; do
+ test -z "$i" && continue
+ echo " if ((err=$i()) < 0)"
+ echo " printk(KERN_WARNING \"$i() returned %d\", err);"
+done)
+}
+EOF
diff --git a/linux/net/ipsec/defconfig b/linux/net/ipsec/defconfig
new file mode 100644
index 000000000..84be04318
--- /dev/null
+++ b/linux/net/ipsec/defconfig
@@ -0,0 +1,140 @@
+
+#
+# RCSID $Id: defconfig,v 1.2 2004/03/22 21:53:19 as Exp $
+#
+
+#
+# FreeS/WAN IPSec implementation, KLIPS kernel config defaults
+#
+
+#
+# First, lets override stuff already set or not in the kernel config.
+#
+# We can't even think about leaving this off...
+CONFIG_INET=y
+
+#
+# This must be on for subnet protection.
+CONFIG_IP_FORWARD=y
+
+# Shut off IPSEC masquerading if it has been enabled, since it will
+# break the compile. IPPROTO_ESP and IPPROTO_AH were included in
+# net/ipv4/ip_masq.c when they should have gone into include/linux/in.h.
+CONFIG_IP_MASQUERADE_IPSEC=n
+
+#
+# Next, lets set the recommended FreeS/WAN configuration.
+#
+
+# To config as static (preferred), 'y'. To config as module, 'm'.
+CONFIG_IPSEC=y
+
+# To do tunnel mode IPSec, this must be enabled.
+CONFIG_IPSEC_IPIP=y
+
+# To enable authentication, say 'y'. (Highly recommended)
+CONFIG_IPSEC_AH=y
+
+# Authentication algorithm(s):
+CONFIG_IPSEC_AUTH_HMAC_MD5=y
+CONFIG_IPSEC_AUTH_HMAC_SHA1=y
+
+# To enable encryption, say 'y'. (Highly recommended)
+CONFIG_IPSEC_ESP=y
+
+# Encryption algorithm(s):
+CONFIG_IPSEC_ENC_3DES=y
+
+# modular algo extensions (and new ALGOs)
+CONFIG_IPSEC_ALG=y
+CONFIG_IPSEC_ALG_3DES=m
+CONFIG_IPSEC_ALG_AES=m
+CONFIG_IPSEC_ALG_TWOFISH=m
+CONFIG_IPSEC_ALG_BLOWFISH=m
+CONFIG_IPSEC_ALG_SERPENT=m
+CONFIG_IPSEC_ALG_MD5=m
+CONFIG_IPSEC_ALG_SHA1=m
+CONFIG_IPSEC_ALG_SHA2=m
+#CONFIG_IPSEC_ALG_CAST=n
+#CONFIG_IPSEC_ALG_NULL=n
+
+# Use CryptoAPI for ALG?
+CONFIG_IPSEC_ALG_CRYPTOAPI=m
+
+
+# IP Compression: new, probably still has minor bugs.
+CONFIG_IPSEC_IPCOMP=y
+
+# To enable userspace-switchable KLIPS debugging, say 'y'.
+CONFIG_IPSEC_DEBUG=y
+
+# NAT Traversal
+CONFIG_IPSEC_NAT_TRAVERSAL=y
+
+#
+#
+# $Log: defconfig,v $
+# Revision 1.2 2004/03/22 21:53:19 as
+# merged alg-0.8.1 branch with HEAD
+#
+# Revision 1.1.2.1.2.1 2004/03/16 09:48:19 as
+# alg-0.8.1rc12 patch merged
+#
+# Revision 1.1.2.1 2004/03/15 22:30:06 as
+# nat-0.6c patch merged
+#
+# Revision 1.1 2004/03/15 20:35:26 as
+# added files from freeswan-2.04-x509-1.5.3
+#
+# Revision 1.22 2003/02/24 19:37:27 mcr
+# changed default compilation mode to static.
+#
+# Revision 1.21 2002/04/24 07:36:27 mcr
+# Moved from ./klips/net/ipsec/defconfig,v
+#
+# Revision 1.20 2002/04/02 04:07:40 mcr
+# default build is now 'm'odule for KLIPS
+#
+# Revision 1.19 2002/03/08 18:57:17 rgb
+# Added a blank line at the beginning of the file to make it easier for
+# other projects to patch ./arch/i386/defconfig, for example
+# LIDS+grSecurity requested by Jason Pattie.
+#
+# Revision 1.18 2000/11/30 17:26:56 rgb
+# Cleaned out unused options and enabled ipcomp by default.
+#
+# Revision 1.17 2000/09/15 11:37:01 rgb
+# Merge in heavily modified Svenning Soerensen's <svenning@post5.tele.dk>
+# IPCOMP zlib deflate code.
+#
+# Revision 1.16 2000/09/08 19:12:55 rgb
+# Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
+#
+# Revision 1.15 2000/05/24 19:37:13 rgb
+# *** empty log message ***
+#
+# Revision 1.14 2000/05/11 21:14:57 henry
+# just commenting the FOOBAR=y lines out is not enough
+#
+# Revision 1.13 2000/05/10 20:17:58 rgb
+# Comment out netlink defaults, which are no longer needed.
+#
+# Revision 1.12 2000/05/10 19:13:38 rgb
+# Added configure option to shut off no eroute passthrough.
+#
+# Revision 1.11 2000/03/16 07:09:46 rgb
+# Hardcode PF_KEYv2 support.
+# Disable IPSEC_ICMP by default.
+# Remove DES config option from defaults file.
+#
+# Revision 1.10 2000/01/11 03:09:42 rgb
+# Added a default of 'y' to PF_KEYv2 keying I/F.
+#
+# Revision 1.9 1999/05/08 21:23:12 rgb
+# Added support for 2.2.x kernels.
+#
+# Revision 1.8 1999/04/06 04:54:25 rgb
+# Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+# patch shell fixes.
+#
+#
diff --git a/linux/net/ipsec/ipcomp.c b/linux/net/ipsec/ipcomp.c
new file mode 100644
index 000000000..ff12f2cdd
--- /dev/null
+++ b/linux/net/ipsec/ipcomp.c
@@ -0,0 +1,725 @@
+/*
+ * IPCOMP zlib interface code.
+ * Copyright (C) 2000 Svenning Soerensen <svenning@post5.tele.dk>
+ * Copyright (C) 2000, 2001 Richard Guy Briggs <rgb@conscoop.ottawa.on.ca>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+char ipcomp_c_version[] = "RCSID $Id: ipcomp.c,v 1.2 2004/06/13 19:57:49 as Exp $";
+
+/* SSS */
+
+#include <linux/config.h>
+#include <linux/version.h>
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/kernel.h> /* printk() */
+
+#include "freeswan/ipsec_param.h"
+
+#ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+#else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+#endif /* MALLOC_SLAB */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/ip.h>
+#include <linux/skbuff.h>
+
+#include <linux/netdevice.h> /* struct device, and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/ip.h> /* struct iphdr */
+#include <linux/skbuff.h>
+
+#include <freeswan.h>
+
+#ifdef NET_21
+# include <net/dst.h>
+# include <asm/uaccess.h>
+# include <linux/in6.h>
+# define proto_priv cb
+#endif /* NET21 */
+#include <asm/checksum.h>
+#include <net/ip.h>
+
+#include "freeswan/radij.h"
+#include "freeswan/ipsec_encap.h"
+#include "freeswan/ipsec_sa.h"
+
+#include "freeswan/ipsec_xform.h"
+#include "freeswan/ipsec_tunnel.h"
+#include "freeswan/ipsec_rcv.h" /* sysctl_ipsec_inbound_policy_check */
+#include "freeswan/ipcomp.h"
+#include "zlib/zlib.h"
+#include "zlib/zutil.h"
+
+#include <pfkeyv2.h> /* SADB_X_CALG_DEFLATE */
+
+#ifdef CONFIG_IPSEC_DEBUG
+int sysctl_ipsec_debug_ipcomp = 0;
+#endif /* CONFIG_IPSEC_DEBUG */
+
+static
+struct sk_buff *skb_copy_ipcomp(struct sk_buff *skb, int data_growth, int gfp_mask);
+
+static
+voidpf my_zcalloc(voidpf opaque, uInt items, uInt size)
+{
+ return (voidpf) kmalloc(items*size, GFP_ATOMIC);
+}
+
+static
+void my_zfree(voidpf opaque, voidpf address)
+{
+ kfree(address);
+}
+
+struct sk_buff *skb_compress(struct sk_buff *skb, struct ipsec_sa *ips, unsigned int *flags)
+{
+ struct iphdr *iph;
+ unsigned int iphlen, pyldsz, cpyldsz;
+ unsigned char *buffer;
+ z_stream zs;
+ int zresult;
+
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_debug:skb_compress: .\n");
+
+ if(skb == NULL) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_debug:skb_compress: "
+ "passed in NULL skb, returning ERROR.\n");
+ if(flags != NULL) {
+ *flags |= IPCOMP_PARMERROR;
+ }
+ return skb;
+ }
+
+ if(ips == NULL) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_debug:skb_compress: "
+ "passed in NULL ipsec_sa needed for cpi, returning ERROR.\n");
+ if(flags) {
+ *flags |= IPCOMP_PARMERROR;
+ }
+ return skb;
+ }
+
+ if (flags == NULL) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_debug:skb_compress: "
+ "passed in NULL flags, returning ERROR.\n");
+ ipsec_kfree_skb(skb);
+ return NULL;
+ }
+
+#ifdef NET_21
+ iph = skb->nh.iph;
+#else /* NET_21 */
+ iph = skb->ip_hdr;
+#endif /* NET_21 */
+
+ switch (iph->protocol) {
+ case IPPROTO_COMP:
+ case IPPROTO_AH:
+ case IPPROTO_ESP:
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_debug:skb_compress: "
+ "skipping compression of packet with ip protocol %d.\n",
+ iph->protocol);
+ *flags |= IPCOMP_UNCOMPRESSABLE;
+ return skb;
+ }
+
+ /* Don't compress packets already fragmented */
+ if (iph->frag_off & __constant_htons(IP_MF | IP_OFFSET)) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_debug:skb_compress: "
+ "skipping compression of fragmented packet.\n");
+ *flags |= IPCOMP_UNCOMPRESSABLE;
+ return skb;
+ }
+
+ iphlen = iph->ihl << 2;
+ pyldsz = ntohs(iph->tot_len) - iphlen;
+
+ /* Don't compress less than 90 bytes (rfc 2394) */
+ if (pyldsz < 90) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_debug:skb_compress: "
+ "skipping compression of tiny packet, len=%d.\n",
+ pyldsz);
+ *flags |= IPCOMP_UNCOMPRESSABLE;
+ return skb;
+ }
+
+ /* Adaptive decision */
+ if (ips->ips_comp_adapt_skip) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_debug:skb_compress: "
+ "skipping compression: ips_comp_adapt_skip=%d.\n",
+ ips->ips_comp_adapt_skip);
+ ips->ips_comp_adapt_skip--;
+ *flags |= IPCOMP_UNCOMPRESSABLE;
+ return skb;
+ }
+
+ zs.zalloc = my_zcalloc;
+ zs.zfree = my_zfree;
+ zs.opaque = 0;
+
+ /* We want to use deflateInit2 because we don't want the adler
+ header. */
+ zresult = deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -11,
+ DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
+ if (zresult != Z_OK) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_error:skb_compress: "
+ "deflateInit2() returned error %d (%s), "
+ "skipping compression.\n",
+ zresult,
+ zs.msg ? zs.msg : zError(zresult));
+ *flags |= IPCOMP_COMPRESSIONERROR;
+ return skb;
+ }
+
+
+ /* Max output size. Result should be max this size.
+ * Implementation specific tweak:
+ * If it's not at least 32 bytes and 6.25% smaller than
+ * the original packet, it's probably not worth wasting
+ * the receiver's CPU cycles decompressing it.
+ * Your mileage may vary.
+ */
+ cpyldsz = pyldsz - sizeof(struct ipcomphdr) - (pyldsz <= 512 ? 32 : pyldsz >> 4);
+
+ buffer = kmalloc(cpyldsz, GFP_ATOMIC);
+ if (!buffer) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_error:skb_compress: "
+ "unable to kmalloc(%d, GFP_ATOMIC), "
+ "skipping compression.\n",
+ cpyldsz);
+ *flags |= IPCOMP_COMPRESSIONERROR;
+ deflateEnd(&zs);
+ return skb;
+ }
+
+#ifdef CONFIG_IPSEC_DEBUG
+ if(sysctl_ipsec_debug_ipcomp && sysctl_ipsec_debug_verbose) {
+ __u8 *c;
+ int i;
+
+ c = (__u8*)iph + iphlen;
+ for(i = 0; i < pyldsz; i++, c++) {
+ if(!(i % 16)) {
+ printk(KERN_INFO "skb_compress: before:");
+ }
+ printk("%02x ", *c);
+ if(!((i + 1) % 16)) {
+ printk("\n");
+ }
+ }
+ if(i % 16) {
+ printk("\n");
+ }
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+
+ zs.next_in = (char *) iph + iphlen; /* start of payload */
+ zs.avail_in = pyldsz;
+ zs.next_out = buffer; /* start of compressed payload */
+ zs.avail_out = cpyldsz;
+
+ /* Finish compression in one step */
+ zresult = deflate(&zs, Z_FINISH);
+
+ /* Free all dynamically allocated buffers */
+ deflateEnd(&zs);
+ if (zresult != Z_STREAM_END) {
+ *flags |= IPCOMP_UNCOMPRESSABLE;
+ kfree(buffer);
+
+ /* Adjust adaptive counters */
+ if (++(ips->ips_comp_adapt_tries) == IPCOMP_ADAPT_INITIAL_TRIES) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_debug:skb_compress: "
+ "first %d packets didn't compress, "
+ "skipping next %d\n",
+ IPCOMP_ADAPT_INITIAL_TRIES,
+ IPCOMP_ADAPT_INITIAL_SKIP);
+ ips->ips_comp_adapt_skip = IPCOMP_ADAPT_INITIAL_SKIP;
+ }
+ else if (ips->ips_comp_adapt_tries == IPCOMP_ADAPT_INITIAL_TRIES + IPCOMP_ADAPT_SUBSEQ_TRIES) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_debug:skb_compress: "
+ "next %d packets didn't compress, "
+ "skipping next %d\n",
+ IPCOMP_ADAPT_SUBSEQ_TRIES,
+ IPCOMP_ADAPT_SUBSEQ_SKIP);
+ ips->ips_comp_adapt_skip = IPCOMP_ADAPT_SUBSEQ_SKIP;
+ ips->ips_comp_adapt_tries = IPCOMP_ADAPT_INITIAL_TRIES;
+ }
+
+ return skb;
+ }
+
+ /* resulting compressed size */
+ cpyldsz -= zs.avail_out;
+
+ /* Insert IPCOMP header */
+ ((struct ipcomphdr*) ((char*) iph + iphlen))->ipcomp_nh = iph->protocol;
+ ((struct ipcomphdr*) ((char*) iph + iphlen))->ipcomp_flags = 0;
+ /* use the bottom 16 bits of the spi for the cpi. The top 16 bits are
+ for internal reference only. */
+ ((struct ipcomphdr*) (((char*)iph) + iphlen))->ipcomp_cpi = htons((__u16)(ntohl(ips->ips_said.spi) & 0x0000ffff));
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_debug:skb_compress: "
+ "spi=%08x, spi&0xffff=%04x, cpi=%04x, payload size: raw=%d, comp=%d.\n",
+ ntohl(ips->ips_said.spi),
+ ntohl(ips->ips_said.spi) & 0x0000ffff,
+ ntohs(((struct ipcomphdr*)(((char*)iph)+iphlen))->ipcomp_cpi),
+ pyldsz,
+ cpyldsz);
+
+ /* Update IP header */
+ iph->protocol = IPPROTO_COMP;
+ iph->tot_len = htons(iphlen + sizeof(struct ipcomphdr) + cpyldsz);
+#if 1 /* XXX checksum is done by ipsec_tunnel ? */
+ iph->check = 0;
+ iph->check = ip_fast_csum((char *) iph, iph->ihl);
+#endif
+
+ /* Copy compressed payload */
+ memcpy((char *) iph + iphlen + sizeof(struct ipcomphdr),
+ buffer,
+ cpyldsz);
+ kfree(buffer);
+
+ /* Update skb length/tail by "unputting" the shrinkage */
+ skb_put(skb,
+ cpyldsz + sizeof(struct ipcomphdr) - pyldsz);
+
+#ifdef CONFIG_IPSEC_DEBUG
+ if(sysctl_ipsec_debug_ipcomp && sysctl_ipsec_debug_verbose) {
+ __u8 *c;
+ int i;
+
+ c = (__u8*)iph + iphlen + sizeof(struct ipcomphdr);
+ for(i = 0; i < cpyldsz; i++, c++) {
+ if(!(i % 16)) {
+ printk(KERN_INFO "skb_compress: result:");
+ }
+ printk("%02x ", *c);
+ if(!((i + 1) % 16)) {
+ printk("\n");
+ }
+ }
+ if(i % 16) {
+ printk("\n");
+ }
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+
+ ips->ips_comp_adapt_skip = 0;
+ ips->ips_comp_adapt_tries = 0;
+
+ return skb;
+}
+
+struct sk_buff *skb_decompress(struct sk_buff *skb, struct ipsec_sa *ips, unsigned int *flags)
+{
+ struct sk_buff *nskb = NULL;
+
+ /* original ip header */
+ struct iphdr *oiph, *iph;
+ unsigned int iphlen, pyldsz, cpyldsz;
+ z_stream zs;
+ int zresult;
+
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_debug:skb_decompress: .\n");
+
+ if(!skb) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_error:skb_decompress: "
+ "passed in NULL skb, returning ERROR.\n");
+ if (flags) *flags |= IPCOMP_PARMERROR;
+ return skb;
+ }
+
+ if(!ips && sysctl_ipsec_inbound_policy_check) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_error:skb_decompress: "
+ "passed in NULL ipsec_sa needed for comp alg, returning ERROR.\n");
+ if (flags) *flags |= IPCOMP_PARMERROR;
+ return skb;
+ }
+
+ if (!flags) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_error:skb_decompress: "
+ "passed in NULL flags, returning ERROR.\n");
+ ipsec_kfree_skb(skb);
+ return NULL;
+ }
+
+#ifdef NET_21
+ oiph = skb->nh.iph;
+#else /* NET_21 */
+ oiph = skb->ip_hdr;
+#endif /* NET_21 */
+
+ iphlen = oiph->ihl << 2;
+
+ if (oiph->protocol != IPPROTO_COMP) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_error:skb_decompress: "
+ "called with non-IPCOMP packet (protocol=%d),"
+ "skipping decompression.\n",
+ oiph->protocol);
+ *flags |= IPCOMP_PARMERROR;
+ return skb;
+ }
+
+ if ( (((struct ipcomphdr*)((char*) oiph + iphlen))->ipcomp_flags != 0)
+ || ((((struct ipcomphdr*) ((char*) oiph + iphlen))->ipcomp_cpi
+ != htons(SADB_X_CALG_DEFLATE))
+ && sysctl_ipsec_inbound_policy_check
+ && (!ips || (ips && (ips->ips_encalg != SADB_X_CALG_DEFLATE)))) ) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_error:skb_decompress: "
+ "called with incompatible IPCOMP packet (flags=%d, "
+ "cpi=%d), ips-compalg=%d, skipping decompression.\n",
+ ntohs(((struct ipcomphdr*) ((char*) oiph + iphlen))->ipcomp_flags),
+ ntohs(((struct ipcomphdr*) ((char*) oiph + iphlen))->ipcomp_cpi),
+ ips ? ips->ips_encalg : 0);
+ *flags |= IPCOMP_PARMERROR;
+
+ return skb;
+ }
+
+ if (ntohs(oiph->frag_off) & ~0x4000) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_error:skb_decompress: "
+ "called with fragmented IPCOMP packet, "
+ "skipping decompression.\n");
+ *flags |= IPCOMP_PARMERROR;
+ return skb;
+ }
+
+ /* original compressed payload size */
+ cpyldsz = ntohs(oiph->tot_len) - iphlen - sizeof(struct ipcomphdr);
+
+ zs.zalloc = my_zcalloc;
+ zs.zfree = my_zfree;
+ zs.opaque = 0;
+
+ zs.next_in = (char *) oiph + iphlen + sizeof(struct ipcomphdr);
+ zs.avail_in = cpyldsz;
+
+ /* Maybe we should be a bit conservative about memory
+ requirements and use inflateInit2 */
+ /* Beware, that this might make us unable to decompress packets
+ from other implementations - HINT: check PGPnet source code */
+ /* We want to use inflateInit2 because we don't want the adler
+ header. */
+ zresult = inflateInit2(&zs, -15);
+ if (zresult != Z_OK) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_error:skb_decompress: "
+ "inflateInit2() returned error %d (%s), "
+ "skipping decompression.\n",
+ zresult,
+ zs.msg ? zs.msg : zError(zresult));
+ *flags |= IPCOMP_DECOMPRESSIONERROR;
+
+ return skb;
+ }
+
+ /* We have no way of knowing the exact length of the resulting
+ decompressed output before we have actually done the decompression.
+ For now, we guess that the packet will not be bigger than the
+ attached ipsec device's mtu or 16260, whichever is biggest.
+ This may be wrong, since the sender's mtu may be bigger yet.
+ XXX This must be dealt with later XXX
+ */
+
+ /* max payload size */
+ pyldsz = skb->dev ? (skb->dev->mtu < 16260 ? 16260 : skb->dev->mtu)
+ : (65520 - iphlen);
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_debug:skb_decompress: "
+ "max payload size: %d\n", pyldsz);
+
+ while (pyldsz > (cpyldsz + sizeof(struct ipcomphdr)) &&
+ (nskb = skb_copy_ipcomp(skb,
+ pyldsz - cpyldsz - sizeof(struct ipcomphdr),
+ GFP_ATOMIC)) == NULL) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_error:skb_decompress: "
+ "unable to skb_copy_ipcomp(skb, %d, GFP_ATOMIC), "
+ "trying with less payload size.\n",
+ (int)(pyldsz - cpyldsz - sizeof(struct ipcomphdr)));
+ pyldsz >>=1;
+ }
+
+ if (!nskb) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_error:skb_decompress: "
+ "unable to allocate memory, dropping packet.\n");
+ *flags |= IPCOMP_DECOMPRESSIONERROR;
+ inflateEnd(&zs);
+
+ return skb;
+ }
+
+#ifdef CONFIG_IPSEC_DEBUG
+ if(sysctl_ipsec_debug_ipcomp && sysctl_ipsec_debug_verbose) {
+ __u8 *c;
+ int i;
+
+ c = (__u8*)oiph + iphlen + sizeof(struct ipcomphdr);
+ for(i = 0; i < cpyldsz; i++, c++) {
+ if(!(i % 16)) {
+ printk(KERN_INFO "skb_decompress: before:");
+ }
+ printk("%02x ", *c);
+ if(!((i + 1) % 16)) {
+ printk("\n");
+ }
+ }
+ if(i % 16) {
+ printk("\n");
+ }
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+
+#ifdef NET_21
+ iph = nskb->nh.iph;
+#else /* NET_21 */
+ iph = nskb->ip_hdr;
+#endif /* NET_21 */
+ zs.next_out = (char *)iph + iphlen;
+ zs.avail_out = pyldsz;
+
+ zresult = inflate(&zs, Z_SYNC_FLUSH);
+
+ /* work around a bug in zlib, which sometimes wants to taste an extra
+ * byte when being used in the (undocumented) raw deflate mode.
+ */
+ if (zresult == Z_OK && !zs.avail_in && zs.avail_out) {
+ __u8 zerostuff = 0;
+
+ zs.next_in = &zerostuff;
+ zs.avail_in = 1;
+ zresult = inflate(&zs, Z_FINISH);
+ }
+
+ inflateEnd(&zs);
+ if (zresult != Z_STREAM_END) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_error:skb_decompress: "
+ "inflate() returned error %d (%s), "
+ "skipping decompression.\n",
+ zresult,
+ zs.msg ? zs.msg : zError(zresult));
+ *flags |= IPCOMP_DECOMPRESSIONERROR;
+ ipsec_kfree_skb(nskb);
+
+ return skb;
+ }
+
+ /* Update IP header */
+ /* resulting decompressed size */
+ pyldsz -= zs.avail_out;
+ iph->tot_len = htons(iphlen + pyldsz);
+ iph->protocol = ((struct ipcomphdr*) ((char*) oiph + iphlen))->ipcomp_nh;
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_debug:skb_decompress: "
+ "spi=%08x, spi&0xffff=%04x, cpi=%04x, payload size: comp=%d, raw=%d, nh=%d.\n",
+ ips ? ntohl(ips->ips_said.spi) : 0,
+ ips ? ntohl(ips->ips_said.spi) & 0x0000ffff : 0,
+ ntohs(((struct ipcomphdr*)(((char*)oiph)+iphlen))->ipcomp_cpi),
+ cpyldsz,
+ pyldsz,
+ iph->protocol);
+
+#if 1 /* XXX checksum is done by ipsec_rcv ? */
+ iph->check = 0;
+ iph->check = ip_fast_csum((char*) iph, iph->ihl);
+#endif
+
+ /* Update skb length/tail by "unputting" the unused data area */
+ skb_put(nskb, -zs.avail_out);
+
+ ipsec_kfree_skb(skb);
+
+ if (iph->protocol == IPPROTO_COMP)
+ {
+#ifdef CONFIG_IPSEC_DEBUG
+ if(sysctl_ipsec_debug_ipcomp)
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_debug:skb_decompress: "
+ "Eh? inner packet is also compressed, dropping.\n");
+#endif /* CONFIG_IPSEC_DEBUG */
+
+ ipsec_kfree_skb(nskb);
+ return NULL;
+ }
+
+#ifdef CONFIG_IPSEC_DEBUG
+ if(sysctl_ipsec_debug_ipcomp && sysctl_ipsec_debug_verbose) {
+ __u8 *c;
+ int i;
+
+ c = (__u8*)iph + iphlen;
+ for(i = 0; i < pyldsz; i++, c++) {
+ if(!(i % 16)) {
+ printk(KERN_INFO "skb_decompress: result:");
+ }
+ printk("%02x ", *c);
+ if(!((i + 1) % 16)) {
+ printk("\n");
+ }
+ }
+ if(i % 16) {
+ printk("\n");
+ }
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+
+ return nskb;
+}
+
+
+/* this is derived from skb_copy() in linux 2.2.14 */
+/* May be incompatible with other kernel versions!! */
+static
+struct sk_buff *skb_copy_ipcomp(struct sk_buff *skb, int data_growth, int gfp_mask)
+{
+ struct sk_buff *n;
+ struct iphdr *iph;
+ unsigned long offset;
+ unsigned int iphlen;
+
+ if(!skb) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_debug:skb_copy_ipcomp: "
+ "passed in NULL skb, returning NULL.\n");
+ return NULL;
+ }
+
+ /*
+ * Allocate the copy buffer
+ */
+
+#ifdef NET_21
+ iph = skb->nh.iph;
+#else /* NET_21 */
+ iph = skb->ip_hdr;
+#endif /* NET_21 */
+ if (!iph) return NULL;
+ iphlen = iph->ihl << 2;
+
+ n=alloc_skb(skb->end - skb->head + data_growth, gfp_mask);
+ if(n==NULL)
+ return NULL;
+
+ /*
+ * Shift between the two data areas in bytes
+ */
+
+ offset=n->head-skb->head;
+
+ /* Set the data pointer */
+ skb_reserve(n,skb->data-skb->head);
+ /* Set the tail pointer and length */
+ skb_put(n,skb->len+data_growth);
+ /* Copy the bytes up to and including the ip header */
+ memcpy(n->head,
+ skb->head,
+ ((char *)iph - (char *)skb->head) + iphlen);
+ n->list=NULL;
+ n->next=NULL;
+ n->prev=NULL;
+ n->sk=NULL;
+ n->dev=skb->dev;
+ if (skb->h.raw)
+ n->h.raw=skb->h.raw+offset;
+ else
+ n->h.raw=NULL;
+ n->protocol=skb->protocol;
+#ifdef NET_21
+ n->csum = 0;
+ n->priority=skb->priority;
+ n->dst=dst_clone(skb->dst);
+ n->nh.raw=skb->nh.raw+offset;
+#ifndef NETDEV_23
+ n->is_clone=0;
+#endif /* NETDEV_23 */
+ atomic_set(&n->users, 1);
+ n->destructor = NULL;
+ n->security=skb->security;
+ memcpy(n->cb, skb->cb, sizeof(skb->cb));
+#ifdef CONFIG_IP_FIREWALL
+ n->fwmark = skb->fwmark;
+#endif
+#else /* NET_21 */
+ n->link3=NULL;
+ n->when=skb->when;
+ n->ip_hdr=(struct iphdr *)(((char *)skb->ip_hdr)+offset);
+ n->saddr=skb->saddr;
+ n->daddr=skb->daddr;
+ n->raddr=skb->raddr;
+ n->seq=skb->seq;
+ n->end_seq=skb->end_seq;
+ n->ack_seq=skb->ack_seq;
+ n->acked=skb->acked;
+ n->free=1;
+ n->arp=skb->arp;
+ n->tries=0;
+ n->lock=0;
+ n->users=0;
+ memcpy(n->proto_priv, skb->proto_priv, sizeof(skb->proto_priv));
+#endif /* NET_21 */
+ if (skb->mac.raw)
+ n->mac.raw=skb->mac.raw+offset;
+ else
+ n->mac.raw=NULL;
+#ifndef NETDEV_23
+ n->used=skb->used;
+#endif /* !NETDEV_23 */
+ n->pkt_type=skb->pkt_type;
+#ifndef NETDEV_23
+ n->pkt_bridged=skb->pkt_bridged;
+#endif /* NETDEV_23 */
+ n->ip_summed=0;
+ n->stamp=skb->stamp;
+#ifndef NETDEV_23 /* this seems to have been removed in 2.4 */
+#if defined(CONFIG_SHAPER) || defined(CONFIG_SHAPER_MODULE)
+ n->shapelatency=skb->shapelatency; /* Latency on frame */
+ n->shapeclock=skb->shapeclock; /* Time it should go out */
+ n->shapelen=skb->shapelen; /* Frame length in clocks */
+ n->shapestamp=skb->shapestamp; /* Stamp for shaper */
+ n->shapepend=skb->shapepend; /* Pending */
+#endif /* defined(CONFIG_SHAPER) || defined(CONFIG_SHAPER_MODULE) */
+#endif /* NETDEV_23 */
+#ifdef CONFIG_HIPPI
+ n->private.ifield=skb->private.ifield;
+#endif /* CONFIG_HIPPI */
+
+ return n;
+}
diff --git a/linux/net/ipsec/ipsec_alg.c b/linux/net/ipsec/ipsec_alg.c
new file mode 100644
index 000000000..c402b7e5b
--- /dev/null
+++ b/linux/net/ipsec/ipsec_alg.c
@@ -0,0 +1,927 @@
+/*
+ * Modular extensions service and registration functions
+ *
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * Version: 0.8.1
+ *
+ * $Id: ipsec_alg.c,v 1.4 2004/06/13 19:57:49 as Exp $
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ */
+#ifdef CONFIG_IPSEC_ALG
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/kernel.h> /* printk() */
+
+#include <linux/netdevice.h> /* struct device, and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/ip.h> /* struct iphdr */
+#include <linux/skbuff.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/types.h>
+#include <linux/string.h> /* memcmp() */
+#include <linux/random.h> /* get_random_bytes() */
+#include <linux/errno.h> /* error codes */
+#ifdef SPINLOCK
+# ifdef SPINLOCK_23
+# include <linux/spinlock.h> /* *lock* */
+# else /* SPINLOCK_23 */
+# include <asm/spinlock.h> /* *lock* */
+# endif /* SPINLOCK_23 */
+#endif /* SPINLOCK */
+#ifdef NET_21
+# include <asm/uaccess.h>
+# include <linux/in6.h>
+# define proto_priv cb
+#endif /* NET21 */
+#include "freeswan/ipsec_param.h"
+#include <freeswan.h>
+#include "freeswan/ipsec_sa.h"
+#include "freeswan/radij.h"
+#include "freeswan/ipsec_encap.h"
+#include "freeswan/ipsec_radij.h"
+#include "freeswan/ipsec_xform.h"
+#include "freeswan/ipsec_tunnel.h"
+#include "freeswan/ipsec_rcv.h"
+#if defined(CONFIG_IPSEC_ESP) || defined(CONFIG_IPSEC_AH)
+# include "freeswan/ipsec_ah.h"
+#endif /* defined(CONFIG_IPSEC_ESP) || defined(CONFIG_IPSEC_AH) */
+#ifdef CONFIG_IPSEC_ESP
+# include "freeswan/ipsec_esp.h"
+#endif /* !CONFIG_IPSEC_ESP */
+#ifdef CONFIG_IPSEC_IPCOMP
+# include "freeswan/ipcomp.h"
+#endif /* CONFIG_IPSEC_COMP */
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "freeswan/ipsec_alg.h"
+
+#ifndef CONFIG_IPSEC_ALG
+#error This file _MUST_ be compiled with CONFIG_IPSEC_ALG enabled !
+#endif
+#if SADB_EALG_MAX < 255
+#warning Compiling with limited ESP support ( SADB_EALG_MAX < 256 )
+#endif
+
+static rwlock_t ipsec_alg_lock = RW_LOCK_UNLOCKED;
+#define IPSEC_ALG_HASHSZ 16 /* must be power of 2, even 2^0=1 */
+static struct list_head ipsec_alg_hash_table[IPSEC_ALG_HASHSZ];
+
+/* Old gcc's will fail here */
+#define barf_out(fmt, args...) do { printk(KERN_ERR "%s: (%s) " fmt, __FUNCTION__, ixt->ixt_name , ## args)\
+ ; goto out; } while(0)
+
+/*
+ * Must be already protected by lock
+ */
+static void __ipsec_alg_usage_inc(struct ipsec_alg *ixt) {
+ if (ixt->ixt_module)
+ __MOD_INC_USE_COUNT(ixt->ixt_module);
+ atomic_inc(&ixt->ixt_refcnt);
+}
+static void __ipsec_alg_usage_dec(struct ipsec_alg *ixt) {
+ atomic_dec(&ixt->ixt_refcnt);
+ if (ixt->ixt_module)
+ __MOD_DEC_USE_COUNT(ixt->ixt_module);
+}
+/*
+ * simple hash function, optimized for 0-hash (1 list) special
+ * case
+ */
+#if IPSEC_ALG_HASHSZ > 1
+static inline unsigned ipsec_alg_hashfn(int alg_type, int alg_id) {
+ return ((alg_type^alg_id)&(IPSEC_ALG_HASHSZ-1));
+}
+#else
+#define ipsec_alg_hashfn(x,y) (0)
+#endif
+
+/*****************************************************************
+ *
+ * INTERNAL table handling: insert, delete, find
+ *
+ *****************************************************************/
+
+/*
+ * hash table initialization, called from ipsec_alg_init()
+ */
+static void ipsec_alg_hash_init(void) {
+ struct list_head *head = ipsec_alg_hash_table;
+ int i = IPSEC_ALG_HASHSZ;
+ do {
+ INIT_LIST_HEAD(head);
+ head++;
+ i--;
+ } while (i);
+}
+/*
+ * hash list lookup by {alg_type, alg_id} and table head,
+ * must be already protected by lock
+ */
+static struct ipsec_alg *__ipsec_alg_find(unsigned alg_type, unsigned alg_id, struct list_head * head) {
+ struct list_head *p;
+ struct ipsec_alg *ixt=NULL;
+ for (p=head->next; p!=head; p=p->next) {
+ ixt = list_entry(p, struct ipsec_alg, ixt_list);
+ if (ixt->ixt_alg_type == alg_type && ixt->ixt_alg_id==alg_id) {
+ goto out;
+ }
+ }
+ ixt=NULL;
+out:
+ return ixt;
+}
+/*
+ * inserts (in front) a new entry in hash table,
+ * called from ipsec_alg_register() when new algorithm is registered.
+ */
+static int ipsec_alg_insert(struct ipsec_alg *ixt) {
+ int ret=-EINVAL;
+ unsigned hashval=ipsec_alg_hashfn(ixt->ixt_alg_type, ixt->ixt_alg_id);
+ struct list_head *head= ipsec_alg_hash_table + hashval;
+ struct ipsec_alg *ixt_cur;
+ /* new element must be virgin ... */
+ if (ixt->ixt_list.next != &ixt->ixt_list ||
+ ixt->ixt_list.prev != &ixt->ixt_list) {
+ printk(KERN_ERR "ipsec_alg_insert: ixt object \"%s\" "
+ "list head not initialized\n",
+ ixt->ixt_name);
+ return ret;
+ }
+ write_lock_bh(&ipsec_alg_lock);
+ ixt_cur = __ipsec_alg_find(ixt->ixt_alg_type, ixt->ixt_alg_id, head);
+ /* if previous (current) ipsec_alg found check excl flag of _anyone_ */
+ if (ixt_cur && ((ixt->ixt_state|ixt_cur->ixt_state) & IPSEC_ALG_ST_EXCL))
+ barf_out("ipsec_alg for alg_type=%d, alg_id=%d already exist. "
+ "Not loaded (ret=%d).\n",
+ ixt->ixt_alg_type,
+ ixt->ixt_alg_id, ret=-EEXIST);
+ list_add(&ixt->ixt_list, head);
+ ixt->ixt_state |= IPSEC_ALG_ST_REGISTERED;
+ ret=0;
+out:
+ write_unlock_bh(&ipsec_alg_lock);
+ return ret;
+}
+/*
+ * deletes an existing entry in hash table,
+ * called from ipsec_alg_unregister() when algorithm is unregistered.
+ */
+static int ipsec_alg_delete(struct ipsec_alg *ixt) {
+ write_lock_bh(&ipsec_alg_lock);
+ list_del(&ixt->ixt_list);
+ write_unlock_bh(&ipsec_alg_lock);
+ return 0;
+}
+/*
+ * here @user context (read-only when @kernel bh context)
+ * -> no bh disabling
+ *
+ * called from ipsec_sa_init() -> ipsec_alg_sa_init()
+ */
+static struct ipsec_alg *ipsec_alg_get(int alg_type, int alg_id) {
+ unsigned hashval=ipsec_alg_hashfn(alg_type, alg_id);
+ struct list_head *head= ipsec_alg_hash_table + hashval;
+ struct ipsec_alg *ixt;
+ read_lock(&ipsec_alg_lock);
+ ixt=__ipsec_alg_find(alg_type, alg_id, head);
+ if (ixt) __ipsec_alg_usage_inc(ixt);
+ read_unlock(&ipsec_alg_lock);
+ return ixt;
+}
+
+static void ipsec_alg_put(struct ipsec_alg *ixt) {
+ __ipsec_alg_usage_dec((struct ipsec_alg *)ixt);
+}
+
+/*****************************************************************
+ *
+ * INTERFACE for ENC services: key creation, encrypt function
+ *
+ *****************************************************************/
+
+/*
+ * main encrypt service entry point
+ * called from ipsec_rcv() with encrypt=IPSEC_ALG_DECRYPT and
+ * ipsec_tunnel_start_xmit with encrypt=IPSEC_ALG_ENCRYPT
+ */
+int ipsec_alg_esp_encrypt(struct ipsec_sa *sa_p, __u8 * idat, int ilen, const __u8 * iv, int encrypt) {
+ int ret;
+ struct ipsec_alg_enc *ixt_e=sa_p->ips_alg_enc;
+ KLIPS_PRINT(debug_rcv||debug_tunnel,
+ "klips_debug:ipsec_alg_esp_encrypt: "
+ "entering with encalg=%d, ixt_e=%p\n",
+ sa_p->ips_encalg, ixt_e);
+ if (!ixt_e) {
+ KLIPS_PRINT(debug_rcv||debug_tunnel,
+ "klips_debug:ipsec_alg_esp_encrypt: "
+ "NULL ipsec_alg_enc object\n");
+ return -1;
+ }
+ KLIPS_PRINT(debug_rcv||debug_tunnel,
+ "klips_debug:ipsec_alg_esp_encrypt: "
+ "calling cbc_encrypt encalg=%d "
+ "ips_key_e=%p idat=%p ilen=%d iv=%p, encrypt=%d\n",
+ sa_p->ips_encalg,
+ sa_p->ips_key_e, idat, ilen, iv, encrypt);
+ ret=ixt_e->ixt_e_cbc_encrypt(ixt_e, sa_p->ips_key_e, idat, ilen, iv, encrypt);
+ KLIPS_PRINT(debug_rcv||debug_tunnel,
+ "klips_debug:ipsec_alg_esp_encrypt: "
+ "returned ret=%d\n",
+ ret);
+ return ret;
+}
+/*
+ * encryption key context creation function
+ * called from pfkey_v2_parser.c:pfkey_ips_init()
+ */
+int ipsec_alg_enc_key_create(struct ipsec_sa *sa_p) {
+ int ret=-EINVAL;
+ int keyminbits, keymaxbits;
+ caddr_t ekp;
+ struct ipsec_alg_enc *ixt_e=sa_p->ips_alg_enc;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:ipsec_alg_enc_key_create: "
+ "entering with encalg=%d ixt_e=%p\n",
+ sa_p->ips_encalg, ixt_e);
+ if (!ixt_e) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:ipsec_alg_enc_key_create: "
+ "NULL ipsec_alg_enc object\n");
+ return -EPROTO;
+ }
+
+ /*
+ * grRRR... DES 7bits jurassic stuff ... f*ckk --jjo
+ */
+ switch(ixt_e->ixt_alg_id) {
+ case ESP_3DES:
+ keyminbits=keymaxbits=192;break;
+ case ESP_DES:
+ keyminbits=keymaxbits=64;break;
+ default:
+ keyminbits=ixt_e->ixt_keyminbits;
+ keymaxbits=ixt_e->ixt_keymaxbits;
+ }
+ if(sa_p->ips_key_bits_e<keyminbits ||
+ sa_p->ips_key_bits_e>keymaxbits) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:ipsec_alg_enc_key_create: "
+ "incorrect encryption key size for id=%d: %d bits -- "
+ "must be between %d,%d bits\n" /*octets (bytes)\n"*/,
+ ixt_e->ixt_alg_id,
+ sa_p->ips_key_bits_e, keyminbits, keymaxbits);
+ ret=-EINVAL;
+ goto ixt_out;
+ }
+ /* save encryption key pointer */
+ ekp = sa_p->ips_key_e;
+
+
+ if (ixt_e->ixt_e_new_key) {
+ sa_p->ips_key_e = ixt_e->ixt_e_new_key(ixt_e,
+ ekp, sa_p->ips_key_bits_e/8);
+ ret = (sa_p->ips_key_e)? 0 : -EINVAL;
+ } else {
+ if((sa_p->ips_key_e = (caddr_t)
+ kmalloc((sa_p->ips_key_e_size = ixt_e->ixt_e_ctx_size),
+ GFP_ATOMIC)) == NULL) {
+ ret=-ENOMEM;
+ goto ixt_out;
+ }
+ /* zero-out key_e */
+ memset(sa_p->ips_key_e, 0, sa_p->ips_key_e_size);
+
+ /* I cast here to allow more decoupling in alg module */
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:ipsec_alg_enc_key_create: about to call:"
+ "set_key(key_e=%p, ekp=%p, key_size=%d)\n",
+ (caddr_t)sa_p->ips_key_e, ekp, sa_p->ips_key_bits_e/8);
+ ret = ixt_e->ixt_e_set_key(ixt_e, (caddr_t)sa_p->ips_key_e, ekp, sa_p->ips_key_bits_e/8);
+ }
+ /* paranoid */
+ memset(ekp, 0, sa_p->ips_key_bits_e/8);
+ kfree(ekp);
+ixt_out:
+ return ret;
+}
+
+/***************************************************************
+ *
+ * INTERFACE for AUTH services: key creation, hash functions
+ *
+ ***************************************************************/
+
+/*
+ * auth key context creation function
+ * called from pfkey_v2_parser.c:pfkey_ips_init()
+ */
+int ipsec_alg_auth_key_create(struct ipsec_sa *sa_p) {
+ int ret=-EINVAL;
+ struct ipsec_alg_auth *ixt_a=sa_p->ips_alg_auth;
+ int keyminbits, keymaxbits;
+ unsigned char *akp;
+ unsigned int aks;
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:ipsec_alg_auth_key_create: "
+ "entering with authalg=%d ixt_a=%p\n",
+ sa_p->ips_authalg, ixt_a);
+ if (!ixt_a) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:ipsec_alg_auth_key_create: "
+ "NULL ipsec_alg_auth object\n");
+ return -EPROTO;
+ }
+ keyminbits=ixt_a->ixt_keyminbits;
+ keymaxbits=ixt_a->ixt_keymaxbits;
+ if(sa_p->ips_key_bits_a<keyminbits || sa_p->ips_key_bits_a>keymaxbits) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:ipsec_alg_auth_key_create: incorrect auth"
+ "key size: %d bits -- must be between %d,%d bits\n"/*octets (bytes)\n"*/,
+ sa_p->ips_key_bits_a, keyminbits, keymaxbits);
+ ret=-EINVAL;
+ goto ixt_out;
+ }
+ /* save auth key pointer */
+ sa_p->ips_auth_bits = ixt_a->ixt_a_keylen * 8; /* XXX XXX */
+ akp = sa_p->ips_key_a;
+ aks = sa_p->ips_key_a_size;
+
+ /* will hold: 2 ctx and a blocksize buffer: kb */
+ sa_p->ips_key_a_size = ixt_a->ixt_a_ctx_size;
+ if((sa_p->ips_key_a =
+ (caddr_t) kmalloc(sa_p->ips_key_a_size, GFP_ATOMIC)) == NULL) {
+ ret=-ENOMEM;
+ goto ixt_out;
+ }
+ ixt_a->ixt_a_hmac_set_key(ixt_a, sa_p->ips_key_a, akp, sa_p->ips_key_bits_a/8); /* XXX XXX */
+ ret=0;
+ memset(akp, 0, aks);
+ kfree(akp);
+
+ixt_out:
+ return ret;
+}
+int ipsec_alg_sa_esp_hash(const struct ipsec_sa *sa_p, const __u8 *espp, int len, __u8 *hash, int hashlen) {
+ struct ipsec_alg_auth *ixt_a=sa_p->ips_alg_auth;
+ if (!ixt_a) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:ipsec_sa_esp_hash: "
+ "NULL ipsec_alg_auth object\n");
+ return -EPROTO;
+ }
+ KLIPS_PRINT(debug_tunnel|debug_rcv,
+ "klips_debug:ipsec_sa_esp_hash: "
+ "hashing %p (%d bytes) to %p (%d bytes)\n",
+ espp, len,
+ hash, hashlen);
+ ixt_a->ixt_a_hmac_hash(ixt_a,
+ sa_p->ips_key_a,
+ espp, len,
+ hash, hashlen);
+ return 0;
+}
+
+/***************************************************************
+ *
+ * INTERFACE for module loading,testing, and unloading
+ *
+ ***************************************************************/
+
+/* validation for registering (enc) module */
+static int check_enc(struct ipsec_alg_enc *ixt) {
+ int ret=-EINVAL;
+ if (ixt->ixt_alg_id==0 || ixt->ixt_alg_id > SADB_EALG_MAX)
+ barf_out("invalid alg_id=%d >= %d\n", ixt->ixt_alg_id, SADB_EALG_MAX);
+ if (ixt->ixt_blocksize==0) /* || ixt->ixt_blocksize%2) need for ESP_NULL */
+ barf_out(KERN_ERR "invalid blocksize=%d\n", ixt->ixt_blocksize);
+ if (ixt->ixt_keyminbits==0 && ixt->ixt_keymaxbits==0 && ixt->ixt_e_keylen==0)
+ goto zero_key_ok;
+ if (ixt->ixt_keyminbits==0)
+ barf_out(KERN_ERR "invalid keyminbits=%d\n", ixt->ixt_keyminbits);
+ if (ixt->ixt_keymaxbits==0)
+ barf_out(KERN_ERR "invalid keymaxbits=%d\n", ixt->ixt_keymaxbits);
+ if (ixt->ixt_e_keylen==0)
+ barf_out(KERN_ERR "invalid keysize=%d\n", ixt->ixt_e_keylen);
+zero_key_ok:
+ if (ixt->ixt_e_ctx_size==0 && ixt->ixt_e_new_key == NULL)
+ barf_out(KERN_ERR "invalid key_e_size=%d and ixt_e_new_key=NULL\n", ixt->ixt_e_ctx_size);
+ if (ixt->ixt_e_cbc_encrypt==NULL)
+ barf_out(KERN_ERR "e_cbc_encrypt() must be not NULL\n");
+ ret=0;
+out:
+ return ret;
+}
+
+/* validation for registering (auth) module */
+static int check_auth(struct ipsec_alg_auth *ixt) {
+ int ret=-EINVAL;
+ if (ixt->ixt_alg_id==0 || ixt->ixt_alg_id > SADB_AALG_MAX)
+ barf_out("invalid alg_id=%d > %d (SADB_AALG_MAX)\n", ixt->ixt_alg_id, SADB_AALG_MAX);
+ if (ixt->ixt_blocksize==0 || ixt->ixt_blocksize%2)
+ barf_out(KERN_ERR "invalid blocksize=%d\n", ixt->ixt_blocksize);
+ if (ixt->ixt_blocksize>AH_BLKLEN_MAX)
+ barf_out(KERN_ERR "sorry blocksize=%d > %d. "
+ "Please increase AH_BLKLEN_MAX and recompile\n",
+ ixt->ixt_blocksize,
+ AH_BLKLEN_MAX);
+ if (ixt->ixt_keyminbits==0 && ixt->ixt_keymaxbits==0 && ixt->ixt_a_keylen==0)
+ goto zero_key_ok;
+ if (ixt->ixt_keyminbits==0)
+ barf_out(KERN_ERR "invalid keyminbits=%d\n", ixt->ixt_keyminbits);
+ if (ixt->ixt_keymaxbits==0)
+ barf_out(KERN_ERR "invalid keymaxbits=%d\n", ixt->ixt_keymaxbits);
+ if (ixt->ixt_keymaxbits!=ixt->ixt_keyminbits)
+ barf_out(KERN_ERR "keymaxbits must equal keyminbits (not sure).\n");
+ if (ixt->ixt_a_keylen==0)
+ barf_out(KERN_ERR "invalid keysize=%d\n", ixt->ixt_a_keylen);
+zero_key_ok:
+ if (ixt->ixt_a_ctx_size==0)
+ barf_out(KERN_ERR "invalid a_ctx_size=%d\n", ixt->ixt_a_ctx_size);
+ if (ixt->ixt_a_hmac_set_key==NULL)
+ barf_out(KERN_ERR "a_hmac_set_key() must be not NULL\n");
+ if (ixt->ixt_a_hmac_hash==NULL)
+ barf_out(KERN_ERR "a_hmac_hash() must be not NULL\n");
+ ret=0;
+out:
+ return ret;
+}
+
+/*
+ * Generic (enc, auth) registration entry point
+ */
+int register_ipsec_alg(struct ipsec_alg *ixt) {
+ int ret=-EINVAL;
+ /* Validation */
+ if (ixt==NULL)
+ barf_out("NULL ipsec_alg object passed\n");
+ if ((ixt->ixt_version&0xffffff00) != (IPSEC_ALG_VERSION&0xffffff00))
+ barf_out("incorrect version: %d.%d.%d-%d, "
+ "must be %d.%d.%d[-%d]\n",
+ IPSEC_ALG_VERSION_QUAD(ixt->ixt_version),
+ IPSEC_ALG_VERSION_QUAD(IPSEC_ALG_VERSION));
+ switch(ixt->ixt_alg_type) {
+ case IPSEC_ALG_TYPE_AUTH:
+ if ((ret=check_auth((struct ipsec_alg_auth *)ixt)<0))
+ goto out;
+ break;
+ case IPSEC_ALG_TYPE_ENCRYPT:
+ if ((ret=check_enc((struct ipsec_alg_enc *)ixt)<0))
+ goto out;
+ /*
+ * Adapted two lines below:
+ * ivlen == 0 is possible (NULL enc has blocksize==1)
+ *
+ * fixed NULL support by David De Reu <DeReu@tComLabs.com>
+ */
+ if (ixt->ixt_ivlen == 0 && ixt->ixt_blocksize > 1)
+ ixt->ixt_ivlen = ixt->ixt_blocksize*8;
+ break;
+ default:
+ barf_out("alg_type=%d not supported\n", ixt->ixt_alg_type);
+ }
+ INIT_LIST_HEAD(&ixt->ixt_list);
+ ret = ipsec_alg_insert(ixt);
+ if (ret<0)
+ barf_out(KERN_WARNING "ipsec_alg for alg_id=%d failed."
+ "Not loaded (ret=%d).\n",
+ ixt->ixt_alg_id, ret);
+
+ ret = pfkey_list_insert_supported((struct supported *)&ixt->ixt_support, &(pfkey_supported_list[SADB_SATYPE_ESP]));
+ if (ret==0) {
+ ixt->ixt_state |= IPSEC_ALG_ST_SUPP;
+ /* send register event to userspace */
+ pfkey_register_reply(SADB_SATYPE_ESP, NULL);
+ } else
+ printk(KERN_ERR "pfkey_list_insert_supported returned %d. "
+ "Loading anyway.\n", ret);
+ ret=0;
+out:
+ return ret;
+}
+
+/*
+ * unregister ipsec_alg object from own tables, if
+ * success => calls pfkey_list_remove_supported()
+ */
+int unregister_ipsec_alg(struct ipsec_alg *ixt) {
+ int ret= -EINVAL;
+ switch(ixt->ixt_alg_type) {
+ case IPSEC_ALG_TYPE_AUTH:
+ case IPSEC_ALG_TYPE_ENCRYPT:
+ break;
+ default:
+ /* this is not a typo :) */
+ barf_out("frog found in list (\"%s\"): ixt_p=NULL\n",
+ ixt->ixt_name);
+ }
+
+ ret=ipsec_alg_delete(ixt);
+ if (ixt->ixt_state&IPSEC_ALG_ST_SUPP) {
+ ixt->ixt_state &= ~IPSEC_ALG_ST_SUPP;
+ pfkey_list_remove_supported((struct supported *)&ixt->ixt_support, &(pfkey_supported_list[SADB_SATYPE_ESP]));
+ /* send register event to userspace */
+ pfkey_register_reply(SADB_SATYPE_ESP, NULL);
+ }
+
+out:
+ return ret;
+}
+/*
+ * Must be called from user context
+ * used at module load type for testing algo implementation
+ */
+static int ipsec_alg_test_encrypt(int enc_alg, int test) {
+ int ret;
+ caddr_t buf = NULL;
+ int iv_size, keysize, key_e_size;
+ struct ipsec_alg_enc *ixt_e;
+ void *tmp_key_e = NULL;
+ #define BUFSZ 1024
+ #define MARGIN 0
+ #define test_enc (buf+MARGIN)
+ #define test_dec (test_enc+BUFSZ+MARGIN)
+ #define test_tmp (test_dec+BUFSZ+MARGIN)
+ #define test_key_e (test_tmp+BUFSZ+MARGIN)
+ #define test_iv (test_key_e+key_e_size+MARGIN)
+ #define test_key (test_iv+iv_size+MARGIN)
+ #define test_size (BUFSZ*3+key_e_size+iv_size+keysize+MARGIN*7)
+ ixt_e=(struct ipsec_alg_enc *)ipsec_alg_get(IPSEC_ALG_TYPE_ENCRYPT, enc_alg);
+ if (ixt_e==NULL) {
+ KLIPS_PRINT(1,
+ "klips_debug: ipsec_alg_test_encrypt: "
+ "encalg=%d object not found\n",
+ enc_alg);
+ ret=-EINVAL;
+ goto out;
+ }
+ iv_size=ixt_e->ixt_ivlen / 8;
+ key_e_size=ixt_e->ixt_e_ctx_size;
+ keysize=ixt_e->ixt_e_keylen;
+ KLIPS_PRINT(1,
+ "klips_debug: ipsec_alg_test_encrypt: "
+ "enc_alg=%d blocksize=%d key_e_size=%d keysize=%d\n",
+ enc_alg, iv_size, key_e_size, keysize);
+ if ((buf=kmalloc (test_size, GFP_KERNEL)) == NULL) {
+ ret= -ENOMEM;
+ goto out;
+ }
+ get_random_bytes(test_key, keysize);
+ get_random_bytes(test_iv, iv_size);
+ if (ixt_e->ixt_e_new_key) {
+ tmp_key_e = ixt_e->ixt_e_new_key(ixt_e, test_key, keysize);
+ ret = tmp_key_e ? 0 : -EINVAL;
+ } else {
+ tmp_key_e = test_key_e;
+ ret = ixt_e->ixt_e_set_key(ixt_e, test_key_e, test_key, keysize);
+ }
+ if (ret < 0)
+ goto out;
+ get_random_bytes(test_enc, BUFSZ);
+ memcpy(test_tmp, test_enc, BUFSZ);
+ ret=ixt_e->ixt_e_cbc_encrypt(ixt_e, tmp_key_e, test_enc, BUFSZ, test_iv, 1);
+ printk(KERN_INFO
+ "klips_info: ipsec_alg_test_encrypt: "
+ "cbc_encrypt=1 ret=%d\n",
+ ret);
+ ret=memcmp(test_enc, test_tmp, BUFSZ);
+ printk(KERN_INFO
+ "klips_info: ipsec_alg_test_encrypt: "
+ "memcmp(enc, tmp) ret=%d: %s\n", ret,
+ ret!=0? "OK. (encr->DIFFers)" : "FAIL! (encr->SAME)" );
+ memcpy(test_dec, test_enc, BUFSZ);
+ ret=ixt_e->ixt_e_cbc_encrypt(ixt_e, tmp_key_e, test_dec, BUFSZ, test_iv, 0);
+ printk(KERN_INFO
+ "klips_info: ipsec_alg_test_encrypt: "
+ "cbc_encrypt=0 ret=%d\n", ret);
+ ret=memcmp(test_dec, test_tmp, BUFSZ);
+ printk(KERN_INFO
+ "klips_info: ipsec_alg_test_encrypt: "
+ "memcmp(dec,tmp) ret=%d: %s\n", ret,
+ ret==0? "OK. (encr->decr->SAME)" : "FAIL! (encr->decr->DIFFers)" );
+ {
+ /* Shamelessly taken from drivers/md sources O:) */
+ unsigned long now;
+ int i, count, max=0;
+ int encrypt, speed;
+ for (encrypt=0; encrypt <2;encrypt ++) {
+ for (i = 0; i < 5; i++) {
+ now = jiffies;
+ count = 0;
+ while (jiffies == now) {
+ mb();
+ ixt_e->ixt_e_cbc_encrypt(ixt_e,
+ tmp_key_e, test_tmp,
+ BUFSZ, test_iv, encrypt);
+ mb();
+ count++;
+ mb();
+ }
+ if (count > max)
+ max = count;
+ }
+ speed = max * (HZ * BUFSZ / 1024);
+ printk(KERN_INFO
+ "klips_info: ipsec_alg_test_encrypt: "
+ "%s %s speed=%d KB/s\n",
+ ixt_e->ixt_name,
+ encrypt? "encrypt": "decrypt", speed);
+ }
+ }
+out:
+ if (tmp_key_e && ixt_e->ixt_e_destroy_key) ixt_e->ixt_e_destroy_key(ixt_e, tmp_key_e);
+ if (buf) kfree(buf);
+ if (ixt_e) ipsec_alg_put((struct ipsec_alg *)ixt_e);
+ return ret;
+ #undef test_enc
+ #undef test_dec
+ #undef test_tmp
+ #undef test_key_e
+ #undef test_iv
+ #undef test_key
+ #undef test_size
+}
+/*
+ * Must be called from user context
+ * used at module load type for testing algo implementation
+ */
+static int ipsec_alg_test_auth(int auth_alg, int test) {
+ int ret;
+ caddr_t buf = NULL;
+ int blocksize, keysize, key_a_size;
+ struct ipsec_alg_auth *ixt_a;
+ #define BUFSZ 1024
+ #define MARGIN 0
+ #define test_auth (buf+MARGIN)
+ #define test_key_a (test_auth+BUFSZ+MARGIN)
+ #define test_key (test_key_a+key_a_size+MARGIN)
+ #define test_hash (test_key+keysize+MARGIN)
+ #define test_size (BUFSZ+key_a_size+keysize+AHHMAC_HASHLEN+MARGIN*4)
+ ixt_a=(struct ipsec_alg_auth *)ipsec_alg_get(IPSEC_ALG_TYPE_AUTH, auth_alg);
+ if (ixt_a==NULL) {
+ KLIPS_PRINT(1,
+ "klips_debug: ipsec_alg_test_auth: "
+ "encalg=%d object not found\n",
+ auth_alg);
+ ret=-EINVAL;
+ goto out;
+ }
+ blocksize=ixt_a->ixt_blocksize;
+ key_a_size=ixt_a->ixt_a_ctx_size;
+ keysize=ixt_a->ixt_a_keylen;
+ KLIPS_PRINT(1,
+ "klips_debug: ipsec_alg_test_auth: "
+ "auth_alg=%d blocksize=%d key_a_size=%d keysize=%d\n",
+ auth_alg, blocksize, key_a_size, keysize);
+ if ((buf=kmalloc (test_size, GFP_KERNEL)) == NULL) {
+ ret= -ENOMEM;
+ goto out;
+ }
+ get_random_bytes(test_key, keysize);
+ ret = ixt_a->ixt_a_hmac_set_key(ixt_a, test_key_a, test_key, keysize);
+ if (ret < 0 )
+ goto out;
+ get_random_bytes(test_auth, BUFSZ);
+ ret=ixt_a->ixt_a_hmac_hash(ixt_a, test_key_a, test_auth, BUFSZ, test_hash, AHHMAC_HASHLEN);
+ printk(KERN_INFO
+ "klips_info: ipsec_alg_test_auth: "
+ "ret=%d\n", ret);
+ {
+ /* Shamelessly taken from drivers/md sources O:) */
+ unsigned long now;
+ int i, count, max=0;
+ int speed;
+ for (i = 0; i < 5; i++) {
+ now = jiffies;
+ count = 0;
+ while (jiffies == now) {
+ mb();
+ ixt_a->ixt_a_hmac_hash(ixt_a, test_key_a, test_auth, BUFSZ, test_hash, AHHMAC_HASHLEN);
+ mb();
+ count++;
+ mb();
+ }
+ if (count > max)
+ max = count;
+ }
+ speed = max * (HZ * BUFSZ / 1024);
+ printk(KERN_INFO
+ "klips_info: ipsec_alg_test_auth: "
+ "%s hash speed=%d KB/s\n",
+ ixt_a->ixt_name,
+ speed);
+ }
+out:
+ if (buf) kfree(buf);
+ if (ixt_a) ipsec_alg_put((struct ipsec_alg *)ixt_a);
+ return ret;
+ #undef test_auth
+ #undef test_key_a
+ #undef test_key
+ #undef test_hash
+ #undef test_size
+}
+int ipsec_alg_test(unsigned alg_type, unsigned alg_id, int test) {
+ switch(alg_type) {
+ case IPSEC_ALG_TYPE_ENCRYPT:
+ return ipsec_alg_test_encrypt(alg_id, test);
+ break;
+ case IPSEC_ALG_TYPE_AUTH:
+ return ipsec_alg_test_auth(alg_id, test);
+ break;
+ }
+ printk(KERN_ERR "klips_info: ipsec_alg_test() called incorrectly: "
+ "alg_type=%d alg_id=%d\n",
+ alg_type, alg_id);
+ return -EINVAL;
+}
+int ipsec_alg_init(void) {
+ KLIPS_PRINT(1, "klips_info:ipsec_alg_init: "
+ "KLIPS alg v=%d.%d.%d-%d (EALG_MAX=%d, AALG_MAX=%d)\n",
+ IPSEC_ALG_VERSION_QUAD(IPSEC_ALG_VERSION),
+ SADB_EALG_MAX, SADB_AALG_MAX);
+ /* Initialize tables */
+ write_lock_bh(&ipsec_alg_lock);
+ ipsec_alg_hash_init();
+ write_unlock_bh(&ipsec_alg_lock);
+ /* Initialize static algos */
+ KLIPS_PRINT(1, "klips_info:ipsec_alg_init: "
+ "calling ipsec_alg_static_init()\n");
+ ipsec_alg_static_init();
+ return 0;
+}
+
+/**********************************************
+ *
+ * INTERFACE for ipsec_sa init and wipe
+ *
+ **********************************************/
+
+/*
+ * Called from pluto -> pfkey_v2_parser.c:pfkey_ipsec_sa_init()
+ */
+int ipsec_alg_sa_init(struct ipsec_sa *sa_p) {
+ struct ipsec_alg_enc *ixt_e;
+ struct ipsec_alg_auth *ixt_a;
+
+ /* Only ESP for now ... */
+ if (sa_p->ips_said.proto != IPPROTO_ESP)
+ return -EPROTONOSUPPORT;
+ KLIPS_PRINT(debug_pfkey, "klips_debug: ipsec_alg_sa_init() :"
+ "entering for encalg=%d, authalg=%d\n",
+ sa_p->ips_encalg, sa_p->ips_authalg);
+ if ((ixt_e=(struct ipsec_alg_enc *)
+ ipsec_alg_get(IPSEC_ALG_TYPE_ENCRYPT, sa_p->ips_encalg))) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug: ipsec_alg_sa_init() :"
+ "found ipsec_alg (ixt_e=%p) for encalg=%d\n",
+ ixt_e, sa_p->ips_encalg);
+ sa_p->ips_alg_enc=ixt_e;
+ }
+ if ((ixt_a=(struct ipsec_alg_auth *)
+ ipsec_alg_get(IPSEC_ALG_TYPE_AUTH, sa_p->ips_authalg))) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug: ipsec_alg_sa_init() :"
+ "found ipsec_alg (ixt_a=%p) for auth=%d\n",
+ ixt_a, sa_p->ips_authalg);
+ sa_p->ips_alg_auth=ixt_a;
+ }
+ return 0;
+}
+
+/*
+ * Called from pluto -> ipsec_sa.c:ipsec_sa_delchain()
+ */
+int ipsec_alg_sa_wipe(struct ipsec_sa *sa_p) {
+ struct ipsec_alg *ixt;
+ if ((ixt=(struct ipsec_alg *)sa_p->ips_alg_enc)) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug: ipsec_alg_sa_wipe() :"
+ "unlinking for encalg=%d\n",
+ ixt->ixt_alg_id);
+ ipsec_alg_put(ixt);
+ }
+ if ((ixt=(struct ipsec_alg *)sa_p->ips_alg_auth)) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug: ipsec_alg_sa_wipe() :"
+ "unlinking for authalg=%d\n",
+ ixt->ixt_alg_id);
+ ipsec_alg_put(ixt);
+ }
+ return 0;
+}
+
+IPSEC_PROCFS_DEBUG_NO_STATIC
+int
+ipsec_xform_get_info(char *buffer,
+ char **start,
+ off_t offset,
+ int length IPSEC_PROC_LAST_ARG)
+{
+ int len = 0;
+ off_t begin = 0;
+ int i;
+ struct list_head *head;
+ struct ipsec_alg *ixt;
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
+ "klips_debug:ipsec_tncfg_get_info: "
+ "buffer=0p%p, *start=0p%p, offset=%d, length=%d\n",
+ buffer,
+ *start,
+ (int)offset,
+ length);
+
+ for(i = 0, head = ipsec_alg_hash_table; i< IPSEC_ALG_HASHSZ; i++, head++)
+ {
+ struct list_head *p;
+ for (p=head->next; p!=head; p=p->next)
+ {
+ ixt = list_entry(p, struct ipsec_alg, ixt_list);
+ len += ipsec_snprintf(buffer+len, length-len,
+ "VERSION=%d TYPE=%d ID=%d NAME=%s REFCNT=%d ",
+ ixt->ixt_version, ixt->ixt_alg_type, ixt->ixt_alg_id,
+ ixt->ixt_name, ixt->ixt_refcnt);
+
+ len += ipsec_snprintf(buffer+len, length-len,
+ "STATE=%08x BLOCKSIZE=%d IVLEN=%d KEYMINBITS=%d KEYMAXBITS=%d ",
+ ixt->ixt_state, ixt->ixt_blocksize,
+ ixt->ixt_ivlen, ixt->ixt_keyminbits, ixt->ixt_keymaxbits);
+
+ len += ipsec_snprintf(buffer+len, length-len,
+ "IVLEN=%d KEYMINBITS=%d KEYMAXBITS=%d ",
+ ixt->ixt_ivlen, ixt->ixt_keyminbits, ixt->ixt_keymaxbits);
+
+ switch(ixt->ixt_alg_type)
+ {
+ case IPSEC_ALG_TYPE_AUTH:
+ {
+ struct ipsec_alg_auth *auth = (struct ipsec_alg_auth *)ixt;
+
+ len += ipsec_snprintf(buffer+len, length-len,
+ "KEYLEN=%d CTXSIZE=%d AUTHLEN=%d ",
+ auth->ixt_a_keylen, auth->ixt_a_ctx_size,
+ auth->ixt_a_authlen);
+ break;
+ }
+ case IPSEC_ALG_TYPE_ENCRYPT:
+ {
+ struct ipsec_alg_enc *enc = (struct ipsec_alg_enc *)ixt;
+ len += ipsec_snprintf(buffer+len, length-len,
+ "KEYLEN=%d CTXSIZE=%d ",
+ enc->ixt_e_keylen, enc->ixt_e_ctx_size);
+
+ break;
+ }
+ }
+
+ len += ipsec_snprintf(buffer+len, length-len, "\n");
+ }
+ }
+
+ *start = buffer + (offset - begin); /* Start of wanted data */
+ len -= (offset - begin); /* Start slop */
+ if (len > length)
+ len = length;
+ return len;
+}
+
+/*
+ * As the author of this module, I ONLY ALLOW using it from
+ * GPL (or same LICENSE TERMS as kernel source) modules.
+ *
+ * In respect to hardware crypto engines this means:
+ * * Closed-source device drivers ARE NOT ALLOWED to use
+ * this interface.
+ * * Closed-source VHDL/Verilog firmware running on
+ * the crypto hardware device IS ALLOWED to use this interface
+ * via a GPL (or same LICENSE TERMS as kernel source) device driver.
+ * --Juan Jose Ciarlante 20/03/2002 (thanks RGB for the correct wording)
+ */
+
+/*
+ * These symbols can only be used from GPL modules
+ * for now, I'm disabling this because it creates false
+ * symbol problems for old modutils.
+ */
+
+/* #ifndef EXPORT_SYMBOL_GPL */
+#undef EXPORT_SYMBOL_GPL
+#define EXPORT_SYMBOL_GPL EXPORT_SYMBOL
+/* #endif */
+EXPORT_SYMBOL_GPL(register_ipsec_alg);
+EXPORT_SYMBOL_GPL(unregister_ipsec_alg);
+EXPORT_SYMBOL_GPL(ipsec_alg_test);
+#endif /* CONFIG_IPSEC_ALG */
diff --git a/linux/net/ipsec/ipsec_init.c b/linux/net/ipsec/ipsec_init.c
new file mode 100644
index 000000000..56512acb6
--- /dev/null
+++ b/linux/net/ipsec/ipsec_init.c
@@ -0,0 +1,755 @@
+/*
+ * @(#) Initialization code.
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Richard Guy Briggs <rgb@freeswan.org>
+ * 2001 Michael Richardson <mcr@freeswan.org>
+ *
+ * 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.
+ *
+ * /proc system code was split out into ipsec_proc.c after rev. 1.70.
+ *
+ */
+
+char ipsec_init_c_version[] = "RCSID $Id: ipsec_init.c,v 1.3 2004/06/13 19:57:49 as Exp $";
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h> /* printk() */
+
+#include "freeswan/ipsec_param.h"
+
+#ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+#else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+#endif /* MALLOC_SLAB */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/interrupt.h> /* mark_bh */
+
+#include <linux/netdevice.h> /* struct device, and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/ip.h> /* struct iphdr */
+#include <linux/in.h> /* struct sockaddr_in */
+#include <linux/skbuff.h>
+#include <linux/random.h> /* get_random_bytes() */
+#include <freeswan.h>
+
+#ifdef SPINLOCK
+# ifdef SPINLOCK_23
+# include <linux/spinlock.h> /* *lock* */
+# else /* 23_SPINLOCK */
+# include <asm/spinlock.h> /* *lock* */
+# endif /* 23_SPINLOCK */
+#endif /* SPINLOCK */
+
+#ifdef NET_21
+# include <asm/uaccess.h>
+# include <linux/in6.h>
+#endif /* NET_21 */
+
+#include <asm/checksum.h>
+#include <net/ip.h>
+
+#ifdef CONFIG_PROC_FS
+# include <linux/proc_fs.h>
+#endif /* CONFIG_PROC_FS */
+
+#ifdef NETLINK_SOCK
+# include <linux/netlink.h>
+#else
+# include <net/netlink.h>
+#endif
+
+#include "freeswan/radij.h"
+
+#include "freeswan/ipsec_life.h"
+#include "freeswan/ipsec_stats.h"
+#include "freeswan/ipsec_sa.h"
+
+#include "freeswan/ipsec_encap.h"
+#include "freeswan/ipsec_radij.h"
+#include "freeswan/ipsec_xform.h"
+#include "freeswan/ipsec_tunnel.h"
+
+#include "freeswan/ipsec_rcv.h"
+#include "freeswan/ipsec_ah.h"
+#include "freeswan/ipsec_esp.h"
+
+#ifdef CONFIG_IPSEC_IPCOMP
+# include "freeswan/ipcomp.h"
+#endif /* CONFIG_IPSEC_IPCOMP */
+
+#include "freeswan/ipsec_proto.h"
+#include "freeswan/ipsec_alg.h"
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#if !defined(CONFIG_IPSEC_ESP) && !defined(CONFIG_IPSEC_AH)
+#error "kernel configuration must include ESP or AH"
+#endif
+
+/*
+ * seems to be present in 2.4.10 (Linus), but also in some RH and other
+ * distro kernels of a lower number.
+ */
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+#ifdef CONFIG_IPSEC_DEBUG
+int debug_eroute = 0;
+int debug_spi = 0;
+int debug_netlink = 0;
+#endif /* CONFIG_IPSEC_DEBUG */
+
+struct prng ipsec_prng;
+
+extern int ipsec_device_event(struct notifier_block *dnot, unsigned long event, void *ptr);
+/*
+ * the following structure is required so that we receive
+ * event notifications when network devices are enabled and
+ * disabled (ifconfig up and down).
+ */
+static struct notifier_block ipsec_dev_notifier={
+ ipsec_device_event,
+ NULL,
+ 0
+};
+
+#ifdef CONFIG_SYSCTL
+extern int ipsec_sysctl_register(void);
+extern void ipsec_sysctl_unregister(void);
+#endif
+
+static inline int
+freeswan_inet_add_protocol(struct inet_protocol *prot, unsigned protocol)
+{
+#ifdef NETDEV_25
+ return inet_add_protocol(prot, protocol);
+#else
+ inet_add_protocol(prot);
+ return 0;
+#endif
+}
+
+static inline int
+freeswan_inet_del_protocol(struct inet_protocol *prot, unsigned protocol)
+{
+#ifdef NETDEV_25
+ return inet_del_protocol(prot, protocol);
+#else
+ inet_del_protocol(prot);
+ return 0;
+#endif
+}
+
+/* void */
+int
+ipsec_init(void)
+{
+ int error = 0;
+ unsigned char seed[256];
+#ifdef CONFIG_IPSEC_ENC_3DES
+ extern int des_check_key;
+
+ /* turn off checking of keys */
+ des_check_key=0;
+#endif /* CONFIG_IPSEC_ENC_3DES */
+
+ KLIPS_PRINT(1, "klips_info:ipsec_init: "
+ "KLIPS startup, FreeS/WAN IPSec version: %s\n",
+ ipsec_version_code());
+
+ error |= ipsec_proc_init();
+
+#ifdef SPINLOCK
+ ipsec_sadb.sadb_lock = SPIN_LOCK_UNLOCKED;
+#else /* SPINLOCK */
+ ipsec_sadb.sadb_lock = 0;
+#endif /* SPINLOCK */
+
+#ifndef SPINLOCK
+ tdb_lock.lock = 0;
+ eroute_lock.lock = 0;
+#endif /* !SPINLOCK */
+
+ error |= ipsec_sadb_init();
+ error |= ipsec_radijinit();
+
+ error |= pfkey_init();
+
+ error |= register_netdevice_notifier(&ipsec_dev_notifier);
+
+#ifdef CONFIG_IPSEC_ESP
+ freeswan_inet_add_protocol(&esp_protocol, IPPROTO_ESP);
+#endif /* CONFIG_IPSEC_ESP */
+
+#ifdef CONFIG_IPSEC_AH
+ freeswan_inet_add_protocol(&ah_protocol, IPPROTO_AH);
+#endif /* CONFIG_IPSEC_AH */
+
+/* we never actually link IPCOMP to the stack */
+#ifdef IPCOMP_USED_ALONE
+#ifdef CONFIG_IPSEC_IPCOMP
+ freeswan_inet_add_protocol(&comp_protocol, IPPROTO_COMP);
+#endif /* CONFIG_IPSEC_IPCOMP */
+#endif
+
+ error |= ipsec_tunnel_init_devices();
+
+
+#ifdef CONFIG_SYSCTL
+ error |= ipsec_sysctl_register();
+#endif
+
+#ifdef CONFIG_IPSEC_ALG
+ ipsec_alg_init();
+#endif
+
+ get_random_bytes((void *)seed, sizeof(seed));
+ prng_init(&ipsec_prng, seed, sizeof(seed));
+
+ return error;
+}
+
+
+/* void */
+int
+ipsec_cleanup(void)
+{
+ int error = 0;
+
+#ifdef CONFIG_SYSCTL
+ ipsec_sysctl_unregister();
+#endif
+ KLIPS_PRINT(debug_netlink, /* debug_tunnel & DB_TN_INIT, */
+ "klips_debug:ipsec_cleanup: "
+ "calling ipsec_tunnel_cleanup_devices.\n");
+ error |= ipsec_tunnel_cleanup_devices();
+
+ KLIPS_PRINT(debug_netlink, "called ipsec_tunnel_cleanup_devices");
+
+/* we never actually link IPCOMP to the stack */
+#ifdef IPCOMP_USED_ALONE
+#ifdef CONFIG_IPSEC_IPCOMP
+ if (freeswan_inet_del_protocol(&comp_protocol, IPPROTO_COMP) < 0)
+ printk(KERN_INFO "klips_debug:ipsec_cleanup: "
+ "comp close: can't remove protocol\n");
+#endif /* CONFIG_IPSEC_IPCOMP */
+#endif /* IPCOMP_USED_ALONE */
+
+#ifdef CONFIG_IPSEC_AH
+ if (freeswan_inet_del_protocol(&ah_protocol, IPPROTO_AH) < 0)
+ printk(KERN_INFO "klips_debug:ipsec_cleanup: "
+ "ah close: can't remove protocol\n");
+#endif /* CONFIG_IPSEC_AH */
+
+#ifdef CONFIG_IPSEC_ESP
+ if (freeswan_inet_del_protocol(&esp_protocol, IPPROTO_ESP) < 0)
+ printk(KERN_INFO "klips_debug:ipsec_cleanup: "
+ "esp close: can't remove protocol\n");
+#endif /* CONFIG_IPSEC_ESP */
+
+ error |= unregister_netdevice_notifier(&ipsec_dev_notifier);
+
+ KLIPS_PRINT(debug_netlink, /* debug_tunnel & DB_TN_INIT, */
+ "klips_debug:ipsec_cleanup: "
+ "calling ipsec_sadb_cleanup.\n");
+ error |= ipsec_sadb_cleanup(0);
+ error |= ipsec_sadb_free();
+
+ KLIPS_PRINT(debug_netlink, /* debug_tunnel & DB_TN_INIT, */
+ "klips_debug:ipsec_cleanup: "
+ "calling ipsec_radijcleanup.\n");
+ error |= ipsec_radijcleanup();
+
+ KLIPS_PRINT(debug_pfkey, /* debug_tunnel & DB_TN_INIT, */
+ "klips_debug:ipsec_cleanup: "
+ "calling pfkey_cleanup.\n");
+ error |= pfkey_cleanup();
+
+ ipsec_proc_cleanup();
+
+ prng_final(&ipsec_prng);
+
+ return error;
+}
+
+#ifdef MODULE
+int
+init_module(void)
+{
+ int error = 0;
+
+ error |= ipsec_init();
+
+ return error;
+}
+
+int
+cleanup_module(void)
+{
+ int error = 0;
+
+ KLIPS_PRINT(debug_netlink, /* debug_tunnel & DB_TN_INIT, */
+ "klips_debug:cleanup_module: "
+ "calling ipsec_cleanup.\n");
+
+ error |= ipsec_cleanup();
+
+ KLIPS_PRINT(1, "klips_info:cleanup_module: "
+ "ipsec module unloaded.\n");
+
+ return error;
+}
+#endif /* MODULE */
+
+/*
+ * $Log: ipsec_init.c,v $
+ * Revision 1.3 2004/06/13 19:57:49 as
+ * removed inclusion of ipsec_netlink.h
+ *
+ * Revision 1.2 2004/03/22 21:53:19 as
+ * merged alg-0.8.1 branch with HEAD
+ *
+ * Revision 1.1.4.1 2004/03/16 09:48:19 as
+ * alg-0.8.1rc12 patch merged
+ *
+ * Revision 1.1 2004/03/15 20:35:26 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.89 2003/07/31 22:47:16 mcr
+ * preliminary (untested by FS-team) 2.5 patches.
+ *
+ * Revision 1.88 2003/06/22 20:05:36 mcr
+ * clarified why IPCOMP was not being registered, and put a new
+ * #ifdef in rather than #if 0.
+ *
+ * Revision 1.87 2002/09/20 15:40:51 rgb
+ * Added a lock to the global ipsec_sadb struct for future use.
+ * Split ipsec_sadb_cleanup from new funciton ipsec_sadb_free to avoid problem
+ * of freeing newly created structures when clearing the reftable upon startup
+ * to start from a known state.
+ *
+ * Revision 1.86 2002/08/15 18:39:15 rgb
+ * Move ipsec_prng outside debug code.
+ *
+ * Revision 1.85 2002/05/14 02:35:29 rgb
+ * Change reference to tdb to ipsa.
+ *
+ * Revision 1.84 2002/04/24 07:55:32 mcr
+ * #include patches and Makefiles for post-reorg compilation.
+ *
+ * Revision 1.83 2002/04/24 07:36:28 mcr
+ * Moved from ./klips/net/ipsec/ipsec_init.c,v
+ *
+ * Revision 1.82 2002/04/20 00:12:25 rgb
+ * Added esp IV CBC attack fix, disabled.
+ *
+ * Revision 1.81 2002/04/09 16:13:32 mcr
+ * switch license to straight GPL.
+ *
+ * Revision 1.80 2002/03/24 07:34:08 rgb
+ * Sanity check for at least one of AH or ESP configured.
+ *
+ * Revision 1.79 2002/02/05 22:55:15 mcr
+ * added MODULE_LICENSE declaration.
+ * This macro does not appear in all kernel versions (see comment).
+ *
+ * Revision 1.78 2002/01/29 17:17:55 mcr
+ * moved include of ipsec_param.h to after include of linux/kernel.h
+ * otherwise, it seems that some option that is set in ipsec_param.h
+ * screws up something subtle in the include path to kernel.h, and
+ * it complains on the snprintf() prototype.
+ *
+ * Revision 1.77 2002/01/29 04:00:51 mcr
+ * more excise of kversions.h header.
+ *
+ * Revision 1.76 2002/01/29 02:13:17 mcr
+ * introduction of ipsec_kversion.h means that include of
+ * ipsec_param.h must preceed any decisions about what files to
+ * include to deal with differences in kernel source.
+ *
+ * Revision 1.75 2001/11/26 09:23:48 rgb
+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
+ *
+ * Revision 1.74 2001/11/22 05:44:11 henry
+ * new version stuff
+ *
+ * Revision 1.71.2.2 2001/10/22 20:51:00 mcr
+ * explicitely set des_check_key.
+ *
+ * Revision 1.71.2.1 2001/09/25 02:19:39 mcr
+ * /proc manipulation code moved to new ipsec_proc.c
+ *
+ * Revision 1.73 2001/11/06 19:47:17 rgb
+ * Changed lifetime_packets to uint32 from uint64.
+ *
+ * Revision 1.72 2001/10/18 04:45:19 rgb
+ * 2.4.9 kernel deprecates linux/malloc.h in favour of linux/slab.h,
+ * lib/freeswan.h version macros moved to lib/kversions.h.
+ * Other compiler directive cleanups.
+ *
+ * Revision 1.71 2001/09/20 15:32:45 rgb
+ * Minor pfkey lifetime fixes.
+ *
+ * Revision 1.70 2001/07/06 19:51:21 rgb
+ * Added inbound policy checking code for IPIP SAs.
+ *
+ * Revision 1.69 2001/06/14 19:33:26 rgb
+ * Silence startup message for console, but allow it to be logged.
+ * Update copyright date.
+ *
+ * Revision 1.68 2001/05/29 05:14:36 rgb
+ * Added PMTU to /proc/net/ipsec_tncfg output. See 'man 5 ipsec_tncfg'.
+ *
+ * Revision 1.67 2001/05/04 16:34:52 rgb
+ * Rremove erroneous checking of return codes for proc_net_* in 2.4.
+ *
+ * Revision 1.66 2001/05/03 19:40:34 rgb
+ * Check error return codes in startup and shutdown.
+ *
+ * Revision 1.65 2001/02/28 05:03:27 rgb
+ * Clean up and rationalise startup messages.
+ *
+ * Revision 1.64 2001/02/27 22:24:53 rgb
+ * Re-formatting debug output (line-splitting, joining, 1arg/line).
+ * Check for satoa() return codes.
+ *
+ * Revision 1.63 2000/11/29 20:14:06 rgb
+ * Add src= to the output of /proc/net/ipsec_spi and delete dst from IPIP.
+ *
+ * Revision 1.62 2000/11/06 04:31:24 rgb
+ * Ditched spin_lock_irqsave in favour of spin_lock_bh.
+ * Fixed longlong for pre-2.4 kernels (Svenning).
+ * Add Svenning's adaptive content compression.
+ * Disabled registration of ipcomp handler.
+ *
+ * Revision 1.61 2000/10/11 13:37:54 rgb
+ * #ifdef out debug print that causes proc/net/ipsec_version to oops.
+ *
+ * Revision 1.60 2000/09/20 03:59:01 rgb
+ * Change static info functions to DEBUG_NO_STATIC to reveal function names
+ * in oopsen.
+ *
+ * Revision 1.59 2000/09/16 01:06:26 rgb
+ * Added cast of var to silence compiler warning about long fed to int
+ * format.
+ *
+ * Revision 1.58 2000/09/15 11:37:01 rgb
+ * Merge in heavily modified Svenning Soerensen's <svenning@post5.tele.dk>
+ * IPCOMP zlib deflate code.
+ *
+ * Revision 1.57 2000/09/12 03:21:50 rgb
+ * Moved radij_c_version printing to ipsec_version_get_info().
+ * Reformatted ipsec_version_get_info().
+ * Added sysctl_{,un}register() calls.
+ *
+ * Revision 1.56 2000/09/08 19:16:50 rgb
+ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
+ * Removed all references to CONFIG_IPSEC_PFKEYv2.
+ *
+ * Revision 1.55 2000/08/30 05:19:03 rgb
+ * Cleaned up no longer used spi_next, netlink register/unregister, other
+ * minor cleanup.
+ * Removed cruft replaced by TDB_XFORM_NAME.
+ * Removed all the rest of the references to tdb_spi, tdb_proto, tdb_dst.
+ * Moved debug version strings to printk when /proc/net/ipsec_version is
+ * called.
+ *
+ * Revision 1.54 2000/08/20 18:31:05 rgb
+ * Changed cosmetic alignment in spi_info.
+ * Changed addtime and usetime to use actual value which is relative
+ * anyways, as intended. (Momchil)
+ *
+ * Revision 1.53 2000/08/18 17:37:03 rgb
+ * Added an (int) cast to shut up the compiler...
+ *
+ * Revision 1.52 2000/08/01 14:51:50 rgb
+ * Removed _all_ remaining traces of DES.
+ *
+ * Revision 1.51 2000/07/25 20:41:22 rgb
+ * Removed duplicate parameter in spi_getinfo.
+ *
+ * Revision 1.50 2000/07/17 03:21:45 rgb
+ * Removed /proc/net/ipsec_spinew.
+ *
+ * Revision 1.49 2000/06/28 05:46:51 rgb
+ * Renamed ivlen to iv_bits for consistency.
+ * Changed output of add and use times to be relative to now.
+ *
+ * Revision 1.48 2000/05/11 18:26:10 rgb
+ * Commented out calls to netlink_attach/detach to avoid activating netlink
+ * in the kenrel config.
+ *
+ * Revision 1.47 2000/05/10 22:35:26 rgb
+ * Comment out most of the startup version information.
+ *
+ * Revision 1.46 2000/03/22 16:15:36 rgb
+ * Fixed renaming of dev_get (MB).
+ *
+ * Revision 1.45 2000/03/16 06:40:48 rgb
+ * Hardcode PF_KEYv2 support.
+ *
+ * Revision 1.44 2000/01/22 23:19:20 rgb
+ * Simplified code to use existing macro TDB_XFORM_NAME().
+ *
+ * Revision 1.43 2000/01/21 06:14:04 rgb
+ * Print individual stats only if non-zero.
+ * Removed 'bits' from each keylength for brevity.
+ * Shortened lifetimes legend for brevity.
+ * Changed wording from 'last_used' to the clearer 'idle'.
+ *
+ * Revision 1.42 1999/12/31 14:57:19 rgb
+ * MB fix for new dummy-less proc_get_info in 2.3.35.
+ *
+ * Revision 1.41 1999/11/23 23:04:03 rgb
+ * Use provided macro ADDRTOA_BUF instead of hardcoded value.
+ * Sort out pfkey and freeswan headers, putting them in a library path.
+ *
+ * Revision 1.40 1999/11/18 18:47:01 rgb
+ * Added dynamic proc registration for 2.3.25+.
+ * Changed all device registrations for static linking to
+ * dynamic to reduce the number and size of patches.
+ * Changed all protocol registrations for static linking to
+ * dynamic to reduce the number and size of patches.
+ *
+ * Revision 1.39 1999/11/18 04:12:07 rgb
+ * Replaced all kernel version macros to shorter, readable form.
+ * Added Marc Boucher's 2.3.25 proc patches.
+ * Converted all PROC_FS entries to dynamic to reduce kernel patching.
+ * Added CONFIG_PROC_FS compiler directives in case it is shut off.
+ *
+ * Revision 1.38 1999/11/17 15:53:38 rgb
+ * Changed all occurrences of #include "../../../lib/freeswan.h"
+ * to #include <freeswan.h> which works due to -Ilibfreeswan in the
+ * klips/net/ipsec/Makefile.
+ *
+ * Revision 1.37 1999/10/16 04:23:06 rgb
+ * Add stats for replaywin_errs, replaywin_max_sequence_difference,
+ * authentication errors, encryption size errors, encryption padding
+ * errors, and time since last packet.
+ *
+ * Revision 1.36 1999/10/16 00:30:47 rgb
+ * Added SA lifetime counting.
+ *
+ * Revision 1.35 1999/10/15 22:14:00 rgb
+ * Clean out cruft.
+ *
+ * Revision 1.34 1999/10/03 18:46:28 rgb
+ * Spinlock fixes for 2.0.xx and 2.3.xx.
+ *
+ * Revision 1.33 1999/10/01 17:08:10 rgb
+ * Disable spinlock init.
+ *
+ * Revision 1.32 1999/10/01 16:22:24 rgb
+ * Switch from assignment init. to functional init. of spinlocks.
+ *
+ * Revision 1.31 1999/10/01 15:44:52 rgb
+ * Move spinlock header include to 2.1> scope.
+ *
+ * Revision 1.30 1999/10/01 00:00:16 rgb
+ * Added eroute structure locking.
+ * Added tdb structure locking.
+ * Minor formatting changes.
+ * Add call to initialize tdb hash table.
+ *
+ * Revision 1.29 1999/09/23 20:22:40 rgb
+ * Enable, tidy and fix network notifier code.
+ *
+ * Revision 1.28 1999/09/18 11:39:56 rgb
+ * Start to add (disabled) netdevice notifier code.
+ *
+ * Revision 1.27 1999/08/28 08:24:47 rgb
+ * Add compiler directives to compile cleanly without debugging.
+ *
+ * Revision 1.26 1999/08/06 16:03:22 rgb
+ * Correct error messages on failure to unload /proc entries.
+ *
+ * Revision 1.25 1999/08/03 17:07:25 rgb
+ * Report device MTU, not private MTU.
+ *
+ * Revision 1.24 1999/05/25 22:24:37 rgb
+ * /PROC/NET/ipsec* init problem fix.
+ *
+ * Revision 1.23 1999/05/25 02:16:38 rgb
+ * Make modular proc_fs entries dynamic and fix for 2.2.x.
+ *
+ * Revision 1.22 1999/05/09 03:25:35 rgb
+ * Fix bug introduced by 2.2 quick-and-dirty patch.
+ *
+ * Revision 1.21 1999/05/05 22:02:30 rgb
+ * Add a quick and dirty port to 2.2 kernels by Marc Boucher <marc@mbsi.ca>.
+ *
+ * Revision 1.20 1999/04/29 15:15:50 rgb
+ * Fix undetected iv_len reporting bug.
+ * Add sanity checking for null pointer to private data space.
+ * Add return values to init and cleanup functions.
+ *
+ * Revision 1.19 1999/04/27 19:24:44 rgb
+ * Added /proc/net/ipsec_klipsdebug support for reading the current debug
+ * settings.
+ * Instrument module load/init/unload.
+ *
+ * Revision 1.18 1999/04/15 15:37:24 rgb
+ * Forward check changes from POST1_00 branch.
+ *
+ * Revision 1.15.2.3 1999/04/13 20:29:19 rgb
+ * /proc/net/ipsec_* cleanup.
+ *
+ * Revision 1.15.2.2 1999/04/02 04:28:23 rgb
+ * /proc/net/ipsec_* formatting enhancements.
+ *
+ * Revision 1.15.2.1 1999/03/30 17:08:33 rgb
+ * Add pfkey initialisation.
+ *
+ * Revision 1.17 1999/04/11 00:28:57 henry
+ * GPL boilerplate
+ *
+ * Revision 1.16 1999/04/06 04:54:25 rgb
+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+ * patch shell fixes.
+ *
+ * Revision 1.15 1999/02/24 20:15:07 rgb
+ * Update output format.
+ *
+ * Revision 1.14 1999/02/17 16:49:39 rgb
+ * Convert DEBUG_IPSEC to KLIPS_PRINT
+ * Ditch NET_IPIP dependancy.
+ *
+ * Revision 1.13 1999/01/26 02:06:37 rgb
+ * Remove ah/esp switching on include files.
+ * Removed CONFIG_IPSEC_ALGO_SWITCH macro.
+ * Removed dead code.
+ * Remove references to INET_GET_PROTOCOL.
+ *
+ * Revision 1.12 1999/01/22 06:19:18 rgb
+ * Cruft clean-out.
+ * 64-bit clean-up.
+ * Added algorithm switch code.
+ *
+ * Revision 1.11 1998/12/01 05:54:53 rgb
+ * Cleanup and order debug version output.
+ *
+ * Revision 1.10 1998/11/30 13:22:54 rgb
+ * Rationalised all the klips kernel file headers. They are much shorter
+ * now and won't conflict under RH5.2.
+ *
+ * Revision 1.9 1998/11/10 05:35:13 rgb
+ * Print direction in/out flag from /proc/net/ipsec_spi.
+ *
+ * Revision 1.8 1998/10/27 13:48:10 rgb
+ * Cleaned up /proc/net/ipsec_* filesystem for easy parsing by scripts.
+ * Fixed less(1) truncated output bug.
+ * Code clean-up.
+ *
+ * Revision 1.7 1998/10/22 06:43:16 rgb
+ * Convert to use satoa for printk.
+ *
+ * Revision 1.6 1998/10/19 14:24:35 rgb
+ * Added inclusion of freeswan.h.
+ *
+ * Revision 1.5 1998/10/09 04:43:35 rgb
+ * Added 'klips_debug' prefix to all klips printk debug statements.
+ *
+ * Revision 1.4 1998/07/27 21:50:22 rgb
+ * Not necessary to traverse mask tree for /proc/net/ipsec_eroute.
+ *
+ * Revision 1.3 1998/06/25 19:51:20 rgb
+ * Clean up #endif comments.
+ * Shift debugging comment control for procfs to debug_tunnel.
+ * Make proc_dir_entries visible to rest of kernel for static link.
+ * Replace hardwired fileperms with macros.
+ * Use macros for procfs inode numbers.
+ * Rearrange initialisations between ipsec_init and module_init as appropriate
+ * for static loading.
+ *
+ * Revision 1.2 1998/06/23 02:55:43 rgb
+ * Slightly quieted init-time messages.
+ * Re-introduced inet_add_protocol after it mysteriously disappeared...
+ * Check for and warn of absence of IPIP protocol on install of module.
+ * Move tdbcleanup to ipsec_xform.c.
+ *
+ * Revision 1.10 1998/06/18 21:29:04 henry
+ * move sources from klips/src to klips/net/ipsec, to keep stupid kernel
+ * build scripts happier in presence of symbolic links
+ *
+ * Revision 1.9 1998/06/14 23:49:40 rgb
+ * Clarify version reporting on module loading.
+ *
+ * Revision 1.8 1998/06/11 05:54:23 rgb
+ * Added /proc/net/ipsec_version to report freeswan and transform versions.
+ * Added /proc/net/ipsec_spinew to generate new and unique spi's..
+ * Fixed /proc/net/ipsec_tncfg bug.
+ *
+ * Revision 1.7 1998/05/25 20:23:13 rgb
+ * proc_register changed to dynamic registration to avoid arbitrary inode
+ * numbers.
+ *
+ * Implement memory recovery from tdb and eroute tables.
+ *
+ * Revision 1.6 1998/05/21 13:08:58 rgb
+ * Rewrote procinfo subroutines to avoid *bad things* when more that 3k of
+ * information is available for printout.
+ *
+ * Revision 1.5 1998/05/18 21:29:48 rgb
+ * Cleaned up /proc/net/ipsec_* output, including a title line, algorithm
+ * names instead of numbers, standard format for numerical output base,
+ * whitespace for legibility, and the names themselves for consistency.
+ *
+ * Added /proc/net/ipsec_spigrp and /proc/net/ipsec_tncfg.
+ *
+ * Revision 1.4 1998/04/30 15:42:24 rgb
+ * Silencing attach for normal operations with #ifdef IPSEC_DEBUG.
+ *
+ * Revision 1.3 1998/04/21 21:28:58 rgb
+ * Rearrange debug switches to change on the fly debug output from user
+ * space. Only kernel changes checked in at this time. radij.c was also
+ * changed to temporarily remove buggy debugging code in rj_delete causing
+ * an OOPS and hence, netlink device open errors.
+ *
+ * Revision 1.2 1998/04/12 22:03:22 rgb
+ * Updated ESP-3DES-HMAC-MD5-96,
+ * ESP-DES-HMAC-MD5-96,
+ * AH-HMAC-MD5-96,
+ * AH-HMAC-SHA1-96 since Henry started freeswan cvs repository
+ * from old standards (RFC182[5-9] to new (as of March 1998) drafts.
+ *
+ * Fixed eroute references in /proc/net/ipsec*.
+ *
+ * Started to patch module unloading memory leaks in ipsec_netlink and
+ * radij tree unloading.
+ *
+ * Revision 1.1 1998/04/09 03:06:05 henry
+ * sources moved up from linux/net/ipsec
+ *
+ * Revision 1.1.1.1 1998/04/08 05:35:02 henry
+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
+ *
+ * Revision 0.4 1997/01/15 01:28:15 ji
+ * No changes.
+ *
+ * Revision 0.3 1996/11/20 14:39:04 ji
+ * Fixed problem with node names of /proc/net entries.
+ * Other minor cleanups.
+ * Rationalized debugging code.
+ *
+ * Revision 0.2 1996/11/02 00:18:33 ji
+ * First limited release.
+ *
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ *
+ */
diff --git a/linux/net/ipsec/ipsec_life.c b/linux/net/ipsec/ipsec_life.c
new file mode 100644
index 000000000..384866c06
--- /dev/null
+++ b/linux/net/ipsec/ipsec_life.c
@@ -0,0 +1,210 @@
+/*
+ * @(#) lifetime structure utilities
+ *
+ * Copyright (C) 2001 Richard Guy Briggs <rgb@freeswan.org>
+ * and Michael Richardson <mcr@freeswan.org>
+ *
+ * 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: ipsec_life.c,v 1.3 2004/04/28 08:06:22 as Exp $
+ *
+ */
+
+/*
+ * This provides series of utility functions for dealing with lifetime
+ * structures.
+ *
+ * ipsec_check_lifetime - returns -1 hard lifetime exceeded
+ * 0 soft lifetime exceeded
+ * 1 everything is okay
+ * based upon whether or not the count exceeds hard/soft
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/config.h> /* for CONFIG_IP_FORWARD */
+#include <linux/version.h>
+#include <linux/kernel.h> /* printk() */
+
+#include "freeswan/ipsec_param.h"
+
+#include <linux/netdevice.h> /* struct device, struct net_device_stats and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/skbuff.h>
+#include <freeswan.h>
+
+#include "freeswan/radij.h"
+#include "freeswan/ipsec_life.h"
+#include "freeswan/ipsec_xform.h"
+#include "freeswan/ipsec_eroute.h"
+#include "freeswan/ipsec_encap.h"
+#include "freeswan/ipsec_radij.h"
+
+#include "freeswan/ipsec_sa.h"
+#include "freeswan/ipsec_tunnel.h"
+#include "freeswan/ipsec_ipe4.h"
+#include "freeswan/ipsec_ah.h"
+#include "freeswan/ipsec_esp.h"
+
+#ifdef CONFIG_IPSEC_IPCOMP
+#include "freeswan/ipcomp.h"
+#endif /* CONFIG_IPSEC_IPCOMP */
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "freeswan/ipsec_proto.h"
+
+
+enum ipsec_life_alive
+ipsec_lifetime_check(struct ipsec_lifetime64 *il64,
+ const char *lifename,
+ const char *saname,
+ enum ipsec_life_type ilt,
+ enum ipsec_direction idir,
+ struct ipsec_sa *ips)
+{
+ __u64 count;
+ const char *dir;
+
+ if(saname == NULL) {
+ saname = "unknown-SA";
+ }
+
+ if(idir == ipsec_incoming) {
+ dir = "incoming";
+ } else {
+ dir = "outgoing";
+ }
+
+
+ if(ilt == ipsec_life_timebased) {
+ count = jiffies/HZ - il64->ipl_count;
+ } else {
+ count = il64->ipl_count;
+ }
+
+ if(il64->ipl_hard &&
+ (count > il64->ipl_hard)) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_lifetime_check: "
+ "hard %s lifetime of SA:<%s%s%s> %s has been reached, SA expired, "
+ "%s packet dropped.\n",
+ lifename,
+ IPS_XFORM_NAME(ips),
+ saname,
+ dir);
+
+ pfkey_expire(ips, 1);
+ return ipsec_life_harddied;
+ }
+
+ if(il64->ipl_soft &&
+ (count > il64->ipl_soft)) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_lifetime_check: "
+ "soft %s lifetime of SA:<%s%s%s> %s has been reached, SA expiring, "
+ "soft expire message sent up, %s packet still processed.\n",
+ lifename,
+ IPS_XFORM_NAME(ips),
+ saname,
+ dir);
+
+ if(ips->ips_state != SADB_SASTATE_DYING) {
+ pfkey_expire(ips, 0);
+ }
+ ips->ips_state = SADB_SASTATE_DYING;
+
+ return ipsec_life_softdied;
+ }
+ return ipsec_life_okay;
+}
+
+
+/*
+ * This function takes a buffer (with length), a lifetime name and type,
+ * and formats a string to represent the current values of the lifetime.
+ *
+ * It returns the number of bytes that the format took (or would take,
+ * if the buffer were large enough: snprintf semantics).
+ * This is used in /proc routines and in debug output.
+ */
+int
+ipsec_lifetime_format(char *buffer,
+ int buflen,
+ char *lifename,
+ enum ipsec_life_type timebaselife,
+ struct ipsec_lifetime64 *lifetime)
+{
+ int len = 0;
+ __u64 count;
+
+ if(timebaselife == ipsec_life_timebased) {
+ count = jiffies/HZ - lifetime->ipl_count;
+ } else {
+ count = lifetime->ipl_count;
+ }
+
+ if(lifetime->ipl_count > 1 ||
+ lifetime->ipl_soft ||
+ lifetime->ipl_hard) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0))
+ len = ipsec_snprintf(buffer, buflen,
+ "%s(%Lu,%Lu,%Lu)",
+ lifename,
+ count,
+ lifetime->ipl_soft,
+ lifetime->ipl_hard);
+#else /* XXX high 32 bits are not displayed */
+ len = ipsec_snprintf(buffer, buflen,
+ "%s(%lu,%lu,%lu)",
+ lifename,
+ (unsigned long)count,
+ (unsigned long)lifetime->ipl_soft,
+ (unsigned long)lifetime->ipl_hard);
+#endif
+ }
+
+ return len;
+}
+
+void
+ipsec_lifetime_update_hard(struct ipsec_lifetime64 *lifetime,
+ __u64 newvalue)
+{
+ if(newvalue &&
+ (!lifetime->ipl_hard ||
+ (newvalue < lifetime->ipl_hard))) {
+ lifetime->ipl_hard = newvalue;
+
+ if(!lifetime->ipl_soft &&
+ (lifetime->ipl_hard < lifetime->ipl_soft)) {
+ lifetime->ipl_soft = lifetime->ipl_hard;
+ }
+ }
+}
+
+void
+ipsec_lifetime_update_soft(struct ipsec_lifetime64 *lifetime,
+ __u64 newvalue)
+{
+ if(newvalue &&
+ (!lifetime->ipl_soft ||
+ (newvalue < lifetime->ipl_soft))) {
+ lifetime->ipl_soft = newvalue;
+
+ if(lifetime->ipl_hard &&
+ (lifetime->ipl_hard < lifetime->ipl_soft)) {
+ lifetime->ipl_soft = lifetime->ipl_hard;
+ }
+ }
+}
diff --git a/linux/net/ipsec/ipsec_mast.c b/linux/net/ipsec/ipsec_mast.c
new file mode 100644
index 000000000..f5216b541
--- /dev/null
+++ b/linux/net/ipsec/ipsec_mast.c
@@ -0,0 +1,1064 @@
+/*
+ * IPSEC MAST code.
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Richard Guy Briggs.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+char ipsec_mast_c_version[] = "RCSID $Id: ipsec_mast.c,v 1.2 2004/06/13 19:57:49 as Exp $";
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/config.h> /* for CONFIG_IP_FORWARD */
+#include <linux/version.h>
+#include <linux/kernel.h> /* printk() */
+
+#include "freeswan/ipsec_param.h"
+
+#ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+#else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+#endif /* MALLOC_SLAB */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/interrupt.h> /* mark_bh */
+
+#include <linux/netdevice.h> /* struct device, struct net_device_stats, dev_queue_xmit() and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/ip.h> /* struct iphdr */
+#include <linux/tcp.h> /* struct tcphdr */
+#include <linux/udp.h> /* struct udphdr */
+#include <linux/skbuff.h>
+#include <freeswan.h>
+#include <asm/uaccess.h>
+#include <linux/in6.h>
+#include <net/dst.h>
+#undef dev_kfree_skb
+#define dev_kfree_skb(a,b) kfree_skb(a)
+#define PHYSDEV_TYPE
+#include <asm/checksum.h>
+#include <net/icmp.h> /* icmp_send() */
+#include <net/ip.h>
+#include <linux/netfilter_ipv4.h>
+
+#include <linux/if_arp.h>
+
+#include "freeswan/radij.h"
+#include "freeswan/ipsec_life.h"
+#include "freeswan/ipsec_xform.h"
+#include "freeswan/ipsec_eroute.h"
+#include "freeswan/ipsec_encap.h"
+#include "freeswan/ipsec_radij.h"
+#include "freeswan/ipsec_sa.h"
+#include "freeswan/ipsec_tunnel.h"
+#include "freeswan/ipsec_mast.h"
+#include "freeswan/ipsec_ipe4.h"
+#include "freeswan/ipsec_ah.h"
+#include "freeswan/ipsec_esp.h"
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "freeswan/ipsec_proto.h"
+
+int ipsec_maxdevice_count = -1;
+
+DEBUG_NO_STATIC int
+ipsec_mast_open(struct device *dev)
+{
+ struct ipsecpriv *prv = dev->priv;
+
+ /*
+ * Can't open until attached.
+ */
+
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_open: "
+ "dev = %s, prv->dev = %s\n",
+ dev->name, prv->dev?prv->dev->name:"NONE");
+
+ if (prv->dev == NULL)
+ return -ENODEV;
+
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+DEBUG_NO_STATIC int
+ipsec_mast_close(struct device *dev)
+{
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+static inline int ipsec_mast_xmit2(struct sk_buff *skb)
+{
+ return ip_send(skb);
+}
+
+enum ipsec_xmit_value
+ipsec_mast_send(struct ipsec_xmit_state*ixs)
+{
+ /* new route/dst cache code from James Morris */
+ ixs->skb->dev = ixs->physdev;
+ /*skb_orphan(ixs->skb);*/
+ if((ixs->error = ip_route_output(&ixs->route,
+ ixs->skb->nh.iph->daddr,
+ ixs->pass ? 0 : ixs->skb->nh.iph->saddr,
+ RT_TOS(ixs->skb->nh.iph->tos),
+ ixs->physdev->iflink /* rgb: should this be 0? */))) {
+ ixs->stats->tx_errors++;
+ KLIPS_PRINT(debug_mast & DB_MAST_XMIT,
+ "klips_debug:ipsec_xmit_send: "
+ "ip_route_output failed with error code %d, rt->u.dst.dev=%s, dropped\n",
+ ixs->error,
+ ixs->route->u.dst.dev->name);
+ return IPSEC_XMIT_ROUTEERR;
+ }
+ if(ixs->dev == ixs->route->u.dst.dev) {
+ ip_rt_put(ixs->route);
+ /* This is recursion, drop it. */
+ ixs->stats->tx_errors++;
+ KLIPS_PRINT(debug_mast & DB_MAST_XMIT,
+ "klips_debug:ipsec_xmit_send: "
+ "suspect recursion, dev=rt->u.dst.dev=%s, dropped\n",
+ ixs->dev->name);
+ return IPSEC_XMIT_RECURSDETECT;
+ }
+ dst_release(ixs->skb->dst);
+ ixs->skb->dst = &ixs->route->u.dst;
+ ixs->stats->tx_bytes += ixs->skb->len;
+ if(ixs->skb->len < ixs->skb->nh.raw - ixs->skb->data) {
+ ixs->stats->tx_errors++;
+ printk(KERN_WARNING
+ "klips_error:ipsec_xmit_send: "
+ "tried to __skb_pull nh-data=%ld, %d available. This should never happen, please report.\n",
+ (unsigned long)(ixs->skb->nh.raw - ixs->skb->data),
+ ixs->skb->len);
+ return IPSEC_XMIT_PUSHPULLERR;
+ }
+ __skb_pull(ixs->skb, ixs->skb->nh.raw - ixs->skb->data);
+#ifdef SKB_RESET_NFCT
+ nf_conntrack_put(ixs->skb->nfct);
+ ixs->skb->nfct = NULL;
+#ifdef CONFIG_NETFILTER_DEBUG
+ ixs->skb->nf_debug = 0;
+#endif /* CONFIG_NETFILTER_DEBUG */
+#endif /* SKB_RESET_NFCT */
+ KLIPS_PRINT(debug_mast & DB_MAST_XMIT,
+ "klips_debug:ipsec_xmit_send: "
+ "...done, calling ip_send() on device:%s\n",
+ ixs->skb->dev ? ixs->skb->dev->name : "NULL");
+ KLIPS_IP_PRINT(debug_mast & DB_MAST_XMIT, ixs->skb->nh.iph);
+ {
+ int err;
+
+ err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, ixs->skb, NULL, ixs->route->u.dst.dev,
+ ipsec_mast_xmit2);
+ if(err != NET_XMIT_SUCCESS && err != NET_XMIT_CN) {
+ if(net_ratelimit())
+ printk(KERN_ERR
+ "klips_error:ipsec_xmit_send: "
+ "ip_send() failed, err=%d\n",
+ -err);
+ ixs->stats->tx_errors++;
+ ixs->stats->tx_aborted_errors++;
+ ixs->skb = NULL;
+ return IPSEC_XMIT_IPSENDFAILURE;
+ }
+ }
+ ixs->stats->tx_packets++;
+
+ ixs->skb = NULL;
+
+ return IPSEC_XMIT_OK;
+}
+
+void
+ipsec_mast_cleanup(struct ipsec_xmit_state*ixs)
+{
+#if defined(HAS_NETIF_QUEUE) || defined (HAVE_NETIF_QUEUE)
+ netif_wake_queue(ixs->dev);
+#else /* defined(HAS_NETIF_QUEUE) || defined (HAVE_NETIF_QUEUE) */
+ ixs->dev->tbusy = 0;
+#endif /* defined(HAS_NETIF_QUEUE) || defined (HAVE_NETIF_QUEUE) */
+ if(ixs->saved_header) {
+ kfree(ixs->saved_header);
+ }
+ if(ixs->skb) {
+ dev_kfree_skb(ixs->skb, FREE_WRITE);
+ }
+ if(ixs->oskb) {
+ dev_kfree_skb(ixs->oskb, FREE_WRITE);
+ }
+ if (ixs->ips.ips_ident_s.data) {
+ kfree(ixs->ips.ips_ident_s.data);
+ }
+ if (ixs->ips.ips_ident_d.data) {
+ kfree(ixs->ips.ips_ident_d.data);
+ }
+}
+
+#if 0
+/*
+ * This function assumes it is being called from dev_queue_xmit()
+ * and that skb is filled properly by that function.
+ */
+int
+ipsec_mast_start_xmit(struct sk_buff *skb, struct device *dev, IPsecSAref_t SAref)
+{
+ struct ipsec_xmit_state ixs_mem;
+ struct ipsec_xmit_state *ixs = &ixs_mem;
+ enum ipsec_xmit_value stat = IPSEC_XMIT_OK;
+
+ /* dev could be a mast device, but should be optional, I think... */
+ /* SAref is also optional, but one of the two must be present. */
+ /* I wonder if it could accept no device or saref and guess? */
+
+/* ipsec_xmit_sanity_check_dev(ixs); */
+
+ ipsec_xmit_sanity_check_skb(ixs);
+
+ ipsec_xmit_adjust_hard_header(ixs);
+
+ stat = ipsec_xmit_encap_bundle(ixs);
+ if(stat != IPSEC_XMIT_OK) {
+ /* SA processing failed */
+ }
+
+ ipsec_xmit_hard_header_restore();
+}
+#endif
+
+DEBUG_NO_STATIC struct net_device_stats *
+ipsec_mast_get_stats(struct device *dev)
+{
+ return &(((struct ipsecpriv *)(dev->priv))->mystats);
+}
+
+/*
+ * Revectored calls.
+ * For each of these calls, a field exists in our private structure.
+ */
+
+DEBUG_NO_STATIC int
+ipsec_mast_hard_header(struct sk_buff *skb, struct device *dev,
+ unsigned short type, void *daddr, void *saddr, unsigned len)
+{
+ struct ipsecpriv *prv = dev->priv;
+ struct device *tmp;
+ int ret;
+ struct net_device_stats *stats; /* This device's statistics */
+
+ if(skb == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_hard_header: "
+ "no skb...\n");
+ return -ENODATA;
+ }
+
+ if(dev == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_hard_header: "
+ "no device...\n");
+ return -ENODEV;
+ }
+
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_hard_header: "
+ "skb->dev=%s dev=%s.\n",
+ skb->dev ? skb->dev->name : "NULL",
+ dev->name);
+
+ if(prv == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_hard_header: "
+ "no private space associated with dev=%s\n",
+ dev->name ? dev->name : "NULL");
+ return -ENODEV;
+ }
+
+ stats = (struct net_device_stats *) &(prv->mystats);
+
+ if(prv->dev == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_hard_header: "
+ "no physical device associated with dev=%s\n",
+ dev->name ? dev->name : "NULL");
+ stats->tx_dropped++;
+ return -ENODEV;
+ }
+
+ /* check if we have to send a IPv6 packet. It might be a Router
+ Solicitation, where the building of the packet happens in
+ reverse order:
+ 1. ll hdr,
+ 2. IPv6 hdr,
+ 3. ICMPv6 hdr
+ -> skb->nh.raw is still uninitialized when this function is
+ called!! If this is no IPv6 packet, we can print debugging
+ messages, otherwise we skip all debugging messages and just
+ build the ll header */
+ if(type != ETH_P_IPV6) {
+ /* execute this only, if we don't have to build the
+ header for a IPv6 packet */
+ if(!prv->hard_header) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_hard_header: "
+ "physical device has been detached, packet dropped 0p%p->0p%p len=%d type=%d dev=%s->NULL ",
+ saddr,
+ daddr,
+ len,
+ type,
+ dev->name);
+ KLIPS_PRINTMORE(debug_mast & DB_MAST_REVEC,
+ "ip=%08x->%08x\n",
+ (__u32)ntohl(skb->nh.iph->saddr),
+ (__u32)ntohl(skb->nh.iph->daddr) );
+ stats->tx_dropped++;
+ return -ENODEV;
+ }
+
+#define da ((struct device *)(prv->dev))->dev_addr
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_hard_header: "
+ "Revectored 0p%p->0p%p len=%d type=%d dev=%s->%s dev_addr=%02x:%02x:%02x:%02x:%02x:%02x ",
+ saddr,
+ daddr,
+ len,
+ type,
+ dev->name,
+ prv->dev->name,
+ da[0], da[1], da[2], da[3], da[4], da[5]);
+ KLIPS_PRINTMORE(debug_mast & DB_MAST_REVEC,
+ "ip=%08x->%08x\n",
+ (__u32)ntohl(skb->nh.iph->saddr),
+ (__u32)ntohl(skb->nh.iph->daddr) );
+ } else {
+ KLIPS_PRINT(debug_mast,
+ "klips_debug:ipsec_mast_hard_header: "
+ "is IPv6 packet, skip debugging messages, only revector and build linklocal header.\n");
+ }
+ tmp = skb->dev;
+ skb->dev = prv->dev;
+ ret = prv->hard_header(skb, prv->dev, type, (void *)daddr, (void *)saddr, len);
+ skb->dev = tmp;
+ return ret;
+}
+
+DEBUG_NO_STATIC int
+ipsec_mast_rebuild_header(struct sk_buff *skb)
+{
+ struct ipsecpriv *prv = skb->dev->priv;
+ struct device *tmp;
+ int ret;
+ struct net_device_stats *stats; /* This device's statistics */
+
+ if(skb->dev == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_rebuild_header: "
+ "no device...");
+ return -ENODEV;
+ }
+
+ if(prv == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_rebuild_header: "
+ "no private space associated with dev=%s",
+ skb->dev->name ? skb->dev->name : "NULL");
+ return -ENODEV;
+ }
+
+ stats = (struct net_device_stats *) &(prv->mystats);
+
+ if(prv->dev == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_rebuild_header: "
+ "no physical device associated with dev=%s",
+ skb->dev->name ? skb->dev->name : "NULL");
+ stats->tx_dropped++;
+ return -ENODEV;
+ }
+
+ if(!prv->rebuild_header) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_rebuild_header: "
+ "physical device has been detached, packet dropped skb->dev=%s->NULL ",
+ skb->dev->name);
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "ip=%08x->%08x\n",
+ (__u32)ntohl(skb->nh.iph->saddr),
+ (__u32)ntohl(skb->nh.iph->daddr) );
+ stats->tx_dropped++;
+ return -ENODEV;
+ }
+
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast: "
+ "Revectored rebuild_header dev=%s->%s ",
+ skb->dev->name, prv->dev->name);
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "ip=%08x->%08x\n",
+ (__u32)ntohl(skb->nh.iph->saddr),
+ (__u32)ntohl(skb->nh.iph->daddr) );
+ tmp = skb->dev;
+ skb->dev = prv->dev;
+
+ ret = prv->rebuild_header(skb);
+ skb->dev = tmp;
+ return ret;
+}
+
+DEBUG_NO_STATIC int
+ipsec_mast_set_mac_address(struct device *dev, void *addr)
+{
+ struct ipsecpriv *prv = dev->priv;
+
+ struct net_device_stats *stats; /* This device's statistics */
+
+ if(dev == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_set_mac_address: "
+ "no device...");
+ return -ENODEV;
+ }
+
+ if(prv == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_set_mac_address: "
+ "no private space associated with dev=%s",
+ dev->name ? dev->name : "NULL");
+ return -ENODEV;
+ }
+
+ stats = (struct net_device_stats *) &(prv->mystats);
+
+ if(prv->dev == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_set_mac_address: "
+ "no physical device associated with dev=%s",
+ dev->name ? dev->name : "NULL");
+ stats->tx_dropped++;
+ return -ENODEV;
+ }
+
+ if(!prv->set_mac_address) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_set_mac_address: "
+ "physical device has been detached, cannot set - skb->dev=%s->NULL\n",
+ dev->name);
+ return -ENODEV;
+ }
+
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_set_mac_address: "
+ "Revectored dev=%s->%s addr=0p%p\n",
+ dev->name, prv->dev->name, addr);
+ return prv->set_mac_address(prv->dev, addr);
+
+}
+
+DEBUG_NO_STATIC void
+ipsec_mast_cache_update(struct hh_cache *hh, struct device *dev, unsigned char * haddr)
+{
+ struct ipsecpriv *prv = dev->priv;
+
+ struct net_device_stats *stats; /* This device's statistics */
+
+ if(dev == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_cache_update: "
+ "no device...");
+ return;
+ }
+
+ if(prv == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_cache_update: "
+ "no private space associated with dev=%s",
+ dev->name ? dev->name : "NULL");
+ return;
+ }
+
+ stats = (struct net_device_stats *) &(prv->mystats);
+
+ if(prv->dev == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_cache_update: "
+ "no physical device associated with dev=%s",
+ dev->name ? dev->name : "NULL");
+ stats->tx_dropped++;
+ return;
+ }
+
+ if(!prv->header_cache_update) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_cache_update: "
+ "physical device has been detached, cannot set - skb->dev=%s->NULL\n",
+ dev->name);
+ return;
+ }
+
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast: "
+ "Revectored cache_update\n");
+ prv->header_cache_update(hh, prv->dev, haddr);
+ return;
+}
+
+DEBUG_NO_STATIC int
+ipsec_mast_neigh_setup(struct neighbour *n)
+{
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_neigh_setup:\n");
+
+ if (n->nud_state == NUD_NONE) {
+ n->ops = &arp_broken_ops;
+ n->output = n->ops->output;
+ }
+ return 0;
+}
+
+DEBUG_NO_STATIC int
+ipsec_mast_neigh_setup_dev(struct device *dev, struct neigh_parms *p)
+{
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_neigh_setup_dev: "
+ "setting up %s\n",
+ dev ? dev->name : "NULL");
+
+ if (p->tbl->family == AF_INET) {
+ p->neigh_setup = ipsec_mast_neigh_setup;
+ p->ucast_probes = 0;
+ p->mcast_probes = 0;
+ }
+ return 0;
+}
+
+/*
+ * We call the attach routine to attach another device.
+ */
+
+DEBUG_NO_STATIC int
+ipsec_mast_attach(struct device *dev, struct device *physdev)
+{
+ int i;
+ struct ipsecpriv *prv = dev->priv;
+
+ if(dev == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_attach: "
+ "no device...");
+ return -ENODEV;
+ }
+
+ if(prv == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_attach: "
+ "no private space associated with dev=%s",
+ dev->name ? dev->name : "NULL");
+ return -ENODATA;
+ }
+
+ prv->dev = physdev;
+ prv->hard_start_xmit = physdev->hard_start_xmit;
+ prv->get_stats = physdev->get_stats;
+
+ if (physdev->hard_header) {
+ prv->hard_header = physdev->hard_header;
+ dev->hard_header = ipsec_mast_hard_header;
+ } else
+ dev->hard_header = NULL;
+
+ if (physdev->rebuild_header) {
+ prv->rebuild_header = physdev->rebuild_header;
+ dev->rebuild_header = ipsec_mast_rebuild_header;
+ } else
+ dev->rebuild_header = NULL;
+
+ if (physdev->set_mac_address) {
+ prv->set_mac_address = physdev->set_mac_address;
+ dev->set_mac_address = ipsec_mast_set_mac_address;
+ } else
+ dev->set_mac_address = NULL;
+
+ if (physdev->header_cache_update) {
+ prv->header_cache_update = physdev->header_cache_update;
+ dev->header_cache_update = ipsec_mast_cache_update;
+ } else
+ dev->header_cache_update = NULL;
+
+ dev->hard_header_len = physdev->hard_header_len;
+
+/* prv->neigh_setup = physdev->neigh_setup; */
+ dev->neigh_setup = ipsec_mast_neigh_setup_dev;
+ dev->mtu = 16260; /* 0xfff0; */ /* dev->mtu; */
+ prv->mtu = physdev->mtu;
+
+#ifdef PHYSDEV_TYPE
+ dev->type = physdev->type; /* ARPHRD_MAST; */
+#endif /* PHYSDEV_TYPE */
+
+ dev->addr_len = physdev->addr_len;
+ for (i=0; i<dev->addr_len; i++) {
+ dev->dev_addr[i] = physdev->dev_addr[i];
+ }
+#ifdef CONFIG_IPSEC_DEBUG
+ if(debug_mast & DB_MAST_INIT) {
+ printk(KERN_INFO "klips_debug:ipsec_mast_attach: "
+ "physical device %s being attached has HW address: %2x",
+ physdev->name, physdev->dev_addr[0]);
+ for (i=1; i < physdev->addr_len; i++) {
+ printk(":%02x", physdev->dev_addr[i]);
+ }
+ printk("\n");
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+
+ return 0;
+}
+
+/*
+ * We call the detach routine to detach the ipsec mast from another device.
+ */
+
+DEBUG_NO_STATIC int
+ipsec_mast_detach(struct device *dev)
+{
+ int i;
+ struct ipsecpriv *prv = dev->priv;
+
+ if(dev == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_detach: "
+ "no device...");
+ return -ENODEV;
+ }
+
+ if(prv == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_detach: "
+ "no private space associated with dev=%s",
+ dev->name ? dev->name : "NULL");
+ return -ENODATA;
+ }
+
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_detach: "
+ "physical device %s being detached from virtual device %s\n",
+ prv->dev ? prv->dev->name : "NULL",
+ dev->name);
+
+ prv->dev = NULL;
+ prv->hard_start_xmit = NULL;
+ prv->get_stats = NULL;
+
+ prv->hard_header = NULL;
+#ifdef DETACH_AND_DOWN
+ dev->hard_header = NULL;
+#endif /* DETACH_AND_DOWN */
+
+ prv->rebuild_header = NULL;
+#ifdef DETACH_AND_DOWN
+ dev->rebuild_header = NULL;
+#endif /* DETACH_AND_DOWN */
+
+ prv->set_mac_address = NULL;
+#ifdef DETACH_AND_DOWN
+ dev->set_mac_address = NULL;
+#endif /* DETACH_AND_DOWN */
+
+ prv->header_cache_update = NULL;
+#ifdef DETACH_AND_DOWN
+ dev->header_cache_update = NULL;
+#endif /* DETACH_AND_DOWN */
+
+#ifdef DETACH_AND_DOWN
+ dev->neigh_setup = NULL;
+#endif /* DETACH_AND_DOWN */
+
+ dev->hard_header_len = 0;
+#ifdef DETACH_AND_DOWN
+ dev->mtu = 0;
+#endif /* DETACH_AND_DOWN */
+ prv->mtu = 0;
+ for (i=0; i<MAX_ADDR_LEN; i++) {
+ dev->dev_addr[i] = 0;
+ }
+ dev->addr_len = 0;
+#ifdef PHYSDEV_TYPE
+ dev->type = ARPHRD_VOID; /* ARPHRD_MAST; */
+#endif /* PHYSDEV_TYPE */
+
+ return 0;
+}
+
+/*
+ * We call the clear routine to detach all ipsec masts from other devices.
+ */
+DEBUG_NO_STATIC int
+ipsec_mast_clear(void)
+{
+ int i;
+ struct device *ipsecdev = NULL, *prvdev;
+ struct ipsecpriv *prv;
+ char name[9];
+ int ret;
+
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_clear: .\n");
+
+ for(i = 0; i < IPSEC_NUM_IF; i++) {
+ sprintf(name, IPSEC_DEV_FORMAT, i);
+ if((ipsecdev = ipsec_dev_get(name)) != NULL) {
+ if((prv = (struct ipsecpriv *)(ipsecdev->priv))) {
+ prvdev = (struct device *)(prv->dev);
+ if(prvdev) {
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_clear: "
+ "physical device for device %s is %s\n",
+ name, prvdev->name);
+ if((ret = ipsec_mast_detach(ipsecdev))) {
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_clear: "
+ "error %d detatching device %s from device %s.\n",
+ ret, name, prvdev->name);
+ return ret;
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+DEBUG_NO_STATIC int
+ipsec_mast_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
+{
+ struct ipsecmastconf *cf = (struct ipsecmastconf *)&ifr->ifr_data;
+ struct ipsecpriv *prv = dev->priv;
+ struct device *them; /* physical device */
+#ifdef CONFIG_IP_ALIAS
+ char *colon;
+ char realphysname[IFNAMSIZ];
+#endif /* CONFIG_IP_ALIAS */
+
+ if(dev == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_ioctl: "
+ "device not supplied.\n");
+ return -ENODEV;
+ }
+
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_ioctl: "
+ "tncfg service call #%d for dev=%s\n",
+ cmd,
+ dev->name ? dev->name : "NULL");
+ switch (cmd) {
+ /* attach a virtual ipsec? device to a physical device */
+ case IPSEC_SET_DEV:
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_ioctl: "
+ "calling ipsec_mast_attatch...\n");
+#ifdef CONFIG_IP_ALIAS
+ /* If this is an IP alias interface, get its real physical name */
+ strncpy(realphysname, cf->cf_name, IFNAMSIZ);
+ realphysname[IFNAMSIZ-1] = 0;
+ colon = strchr(realphysname, ':');
+ if (colon) *colon = 0;
+ them = ipsec_dev_get(realphysname);
+#else /* CONFIG_IP_ALIAS */
+ them = ipsec_dev_get(cf->cf_name);
+#endif /* CONFIG_IP_ALIAS */
+
+ if (them == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_ioctl: "
+ "physical device %s requested is null\n",
+ cf->cf_name);
+ return -ENXIO;
+ }
+
+#if 0
+ if (them->flags & IFF_UP) {
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_ioctl: "
+ "physical device %s requested is not up.\n",
+ cf->cf_name);
+ return -ENXIO;
+ }
+#endif
+
+ if (prv && prv->dev) {
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_ioctl: "
+ "virtual device is already connected to %s.\n",
+ prv->dev->name ? prv->dev->name : "NULL");
+ return -EBUSY;
+ }
+ return ipsec_mast_attach(dev, them);
+
+ case IPSEC_DEL_DEV:
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_ioctl: "
+ "calling ipsec_mast_detatch.\n");
+ if (! prv->dev) {
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_ioctl: "
+ "physical device not connected.\n");
+ return -ENODEV;
+ }
+ return ipsec_mast_detach(dev);
+
+ case IPSEC_CLR_DEV:
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_ioctl: "
+ "calling ipsec_mast_clear.\n");
+ return ipsec_mast_clear();
+
+ default:
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_ioctl: "
+ "unknown command %d.\n",
+ cmd);
+ return -EOPNOTSUPP;
+ }
+}
+
+int
+ipsec_mast_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
+{
+ struct device *dev = ptr;
+ struct device *ipsec_dev;
+ struct ipsecpriv *priv;
+ char name[9];
+ int i;
+
+ if (dev == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_device_event: "
+ "dev=NULL for event type %ld.\n",
+ event);
+ return(NOTIFY_DONE);
+ }
+
+ /* check for loopback devices */
+ if (dev && (dev->flags & IFF_LOOPBACK)) {
+ return(NOTIFY_DONE);
+ }
+
+ switch (event) {
+ case NETDEV_DOWN:
+ /* look very carefully at the scope of these compiler
+ directives before changing anything... -- RGB */
+
+ case NETDEV_UNREGISTER:
+ switch (event) {
+ case NETDEV_DOWN:
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_device_event: "
+ "NETDEV_DOWN dev=%s flags=%x\n",
+ dev->name,
+ dev->flags);
+ if(strncmp(dev->name, "ipsec", strlen("ipsec")) == 0) {
+ printk(KERN_CRIT "IPSEC EVENT: KLIPS device %s shut down.\n",
+ dev->name);
+ }
+ break;
+ case NETDEV_UNREGISTER:
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_device_event: "
+ "NETDEV_UNREGISTER dev=%s flags=%x\n",
+ dev->name,
+ dev->flags);
+ break;
+ }
+
+ /* find the attached physical device and detach it. */
+ for(i = 0; i < IPSEC_NUM_IF; i++) {
+ sprintf(name, IPSEC_DEV_FORMAT, i);
+ ipsec_dev = ipsec_dev_get(name);
+ if(ipsec_dev) {
+ priv = (struct ipsecpriv *)(ipsec_dev->priv);
+ if(priv) {
+ ;
+ if(((struct device *)(priv->dev)) == dev) {
+ /* dev_close(ipsec_dev); */
+ /* return */ ipsec_mast_detach(ipsec_dev);
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_device_event: "
+ "device '%s' has been detached.\n",
+ ipsec_dev->name);
+ break;
+ }
+ } else {
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_device_event: "
+ "device '%s' has no private data space!\n",
+ ipsec_dev->name);
+ }
+ }
+ }
+ break;
+ case NETDEV_UP:
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_device_event: "
+ "NETDEV_UP dev=%s\n",
+ dev->name);
+ break;
+ case NETDEV_REBOOT:
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_device_event: "
+ "NETDEV_REBOOT dev=%s\n",
+ dev->name);
+ break;
+ case NETDEV_CHANGE:
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_device_event: "
+ "NETDEV_CHANGE dev=%s flags=%x\n",
+ dev->name,
+ dev->flags);
+ break;
+ case NETDEV_REGISTER:
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_device_event: "
+ "NETDEV_REGISTER dev=%s\n",
+ dev->name);
+ break;
+ case NETDEV_CHANGEMTU:
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_device_event: "
+ "NETDEV_CHANGEMTU dev=%s to mtu=%d\n",
+ dev->name,
+ dev->mtu);
+ break;
+ case NETDEV_CHANGEADDR:
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_device_event: "
+ "NETDEV_CHANGEADDR dev=%s\n",
+ dev->name);
+ break;
+ case NETDEV_GOING_DOWN:
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_device_event: "
+ "NETDEV_GOING_DOWN dev=%s\n",
+ dev->name);
+ break;
+ case NETDEV_CHANGENAME:
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_device_event: "
+ "NETDEV_CHANGENAME dev=%s\n",
+ dev->name);
+ break;
+ default:
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_device_event: "
+ "event type %ld unrecognised for dev=%s\n",
+ event,
+ dev->name);
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
+/*
+ * Called when an ipsec mast device is initialized.
+ * The ipsec mast device structure is passed to us.
+ */
+
+int
+ipsec_mast_init(struct device *dev)
+{
+ int i;
+
+ KLIPS_PRINT(debug_mast,
+ "klips_debug:ipsec_mast_init: "
+ "allocating %lu bytes initialising device: %s\n",
+ (unsigned long) sizeof(struct ipsecpriv),
+ dev->name ? dev->name : "NULL");
+
+ /* Add our mast functions to the device */
+ dev->open = ipsec_mast_open;
+ dev->stop = ipsec_mast_close;
+ dev->hard_start_xmit = ipsec_mast_start_xmit;
+ dev->get_stats = ipsec_mast_get_stats;
+
+ dev->priv = kmalloc(sizeof(struct ipsecpriv), GFP_KERNEL);
+ if (dev->priv == NULL)
+ return -ENOMEM;
+ memset((caddr_t)(dev->priv), 0, sizeof(struct ipsecpriv));
+
+ for(i = 0; i < sizeof(zeroes); i++) {
+ ((__u8*)(zeroes))[i] = 0;
+ }
+
+ dev->set_multicast_list = NULL;
+ dev->do_ioctl = ipsec_mast_ioctl;
+ dev->hard_header = NULL;
+ dev->rebuild_header = NULL;
+ dev->set_mac_address = NULL;
+ dev->header_cache_update= NULL;
+ dev->neigh_setup = ipsec_mast_neigh_setup_dev;
+ dev->hard_header_len = 0;
+ dev->mtu = 0;
+ dev->addr_len = 0;
+ dev->type = ARPHRD_VOID; /* ARPHRD_MAST; */ /* ARPHRD_ETHER; */
+ dev->tx_queue_len = 10; /* Small queue */
+ memset((caddr_t)(dev->broadcast),0xFF, ETH_ALEN); /* what if this is not attached to ethernet? */
+
+ /* New-style flags. */
+ dev->flags = IFF_NOARP /* 0 */ /* Petr Novak */;
+ dev_init_buffers(dev);
+
+ /* We're done. Have I forgotten anything? */
+ return 0;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* Module specific interface (but it links with the rest of IPSEC) */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int
+ipsec_mast_probe(struct device *dev)
+{
+ ipsec_mast_init(dev);
+ return 0;
+}
+
+int
+ipsec_mast_init_devices(void)
+{
+ return 0;
+}
+
+/* void */
+int
+ipsec_mast_cleanup_devices(void)
+{
+ int error = 0;
+ int i;
+ char name[10];
+ struct device *dev_mast;
+
+ for(i = 0; i < ipsec_mastdevice_count; i++) {
+ sprintf(name, MAST_DEV_FORMAT, i);
+ if((dev_mast = ipsec_dev_get(name)) == NULL) {
+ break;
+ }
+ unregister_netdev(dev_mast);
+ kfree(dev_mast->priv);
+ dev_mast->priv=NULL;
+ }
+ return error;
+}
diff --git a/linux/net/ipsec/ipsec_md5c.c b/linux/net/ipsec/ipsec_md5c.c
new file mode 100644
index 000000000..41a1551c1
--- /dev/null
+++ b/linux/net/ipsec/ipsec_md5c.c
@@ -0,0 +1,448 @@
+/*
+ * RCSID $Id: ipsec_md5c.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+
+/*
+ * The rest of the code is derived from MD5C.C by RSADSI. Minor cosmetic
+ * changes to accomodate it in the kernel by ji.
+ */
+
+#include <asm/byteorder.h>
+#include <linux/string.h>
+
+#include "freeswan/ipsec_md5h.h"
+
+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+/*
+ * Additions by JI
+ *
+ * HAVEMEMCOPY is defined if mem* routines are available
+ *
+ * HAVEHTON is defined if htons() and htonl() can be used
+ * for big/little endian conversions
+ *
+ */
+
+#define HAVEMEMCOPY
+#ifdef __LITTLE_ENDIAN
+#define LITTLENDIAN
+#endif
+#ifdef __BIG_ENDIAN
+#define BIGENDIAN
+#endif
+
+/* Constants for MD5Transform routine.
+ */
+
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64]));
+
+#ifdef LITTLEENDIAN
+#define Encode MD5_memcpy
+#define Decode MD5_memcpy
+#else
+static void Encode PROTO_LIST
+ ((unsigned char *, UINT4 *, unsigned int));
+static void Decode PROTO_LIST
+ ((UINT4 *, unsigned char *, unsigned int));
+#endif
+
+#ifdef HAVEMEMCOPY
+/* no need to include <memory.h> here; <linux/string.h> defines these */
+#define MD5_memcpy memcpy
+#define MD5_memset memset
+#else
+#ifdef HAVEBCOPY
+#define MD5_memcpy(_a,_b,_c) bcopy((_b),(_a),(_c))
+#define MD5_memset(_a,_b,_c) bzero((_a),(_c))
+#else
+static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
+static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
+#endif
+#endif
+static unsigned char PADDING[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+/*
+ * MD5 initialization. Begins an MD5 operation, writing a new context.
+ */
+void MD5Init(void *vcontext)
+{
+ MD5_CTX *context = vcontext;
+
+ context->count[0] = context->count[1] = 0;
+ /* Load magic initialization constants.
+*/
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xefcdab89;
+ context->state[2] = 0x98badcfe;
+ context->state[3] = 0x10325476;
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest
+ operation, processing another message block, and updating the
+ context.
+ */
+void MD5Update (vcontext, input, inputLen)
+ void *vcontext;
+ unsigned char *input; /* input block */
+ __u32 inputLen; /* length of input block */
+{
+ MD5_CTX *context = vcontext;
+ __u32 i;
+ unsigned int index, partLen;
+
+ /* Compute number of bytes mod 64 */
+ index = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+ /* Update number of bits */
+ if ((context->count[0] += ((UINT4)inputLen << 3))
+ < ((UINT4)inputLen << 3))
+ context->count[1]++;
+ context->count[1] += ((UINT4)inputLen >> 29);
+
+ partLen = 64 - index;
+
+ /* Transform as many times as possible.
+*/
+ if (inputLen >= partLen) {
+ MD5_memcpy
+ ((POINTER)&context->buffer[index], (POINTER)input, partLen);
+ MD5Transform (context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ MD5Transform (context->state, &input[i]);
+
+ index = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ MD5_memcpy
+ ((POINTER)&context->buffer[index], (POINTER)&input[i],
+ inputLen-i);
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+ the message digest and zeroizing the context.
+ */
+void MD5Final (digest, vcontext)
+unsigned char digest[16]; /* message digest */
+void *vcontext; /* context */
+{
+ MD5_CTX *context = vcontext;
+ unsigned char bits[8];
+ unsigned int index, padLen;
+
+ /* Save number of bits */
+ Encode (bits, context->count, 8);
+
+ /* Pad out to 56 mod 64.
+*/
+ index = (unsigned int)((context->count[0] >> 3) & 0x3f);
+ padLen = (index < 56) ? (56 - index) : (120 - index);
+ MD5Update (context, PADDING, padLen);
+
+ /* Append length (before padding) */
+ MD5Update (context, bits, 8);
+
+ if (digest != NULL) /* Bill Simpson's padding */
+ {
+ /* store state in digest */
+ Encode (digest, context->state, 16);
+
+ /* Zeroize sensitive information.
+ */
+ MD5_memset ((POINTER)context, 0, sizeof (*context));
+ }
+}
+
+/* MD5 basic transformation. Transforms state based on block.
+ */
+static void MD5Transform (state, block)
+UINT4 state[4];
+unsigned char block[64];
+{
+ UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ Decode (x, block, 64);
+
+ /* Round 1 */
+ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
+ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ /* Zeroize sensitive information.
+*/
+ MD5_memset ((POINTER)x, 0, sizeof (x));
+}
+
+#ifndef LITTLEENDIAN
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+ a multiple of 4.
+ */
+static void Encode (output, input, len)
+unsigned char *output;
+UINT4 *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (unsigned char)(input[i] & 0xff);
+ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+ }
+}
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+ a multiple of 4.
+ */
+static void Decode (output, input, len)
+UINT4 *output;
+unsigned char *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
+ (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
+
+#endif
+
+#ifndef HAVEMEMCOPY
+#ifndef HAVEBCOPY
+/* Note: Replace "for loop" with standard memcpy if possible.
+ */
+
+static void MD5_memcpy (output, input, len)
+POINTER output;
+POINTER input;
+unsigned int len;
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+
+ output[i] = input[i];
+}
+
+/* Note: Replace "for loop" with standard memset if possible.
+ */
+
+static void MD5_memset (output, value, len)
+POINTER output;
+int value;
+unsigned int len;
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+ ((char *)output)[i] = (char)value;
+}
+#endif
+#endif
+
+/*
+ * $Log: ipsec_md5c.c,v $
+ * Revision 1.1 2004/03/15 20:35:26 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.7 2002/09/10 01:45:14 mcr
+ * changed type of MD5_CTX and SHA1_CTX to void * so that
+ * the function prototypes would match, and could be placed
+ * into a pointer to a function.
+ *
+ * Revision 1.6 2002/04/24 07:55:32 mcr
+ * #include patches and Makefiles for post-reorg compilation.
+ *
+ * Revision 1.5 2002/04/24 07:36:28 mcr
+ * Moved from ./klips/net/ipsec/ipsec_md5c.c,v
+ *
+ * Revision 1.4 1999/12/13 13:59:12 rgb
+ * Quick fix to argument size to Update bugs.
+ *
+ * Revision 1.3 1999/05/21 18:09:28 henry
+ * unnecessary <memory.h> include causes trouble in 2.2
+ *
+ * Revision 1.2 1999/04/06 04:54:26 rgb
+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+ * patch shell fixes.
+ *
+ * Revision 1.1 1998/06/18 21:27:48 henry
+ * move sources from klips/src to klips/net/ipsec, to keep stupid
+ * kernel-build scripts happier in the presence of symlinks
+ *
+ * Revision 1.2 1998/04/23 20:54:02 rgb
+ * Fixed md5 and sha1 include file nesting issues, to be cleaned up when
+ * verified.
+ *
+ * Revision 1.1 1998/04/09 03:06:08 henry
+ * sources moved up from linux/net/ipsec
+ *
+ * Revision 1.1.1.1 1998/04/08 05:35:04 henry
+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
+ *
+ * Revision 0.3 1996/11/20 14:48:53 ji
+ * Release update only.
+ *
+ * Revision 0.2 1996/11/02 00:18:33 ji
+ * First limited release.
+ *
+ *
+ */
diff --git a/linux/net/ipsec/ipsec_proc.c b/linux/net/ipsec/ipsec_proc.c
new file mode 100644
index 000000000..5d2bba554
--- /dev/null
+++ b/linux/net/ipsec/ipsec_proc.c
@@ -0,0 +1,1003 @@
+/*
+ * @(#) /proc file system interface code.
+ *
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 1998, 1999, 2000, 2001 Richard Guy Briggs <rgb@freeswan.org>
+ * 2001 Michael Richardson <mcr@freeswan.org>
+ *
+ * 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.
+ *
+ * Split out from ipsec_init.c version 1.70.
+ */
+
+char ipsec_proc_c_version[] = "RCSID $Id: ipsec_proc.c,v 1.8 2004/04/28 08:06:22 as Exp $";
+
+#include <linux/config.h>
+#include <linux/version.h>
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/kernel.h> /* printk() */
+
+#include "freeswan/ipsec_param.h"
+
+#ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+#else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+#endif /* MALLOC_SLAB */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/interrupt.h> /* mark_bh */
+
+#include <linux/netdevice.h> /* struct device, and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/ip.h> /* struct iphdr */
+#include <linux/in.h> /* struct sockaddr_in */
+#include <linux/skbuff.h>
+#include <freeswan.h>
+#ifdef SPINLOCK
+#ifdef SPINLOCK_23
+#include <linux/spinlock.h> /* *lock* */
+#else /* SPINLOCK_23 */
+#include <asm/spinlock.h> /* *lock* */
+#endif /* SPINLOCK_23 */
+#endif /* SPINLOCK */
+#ifdef NET_21
+#include <asm/uaccess.h>
+#include <linux/in6.h>
+#endif /* NET_21 */
+#include <asm/checksum.h>
+#include <net/ip.h>
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#endif /* CONFIG_PROC_FS */
+#ifdef NETLINK_SOCK
+#include <linux/netlink.h>
+#else
+#include <net/netlink.h>
+#endif
+
+#include "freeswan/radij.h"
+
+#include "freeswan/ipsec_life.h"
+#include "freeswan/ipsec_stats.h"
+#include "freeswan/ipsec_sa.h"
+
+#include "freeswan/ipsec_encap.h"
+#include "freeswan/ipsec_radij.h"
+#include "freeswan/ipsec_xform.h"
+#include "freeswan/ipsec_tunnel.h"
+#include "freeswan/ipsec_xmit.h"
+
+#include "freeswan/ipsec_rcv.h"
+#include "freeswan/ipsec_ah.h"
+#include "freeswan/ipsec_esp.h"
+
+#ifdef CONFIG_IPSEC_IPCOMP
+#include "freeswan/ipcomp.h"
+#endif /* CONFIG_IPSEC_IPCOMP */
+
+#include "freeswan/ipsec_proto.h"
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#ifdef CONFIG_PROC_FS
+
+#ifdef IPSEC_PROC_SUBDIRS
+static struct proc_dir_entry *proc_net_ipsec_dir = NULL;
+static struct proc_dir_entry *proc_eroute_dir = NULL;
+static struct proc_dir_entry *proc_spi_dir = NULL;
+static struct proc_dir_entry *proc_spigrp_dir = NULL;
+static struct proc_dir_entry *proc_birth_dir = NULL;
+static struct proc_dir_entry *proc_stats_dir = NULL;
+#endif
+
+struct ipsec_birth_reply ipsec_ipv4_birth_packet;
+struct ipsec_birth_reply ipsec_ipv6_birth_packet;
+
+extern int ipsec_xform_get_info(char *buffer, char **start,
+ off_t offset, int length IPSEC_PROC_LAST_ARG);
+
+
+/* ipsec_snprintf: like snprintf except
+ * - size is signed and a negative value is treated as if it were 0
+ * - the returned result is never negative --
+ * an error generates a "?" or null output (depending on space).
+ * (Our callers are too lazy to check for an error return.)
+ *
+ * @param buf String buffer
+ * @param size Size of the string
+ * @param fmt printf string
+ * @param ... Variables to be displayed in fmt
+ * @return int Return code
+ */
+int ipsec_snprintf(char *buf, ssize_t size, const char *fmt, ...)
+{
+ va_list args;
+ int i;
+ size_t possize = size < 0? 0 : size;
+ va_start(args, fmt);
+ i = vsnprintf(buf,possize,fmt,args);
+ va_end(args);
+ if (i < 0) {
+ /* create empty output in place of error */
+ i = 0;
+ if (size > 0) {
+ *buf = '\0';
+ }
+ }
+ return i;
+}
+
+
+IPSEC_PROCFS_DEBUG_NO_STATIC
+int
+ipsec_eroute_get_info(char *buffer,
+ char **start,
+ off_t offset,
+ int length IPSEC_PROC_LAST_ARG)
+{
+ struct wsbuf w = {buffer, length, offset, 0, 0};
+
+#ifdef CONFIG_IPSEC_DEBUG
+ if (debug_radij & DB_RJ_DUMPTREES)
+ rj_dumptrees(); /* XXXXXXXXX */
+#endif /* CONFIG_IPSEC_DEBUG */
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
+ "klips_debug:ipsec_eroute_get_info: "
+ "buffer=0p%p, *start=0p%p, offset=%d, length=%d\n",
+ buffer,
+ *start,
+ (int)offset,
+ length);
+
+ spin_lock_bh(&eroute_lock);
+
+ rj_walktree(rnh, ipsec_rj_walker_procprint, &w);
+/* rj_walktree(mask_rjhead, ipsec_rj_walker_procprint, &w); */
+
+ spin_unlock_bh(&eroute_lock);
+
+ *start = buffer + (offset - w.begin); /* Start of wanted data */
+ return w.len - (offset - w.begin);
+}
+
+IPSEC_PROCFS_DEBUG_NO_STATIC
+int
+ipsec_spi_get_info(char *buffer,
+ char **start,
+ off_t offset,
+ int length IPSEC_PROC_LAST_ARG)
+{
+ /* Limit of useful snprintf output */
+ const int max_content = length > 0? length-1 : 0;
+
+ int len = 0;
+ off_t begin = 0;
+ int i;
+ struct ipsec_sa *sa_p;
+ char sa[SATOA_BUF];
+ char buf_s[SUBNETTOA_BUF];
+ char buf_d[SUBNETTOA_BUF];
+ size_t sa_len;
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
+ "klips_debug:ipsec_spi_get_info: "
+ "buffer=0p%p, *start=0p%p, offset=%d, length=%d\n",
+ buffer,
+ *start,
+ (int)offset,
+ length);
+
+ spin_lock_bh(&tdb_lock);
+
+
+
+ for (i = 0; i < SADB_HASHMOD; i++) {
+ for (sa_p = ipsec_sadb_hash[i];
+ sa_p;
+ sa_p = sa_p->ips_hnext) {
+ atomic_inc(&sa_p->ips_refcount);
+ sa_len = satoa(sa_p->ips_said, 0, sa, SATOA_BUF);
+ len += ipsec_snprintf(buffer+len, length-len, "%s ",
+ sa_len ? sa : " (error)");
+
+ len += ipsec_snprintf(buffer+len, length-len, "%s%s%s",
+ IPS_XFORM_NAME(sa_p));
+
+ len += ipsec_snprintf(buffer+len, length-len, ": dir=%s",
+ (sa_p->ips_flags & EMT_INBOUND) ?
+ "in " : "out");
+
+ if(sa_p->ips_addr_s) {
+ addrtoa(((struct sockaddr_in*)(sa_p->ips_addr_s))->sin_addr,
+ 0, buf_s, sizeof(buf_s));
+ len += ipsec_snprintf(buffer+len, length-len, " src=%s",
+ buf_s);
+ }
+
+ if((sa_p->ips_said.proto == IPPROTO_IPIP)
+ && (sa_p->ips_flags & SADB_X_SAFLAGS_INFLOW)) {
+ subnettoa(sa_p->ips_flow_s.u.v4.sin_addr,
+ sa_p->ips_mask_s.u.v4.sin_addr,
+ 0,
+ buf_s,
+ sizeof(buf_s));
+
+ subnettoa(sa_p->ips_flow_d.u.v4.sin_addr,
+ sa_p->ips_mask_d.u.v4.sin_addr,
+ 0,
+ buf_d,
+ sizeof(buf_d));
+
+ len += ipsec_snprintf(buffer+len, length-len, " policy=%s->%s",
+ buf_s, buf_d);
+ }
+
+ if(sa_p->ips_iv_bits) {
+ int j;
+ len += ipsec_snprintf(buffer+len, length-len, " iv_bits=%dbits iv=0x",
+ sa_p->ips_iv_bits);
+
+ for(j = 0; j < sa_p->ips_iv_bits / 8; j++) {
+ len += ipsec_snprintf(buffer+len, length-len, "%02x",
+ (__u32)((__u8*)(sa_p->ips_iv))[j]);
+ }
+ }
+
+ if(sa_p->ips_encalg || sa_p->ips_authalg) {
+ if(sa_p->ips_replaywin) {
+ len += ipsec_snprintf(buffer+len, length-len, " ooowin=%d",
+ sa_p->ips_replaywin);
+ }
+ if(sa_p->ips_errs.ips_replaywin_errs) {
+ len += ipsec_snprintf(buffer+len, length-len, " ooo_errs=%d",
+ sa_p->ips_errs.ips_replaywin_errs);
+ }
+ if(sa_p->ips_replaywin_lastseq) {
+ len += ipsec_snprintf(buffer+len, length-len, " seq=%d",
+ sa_p->ips_replaywin_lastseq);
+ }
+ if(sa_p->ips_replaywin_bitmap) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+ len += ipsec_snprintf(buffer+len, length-len, " bit=0x%Lx",
+ sa_p->ips_replaywin_bitmap);
+#else
+ len += ipsec_snprintf(buffer+len, length-len, " bit=0x%x%08x",
+ (__u32)(sa_p->ips_replaywin_bitmap >> 32),
+ (__u32)sa_p->ips_replaywin_bitmap);
+#endif
+ }
+ if(sa_p->ips_replaywin_maxdiff) {
+ len += ipsec_snprintf(buffer+len, length-len, " max_seq_diff=%d",
+ sa_p->ips_replaywin_maxdiff);
+ }
+ }
+ if(sa_p->ips_flags & ~EMT_INBOUND) {
+ len += ipsec_snprintf(buffer+len, length-len, " flags=0x%x",
+ sa_p->ips_flags & ~EMT_INBOUND);
+ len += ipsec_snprintf(buffer+len, length-len, "<");
+ /* flag printing goes here */
+ len += ipsec_snprintf(buffer+len, length-len, ">");
+ }
+ if(sa_p->ips_auth_bits) {
+ len += ipsec_snprintf(buffer+len, length-len, " alen=%d",
+ sa_p->ips_auth_bits);
+ }
+ if(sa_p->ips_key_bits_a) {
+ len += ipsec_snprintf(buffer+len, length-len, " aklen=%d",
+ sa_p->ips_key_bits_a);
+ }
+ if(sa_p->ips_errs.ips_auth_errs) {
+ len += ipsec_snprintf(buffer+len, length-len, " auth_errs=%d",
+ sa_p->ips_errs.ips_auth_errs);
+ }
+ if(sa_p->ips_key_bits_e) {
+ len += ipsec_snprintf(buffer+len, length-len, " eklen=%d",
+ sa_p->ips_key_bits_e);
+ }
+ if(sa_p->ips_errs.ips_encsize_errs) {
+ len += ipsec_snprintf(buffer+len, length-len, " encr_size_errs=%d",
+ sa_p->ips_errs.ips_encsize_errs);
+ }
+ if(sa_p->ips_errs.ips_encpad_errs) {
+ len += ipsec_snprintf(buffer+len, length-len, " encr_pad_errs=%d",
+ sa_p->ips_errs.ips_encpad_errs);
+ }
+
+ len += ipsec_snprintf(buffer+len, length-len, " life(c,s,h)=");
+
+ len += ipsec_lifetime_format(buffer + len,
+ length - len,
+ "alloc",
+ ipsec_life_countbased,
+ &sa_p->ips_life.ipl_allocations);
+
+ len += ipsec_lifetime_format(buffer + len,
+ length - len,
+ "bytes",
+ ipsec_life_countbased,
+ &sa_p->ips_life.ipl_bytes);
+
+ len += ipsec_lifetime_format(buffer + len,
+ length - len,
+ "addtime",
+ ipsec_life_timebased,
+ &sa_p->ips_life.ipl_addtime);
+
+ len += ipsec_lifetime_format(buffer + len,
+ length - len,
+ "usetime",
+ ipsec_life_timebased,
+ &sa_p->ips_life.ipl_usetime);
+
+ len += ipsec_lifetime_format(buffer + len,
+ length - len,
+ "packets",
+ ipsec_life_countbased,
+ &sa_p->ips_life.ipl_packets);
+
+ if(sa_p->ips_life.ipl_usetime.ipl_last) { /* XXX-MCR should be last? */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+ len += ipsec_snprintf(buffer+len, length-len, " idle=%Ld",
+ jiffies / HZ - sa_p->ips_life.ipl_usetime.ipl_last);
+#else
+ len += ipsec_snprintf(buffer+len, length-len, " idle=%lu",
+ jiffies / HZ - (unsigned long)sa_p->ips_life.ipl_usetime.ipl_last);
+#endif
+ }
+
+#ifdef CONFIG_IPSEC_IPCOMP
+ if(sa_p->ips_said.proto == IPPROTO_COMP &&
+ (sa_p->ips_comp_ratio_dbytes ||
+ sa_p->ips_comp_ratio_cbytes)) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+ len += ipsec_snprintf(buffer+len, length-len, " ratio=%Ld:%Ld",
+ sa_p->ips_comp_ratio_dbytes,
+ sa_p->ips_comp_ratio_cbytes);
+#else
+ len += ipsec_snprintf(buffer+len, length-len, " ratio=%lu:%lu",
+ (unsigned long)sa_p->ips_comp_ratio_dbytes,
+ (unsigned long)sa_p->ips_comp_ratio_cbytes);
+#endif
+ }
+#endif /* CONFIG_IPSEC_IPCOMP */
+
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ if(sa_p->ips_natt_type != 0) {
+ char *natttype_name;
+
+ switch(sa_p->ips_natt_type)
+ {
+ case ESPINUDP_WITH_NON_IKE:
+ natttype_name="nonike";
+ break;
+ case ESPINUDP_WITH_NON_ESP:
+ natttype_name="nonesp";
+ break;
+ default:
+ natttype_name="unknown";
+ break;
+ }
+
+ len += ipsec_snprintf(buffer+len, length-len, " natencap=%s",
+ natttype_name);
+
+ len += ipsec_snprintf(buffer+len, length-len, " natsport=%d",
+ sa_p->ips_natt_sport);
+
+ len += ipsec_snprintf(buffer+len, length-len, " natdport=%d",
+ sa_p->ips_natt_dport);
+ }
+#endif /* CONFIG_IPSEC_NAT_TRAVERSAL */
+
+ len += ipsec_snprintf(buffer+len, length-len, " refcount=%d",
+ atomic_read(&sa_p->ips_refcount));
+
+ len += ipsec_snprintf(buffer+len, length-len, " ref=%d",
+ sa_p->ips_ref);
+#ifdef CONFIG_IPSEC_DEBUG
+ if(debug_xform) {
+ len += ipsec_snprintf(buffer+len, length-len, " reftable=%lu refentry=%lu",
+ (unsigned long)IPsecSAref2table(sa_p->ips_ref),
+ (unsigned long)IPsecSAref2entry(sa_p->ips_ref));
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+
+ len += ipsec_snprintf(buffer+len, length-len, "\n");
+
+ atomic_dec(&sa_p->ips_refcount);
+
+ if (len >= max_content) {
+ /* we've done all that can fit -- stop loops */
+ len = max_content; /* truncate crap */
+ goto done_spi_i;
+ } else {
+ const off_t pos = begin + len;
+
+ if (pos <= offset) {
+ /* all is before first interesting character:
+ * discard, but note where we are.
+ */
+ len = 0;
+ begin = pos;
+ }
+ }
+ }
+ }
+
+done_spi_i:
+ spin_unlock_bh(&tdb_lock);
+
+ *start = buffer + (offset - begin); /* Start of wanted data */
+ return len - (offset - begin);
+}
+
+IPSEC_PROCFS_DEBUG_NO_STATIC
+int
+ipsec_spigrp_get_info(char *buffer,
+ char **start,
+ off_t offset,
+ int length IPSEC_PROC_LAST_ARG)
+{
+ /* limit of useful snprintf output */
+ const int max_content = length > 0? length-1 : 0;
+
+ int len = 0;
+ off_t begin = 0;
+ int i;
+ struct ipsec_sa *sa_p, *sa_p2;
+ char sa[SATOA_BUF];
+ size_t sa_len;
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
+ "klips_debug:ipsec_spigrp_get_info: "
+ "buffer=0p%p, *start=0p%p, offset=%d, length=%d\n",
+ buffer,
+ *start,
+ (int)offset,
+ length);
+
+ spin_lock_bh(&tdb_lock);
+
+ for (i = 0; i < SADB_HASHMOD; i++) {
+ for (sa_p = ipsec_sadb_hash[i];
+ sa_p != NULL;
+ sa_p = sa_p->ips_hnext)
+ {
+ atomic_inc(&sa_p->ips_refcount);
+ if(sa_p->ips_inext == NULL) {
+ sa_p2 = sa_p;
+ while(sa_p2 != NULL) {
+ atomic_inc(&sa_p2->ips_refcount);
+ sa_len = satoa(sa_p2->ips_said,
+ 0, sa, SATOA_BUF);
+
+ len += ipsec_snprintf(buffer+len, length-len, "%s ",
+ sa_len ? sa : " (error)");
+ atomic_dec(&sa_p2->ips_refcount);
+ sa_p2 = sa_p2->ips_onext;
+ }
+ len += ipsec_snprintf(buffer+len, length-len, "\n");
+ }
+
+ atomic_dec(&sa_p->ips_refcount);
+
+ if (len >= max_content) {
+ /* we've done all that can fit -- stop loops */
+ len = max_content; /* truncate crap */
+ goto done_spigrp_i;
+ } else {
+ const off_t pos = begin + len;
+
+ if (pos <= offset) {
+ /* all is before first interesting character:
+ * discard, but note where we are.
+ */
+ len = 0;
+ begin = pos;
+ }
+ }
+ }
+ }
+
+ done_spigrp_i:
+ spin_unlock_bh(&tdb_lock);
+
+ *start = buffer + (offset - begin); /* Start of wanted data */
+ return len - (offset - begin);
+}
+
+IPSEC_PROCFS_DEBUG_NO_STATIC
+int
+ipsec_tncfg_get_info(char *buffer,
+ char **start,
+ off_t offset,
+ int length IPSEC_PROC_LAST_ARG)
+{
+ /* limit of useful snprintf output */
+ const int max_content = length > 0? length-1 : 0;
+
+ int len = 0;
+ off_t begin = 0;
+ int i;
+ char name[9];
+ struct device *dev, *privdev;
+ struct ipsecpriv *priv;
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
+ "klips_debug:ipsec_tncfg_get_info: "
+ "buffer=0p%p, *start=0p%p, offset=%d, length=%d\n",
+ buffer,
+ *start,
+ (int)offset,
+ length);
+
+ for(i = 0; i < IPSEC_NUM_IF; i++) {
+ ipsec_snprintf(name, (ssize_t) sizeof(name), IPSEC_DEV_FORMAT, i);
+ dev = __ipsec_dev_get(name);
+ if(dev) {
+ priv = (struct ipsecpriv *)(dev->priv);
+ len += ipsec_snprintf(buffer+len, length-len, "%s",
+ dev->name);
+ if(priv) {
+ privdev = (struct device *)(priv->dev);
+ len += ipsec_snprintf(buffer+len, length-len, " -> %s",
+ privdev ? privdev->name : "NULL");
+ len += ipsec_snprintf(buffer+len, length-len, " mtu=%d(%d) -> %d",
+ dev->mtu,
+ priv->mtu,
+ privdev ? privdev->mtu : 0);
+ } else {
+ KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
+ "klips_debug:ipsec_tncfg_get_info: device '%s' has no private data space!\n",
+ dev->name);
+ }
+ len += ipsec_snprintf(buffer+len, length-len, "\n");
+
+ if (len >= max_content) {
+ /* we've done all that can fit -- stop loop */
+ len = max_content; /* truncate crap */
+ break;
+ } else {
+ const off_t pos = begin + len;
+ if (pos <= offset) {
+ len = 0;
+ begin = pos;
+ }
+ }
+ }
+ }
+ *start = buffer + (offset - begin); /* Start of wanted data */
+ len -= (offset - begin); /* Start slop */
+ if (len > length)
+ len = length;
+ return len;
+}
+
+IPSEC_PROCFS_DEBUG_NO_STATIC
+int
+ipsec_version_get_info(char *buffer,
+ char **start,
+ off_t offset,
+ int length IPSEC_PROC_LAST_ARG)
+{
+ int len = 0;
+ off_t begin = 0;
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
+ "klips_debug:ipsec_version_get_info: "
+ "buffer=0p%p, *start=0p%p, offset=%d, length=%d\n",
+ buffer,
+ *start,
+ (int)offset,
+ length);
+
+ len += ipsec_snprintf(buffer+len, length-len, "strongSwan version: %s\n",
+ ipsec_version_code());
+#if 0
+ KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
+ "klips_debug:ipsec_version_get_info: "
+ "ipsec_init version: %s\n",
+ ipsec_init_c_version);
+ KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
+ "klips_debug:ipsec_version_get_info: "
+ "ipsec_tunnel version: %s\n",
+ ipsec_tunnel_c_version);
+ KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
+ "klips_debug:ipsec_version_get_info: "
+ "ipsec_netlink version: %s\n",
+ ipsec_netlink_c_version);
+ KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
+ "klips_debug:ipsec_version_get_info: "
+ "radij_c_version: %s\n",
+ radij_c_version);
+#endif
+
+ *start = buffer + (offset - begin); /* Start of wanted data */
+ len -= (offset - begin); /* Start slop */
+ if (len > length)
+ len = length;
+ return len;
+}
+
+IPSEC_PROCFS_DEBUG_NO_STATIC
+int
+ipsec_birth_info(char *page,
+ char **start,
+ off_t offset,
+ int count,
+ int *eof,
+ void *data)
+{
+ struct ipsec_birth_reply *ibr = (struct ipsec_birth_reply *)data;
+ int len;
+
+ if(offset >= ibr->packet_template_len) {
+ if(eof) {
+ *eof=1;
+ }
+ return 0;
+ }
+
+ len = ibr->packet_template_len;
+ len -= offset;
+ if (len > count)
+ len = count;
+
+ memcpy(page + offset, ibr->packet_template+offset, len);
+
+ return len;
+}
+
+IPSEC_PROCFS_DEBUG_NO_STATIC
+int
+ipsec_birth_set(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ struct ipsec_birth_reply *ibr = (struct ipsec_birth_reply *)data;
+ int len;
+
+ MOD_INC_USE_COUNT;
+ if(count > IPSEC_BIRTH_TEMPLATE_MAXLEN) {
+ len = IPSEC_BIRTH_TEMPLATE_MAXLEN;
+ } else {
+ len = count;
+ }
+
+ if(copy_from_user(ibr->packet_template, buffer, len)) {
+ MOD_DEC_USE_COUNT;
+ return -EFAULT;
+ }
+ ibr->packet_template_len = len;
+
+ MOD_DEC_USE_COUNT;
+
+ return len;
+}
+
+
+#ifdef CONFIG_IPSEC_DEBUG
+IPSEC_PROCFS_DEBUG_NO_STATIC
+int
+ipsec_klipsdebug_get_info(char *buffer,
+ char **start,
+ off_t offset,
+ int length IPSEC_PROC_LAST_ARG)
+{
+ int len = 0;
+ off_t begin = 0;
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
+ "klips_debug:ipsec_klipsdebug_get_info: "
+ "buffer=0p%p, *start=0p%p, offset=%d, length=%d\n",
+ buffer,
+ *start,
+ (int)offset,
+ length);
+
+ len += ipsec_snprintf(buffer+len, length-len, "debug_tunnel=%08x.\n", debug_tunnel);
+ len += ipsec_snprintf(buffer+len, length-len, "debug_xform=%08x.\n", debug_xform);
+ len += ipsec_snprintf(buffer+len, length-len, "debug_eroute=%08x.\n", debug_eroute);
+ len += ipsec_snprintf(buffer+len, length-len, "debug_spi=%08x.\n", debug_spi);
+ len += ipsec_snprintf(buffer+len, length-len, "debug_radij=%08x.\n", debug_radij);
+ len += ipsec_snprintf(buffer+len, length-len, "debug_esp=%08x.\n", debug_esp);
+ len += ipsec_snprintf(buffer+len, length-len, "debug_ah=%08x.\n", debug_ah);
+ len += ipsec_snprintf(buffer+len, length-len, "debug_rcv=%08x.\n", debug_rcv);
+ len += ipsec_snprintf(buffer+len, length-len, "debug_pfkey=%08x.\n", debug_pfkey);
+
+ *start = buffer + (offset - begin); /* Start of wanted data */
+ len -= (offset - begin); /* Start slop */
+ if (len > length)
+ len = length;
+ return len;
+}
+#endif /* CONFIG_IPSEC_DEBUG */
+
+IPSEC_PROCFS_DEBUG_NO_STATIC
+int
+ipsec_stats_get_int_info(char *buffer,
+ char **start,
+ off_t offset,
+ int length,
+ int *eof,
+ void *data)
+{
+ /* Limit of useful snprintf output */
+ const int max_content = length > 0? length-1 : 0;
+
+ int len = 0;
+ int *thing;
+
+ thing = (int *)data;
+
+ len = ipsec_snprintf(buffer+len, length-len, "%08x\n", *thing);
+
+ if (len >= max_content)
+ len = max_content; /* truncate crap */
+
+ *start = buffer + offset; /* Start of wanted data */
+ return len > offset? len - offset : 0;
+}
+
+#ifndef PROC_FS_2325
+struct proc_dir_entry ipsec_eroute =
+{
+ 0,
+ 12, "ipsec_eroute",
+ S_IFREG | S_IRUGO, 1, 0, 0, 0,
+ &proc_net_inode_operations,
+ ipsec_eroute_get_info,
+ NULL, NULL, NULL, NULL, NULL
+};
+
+struct proc_dir_entry ipsec_spi =
+{
+ 0,
+ 9, "ipsec_spi",
+ S_IFREG | S_IRUGO, 1, 0, 0, 0,
+ &proc_net_inode_operations,
+ ipsec_spi_get_info,
+ NULL, NULL, NULL, NULL, NULL
+};
+
+struct proc_dir_entry ipsec_spigrp =
+{
+ 0,
+ 12, "ipsec_spigrp",
+ S_IFREG | S_IRUGO, 1, 0, 0, 0,
+ &proc_net_inode_operations,
+ ipsec_spigrp_get_info,
+ NULL, NULL, NULL, NULL, NULL
+};
+
+struct proc_dir_entry ipsec_tncfg =
+{
+ 0,
+ 11, "ipsec_tncfg",
+ S_IFREG | S_IRUGO, 1, 0, 0, 0,
+ &proc_net_inode_operations,
+ ipsec_tncfg_get_info,
+ NULL, NULL, NULL, NULL, NULL
+};
+
+struct proc_dir_entry ipsec_version =
+{
+ 0,
+ 13, "ipsec_version",
+ S_IFREG | S_IRUGO, 1, 0, 0, 0,
+ &proc_net_inode_operations,
+ ipsec_version_get_info,
+ NULL, NULL, NULL, NULL, NULL
+};
+
+#ifdef CONFIG_IPSEC_DEBUG
+struct proc_dir_entry ipsec_klipsdebug =
+{
+ 0,
+ 16, "ipsec_klipsdebug",
+ S_IFREG | S_IRUGO, 1, 0, 0, 0,
+ &proc_net_inode_operations,
+ ipsec_klipsdebug_get_info,
+ NULL, NULL, NULL, NULL, NULL
+};
+#endif /* CONFIG_IPSEC_DEBUG */
+#endif /* !PROC_FS_2325 */
+#endif /* CONFIG_PROC_FS */
+
+#if defined(PROC_FS_2325)
+struct ipsec_proc_list {
+ char *name;
+ struct proc_dir_entry **parent;
+ struct proc_dir_entry **dir;
+ read_proc_t *readthing;
+ write_proc_t *writething;
+ void *data;
+};
+static struct ipsec_proc_list proc_items[]={
+#ifdef CONFIG_IPSEC_DEBUG
+ {"klipsdebug", &proc_net_ipsec_dir, NULL, ipsec_klipsdebug_get_info, NULL, NULL},
+#endif
+ {"eroute", &proc_net_ipsec_dir, &proc_eroute_dir, NULL, NULL, NULL},
+ {"all", &proc_eroute_dir, NULL, ipsec_eroute_get_info, NULL, NULL},
+ {"spi", &proc_net_ipsec_dir, &proc_spi_dir, NULL, NULL, NULL},
+ {"all", &proc_spi_dir, NULL, ipsec_spi_get_info, NULL, NULL},
+ {"spigrp", &proc_net_ipsec_dir, &proc_spigrp_dir, NULL, NULL, NULL},
+ {"all", &proc_spigrp_dir, NULL, ipsec_spigrp_get_info, NULL, NULL},
+ {"birth", &proc_net_ipsec_dir, &proc_birth_dir, NULL, NULL, NULL},
+ {"ipv4", &proc_birth_dir, NULL, ipsec_birth_info, ipsec_birth_set, (void *)&ipsec_ipv4_birth_packet},
+ {"ipv6", &proc_birth_dir, NULL, ipsec_birth_info, ipsec_birth_set, (void *)&ipsec_ipv6_birth_packet},
+ {"xforms", &proc_net_ipsec_dir, NULL, ipsec_xform_get_info, NULL, NULL},
+ {"tncfg", &proc_net_ipsec_dir, NULL, ipsec_tncfg_get_info, NULL, NULL},
+ {"stats", &proc_net_ipsec_dir, &proc_stats_dir, NULL, NULL, NULL},
+ {"trap_count", &proc_stats_dir, NULL, ipsec_stats_get_int_info, NULL, &ipsec_xmit_trap_count},
+ {"trap_sendcount", &proc_stats_dir, NULL, ipsec_stats_get_int_info, NULL, &ipsec_xmit_trap_sendcount},
+ {"version", &proc_net_ipsec_dir, NULL, ipsec_version_get_info, NULL, NULL},
+ {NULL, NULL, NULL, NULL, NULL, NULL}
+};
+#endif
+
+int
+ipsec_proc_init()
+{
+ int error = 0;
+#ifdef IPSEC_PROC_SUBDIRS
+ struct proc_dir_entry *item;
+#endif
+
+ /*
+ * just complain because pluto won't run without /proc!
+ */
+#ifndef CONFIG_PROC_FS
+#error You must have PROC_FS built in to use KLIPS
+#endif
+
+ /* for 2.0 kernels */
+#if !defined(PROC_FS_2325) && !defined(PROC_FS_21)
+ error |= proc_register_dynamic(&proc_net, &ipsec_eroute);
+ error |= proc_register_dynamic(&proc_net, &ipsec_spi);
+ error |= proc_register_dynamic(&proc_net, &ipsec_spigrp);
+ error |= proc_register_dynamic(&proc_net, &ipsec_tncfg);
+ error |= proc_register_dynamic(&proc_net, &ipsec_version);
+#ifdef CONFIG_IPSEC_DEBUG
+ error |= proc_register_dynamic(&proc_net, &ipsec_klipsdebug);
+#endif /* CONFIG_IPSEC_DEBUG */
+#endif
+
+ /* for 2.2 kernels */
+#if !defined(PROC_FS_2325) && defined(PROC_FS_21)
+ error |= proc_register(proc_net, &ipsec_eroute);
+ error |= proc_register(proc_net, &ipsec_spi);
+ error |= proc_register(proc_net, &ipsec_spigrp);
+ error |= proc_register(proc_net, &ipsec_tncfg);
+ error |= proc_register(proc_net, &ipsec_version);
+#ifdef CONFIG_IPSEC_DEBUG
+ error |= proc_register(proc_net, &ipsec_klipsdebug);
+#endif /* CONFIG_IPSEC_DEBUG */
+#endif
+
+ /* for 2.4 kernels */
+#if defined(PROC_FS_2325)
+ /* create /proc/net/ipsec */
+
+ /* zero these out before we initialize /proc/net/ipsec/birth/stuff */
+ memset(&ipsec_ipv4_birth_packet, 0, sizeof(struct ipsec_birth_reply));
+ memset(&ipsec_ipv6_birth_packet, 0, sizeof(struct ipsec_birth_reply));
+
+ proc_net_ipsec_dir = proc_mkdir("ipsec", proc_net);
+ if(proc_net_ipsec_dir == NULL) {
+ /* no point in continuing */
+ return 1;
+ }
+
+ {
+ struct ipsec_proc_list *it;
+
+ it=proc_items;
+ while(it->name!=NULL) {
+ if(it->dir) {
+ /* make a dir instead */
+ item = proc_mkdir(it->name, *it->parent);
+ *it->dir = item;
+ } else {
+ item = create_proc_entry(it->name, 0400, *it->parent);
+ }
+ if(item) {
+ item->read_proc = it->readthing;
+ item->write_proc = it->writething;
+ item->data = it->data;
+#ifdef MODULE
+ item->owner = THIS_MODULE;
+#endif
+ } else {
+ error |= 1;
+ }
+ it++;
+ }
+ }
+
+ /* now create some symlinks to provide compatibility */
+ proc_symlink("ipsec_eroute", proc_net, "ipsec/eroute/all");
+ proc_symlink("ipsec_spi", proc_net, "ipsec/spi/all");
+ proc_symlink("ipsec_spigrp", proc_net, "ipsec/spigrp/all");
+ proc_symlink("ipsec_tncfg", proc_net, "ipsec/tncfg");
+ proc_symlink("ipsec_version",proc_net, "ipsec/version");
+ proc_symlink("ipsec_klipsdebug",proc_net,"ipsec/klipsdebug");
+
+#endif /* !PROC_FS_2325 */
+
+ return error;
+}
+
+void
+ipsec_proc_cleanup()
+{
+
+ /* for 2.0 and 2.2 kernels */
+#if !defined(PROC_FS_2325)
+
+#ifdef CONFIG_IPSEC_DEBUG
+ if (proc_net_unregister(ipsec_klipsdebug.low_ino) != 0)
+ printk("klips_debug:ipsec_cleanup: "
+ "cannot unregister /proc/net/ipsec_klipsdebug\n");
+#endif /* CONFIG_IPSEC_DEBUG */
+
+ if (proc_net_unregister(ipsec_version.low_ino) != 0)
+ printk("klips_debug:ipsec_cleanup: "
+ "cannot unregister /proc/net/ipsec_version\n");
+ if (proc_net_unregister(ipsec_eroute.low_ino) != 0)
+ printk("klips_debug:ipsec_cleanup: "
+ "cannot unregister /proc/net/ipsec_eroute\n");
+ if (proc_net_unregister(ipsec_spi.low_ino) != 0)
+ printk("klips_debug:ipsec_cleanup: "
+ "cannot unregister /proc/net/ipsec_spi\n");
+ if (proc_net_unregister(ipsec_spigrp.low_ino) != 0)
+ printk("klips_debug:ipsec_cleanup: "
+ "cannot unregister /proc/net/ipsec_spigrp\n");
+ if (proc_net_unregister(ipsec_tncfg.low_ino) != 0)
+ printk("klips_debug:ipsec_cleanup: "
+ "cannot unregister /proc/net/ipsec_tncfg\n");
+#endif
+
+ /* for 2.4 kernels */
+#if defined(PROC_FS_2325)
+ {
+ struct ipsec_proc_list *it;
+
+ /* find end of list */
+ it=proc_items;
+ while(it->name!=NULL) {
+ it++;
+ }
+ it--;
+
+ do {
+ remove_proc_entry(it->name, *it->parent);
+ it--;
+ } while(it > proc_items);
+ }
+
+
+#ifdef CONFIG_IPSEC_DEBUG
+ remove_proc_entry("ipsec_klipsdebug", proc_net);
+#endif /* CONFIG_IPSEC_DEBUG */
+ remove_proc_entry("ipsec_eroute", proc_net);
+ remove_proc_entry("ipsec_spi", proc_net);
+ remove_proc_entry("ipsec_spigrp", proc_net);
+ remove_proc_entry("ipsec_tncfg", proc_net);
+ remove_proc_entry("ipsec_version", proc_net);
+ remove_proc_entry("ipsec", proc_net);
+#endif /* 2.4 kernel */
+}
+
+
diff --git a/linux/net/ipsec/ipsec_radij.c b/linux/net/ipsec/ipsec_radij.c
new file mode 100644
index 000000000..b20eb7a6f
--- /dev/null
+++ b/linux/net/ipsec/ipsec_radij.c
@@ -0,0 +1,550 @@
+/*
+ * Interface between the IPSEC code and the radix (radij) tree code
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 1998, 1999, 2000, 2001 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: ipsec_radij.c,v 1.5 2005/04/10 21:38:32 as Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/kernel.h> /* printk() */
+
+#include "freeswan/ipsec_param.h"
+
+#ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+#else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+#endif /* MALLOC_SLAB */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/interrupt.h> /* mark_bh */
+
+#include <linux/netdevice.h> /* struct device, struct net_device_stats and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/ip.h> /* struct iphdr */
+#include <linux/skbuff.h>
+#include <freeswan.h>
+#ifdef SPINLOCK
+# ifdef SPINLOCK_23
+# include <linux/spinlock.h> /* *lock* */
+# else /* 23_SPINLOCK */
+# include <asm/spinlock.h> /* *lock* */
+# endif /* 23_SPINLOCK */
+#endif /* SPINLOCK */
+#ifdef NET_21
+# include <asm/uaccess.h>
+# include <linux/in6.h>
+#endif
+#include <asm/checksum.h>
+#include <net/ip.h>
+
+#include "freeswan/ipsec_eroute.h"
+#include "freeswan/ipsec_sa.h"
+
+#include "freeswan/radij.h"
+#include "freeswan/ipsec_encap.h"
+#include "freeswan/radij.h"
+#include "freeswan/ipsec_encap.h"
+#include "freeswan/ipsec_radij.h"
+#include "freeswan/ipsec_tunnel.h" /* struct ipsecpriv */
+#include "freeswan/ipsec_xform.h"
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "freeswan/ipsec_proto.h"
+
+#ifdef CONFIG_IPSEC_DEBUG
+int debug_radij = 0;
+#endif /* CONFIG_IPSEC_DEBUG */
+
+struct radij_node_head *rnh = NULL;
+#ifdef SPINLOCK
+spinlock_t eroute_lock = SPIN_LOCK_UNLOCKED;
+#else /* SPINLOCK */
+spinlock_t eroute_lock;
+#endif /* SPINLOCK */
+
+int
+ipsec_radijinit(void)
+{
+ maj_keylen = sizeof (struct sockaddr_encap);
+
+ rj_init();
+
+ if (rj_inithead((void **)&rnh, /*16*/offsetof(struct sockaddr_encap, sen_type) * sizeof(__u8)) == 0) /* 16 is bit offset of sen_type */
+ return -1;
+ return 0;
+}
+
+int
+ipsec_radijcleanup(void)
+{
+ int error;
+
+ spin_lock_bh(&eroute_lock);
+
+ error = radijcleanup();
+
+ spin_unlock_bh(&eroute_lock);
+
+ return error;
+}
+
+int
+ipsec_cleareroutes(void)
+{
+ int error;
+
+ spin_lock_bh(&eroute_lock);
+
+ error = radijcleartree();
+
+ spin_unlock_bh(&eroute_lock);
+
+ return error;
+}
+
+int
+ipsec_breakroute(struct sockaddr_encap *eaddr,
+ struct sockaddr_encap *emask,
+ struct sk_buff **first,
+ struct sk_buff **last)
+{
+ struct eroute *ro;
+ struct radij_node *rn;
+ int error;
+#ifdef CONFIG_IPSEC_DEBUG
+
+ if (debug_eroute) {
+ char buf1[SUBNETTOA_BUF], buf2[SUBNETTOA_BUF];
+
+ subnettoa(eaddr->sen_ip_src, emask->sen_ip_src, 0, buf1, sizeof(buf1));
+ subnettoa(eaddr->sen_ip_dst, emask->sen_ip_dst, 0, buf2, sizeof(buf2));
+ KLIPS_PRINT(debug_eroute,
+ "klips_debug:ipsec_breakroute: "
+ "attempting to delete eroute for %s:%d->%s:%d %d\n",
+ buf1, ntohs(eaddr->sen_sport),
+ buf2, ntohs(eaddr->sen_dport), eaddr->sen_proto);
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+
+ spin_lock_bh(&eroute_lock);
+
+ if ((error = rj_delete(eaddr, emask, rnh, &rn)) != 0) {
+ spin_unlock_bh(&eroute_lock);
+ KLIPS_PRINT(debug_eroute,
+ "klips_debug:ipsec_breakroute: "
+ "node not found, eroute delete failed.\n");
+ return error;
+ }
+
+ spin_unlock_bh(&eroute_lock);
+
+ ro = (struct eroute *)rn;
+
+ KLIPS_PRINT(debug_eroute,
+ "klips_debug:ipsec_breakroute: "
+ "deleted eroute=0p%p, ident=0p%p->0p%p, first=0p%p, last=0p%p\n",
+ ro,
+ ro->er_ident_s.data,
+ ro->er_ident_d.data,
+ ro->er_first,
+ ro->er_last);
+
+ if (ro->er_ident_s.data != NULL) {
+ kfree(ro->er_ident_s.data);
+ }
+ if (ro->er_ident_d.data != NULL) {
+ kfree(ro->er_ident_d.data);
+ }
+ if (ro->er_first != NULL) {
+#if 0
+ struct net_device_stats *stats = (struct net_device_stats *) &(((struct ipsecpriv *)(ro->er_first->dev->priv))->mystats);
+ stats->tx_dropped--;
+#endif
+ *first = ro->er_first;
+ }
+ if (ro->er_last != NULL) {
+#if 0
+ struct net_device_stats *stats = (struct net_device_stats *) &(((struct ipsecpriv *)(ro->er_last->dev->priv))->mystats);
+ stats->tx_dropped--;
+#endif
+ *last = ro->er_last;
+ }
+
+ if (rn->rj_flags & (RJF_ACTIVE | RJF_ROOT))
+ panic ("ipsec_breakroute RMT_DELEROUTE root or active node\n");
+ memset((caddr_t)rn, 0, sizeof (struct eroute));
+ kfree(rn);
+
+ return 0;
+}
+
+int
+ipsec_makeroute(struct sockaddr_encap *eaddr,
+ struct sockaddr_encap *emask,
+ struct sa_id said,
+ uint32_t pid,
+ struct sk_buff *skb,
+ struct ident *ident_s,
+ struct ident *ident_d)
+{
+ struct eroute *retrt;
+ int error;
+ char sa[SATOA_BUF];
+ size_t sa_len;
+#ifdef CONFIG_IPSEC_DEBUG
+
+ if (debug_eroute) {
+ {
+ char buf1[SUBNETTOA_BUF], buf2[SUBNETTOA_BUF];
+
+ subnettoa(eaddr->sen_ip_src, emask->sen_ip_src, 0, buf1, sizeof(buf1));
+ subnettoa(eaddr->sen_ip_dst, emask->sen_ip_dst, 0, buf2, sizeof(buf2));
+ sa_len = satoa(said, 0, sa, SATOA_BUF);
+ KLIPS_PRINT(debug_eroute,
+ "klips_debug:ipsec_makeroute: "
+ "attempting to allocate %lu bytes to insert eroute for %s:%d->%s:%d %d, SA: %s, PID:%d, skb=0p%p, ident:%s->%s\n",
+ (unsigned long) sizeof(struct eroute),
+ buf1, ntohs(eaddr->sen_sport),
+ buf2, ntohs(eaddr->sen_dport),
+ eaddr->sen_proto,
+ sa_len ? sa : " (error)",
+ pid,
+ skb,
+ (ident_s ? (ident_s->data ? ident_s->data : "NULL") : "NULL"),
+ (ident_d ? (ident_d->data ? ident_d->data : "NULL") : "NULL"));
+ }
+ {
+ char buf1[sizeof(struct sockaddr_encap)*2 + 1];
+ char buf2[sizeof(struct sockaddr_encap)*2 + 1];
+ int i;
+ unsigned char *b1 = buf1,
+ *b2 = buf2,
+ *ea = (unsigned char *)eaddr,
+ *em = (unsigned char *)emask;
+
+ for (i=0; i<sizeof(struct sockaddr_encap); i++) {
+ sprintf(b1, "%02x", ea[i]);
+ sprintf(b2, "%02x", em[i]);
+ b1+=2;
+ b2+=2;
+ }
+ KLIPS_PRINT(debug_eroute, "klips_debug:ipsec_makeroute: %s / %s \n", buf1, buf2);
+ }
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+
+ retrt = (struct eroute *)kmalloc(sizeof (struct eroute), GFP_ATOMIC);
+ if (retrt == NULL) {
+ printk("klips_error:ipsec_makeroute: "
+ "not able to allocate kernel memory");
+ return -ENOMEM;
+ }
+ memset((caddr_t)retrt, 0, sizeof (struct eroute));
+
+ retrt->er_eaddr = *eaddr;
+ retrt->er_emask = *emask;
+ retrt->er_said = said;
+ retrt->er_pid = pid;
+ retrt->er_count = 0;
+ retrt->er_lasttime = jiffies/HZ;
+ {
+ struct sockaddr_encap **rkeyp = (struct sockaddr_encap**)&((retrt->er_rjt).rd_nodes->rj_key);
+ *rkeyp = &(retrt->er_eaddr);
+ }
+
+ if (ident_s && ident_s->type != SADB_IDENTTYPE_RESERVED) {
+ int data_len = ident_s->len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident);
+
+ retrt->er_ident_s.type = ident_s->type;
+ retrt->er_ident_s.id = ident_s->id;
+ retrt->er_ident_s.len = ident_s->len;
+ if(data_len) {
+ KLIPS_PRINT(debug_eroute,
+ "klips_debug:ipsec_makeroute: "
+ "attempting to allocate %u bytes for ident_s.\n",
+ data_len);
+ if(!(retrt->er_ident_s.data = kmalloc(data_len, GFP_KERNEL))) {
+ kfree(retrt);
+ printk("klips_error:ipsec_makeroute: not able to allocate kernel memory (%d)\n", data_len);
+ return ENOMEM;
+ }
+ memcpy(retrt->er_ident_s.data, ident_s->data, data_len);
+ } else {
+ retrt->er_ident_s.data = NULL;
+ }
+ }
+
+ if (ident_d && ident_d->type != SADB_IDENTTYPE_RESERVED) {
+ int data_len = ident_d->len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident);
+
+ retrt->er_ident_d.type = ident_d->type;
+ retrt->er_ident_d.id = ident_d->id;
+ retrt->er_ident_d.len = ident_d->len;
+ if(data_len) {
+ KLIPS_PRINT(debug_eroute,
+ "klips_debug:ipsec_makeroute: "
+ "attempting to allocate %u bytes for ident_d.\n",
+ data_len);
+ if(!(retrt->er_ident_d.data = kmalloc(data_len, GFP_KERNEL))) {
+ if (retrt->er_ident_s.data)
+ kfree(retrt->er_ident_s.data);
+ kfree(retrt);
+ printk("klips_error:ipsec_makeroute: not able to allocate kernel memory (%d)\n", data_len);
+ return ENOMEM;
+ }
+ memcpy(retrt->er_ident_d.data, ident_d->data, data_len);
+ } else {
+ retrt->er_ident_d.data = NULL;
+ }
+ }
+ retrt->er_first = skb;
+ retrt->er_last = NULL;
+
+ KLIPS_PRINT(debug_eroute,
+ "klips_debug:ipsec_makeroute: "
+ "calling rj_addroute now\n");
+
+ spin_lock_bh(&eroute_lock);
+
+ error = rj_addroute(&(retrt->er_eaddr), &(retrt->er_emask),
+ rnh, retrt->er_rjt.rd_nodes);
+
+ spin_unlock_bh(&eroute_lock);
+
+ if(error) {
+ sa_len = satoa(said, 0, sa, SATOA_BUF);
+ KLIPS_PRINT(debug_eroute,
+ "klips_debug:ipsec_makeroute: "
+ "rj_addroute not able to insert eroute for SA:%s (error:%d)\n",
+ sa_len ? sa : " (error)", error);
+ if (retrt->er_ident_s.data)
+ kfree(retrt->er_ident_s.data);
+ if (retrt->er_ident_d.data)
+ kfree(retrt->er_ident_d.data);
+
+ kfree(retrt);
+
+ return error;
+ }
+
+#ifdef CONFIG_IPSEC_DEBUG
+ if (debug_eroute) {
+ char buf1[SUBNETTOA_BUF], buf2[SUBNETTOA_BUF];
+/*
+ subnettoa(eaddr->sen_ip_src, emask->sen_ip_src, 0, buf1, sizeof(buf1));
+ subnettoa(eaddr->sen_ip_dst, emask->sen_ip_dst, 0, buf2, sizeof(buf2));
+*/
+ subnettoa(rd_key((&(retrt->er_rjt)))->sen_ip_src, rd_mask((&(retrt->er_rjt)))->sen_ip_src, 0, buf1, sizeof(buf1));
+ subnettoa(rd_key((&(retrt->er_rjt)))->sen_ip_dst, rd_mask((&(retrt->er_rjt)))->sen_ip_dst, 0, buf2, sizeof(buf2));
+ sa_len = satoa(retrt->er_said, 0, sa, SATOA_BUF);
+
+ KLIPS_PRINT(debug_eroute,
+ "klips_debug:ipsec_makeroute: "
+ "pid=%05d "
+ "count=%10d "
+ "lasttime=%6d "
+ "%-18s -> %-18s => %s\n",
+ retrt->er_pid,
+ retrt->er_count,
+ (int)(jiffies/HZ - retrt->er_lasttime),
+ buf1,
+ buf2,
+ sa_len ? sa : " (error)");
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+ KLIPS_PRINT(debug_eroute,
+ "klips_debug:ipsec_makeroute: "
+ "succeeded.\n");
+ return 0;
+}
+
+struct eroute *
+ipsec_findroute(struct sockaddr_encap *eaddr)
+{
+ struct radij_node *rn;
+#ifdef CONFIG_IPSEC_DEBUG
+ char buf1[ADDRTOA_BUF], buf2[ADDRTOA_BUF];
+
+ if (debug_radij & DB_RJ_FINDROUTE) {
+ addrtoa(eaddr->sen_ip_src, 0, buf1, sizeof(buf1));
+ addrtoa(eaddr->sen_ip_dst, 0, buf2, sizeof(buf2));
+ KLIPS_PRINT(debug_eroute,
+ "klips_debug:ipsec_findroute: "
+ "%s:%d->%s:%d %d\n",
+ buf1, ntohs(eaddr->sen_sport),
+ buf2, ntohs(eaddr->sen_dport),
+ eaddr->sen_proto);
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+ rn = rj_match((caddr_t)eaddr, rnh);
+ if(rn) {
+ KLIPS_PRINT(debug_eroute && sysctl_ipsec_debug_verbose,
+ "klips_debug:ipsec_findroute: "
+ "found, points to proto=%d, spi=%x, dst=%x.\n",
+ ((struct eroute*)rn)->er_said.proto,
+ ntohl(((struct eroute*)rn)->er_said.spi),
+ ntohl(((struct eroute*)rn)->er_said.dst.s_addr));
+ }
+ return (struct eroute *)rn;
+}
+
+#ifdef CONFIG_PROC_FS
+/** ipsec_rj_walker_procprint: print one line of eroute table output.
+ *
+ * Theoretical BUG: if w->length is less than the length
+ * of some line we should produce, that line will never
+ * be finished. In effect, the "file" will stop part way
+ * through that line.
+ */
+int
+ipsec_rj_walker_procprint(struct radij_node *rn, void *w0)
+{
+ struct eroute *ro = (struct eroute *)rn;
+ struct rjtentry *rd = (struct rjtentry *)rn;
+ struct wsbuf *w = (struct wsbuf *)w0;
+ char buf1[SUBNETTOA_BUF], buf2[SUBNETTOA_BUF];
+ char buf3[16];
+ char sa[SATOA_BUF];
+ size_t sa_len, buf_len;
+ struct sockaddr_encap *key, *mask;
+
+ KLIPS_PRINT(debug_radij,
+ "klips_debug:ipsec_rj_walker_procprint: "
+ "rn=0p%p, w0=0p%p\n",
+ rn,
+ w0);
+ if (rn->rj_b >= 0) {
+ return 0;
+ }
+
+ key = rd_key(rd);
+ mask = rd_mask(rd);
+
+ if (key == NULL || mask == NULL) {
+ return 0;
+ }
+
+ buf_len = subnettoa(key->sen_ip_src, mask->sen_ip_src, 0, buf1, sizeof(buf1));
+ if(key->sen_sport != 0) {
+ sprintf(buf1+buf_len-1, ":%d", ntohs(key->sen_sport));
+ }
+
+ buf_len = subnettoa(key->sen_ip_dst, mask->sen_ip_dst, 0, buf2, sizeof(buf2));
+ if(key->sen_dport != 0) {
+ sprintf(buf2+buf_len-1, ":%d", ntohs(key->sen_dport));
+ }
+
+ buf3[0]='\0';
+ if(key->sen_proto != 0) {
+ sprintf(buf3, ":%d", key->sen_proto);
+ }
+
+ sa_len = satoa(ro->er_said, 0, sa, SATOA_BUF);
+
+ w->len += ipsec_snprintf(w->buffer + w->len,
+ w->length - w->len,
+ "%-10d "
+ "%-18s -> %-18s => %s%s\n",
+ ro->er_count,
+ buf1,
+ buf2,
+ sa_len ? sa : " (error)",
+ buf3);
+
+ {
+ /* snprintf can only fill the last character with NUL
+ * so the maximum useful character is w->length-1.
+ * However, if w->length == 0, we cannot go back.
+ * (w->length surely cannot be negative.)
+ */
+ int max_content = w->length > 0? w->length-1 : 0;
+
+ if (w->len >= max_content) {
+ /* we've done all that can fit -- stop treewalking */
+ w->len = max_content; /* truncate crap */
+ return -ENOBUFS;
+ } else {
+ const off_t pos = w->begin + w->len; /* file position of end of what we've generated */
+
+ if (pos <= w->offset) {
+ /* all is before first interesting character:
+ * discard, but note where we are.
+ */
+ w->len = 0;
+ w->begin = pos;
+ }
+ return 0;
+ }
+ }
+}
+#endif /* CONFIG_PROC_FS */
+
+int
+ipsec_rj_walker_delete(struct radij_node *rn, void *w0)
+{
+ struct eroute *ro;
+ struct rjtentry *rd = (struct rjtentry *)rn;
+ struct radij_node *rn2;
+ int error;
+ struct sockaddr_encap *key, *mask;
+
+ key = rd_key(rd);
+ mask = rd_mask(rd);
+
+ if(!key || !mask) {
+ return -ENODATA;
+ }
+#ifdef CONFIG_IPSEC_DEBUG
+ if(debug_radij) {
+ char buf1[SUBNETTOA_BUF], buf2[SUBNETTOA_BUF];
+
+ subnettoa(key->sen_ip_src, mask->sen_ip_src, 0, buf1, sizeof(buf1));
+ subnettoa(key->sen_ip_dst, mask->sen_ip_dst, 0, buf2, sizeof(buf2));
+ KLIPS_PRINT(debug_radij,
+ "klips_debug:ipsec_rj_walker_delete: "
+ "deleting: %s -> %s\n",
+ buf1,
+ buf2);
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+
+ if((error = rj_delete(key, mask, rnh, &rn2))) {
+ KLIPS_PRINT(debug_radij,
+ "klips_debug:ipsec_rj_walker_delete: "
+ "rj_delete failed with error=%d.\n", error);
+ return error;
+ }
+
+ if(rn2 != rn) {
+ printk("klips_debug:ipsec_rj_walker_delete: "
+ "tried to delete a different node?!? This should never happen!\n");
+ }
+
+ ro = (struct eroute *)rn;
+
+ if (ro->er_ident_s.data)
+ kfree(ro->er_ident_s.data);
+ if (ro->er_ident_d.data)
+ kfree(ro->er_ident_d.data);
+
+ memset((caddr_t)rn, 0, sizeof (struct eroute));
+ kfree(rn);
+
+ return 0;
+}
+
diff --git a/linux/net/ipsec/ipsec_rcv.c b/linux/net/ipsec/ipsec_rcv.c
new file mode 100644
index 000000000..4df839fe2
--- /dev/null
+++ b/linux/net/ipsec/ipsec_rcv.c
@@ -0,0 +1,2204 @@
+/*
+ * receive code
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 1998, 1999, 2000, 2001 Richard Guy Briggs.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+char ipsec_rcv_c_version[] = "RCSID $Id: ipsec_rcv.c,v 1.5 2005/04/10 21:38:32 as Exp $";
+
+#include <linux/config.h>
+#include <linux/version.h>
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/kernel.h> /* printk() */
+
+#include "freeswan/ipsec_param.h"
+
+#ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+#else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+#endif /* MALLOC_SLAB */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/interrupt.h> /* mark_bh */
+
+#include <linux/netdevice.h> /* struct device, and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/ip.h> /* struct iphdr */
+#include <linux/skbuff.h>
+#include <freeswan.h>
+#ifdef SPINLOCK
+# ifdef SPINLOCK_23
+# include <linux/spinlock.h> /* *lock* */
+# else /* SPINLOCK_23 */
+# include <asm/spinlock.h> /* *lock* */
+# endif /* SPINLOCK_23 */
+#endif /* SPINLOCK */
+#ifdef NET_21
+# include <asm/uaccess.h>
+# include <linux/in6.h>
+# define proto_priv cb
+#endif /* NET21 */
+#include <asm/checksum.h>
+#include <net/ip.h>
+
+#include "freeswan/radij.h"
+#include "freeswan/ipsec_encap.h"
+#include "freeswan/ipsec_sa.h"
+
+#include "freeswan/ipsec_radij.h"
+#include "freeswan/ipsec_xform.h"
+#include "freeswan/ipsec_tunnel.h"
+#include "freeswan/ipsec_rcv.h"
+
+#if defined(CONFIG_IPSEC_ESP) || defined(CONFIG_IPSEC_AH)
+#include "freeswan/ipsec_ah.h"
+#endif /* defined(CONFIG_IPSEC_ESP) || defined(CONFIG_IPSEC_AH) */
+
+#ifdef CONFIG_IPSEC_ESP
+#include "freeswan/ipsec_esp.h"
+#endif /* !CONFIG_IPSEC_ESP */
+
+#ifdef CONFIG_IPSEC_IPCOMP
+#include "freeswan/ipcomp.h"
+#endif /* CONFIG_IPSEC_COMP */
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "freeswan/ipsec_proto.h"
+#include "freeswan/ipsec_alg.h"
+
+#ifdef CONFIG_IPSEC_DEBUG
+int debug_ah = 0;
+int debug_esp = 0;
+int debug_rcv = 0;
+#endif /* CONFIG_IPSEC_DEBUG */
+
+int sysctl_ipsec_inbound_policy_check = 1;
+
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+#include <linux/udp.h>
+#endif
+
+#ifdef CONFIG_IPSEC_DEBUG
+static void
+rcv_dmp(char *s, caddr_t bb, int len)
+{
+ int i;
+ unsigned char *b = bb;
+
+ if (debug_rcv && sysctl_ipsec_debug_verbose) {
+ printk(KERN_INFO "klips_debug:ipsec_tunnel_:dmp: "
+ "at %s, len=%d:",
+ s,
+ len);
+ for (i=0; i < len; i++) {
+ if(!(i%16)){
+ printk("\nklips_debug: ");
+ }
+ printk(" %02x", *b++);
+ }
+ printk("\n");
+ }
+}
+#else /* CONFIG_IPSEC_DEBUG */
+#define rcv_dmp(_x, _y, _z)
+#endif /* CONFIG_IPSEC_DEBUG */
+
+
+#if defined(CONFIG_IPSEC_ESP) || defined(CONFIG_IPSEC_AH)
+__u32 zeroes[AH_AMAX];
+#endif /* defined(CONFIG_IPSEC_ESP) || defined(CONFIG_IPSEC_AH) */
+
+/*
+ * Check-replay-window routine, adapted from the original
+ * by J. Hughes, from draft-ietf-ipsec-esp-des-md5-03.txt
+ *
+ * This is a routine that implements a 64 packet window. This is intend-
+ * ed on being an implementation sample.
+ */
+
+DEBUG_NO_STATIC int
+ipsec_checkreplaywindow(struct ipsec_sa*ipsp, __u32 seq)
+{
+ __u32 diff;
+
+ if (ipsp->ips_replaywin == 0) /* replay shut off */
+ return 1;
+ if (seq == 0)
+ return 0; /* first == 0 or wrapped */
+
+ /* new larger sequence number */
+ if (seq > ipsp->ips_replaywin_lastseq) {
+ return 1; /* larger is good */
+ }
+ diff = ipsp->ips_replaywin_lastseq - seq;
+
+ /* too old or wrapped */ /* if wrapped, kill off SA? */
+ if (diff >= ipsp->ips_replaywin) {
+ return 0;
+ }
+ /* this packet already seen */
+ if (ipsp->ips_replaywin_bitmap & (1 << diff))
+ return 0;
+ return 1; /* out of order but good */
+}
+
+DEBUG_NO_STATIC int
+ipsec_updatereplaywindow(struct ipsec_sa*ipsp, __u32 seq)
+{
+ __u32 diff;
+
+ if (ipsp->ips_replaywin == 0) /* replay shut off */
+ return 1;
+ if (seq == 0)
+ return 0; /* first == 0 or wrapped */
+
+ /* new larger sequence number */
+ if (seq > ipsp->ips_replaywin_lastseq) {
+ diff = seq - ipsp->ips_replaywin_lastseq;
+
+ /* In win, set bit for this pkt */
+ if (diff < ipsp->ips_replaywin)
+ ipsp->ips_replaywin_bitmap =
+ (ipsp->ips_replaywin_bitmap << diff) | 1;
+ else
+ /* This packet has way larger seq num */
+ ipsp->ips_replaywin_bitmap = 1;
+
+ if(seq - ipsp->ips_replaywin_lastseq - 1 > ipsp->ips_replaywin_maxdiff) {
+ ipsp->ips_replaywin_maxdiff = seq - ipsp->ips_replaywin_lastseq - 1;
+ }
+ ipsp->ips_replaywin_lastseq = seq;
+ return 1; /* larger is good */
+ }
+ diff = ipsp->ips_replaywin_lastseq - seq;
+
+ /* too old or wrapped */ /* if wrapped, kill off SA? */
+ if (diff >= ipsp->ips_replaywin) {
+/*
+ if(seq < 0.25*max && ipsp->ips_replaywin_lastseq > 0.75*max) {
+ ipsec_sa_delchain(ipsp);
+ }
+*/
+ return 0;
+ }
+ /* this packet already seen */
+ if (ipsp->ips_replaywin_bitmap & (1 << diff))
+ return 0;
+ ipsp->ips_replaywin_bitmap |= (1 << diff); /* mark as seen */
+ return 1; /* out of order but good */
+}
+
+#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
+struct auth_alg ipsec_rcv_md5[]={
+ {MD5Init, MD5Update, MD5Final, AHMD596_ALEN}
+};
+
+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
+
+#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
+struct auth_alg ipsec_rcv_sha1[]={
+ {SHA1Init, SHA1Update, SHA1Final, AHSHA196_ALEN}
+};
+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
+
+enum ipsec_rcv_value {
+ IPSEC_RCV_LASTPROTO=1,
+ IPSEC_RCV_OK=0,
+ IPSEC_RCV_BADPROTO=-1,
+ IPSEC_RCV_BADLEN=-2,
+ IPSEC_RCV_ESP_BADALG=-3,
+ IPSEC_RCV_3DES_BADBLOCKING=-4,
+ IPSEC_RCV_ESP_DECAPFAIL=-5,
+ IPSEC_RCV_DECAPFAIL=-6,
+ IPSEC_RCV_SAIDNOTFOUND=-7,
+ IPSEC_RCV_IPCOMPALONE=-8,
+ IPSEC_RCV_IPCOMPFAILED=-10,
+ IPSEC_RCV_SAIDNOTLIVE=-11,
+ IPSEC_RCV_FAILEDINBOUND=-12,
+ IPSEC_RCV_LIFETIMEFAILED=-13,
+ IPSEC_RCV_BADAUTH=-14,
+ IPSEC_RCV_REPLAYFAILED=-15,
+ IPSEC_RCV_AUTHFAILED=-16,
+ IPSEC_RCV_REPLAYROLLED=-17,
+ IPSEC_RCV_BAD_DECRYPT=-18
+};
+
+struct ipsec_rcv_state {
+ struct sk_buff *skb;
+ struct net_device_stats *stats;
+ struct iphdr *ipp;
+ struct ipsec_sa *ipsp;
+ int len;
+ int ilen;
+ int authlen;
+ int hard_header_len;
+ int iphlen;
+ struct auth_alg *authfuncs;
+ struct sa_id said;
+ char sa[SATOA_BUF];
+ size_t sa_len;
+ __u8 next_header;
+ __u8 hash[AH_AMAX];
+ char ipsaddr_txt[ADDRTOA_BUF];
+ char ipdaddr_txt[ADDRTOA_BUF];
+ __u8 *octx;
+ __u8 *ictx;
+ int ictx_len;
+ int octx_len;
+ union {
+ struct {
+ struct esphdr *espp;
+ } espstuff;
+ struct {
+ struct ahhdr *ahp;
+ } ahstuff;
+ struct {
+ struct ipcomphdr *compp;
+ } ipcompstuff;
+ } protostuff;
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ __u16 natt_len;
+ __u16 natt_sport;
+ __u16 natt_dport;
+ __u8 natt_type;
+#endif
+};
+
+struct xform_functions {
+ enum ipsec_rcv_value (*checks)(struct ipsec_rcv_state *irs,
+ struct sk_buff *skb);
+ enum ipsec_rcv_value (*decrypt)(struct ipsec_rcv_state *irs);
+
+ enum ipsec_rcv_value (*setup_auth)(struct ipsec_rcv_state *irs,
+ struct sk_buff *skb,
+ __u32 *replay,
+ unsigned char **authenticator);
+ enum ipsec_rcv_value (*calc_auth)(struct ipsec_rcv_state *irs,
+ struct sk_buff *skb);
+};
+
+#ifdef CONFIG_IPSEC_ESP
+enum ipsec_rcv_value
+ipsec_rcv_esp_checks(struct ipsec_rcv_state *irs,
+ struct sk_buff *skb)
+{
+ __u8 proto;
+ int len; /* packet length */
+
+ len = skb->len;
+ proto = irs->ipp->protocol;
+
+ /* XXX this will need to be 8 for IPv6 */
+ if ((proto == IPPROTO_ESP) && ((len - irs->iphlen) % 4)) {
+ printk("klips_error:ipsec_rcv: "
+ "got packet with content length = %d from %s -- should be on 4 octet boundary, packet dropped\n",
+ len - irs->iphlen,
+ irs->ipsaddr_txt);
+ if(irs->stats) {
+ irs->stats->rx_errors++;
+ }
+ return IPSEC_RCV_BADLEN;
+ }
+
+ if(skb->len < (irs->hard_header_len + sizeof(struct iphdr) + sizeof(struct esphdr))) {
+ KLIPS_PRINT(debug_rcv & DB_RX_INAU,
+ "klips_debug:ipsec_rcv: "
+ "runt esp packet of skb->len=%d received from %s, dropped.\n",
+ skb->len,
+ irs->ipsaddr_txt);
+ if(irs->stats) {
+ irs->stats->rx_errors++;
+ }
+ return IPSEC_RCV_BADLEN;
+ }
+
+ irs->protostuff.espstuff.espp = (struct esphdr *)(skb->data + irs->iphlen);
+ irs->said.spi = irs->protostuff.espstuff.espp->esp_spi;
+
+ return IPSEC_RCV_OK;
+}
+
+enum ipsec_rcv_value
+ipsec_rcv_esp_decrypt_setup(struct ipsec_rcv_state *irs,
+ struct sk_buff *skb,
+ __u32 *replay,
+ unsigned char **authenticator)
+{
+ struct esphdr *espp = irs->protostuff.espstuff.espp;
+
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "packet from %s received with seq=%d (iv)=0x%08x%08x iplen=%d esplen=%d sa=%s\n",
+ irs->ipsaddr_txt,
+ (__u32)ntohl(espp->esp_rpl),
+ (__u32)ntohl(*((__u32 *)(espp->esp_iv) )),
+ (__u32)ntohl(*((__u32 *)(espp->esp_iv) + 1)),
+ irs->len,
+ irs->ilen,
+ irs->sa_len ? irs->sa : " (error)");
+
+ *replay = ntohl(espp->esp_rpl);
+ *authenticator = &(skb->data[irs->len - irs->authlen]);
+
+ return IPSEC_RCV_OK;
+}
+
+enum ipsec_rcv_value
+ipsec_rcv_esp_authcalc(struct ipsec_rcv_state *irs,
+ struct sk_buff *skb)
+{
+ struct auth_alg *aa;
+ struct esphdr *espp = irs->protostuff.espstuff.espp;
+ union {
+ MD5_CTX md5;
+ SHA1_CTX sha1;
+ } tctx;
+
+#ifdef CONFIG_IPSEC_ALG
+ if (irs->ipsp->ips_alg_auth) {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "ipsec_alg hashing proto=%d... ",
+ irs->said.proto);
+ if(irs->said.proto == IPPROTO_ESP) {
+ ipsec_alg_sa_esp_hash(irs->ipsp,
+ (caddr_t)espp, irs->ilen,
+ irs->hash, AHHMAC_HASHLEN);
+ return IPSEC_RCV_OK;
+ }
+ return IPSEC_RCV_BADPROTO;
+ }
+#endif
+ aa = irs->authfuncs;
+
+ /* copy the initialized keying material */
+ memcpy(&tctx, irs->ictx, irs->ictx_len);
+
+ (*aa->update)((void *)&tctx, (caddr_t)espp, irs->ilen);
+
+ (*aa->final)(irs->hash, (void *)&tctx);
+
+ memcpy(&tctx, irs->octx, irs->octx_len);
+
+ (*aa->update)((void *)&tctx, irs->hash, aa->hashlen);
+ (*aa->final)(irs->hash, (void *)&tctx);
+
+ return IPSEC_RCV_OK;
+}
+
+
+enum ipsec_rcv_value
+ipsec_rcv_esp_decrypt(struct ipsec_rcv_state *irs)
+{
+ struct ipsec_sa *ipsp = irs->ipsp;
+ struct esphdr *espp = irs->protostuff.espstuff.espp;
+ int esphlen = 0;
+ __u8 *idat; /* pointer to content to be decrypted/authenticated */
+#ifdef CONFIG_IPSEC_ENC_3DES
+ __u32 iv[2];
+#endif /* !CONFIG_IPSEC_ENC_3DES */
+ int pad = 0, padlen;
+ int badpad = 0;
+ int i;
+ struct sk_buff *skb;
+#ifdef CONFIG_IPSEC_ALG
+ struct ipsec_alg_enc *ixt_e=NULL;
+#endif /* CONFIG_IPSEC_ALG */
+
+ skb=irs->skb;
+
+ idat = skb->data + irs->iphlen;
+
+#ifdef CONFIG_IPSEC_ALG
+ if ((ixt_e=ipsp->ips_alg_enc)) {
+ esphlen = ESP_HEADER_LEN + ixt_e->ixt_ivlen/8;
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "encalg=%d esphlen=%d\n",
+ ipsp->ips_encalg, esphlen);
+ } else
+#endif /* CONFIG_IPSEC_ALG */
+ switch(ipsp->ips_encalg) {
+#ifdef CONFIG_IPSEC_ENC_3DES
+ case ESP_3DES:
+ iv[0] = *((__u32 *)(espp->esp_iv) );
+ iv[1] = *((__u32 *)(espp->esp_iv) + 1);
+ esphlen = sizeof(struct esphdr);
+ break;
+#endif /* !CONFIG_IPSEC_ENC_3DES */
+ default:
+ ipsp->ips_errs.ips_alg_errs += 1;
+ if(irs->stats) {
+ irs->stats->rx_errors++;
+ }
+ return IPSEC_RCV_ESP_BADALG;
+ }
+
+ idat += esphlen;
+ irs->ilen -= esphlen;
+
+#ifdef CONFIG_IPSEC_ALG
+ if (ixt_e)
+ {
+ if (ipsec_alg_esp_encrypt(ipsp,
+ idat, irs->ilen, espp->esp_iv,
+ IPSEC_ALG_DECRYPT) <= 0)
+ {
+ printk("klips_error:ipsec_rcv: "
+ "got packet with esplen = %d "
+ "from %s -- should be on "
+ "ENC(%d) octet boundary, "
+ "packet dropped\n",
+ irs->ilen,
+ irs->ipsaddr_txt,
+ ipsp->ips_encalg);
+ if(irs->stats) {
+ irs->stats->rx_errors++;
+ }
+ return IPSEC_RCV_BAD_DECRYPT;
+ }
+ } else
+#endif /* CONFIG_IPSEC_ALG */
+ switch(ipsp->ips_encalg) {
+#ifdef CONFIG_IPSEC_ENC_3DES
+ case ESP_3DES:
+ if ((irs->ilen) % 8) {
+ ipsp->ips_errs.ips_encsize_errs += 1;
+ printk("klips_error:ipsec_rcv: "
+ "got packet with esplen = %d from %s -- should be on 8 octet boundary, packet dropped\n",
+ irs->ilen,
+ irs->ipsaddr_txt);
+ if(irs->stats) {
+ irs->stats->rx_errors++;
+ }
+ return IPSEC_RCV_3DES_BADBLOCKING;
+ }
+ des_ede3_cbc_encrypt((des_cblock *)idat,
+ (des_cblock *)idat,
+ irs->ilen,
+ ((struct des_eks *)(ipsp->ips_key_e))[0].ks,
+ ((struct des_eks *)(ipsp->ips_key_e))[1].ks,
+ ((struct des_eks *)(ipsp->ips_key_e))[2].ks,
+ (des_cblock *)iv, 0);
+ break;
+#endif /* !CONFIG_IPSEC_ENC_3DES */
+ }
+
+ rcv_dmp("postdecrypt", skb->data, skb->len);
+
+ irs->next_header = idat[irs->ilen - 1];
+ padlen = idat[irs->ilen - 2];
+ pad = padlen + 2 + irs->authlen;
+
+ KLIPS_PRINT(debug_rcv & DB_RX_IPAD,
+ "klips_debug:ipsec_rcv: "
+ "padlen=%d, contents: 0x<offset>: 0x<value> 0x<value> ...\n",
+ padlen);
+
+ for (i = 1; i <= padlen; i++) {
+ if((i % 16) == 1) {
+ KLIPS_PRINT(debug_rcv & DB_RX_IPAD,
+ "klips_debug: %02x:",
+ i - 1);
+ }
+ KLIPS_PRINTMORE(debug_rcv & DB_RX_IPAD,
+ " %02x",
+ idat[irs->ilen - 2 - padlen + i - 1]);
+ if(i != idat[irs->ilen - 2 - padlen + i - 1]) {
+ badpad = 1;
+ }
+ if((i % 16) == 0) {
+ KLIPS_PRINTMORE(debug_rcv & DB_RX_IPAD,
+ "\n");
+ }
+ }
+ if((i % 16) != 1) {
+ KLIPS_PRINTMORE(debug_rcv & DB_RX_IPAD,
+ "\n");
+ }
+ if(badpad) {
+ KLIPS_PRINT(debug_rcv & DB_RX_IPAD,
+ "klips_debug:ipsec_rcv: "
+ "warning, decrypted packet from %s has bad padding\n",
+ irs->ipsaddr_txt);
+ KLIPS_PRINT(debug_rcv & DB_RX_IPAD,
+ "klips_debug:ipsec_rcv: "
+ "...may be bad decryption -- not dropped\n");
+ ipsp->ips_errs.ips_encpad_errs += 1;
+ }
+
+ KLIPS_PRINT(debug_rcv & DB_RX_IPAD,
+ "klips_debug:ipsec_rcv: "
+ "packet decrypted from %s: next_header = %d, padding = %d\n",
+ irs->ipsaddr_txt,
+ irs->next_header,
+ pad - 2 - irs->authlen);
+
+ irs->ipp->tot_len = htons(ntohs(irs->ipp->tot_len) - (esphlen + pad));
+
+ /*
+ * move the IP header forward by the size of the ESP header, which
+ * will remove the the ESP header from the packet.
+ */
+ memmove((void *)(skb->data + esphlen),
+ (void *)(skb->data), irs->iphlen);
+
+ rcv_dmp("esp postmove", skb->data, skb->len);
+
+ /* skb_pull below, will move up by esphlen */
+
+ /* XXX not clear how this can happen, as the message indicates */
+ if(skb->len < esphlen) {
+ printk(KERN_WARNING
+ "klips_error:ipsec_rcv: "
+ "tried to skb_pull esphlen=%d, %d available. This should never happen, please report.\n",
+ esphlen, (int)(skb->len));
+ return IPSEC_RCV_ESP_DECAPFAIL;
+ }
+ skb_pull(skb, esphlen);
+
+ irs->ipp = (struct iphdr *)skb->data;
+
+ rcv_dmp("esp postpull", skb->data, skb->len);
+
+ /* now, trip off the padding from the end */
+ KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
+ "klips_debug:ipsec_rcv: "
+ "trimming to %d.\n",
+ irs->len - esphlen - pad);
+ if(pad + esphlen <= irs->len) {
+ skb_trim(skb, irs->len - esphlen - pad);
+ } else {
+ KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
+ "klips_debug:ipsec_rcv: "
+ "bogus packet, size is zero or negative, dropping.\n");
+ return IPSEC_RCV_DECAPFAIL;
+ }
+
+ return IPSEC_RCV_OK;
+}
+
+
+struct xform_functions esp_rcv_funcs[]={
+ { checks: ipsec_rcv_esp_checks,
+ setup_auth: ipsec_rcv_esp_decrypt_setup,
+ calc_auth: ipsec_rcv_esp_authcalc,
+ decrypt: ipsec_rcv_esp_decrypt,
+ },
+};
+#endif /* !CONFIG_IPSEC_ESP */
+
+#ifdef CONFIG_IPSEC_AH
+enum ipsec_rcv_value
+ipsec_rcv_ah_checks(struct ipsec_rcv_state *irs,
+ struct sk_buff *skb)
+{
+ int ahminlen;
+
+ ahminlen = irs->hard_header_len + sizeof(struct iphdr);
+
+ /* take care not to deref this pointer until we check the minlen though */
+ irs->protostuff.ahstuff.ahp = (struct ahhdr *) (skb->data + irs->iphlen);
+
+ if((skb->len < ahminlen+sizeof(struct ahhdr)) ||
+ (skb->len < ahminlen+(irs->protostuff.ahstuff.ahp->ah_hl << 2))) {
+ KLIPS_PRINT(debug_rcv & DB_RX_INAU,
+ "klips_debug:ipsec_rcv: "
+ "runt ah packet of skb->len=%d received from %s, dropped.\n",
+ skb->len,
+ irs->ipsaddr_txt);
+ if(irs->stats) {
+ irs->stats->rx_errors++;
+ }
+ return IPSEC_RCV_BADLEN;
+ }
+
+ irs->said.spi = irs->protostuff.ahstuff.ahp->ah_spi;
+
+ /* XXX we only support the one 12-byte authenticator for now */
+ if(irs->protostuff.ahstuff.ahp->ah_hl != ((AHHMAC_HASHLEN+AHHMAC_RPLLEN) >> 2)) {
+ KLIPS_PRINT(debug_rcv & DB_RX_INAU,
+ "klips_debug:ipsec_rcv: "
+ "bad authenticator length %ld, expected %lu from %s.\n",
+ (long)(irs->protostuff.ahstuff.ahp->ah_hl << 2),
+ (unsigned long) sizeof(struct ahhdr),
+ irs->ipsaddr_txt);
+ if(irs->stats) {
+ irs->stats->rx_errors++;
+ }
+ return IPSEC_RCV_BADLEN;
+ }
+
+ return IPSEC_RCV_OK;
+}
+
+
+enum ipsec_rcv_value
+ipsec_rcv_ah_setup_auth(struct ipsec_rcv_state *irs,
+ struct sk_buff *skb,
+ __u32 *replay,
+ unsigned char **authenticator)
+{
+ struct ahhdr *ahp = irs->protostuff.ahstuff.ahp;
+
+ *replay = ntohl(ahp->ah_rpl);
+ *authenticator = ahp->ah_data;
+
+ return IPSEC_RCV_OK;
+}
+
+enum ipsec_rcv_value
+ipsec_rcv_ah_authcalc(struct ipsec_rcv_state *irs,
+ struct sk_buff *skb)
+{
+ struct auth_alg *aa;
+ struct ahhdr *ahp = irs->protostuff.ahstuff.ahp;
+ union {
+ MD5_CTX md5;
+ SHA1_CTX sha1;
+ } tctx;
+ struct iphdr ipo;
+ int ahhlen;
+
+ aa = irs->authfuncs;
+
+ /* copy the initialized keying material */
+ memcpy(&tctx, irs->ictx, irs->ictx_len);
+
+ ipo = *irs->ipp;
+ ipo.tos = 0; /* mutable RFC 2402 3.3.3.1.1.1 */
+ ipo.frag_off = 0;
+ ipo.ttl = 0;
+ ipo.check = 0;
+
+
+ /* do the sanitized header */
+ (*aa->update)((void*)&tctx, (caddr_t)&ipo, sizeof(struct iphdr));
+
+ /* XXX we didn't do the options here! */
+
+ /* now do the AH header itself */
+ ahhlen = AH_BASIC_LEN + (ahp->ah_hl << 2);
+ (*aa->update)((void*)&tctx, (caddr_t)ahp, ahhlen - AHHMAC_HASHLEN);
+
+ /* now, do some zeroes */
+ (*aa->update)((void*)&tctx, (caddr_t)zeroes, AHHMAC_HASHLEN);
+
+ /* finally, do the packet contents themselves */
+ (*aa->update)((void*)&tctx,
+ (caddr_t)skb->data + irs->iphlen + ahhlen,
+ skb->len - irs->iphlen - ahhlen);
+
+ (*aa->final)(irs->hash, (void *)&tctx);
+
+ memcpy(&tctx, irs->octx, irs->octx_len);
+
+ (*aa->update)((void *)&tctx, irs->hash, aa->hashlen);
+ (*aa->final)(irs->hash, (void *)&tctx);
+
+ return IPSEC_RCV_OK;
+}
+
+enum ipsec_rcv_value
+ipsec_rcv_ah_decap(struct ipsec_rcv_state *irs)
+{
+ struct ahhdr *ahp = irs->protostuff.ahstuff.ahp;
+ struct sk_buff *skb;
+ int ahhlen;
+
+ skb=irs->skb;
+
+ ahhlen = AH_BASIC_LEN + (ahp->ah_hl << 2);
+
+ irs->ipp->tot_len = htons(ntohs(irs->ipp->tot_len) - ahhlen);
+ irs->next_header = ahp->ah_nh;
+
+ /*
+ * move the IP header forward by the size of the AH header, which
+ * will remove the the AH header from the packet.
+ */
+ memmove((void *)(skb->data + ahhlen),
+ (void *)(skb->data), irs->iphlen);
+
+ rcv_dmp("ah postmove", skb->data, skb->len);
+
+ /* skb_pull below, will move up by ahhlen */
+
+ /* XXX not clear how this can happen, as the message indicates */
+ if(skb->len < ahhlen) {
+ printk(KERN_WARNING
+ "klips_error:ipsec_rcv: "
+ "tried to skb_pull ahhlen=%d, %d available. This should never happen, please report.\n",
+ ahhlen,
+ (int)(skb->len));
+ return IPSEC_RCV_DECAPFAIL;
+ }
+ skb_pull(skb, ahhlen);
+
+ irs->ipp = (struct iphdr *)skb->data;
+
+ rcv_dmp("ah postpull", skb->data, skb->len);
+
+ return IPSEC_RCV_OK;
+}
+
+
+struct xform_functions ah_rcv_funcs[]={
+ { checks: ipsec_rcv_ah_checks,
+ setup_auth: ipsec_rcv_ah_setup_auth,
+ calc_auth: ipsec_rcv_ah_authcalc,
+ decrypt: ipsec_rcv_ah_decap,
+ },
+};
+
+#endif /* CONFIG_IPSEC_AH */
+
+#ifdef CONFIG_IPSEC_IPCOMP
+enum ipsec_rcv_value
+ipsec_rcv_ipcomp_checks(struct ipsec_rcv_state *irs,
+ struct sk_buff *skb)
+{
+ int ipcompminlen;
+
+ ipcompminlen = irs->hard_header_len + sizeof(struct iphdr);
+
+ if(skb->len < (ipcompminlen + sizeof(struct ipcomphdr))) {
+ KLIPS_PRINT(debug_rcv & DB_RX_INAU,
+ "klips_debug:ipsec_rcv: "
+ "runt comp packet of skb->len=%d received from %s, dropped.\n",
+ skb->len,
+ irs->ipsaddr_txt);
+ if(irs->stats) {
+ irs->stats->rx_errors++;
+ }
+ return IPSEC_RCV_BADLEN;
+ }
+
+ irs->protostuff.ipcompstuff.compp = (struct ipcomphdr *)(skb->data + irs->iphlen);
+ irs->said.spi = htonl((__u32)ntohs(irs->protostuff.ipcompstuff.compp->ipcomp_cpi));
+ return IPSEC_RCV_OK;
+}
+
+enum ipsec_rcv_value
+ipsec_rcv_ipcomp_decomp(struct ipsec_rcv_state *irs)
+{
+ unsigned int flags = 0;
+ struct ipsec_sa *ipsp = irs->ipsp;
+ struct sk_buff *skb;
+
+ skb=irs->skb;
+
+ rcv_dmp("ipcomp", skb->data, skb->len);
+
+ if(ipsp == NULL) {
+ return IPSEC_RCV_SAIDNOTFOUND;
+ }
+
+#if 0
+ /* we want to check that this wasn't the first SA on the list, because
+ * we don't support bare IPCOMP, for unexplained reasons. MCR
+ */
+ if (ipsp->ips_onext != NULL) {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "Incoming packet with outer IPCOMP header SA:%s: not yet supported by KLIPS, dropped\n",
+ irs->sa_len ? irs->sa : " (error)");
+ if(irs->stats) {
+ irs->stats->rx_dropped++;
+ }
+
+ return IPSEC_RCV_IPCOMPALONE;
+ }
+#endif
+
+ if(sysctl_ipsec_inbound_policy_check &&
+ ((((ntohl(ipsp->ips_said.spi) & 0x0000ffff) != ntohl(irs->said.spi)) &&
+ (ipsp->ips_encalg != ntohl(irs->said.spi)) /* this is a workaround for peer non-compliance with rfc2393 */
+ ))) {
+ char sa2[SATOA_BUF];
+ size_t sa_len2 = 0;
+
+ sa_len2 = satoa(ipsp->ips_said, 0, sa2, SATOA_BUF);
+
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "Incoming packet with SA(IPCA):%s does not match policy SA(IPCA):%s cpi=%04x cpi->spi=%08x spi=%08x, spi->cpi=%04x for SA grouping, dropped.\n",
+ irs->sa_len ? irs->sa : " (error)",
+ ipsp != NULL ? (sa_len2 ? sa2 : " (error)") : "NULL",
+ ntohs(irs->protostuff.ipcompstuff.compp->ipcomp_cpi),
+ (__u32)ntohl(irs->said.spi),
+ ipsp != NULL ? (__u32)ntohl((ipsp->ips_said.spi)) : 0,
+ ipsp != NULL ? (__u16)(ntohl(ipsp->ips_said.spi) & 0x0000ffff) : 0);
+ if(irs->stats) {
+ irs->stats->rx_dropped++;
+ }
+ return IPSEC_RCV_SAIDNOTFOUND;
+ }
+
+ ipsp->ips_comp_ratio_cbytes += ntohs(irs->ipp->tot_len);
+ irs->next_header = irs->protostuff.ipcompstuff.compp->ipcomp_nh;
+
+ skb = skb_decompress(skb, ipsp, &flags);
+ if (!skb || flags) {
+ spin_unlock(&tdb_lock);
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "skb_decompress() returned error flags=%x, dropped.\n",
+ flags);
+ if (irs->stats) {
+ if (flags)
+ irs->stats->rx_errors++;
+ else
+ irs->stats->rx_dropped++;
+ }
+ return IPSEC_RCV_IPCOMPFAILED;
+ }
+
+ /* make sure we update the pointer */
+ irs->skb = skb;
+
+#ifdef NET_21
+ irs->ipp = skb->nh.iph;
+#else /* NET_21 */
+ irs->ipp = skb->ip_hdr;
+#endif /* NET_21 */
+
+ ipsp->ips_comp_ratio_dbytes += ntohs(irs->ipp->tot_len);
+
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "packet decompressed SA(IPCA):%s cpi->spi=%08x spi=%08x, spi->cpi=%04x, nh=%d.\n",
+ irs->sa_len ? irs->sa : " (error)",
+ (__u32)ntohl(irs->said.spi),
+ ipsp != NULL ? (__u32)ntohl((ipsp->ips_said.spi)) : 0,
+ ipsp != NULL ? (__u16)(ntohl(ipsp->ips_said.spi) & 0x0000ffff) : 0,
+ irs->next_header);
+ KLIPS_IP_PRINT(debug_rcv & DB_RX_PKTRX, irs->ipp);
+
+ return IPSEC_RCV_OK;
+}
+
+
+struct xform_functions ipcomp_rcv_funcs[]={
+ {checks: ipsec_rcv_ipcomp_checks,
+ decrypt: ipsec_rcv_ipcomp_decomp,
+ },
+};
+
+#endif /* CONFIG_IPSEC_IPCOMP */
+
+enum ipsec_rcv_value
+ipsec_rcv_decap_once(struct ipsec_rcv_state *irs)
+{
+ int iphlen;
+ unsigned char *dat;
+ __u8 proto;
+ struct in_addr ipsaddr;
+ struct in_addr ipdaddr;
+ int replay = 0; /* replay value in AH or ESP packet */
+ struct ipsec_sa* ipsnext = NULL; /* next SA towards inside of packet */
+ struct xform_functions *proto_funcs;
+ struct ipsec_sa *newipsp;
+ struct iphdr *ipp;
+ struct sk_buff *skb;
+#ifdef CONFIG_IPSEC_ALG
+ struct ipsec_alg_auth *ixt_a=NULL;
+#endif /* CONFIG_IPSEC_ALG */
+
+ skb = irs->skb;
+ irs->len = skb->len;
+ dat = skb->data;
+ ipp = irs->ipp;
+ proto = ipp->protocol;
+ ipsaddr.s_addr = ipp->saddr;
+ addrtoa(ipsaddr, 0, irs->ipsaddr_txt, sizeof(irs->ipsaddr_txt));
+ ipdaddr.s_addr = ipp->daddr;
+ addrtoa(ipdaddr, 0, irs->ipdaddr_txt, sizeof(irs->ipdaddr_txt));
+
+ iphlen = ipp->ihl << 2;
+ irs->iphlen=iphlen;
+ ipp->check = 0; /* we know the sum is good */
+
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv_decap_once: "
+ "decap (%d) from %s -> %s\n",
+ proto, irs->ipsaddr_txt, irs->ipdaddr_txt);
+
+ switch(proto) {
+#ifdef CONFIG_IPSEC_ESP
+ case IPPROTO_ESP:
+ proto_funcs = esp_rcv_funcs;
+ break;
+#endif /* !CONFIG_IPSEC_ESP */
+
+#ifdef CONFIG_IPSEC_AH
+ case IPPROTO_AH:
+ proto_funcs = ah_rcv_funcs;
+ break;
+#endif /* !CONFIG_IPSEC_AH */
+
+#ifdef CONFIG_IPSEC_IPCOMP
+ case IPPROTO_COMP:
+ proto_funcs = ipcomp_rcv_funcs;
+ break;
+#endif /* !CONFIG_IPSEC_IPCOMP */
+ default:
+ if(irs->stats) {
+ irs->stats->rx_errors++;
+ }
+ return IPSEC_RCV_BADPROTO;
+ }
+
+ /*
+ * Find tunnel control block and (indirectly) call the
+ * appropriate tranform routine. The resulting sk_buf
+ * is a valid IP packet ready to go through input processing.
+ */
+
+ irs->said.dst.s_addr = ipp->daddr;
+
+ if(proto_funcs->checks) {
+ enum ipsec_rcv_value retval = (*proto_funcs->checks)(irs, skb);
+
+ if(retval < 0) {
+ return retval;
+ }
+ }
+
+ irs->said.proto = proto;
+ irs->sa_len = satoa(irs->said, 0, irs->sa, SATOA_BUF);
+ if(irs->sa_len == 0) {
+ strcpy(irs->sa, "(error)");
+ }
+
+ newipsp = ipsec_sa_getbyid(&irs->said);
+ if (newipsp == NULL) {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "no ipsec_sa for SA:%s: incoming packet with no SA dropped\n",
+ irs->sa_len ? irs->sa : " (error)");
+ if(irs->stats) {
+ irs->stats->rx_dropped++;
+ }
+ return IPSEC_RCV_SAIDNOTFOUND;
+ }
+
+ /* MCR - XXX this is bizarre. ipsec_sa_getbyid returned it, having incremented the refcount,
+ * why in the world would we decrement it here?
+
+ ipsec_sa_put(irs->ipsp);*/ /* incomplete */
+
+ /* If it is in larval state, drop the packet, we cannot process yet. */
+ if(newipsp->ips_state == SADB_SASTATE_LARVAL) {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "ipsec_sa in larval state, cannot be used yet, dropping packet.\n");
+ if(irs->stats) {
+ irs->stats->rx_dropped++;
+ }
+ ipsec_sa_put(newipsp);
+ return IPSEC_RCV_SAIDNOTLIVE;
+ }
+
+ if(newipsp->ips_state == SADB_SASTATE_DEAD) {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "ipsec_sa in dead state, cannot be used any more, dropping packet.\n");
+ if(irs->stats) {
+ irs->stats->rx_dropped++;
+ }
+ ipsec_sa_put(newipsp);
+ return IPSEC_RCV_SAIDNOTLIVE;
+ }
+
+ if(sysctl_ipsec_inbound_policy_check) {
+ if(irs->ipp->saddr != ((struct sockaddr_in*)(newipsp->ips_addr_s))->sin_addr.s_addr) {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "SA:%s, src=%s of pkt does not agree with expected SA source address policy.\n",
+ irs->sa_len ? irs->sa : " (error)",
+ irs->ipsaddr_txt);
+ if(irs->stats) {
+ irs->stats->rx_dropped++;
+ }
+ ipsec_sa_put(newipsp);
+ return IPSEC_RCV_FAILEDINBOUND;
+ }
+
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "SA:%s, src=%s of pkt agrees with expected SA source address policy.\n",
+ irs->sa_len ? irs->sa : " (error)",
+ irs->ipsaddr_txt);
+
+ /*
+ * at this point, we have looked up a new SA, and we want to make sure that if this
+ * isn't the first SA in the list, that the previous SA actually points at this one.
+ */
+ if(irs->ipsp) {
+ if(irs->ipsp->ips_inext != newipsp) {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "unexpected SA:%s: does not agree with ips->inext policy, dropped\n",
+ irs->sa_len ? irs->sa : " (error)");
+ if(irs->stats) {
+ irs->stats->rx_dropped++;
+ }
+ ipsec_sa_put(newipsp);
+ return IPSEC_RCV_FAILEDINBOUND;
+ }
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "SA:%s grouping from previous SA is OK.\n",
+ irs->sa_len ? irs->sa : " (error)");
+ } else {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "SA:%s First SA in group.\n",
+ irs->sa_len ? irs->sa : " (error)");
+ }
+
+ /*
+ * previously, at this point, we checked if the back pointer from the new SA that
+ * we just found matched the back pointer. But, we won't do this check anymore,
+ * because we want to be able to nest SAs
+ */
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "natt_type=%u tdbp->ips_natt_type=%u : %s\n",
+ irs->natt_type, newipsp->ips_natt_type,
+ (irs->natt_type==newipsp->ips_natt_type)?"ok":"bad");
+ if (irs->natt_type != newipsp->ips_natt_type) {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "SA:%s does not agree with expected NAT-T policy.\n",
+ irs->sa_len ? irs->sa : " (error)");
+ if(irs->stats) {
+ irs->stats->rx_dropped++;
+ }
+ ipsec_sa_put(newipsp);
+ return IPSEC_RCV_FAILEDINBOUND;
+ }
+#endif
+ }
+
+ /* okay, SA checks out, so free any previous SA, and record a new one */
+
+ if(irs->ipsp) {
+ ipsec_sa_put(irs->ipsp);
+ }
+ irs->ipsp=newipsp;
+
+ /* note that the outer code will free the irs->ipsp if there is an error */
+
+
+ /* now check the lifetimes */
+ if(ipsec_lifetime_check(&irs->ipsp->ips_life.ipl_bytes, "bytes", irs->sa,
+ ipsec_life_countbased, ipsec_incoming, irs->ipsp) == ipsec_life_harddied ||
+ ipsec_lifetime_check(&irs->ipsp->ips_life.ipl_addtime, "addtime",irs->sa,
+ ipsec_life_timebased, ipsec_incoming, irs->ipsp) == ipsec_life_harddied ||
+ ipsec_lifetime_check(&irs->ipsp->ips_life.ipl_addtime, "usetime",irs->sa,
+ ipsec_life_timebased, ipsec_incoming, irs->ipsp) == ipsec_life_harddied ||
+ ipsec_lifetime_check(&irs->ipsp->ips_life.ipl_packets, "packets",irs->sa,
+ ipsec_life_countbased, ipsec_incoming, irs->ipsp) == ipsec_life_harddied) {
+ ipsec_sa_delchain(irs->ipsp);
+ if(irs->stats) {
+ irs->stats->rx_dropped++;
+ }
+
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv_decap_once: "
+ "decap (%d) failed lifetime check\n",
+ proto);
+
+ return IPSEC_RCV_LIFETIMEFAILED;
+ }
+
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ if ((irs->natt_type) &&
+ ( (irs->ipp->saddr != (((struct sockaddr_in*)(newipsp->ips_addr_s))->sin_addr.s_addr)) ||
+ (irs->natt_sport != newipsp->ips_natt_sport)
+ )) {
+ struct sockaddr sipaddr;
+ /** Advertise NAT-T addr change to pluto **/
+ sipaddr.sa_family = AF_INET;
+ ((struct sockaddr_in*)&sipaddr)->sin_addr.s_addr = irs->ipp->saddr;
+ ((struct sockaddr_in*)&sipaddr)->sin_port = htons(irs->natt_sport);
+ pfkey_nat_t_new_mapping(newipsp, &sipaddr, irs->natt_sport);
+ /**
+ * Then allow or block packet depending on
+ * sysctl_ipsec_inbound_policy_check.
+ *
+ * In all cases, pluto will update SA if new mapping is
+ * accepted.
+ */
+ if (sysctl_ipsec_inbound_policy_check) {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "SA:%s, src=%s:%u of pkt does not agree with expected "
+ "SA source address policy (pluto has been informed).\n",
+ irs->sa_len ? irs->sa : " (error)",
+ irs->ipsaddr_txt, irs->natt_sport);
+ if(irs->stats) {
+ irs->stats->rx_dropped++;
+ }
+ ipsec_sa_put(newipsp);
+ return IPSEC_RCV_FAILEDINBOUND;
+ }
+ }
+#endif
+
+ irs->authfuncs=NULL;
+ /* authenticate, if required */
+#ifdef CONFIG_IPSEC_ALG
+ if ((ixt_a=irs->ipsp->ips_alg_auth)) {
+ irs->authlen = AHHMAC_HASHLEN;
+ irs->authfuncs = NULL;
+ irs->ictx = NULL;
+ irs->octx = NULL;
+ irs->ictx_len = 0;
+ irs->octx_len = 0;
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "authalg=%d authlen=%d\n",
+ irs->ipsp->ips_authalg,
+ irs->authlen);
+ } else
+#endif /* CONFIG_IPSEC_ALG */
+ switch(irs->ipsp->ips_authalg) {
+#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
+ case AH_MD5:
+ irs->authlen = AHHMAC_HASHLEN;
+ irs->authfuncs = ipsec_rcv_md5;
+ irs->ictx = (void *)&((struct md5_ctx*)(irs->ipsp->ips_key_a))->ictx;
+ irs->octx = (void *)&((struct md5_ctx*)(irs->ipsp->ips_key_a))->octx;
+ irs->ictx_len = sizeof(((struct md5_ctx*)(irs->ipsp->ips_key_a))->ictx);
+ irs->octx_len = sizeof(((struct md5_ctx*)(irs->ipsp->ips_key_a))->octx);
+ break;
+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
+#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
+ case AH_SHA:
+ irs->authlen = AHHMAC_HASHLEN;
+ irs->authfuncs = ipsec_rcv_sha1;
+ irs->ictx = (void *)&((struct sha1_ctx*)(irs->ipsp->ips_key_a))->ictx;
+ irs->octx = (void *)&((struct sha1_ctx*)(irs->ipsp->ips_key_a))->octx;
+ irs->ictx_len = sizeof(((struct sha1_ctx*)(irs->ipsp->ips_key_a))->ictx);
+ irs->octx_len = sizeof(((struct sha1_ctx*)(irs->ipsp->ips_key_a))->octx);
+ break;
+#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
+ case AH_NONE:
+ irs->authlen = 0;
+ irs->authfuncs = NULL;
+ irs->ictx = NULL;
+ irs->octx = NULL;
+ irs->ictx_len = 0;
+ irs->octx_len = 0;
+
+ break;
+ default:
+ irs->ipsp->ips_errs.ips_alg_errs += 1;
+ if(irs->stats) {
+ irs->stats->rx_errors++;
+ }
+ return IPSEC_RCV_BADAUTH;
+ }
+
+ irs->ilen = irs->len - iphlen - irs->authlen;
+ if(irs->ilen <= 0) {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "runt %s packet with no data, dropping.\n",
+ (proto == IPPROTO_ESP ? "esp" : "ah"));
+ if(irs->stats) {
+ irs->stats->rx_dropped++;
+ }
+ return IPSEC_RCV_BADLEN;
+ }
+
+#ifdef CONFIG_IPSEC_ALG
+ if(irs->authfuncs || ixt_a) {
+#else
+ if(irs->authfuncs) {
+#endif
+ unsigned char *authenticator = NULL;
+
+ if(proto_funcs->setup_auth) {
+ enum ipsec_rcv_value retval
+ = (*proto_funcs->setup_auth)(irs, skb,
+ &replay,
+ &authenticator);
+ if(retval < 0) {
+ return retval;
+ }
+ }
+
+ if(!authenticator) {
+ irs->ipsp->ips_errs.ips_auth_errs += 1;
+ if(irs->stats) {
+ irs->stats->rx_dropped++;
+ }
+ return IPSEC_RCV_BADAUTH;
+ }
+
+ if(!ipsec_checkreplaywindow(irs->ipsp, replay)) {
+ irs->ipsp->ips_errs.ips_replaywin_errs += 1;
+ KLIPS_PRINT(debug_rcv & DB_RX_REPLAY,
+ "klips_debug:ipsec_rcv: "
+ "duplicate frame from %s, packet dropped\n",
+ irs->ipsaddr_txt);
+ if(irs->stats) {
+ irs->stats->rx_dropped++;
+ }
+ return IPSEC_RCV_REPLAYFAILED;
+ }
+
+ /*
+ * verify authenticator
+ */
+
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "encalg = %d, authalg = %d.\n",
+ irs->ipsp->ips_encalg,
+ irs->ipsp->ips_authalg);
+
+ /* calculate authenticator */
+ if(proto_funcs->calc_auth == NULL) {
+ return IPSEC_RCV_BADAUTH;
+ }
+ (*proto_funcs->calc_auth)(irs, skb);
+
+ if (memcmp(irs->hash, authenticator, irs->authlen)) {
+ irs->ipsp->ips_errs.ips_auth_errs += 1;
+ KLIPS_PRINT(debug_rcv & DB_RX_INAU,
+ "klips_debug:ipsec_rcv: "
+ "auth failed on incoming packet from %s: hash=%08x%08x%08x auth=%08x%08x%08x, dropped\n",
+ irs->ipsaddr_txt,
+ ntohl(*(__u32*)&irs->hash[0]),
+ ntohl(*(__u32*)&irs->hash[4]),
+ ntohl(*(__u32*)&irs->hash[8]),
+ ntohl(*(__u32*)authenticator),
+ ntohl(*((__u32*)authenticator + 1)),
+ ntohl(*((__u32*)authenticator + 2)));
+ if(irs->stats) {
+ irs->stats->rx_dropped++;
+ }
+ return IPSEC_RCV_AUTHFAILED;
+ } else {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "authentication successful.\n");
+ }
+
+ /* Crypto hygiene: clear memory used to calculate autheticator.
+ * The length varies with the algorithm.
+ */
+ memset(irs->hash, 0, irs->authlen);
+
+ /* If the sequence number == 0, expire SA, it had rolled */
+ if(irs->ipsp->ips_replaywin && !replay /* !irs->ipsp->ips_replaywin_lastseq */) {
+ ipsec_sa_delchain(irs->ipsp);
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "replay window counter rolled, expiring SA.\n");
+ if(irs->stats) {
+ irs->stats->rx_dropped++;
+ }
+ return IPSEC_RCV_REPLAYROLLED;
+ }
+
+ /* now update the replay counter */
+ if (!ipsec_updatereplaywindow(irs->ipsp, replay)) {
+ irs->ipsp->ips_errs.ips_replaywin_errs += 1;
+ KLIPS_PRINT(debug_rcv & DB_RX_REPLAY,
+ "klips_debug:ipsec_rcv: "
+ "duplicate frame from %s, packet dropped\n",
+ irs->ipsaddr_txt);
+ if(irs->stats) {
+ irs->stats->rx_dropped++;
+ }
+ return IPSEC_RCV_REPLAYROLLED;
+ }
+ }
+
+ if(proto_funcs->decrypt) {
+ enum ipsec_rcv_value retval =
+ (*proto_funcs->decrypt)(irs);
+
+ if(retval != IPSEC_RCV_OK) {
+ return retval;
+ }
+ }
+
+ /*
+ * Adjust pointers
+ */
+ skb = irs->skb;
+ irs->len = skb->len;
+ dat = skb->data;
+
+#ifdef NET_21
+/* skb->h.ipiph=(struct iphdr *)skb->data; */
+ skb->nh.raw = skb->data;
+ skb->h.raw = skb->nh.raw + (skb->nh.iph->ihl << 2);
+
+ memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
+#else /* NET_21 */
+ skb->h.iph=(struct iphdr *)skb->data;
+ skb->ip_hdr=(struct iphdr *)skb->data;
+ memset(skb->proto_priv, 0, sizeof(struct options));
+#endif /* NET_21 */
+
+ ipp = (struct iphdr *)dat;
+ ipsaddr.s_addr = ipp->saddr;
+ addrtoa(ipsaddr, 0, irs->ipsaddr_txt, sizeof(irs->ipsaddr_txt));
+ ipdaddr.s_addr = ipp->daddr;
+ addrtoa(ipdaddr, 0, irs->ipdaddr_txt, sizeof(irs->ipdaddr_txt));
+ /*
+ * Discard the original ESP/AH header
+ */
+ ipp->protocol = irs->next_header;
+
+ ipp->check = 0; /* NOTE: this will be included in checksum */
+ ipp->check = ip_fast_csum((unsigned char *)dat, iphlen >> 2);
+
+ KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
+ "klips_debug:ipsec_rcv: "
+ "after <%s%s%s>, SA:%s:\n",
+ IPS_XFORM_NAME(irs->ipsp),
+ irs->sa_len ? irs->sa : " (error)");
+ KLIPS_IP_PRINT(debug_rcv & DB_RX_PKTRX, ipp);
+
+ skb->protocol = htons(ETH_P_IP);
+ skb->ip_summed = 0;
+
+ ipsnext = irs->ipsp->ips_inext;
+ if(sysctl_ipsec_inbound_policy_check) {
+ if(ipsnext) {
+ if(
+ ipp->protocol != IPPROTO_AH
+ && ipp->protocol != IPPROTO_ESP
+#ifdef CONFIG_IPSEC_IPCOMP
+ && ipp->protocol != IPPROTO_COMP
+ && (ipsnext->ips_said.proto != IPPROTO_COMP
+ || ipsnext->ips_inext)
+#endif /* CONFIG_IPSEC_IPCOMP */
+ && ipp->protocol != IPPROTO_IPIP
+ ) {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "packet with incomplete policy dropped, last successful SA:%s.\n",
+ irs->sa_len ? irs->sa : " (error)");
+ if(irs->stats) {
+ irs->stats->rx_dropped++;
+ }
+ return IPSEC_RCV_FAILEDINBOUND;
+ }
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "SA:%s, Another IPSEC header to process.\n",
+ irs->sa_len ? irs->sa : " (error)");
+ } else {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "No ips_inext from this SA:%s.\n",
+ irs->sa_len ? irs->sa : " (error)");
+ }
+ }
+
+#ifdef CONFIG_IPSEC_IPCOMP
+ /* update ipcomp ratio counters, even if no ipcomp packet is present */
+ if (ipsnext
+ && ipsnext->ips_said.proto == IPPROTO_COMP
+ && ipp->protocol != IPPROTO_COMP) {
+ ipsnext->ips_comp_ratio_cbytes += ntohs(ipp->tot_len);
+ ipsnext->ips_comp_ratio_dbytes += ntohs(ipp->tot_len);
+ }
+#endif /* CONFIG_IPSEC_IPCOMP */
+
+ irs->ipsp->ips_life.ipl_bytes.ipl_count += irs->len;
+ irs->ipsp->ips_life.ipl_bytes.ipl_last = irs->len;
+
+ if(!irs->ipsp->ips_life.ipl_usetime.ipl_count) {
+ irs->ipsp->ips_life.ipl_usetime.ipl_count = jiffies / HZ;
+ }
+ irs->ipsp->ips_life.ipl_usetime.ipl_last = jiffies / HZ;
+ irs->ipsp->ips_life.ipl_packets.ipl_count += 1;
+
+#ifdef CONFIG_NETFILTER
+ if(proto == IPPROTO_ESP || proto == IPPROTO_AH) {
+ skb->nfmark = (skb->nfmark & (~(IPsecSAref2NFmark(IPSEC_SA_REF_MASK))))
+ | IPsecSAref2NFmark(IPsecSA2SAref(irs->ipsp));
+ KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
+ "klips_debug:ipsec_rcv: "
+ "%s SA sets skb->nfmark=0x%x.\n",
+ proto == IPPROTO_ESP ? "ESP" : "AH",
+ (unsigned)skb->nfmark);
+ }
+#endif /* CONFIG_NETFILTER */
+
+ return IPSEC_RCV_OK;
+}
+
+
+int
+#ifdef PROTO_HANDLER_SINGLE_PARM
+ipsec_rcv(struct sk_buff *skb)
+#else /* PROTO_HANDLER_SINGLE_PARM */
+#ifdef NET_21
+ipsec_rcv(struct sk_buff *skb, unsigned short xlen)
+#else /* NET_21 */
+ipsec_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
+ __u32 daddr_unused, unsigned short xlen, __u32 saddr,
+ int redo, struct inet_protocol *protocol)
+#endif /* NET_21 */
+#endif /* PROTO_HANDLER_SINGLE_PARM */
+{
+#ifdef NET_21
+#ifdef CONFIG_IPSEC_DEBUG
+ struct device *dev = skb->dev;
+#endif /* CONFIG_IPSEC_DEBUG */
+#endif /* NET_21 */
+ unsigned char protoc;
+ struct iphdr *ipp;
+#if defined(CONFIG_IPSEC_ESP) || defined(CONFIG_IPSEC_AH)
+#endif /* defined(CONFIG_IPSEC_ESP) || defined(CONFIG_IPSEC_AH) */
+
+ struct ipsec_sa *ipsp = NULL;
+ struct net_device_stats *stats = NULL; /* This device's statistics */
+ struct device *ipsecdev = NULL, *prvdev;
+ struct ipsecpriv *prv;
+ char name[9];
+ int i;
+ struct in_addr ipsaddr;
+ struct in_addr ipdaddr;
+
+ struct ipsec_sa* ipsnext = NULL; /* next SA towards inside of packet */
+ struct ipsec_rcv_state irs;
+
+ /* Don't unlink in the middle of a turnaround */
+ MOD_INC_USE_COUNT;
+
+ memset(&irs, 0, sizeof(struct ipsec_rcv_state));
+
+ if (skb == NULL) {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "NULL skb passed in.\n");
+ goto rcvleave;
+ }
+
+ if (skb->data == NULL) {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "NULL skb->data passed in, packet is bogus, dropping.\n");
+ goto rcvleave;
+ }
+
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ if (skb->sk && skb->nh.iph && skb->nh.iph->protocol==IPPROTO_UDP) {
+ /**
+ * Packet comes from udp_queue_rcv_skb so it is already defrag,
+ * checksum verified, ... (ie safe to use)
+ *
+ * If the packet is not for us, return -1 and udp_queue_rcv_skb
+ * will continue to handle it (do not kfree skb !!).
+ */
+ struct udp_opt *tp = &(skb->sk->tp_pinfo.af_udp);
+ struct iphdr *ip = (struct iphdr *)skb->nh.iph;
+ struct udphdr *udp = (struct udphdr *)((__u32 *)ip+ip->ihl);
+ __u8 *udpdata = (__u8 *)udp + sizeof(struct udphdr);
+ __u32 *udpdata32 = (__u32 *)udpdata;
+
+ irs.natt_sport = ntohs(udp->source);
+ irs.natt_dport = ntohs(udp->dest);
+
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "suspected ESPinUDP packet (NAT-Traversal) [%d].\n",
+ tp->esp_in_udp);
+ KLIPS_IP_PRINT(debug_rcv, ip);
+
+ if (udpdata < skb->tail) {
+ unsigned int len = skb->tail - udpdata;
+ if ((len==1) && (udpdata[0]==0xff)) {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ /* not IPv6 compliant message */
+ "NAT-keepalive from %d.%d.%d.%d.\n", NIPQUAD(ip->saddr));
+ goto rcvleave;
+ }
+ else if ( (tp->esp_in_udp == ESPINUDP_WITH_NON_IKE) &&
+ (len > (2*sizeof(__u32) + sizeof(struct esphdr))) &&
+ (udpdata32[0]==0) && (udpdata32[1]==0) ) {
+ /* ESP Packet with Non-IKE header */
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "ESPinUDP pkt with Non-IKE - spi=0x%x\n",
+ udpdata32[2]);
+ irs.natt_type = ESPINUDP_WITH_NON_IKE;
+ irs.natt_len = sizeof(struct udphdr)+(2*sizeof(__u32));
+ }
+ else if ( (tp->esp_in_udp == ESPINUDP_WITH_NON_ESP) &&
+ (len > sizeof(struct esphdr)) &&
+ (udpdata32[0]!=0) ) {
+ /* ESP Packet without Non-ESP header */
+ irs.natt_type = ESPINUDP_WITH_NON_ESP;
+ irs.natt_len = sizeof(struct udphdr);
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "ESPinUDP pkt without Non-ESP - spi=0x%x\n",
+ udpdata32[0]);
+ }
+ else {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "IKE packet - not handled here\n");
+ MOD_DEC_USE_COUNT;
+ return -1;
+ }
+ }
+ else {
+ MOD_DEC_USE_COUNT;
+ return -1;
+ }
+ }
+#endif
+
+#ifdef IPH_is_SKB_PULLED
+ /* In Linux 2.4.4, the IP header has been skb_pull()ed before the
+ packet is passed to us. So we'll skb_push() to get back to it. */
+ if (skb->data == skb->h.raw) {
+ skb_push(skb, skb->h.raw - skb->nh.raw);
+ }
+#endif /* IPH_is_SKB_PULLED */
+
+ /* dev->hard_header_len is unreliable and should not be used */
+ irs.hard_header_len = skb->mac.raw ? (skb->data - skb->mac.raw) : 0;
+ if((irs.hard_header_len < 0) || (irs.hard_header_len > skb_headroom(skb)))
+ irs.hard_header_len = 0;
+
+#ifdef NET_21
+ /* if skb was cloned (most likely due to a packet sniffer such as
+ tcpdump being momentarily attached to the interface), make
+ a copy of our own to modify */
+ if(skb_cloned(skb)) {
+ /* include any mac header while copying.. */
+ if(skb_headroom(skb) < irs.hard_header_len) {
+ printk(KERN_WARNING "klips_error:ipsec_rcv: "
+ "tried to skb_push hhlen=%d, %d available. This should never happen, please report.\n",
+ irs.hard_header_len,
+ skb_headroom(skb));
+ goto rcvleave;
+ }
+ skb_push(skb, irs.hard_header_len);
+ if
+#ifdef SKB_COW_NEW
+ (skb_cow(skb, skb_headroom(skb)) != 0)
+#else /* SKB_COW_NEW */
+ ((skb = skb_cow(skb, skb_headroom(skb))) == NULL)
+#endif /* SKB_COW_NEW */
+ {
+ goto rcvleave;
+ }
+ if(skb->len < irs.hard_header_len) {
+ printk(KERN_WARNING "klips_error:ipsec_rcv: "
+ "tried to skb_pull hhlen=%d, %d available. This should never happen, please report.\n",
+ irs.hard_header_len,
+ skb->len);
+ goto rcvleave;
+ }
+ skb_pull(skb, irs.hard_header_len);
+ }
+
+#endif /* NET_21 */
+
+#if IP_FRAGMENT_LINEARIZE
+ /* In Linux 2.4.4, we may have to reassemble fragments. They are
+ not assembled automatically to save TCP from having to copy
+ twice.
+ */
+ if (skb_is_nonlinear(skb)) {
+ if (skb_linearize(skb, GFP_ATOMIC) != 0) {
+ goto rcvleave;
+ }
+ }
+#endif /* IP_FRAGMENT_LINEARIZE */
+
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ if (irs.natt_len) {
+ /**
+ * Now, we are sure packet is ESPinUDP. Remove natt_len bytes from
+ * packet and modify protocol to ESP.
+ */
+ if (((unsigned char *)skb->data > (unsigned char *)skb->nh.iph) &&
+ ((unsigned char *)skb->nh.iph > (unsigned char *)skb->head)) {
+ unsigned int _len = (unsigned char *)skb->data -
+ (unsigned char *)skb->nh.iph;
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: adjusting skb: skb_push(%u)\n",
+ _len);
+ skb_push(skb, _len);
+ }
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "removing %d bytes from ESPinUDP packet\n", irs.natt_len);
+ ipp = (struct iphdr *)skb->data;
+ irs.iphlen = ipp->ihl << 2;
+ ipp->tot_len = htons(ntohs(ipp->tot_len) - irs.natt_len);
+ if (skb->len < irs.iphlen + irs.natt_len) {
+ printk(KERN_WARNING
+ "klips_error:ipsec_rcv: "
+ "ESPinUDP packet is too small (%d < %d+%d). "
+ "This should never happen, please report.\n",
+ (int)(skb->len), irs.iphlen, irs.natt_len);
+ goto rcvleave;
+ }
+ memmove(skb->data + irs.natt_len, skb->data, irs.iphlen);
+ skb_pull(skb, irs.natt_len);
+
+ /* update nh.iph */
+ ipp = skb->nh.iph = (struct iphdr *)skb->data;
+
+ /* modify protocol */
+ ipp->protocol = IPPROTO_ESP;
+
+ skb->sk = NULL;
+
+ KLIPS_IP_PRINT(debug_rcv, skb->nh.iph);
+ }
+#endif
+
+ ipp = skb->nh.iph;
+ ipsaddr.s_addr = ipp->saddr;
+ addrtoa(ipsaddr, 0, irs.ipsaddr_txt, sizeof(irs.ipsaddr_txt));
+ ipdaddr.s_addr = ipp->daddr;
+ addrtoa(ipdaddr, 0, irs.ipdaddr_txt, sizeof(irs.ipdaddr_txt));
+ irs.iphlen = ipp->ihl << 2;
+
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "<<< Info -- ");
+ KLIPS_PRINTMORE(debug_rcv && skb->dev, "skb->dev=%s ",
+ skb->dev->name ? skb->dev->name : "NULL");
+ KLIPS_PRINTMORE(debug_rcv && dev, "dev=%s ",
+ dev->name ? dev->name : "NULL");
+ KLIPS_PRINTMORE(debug_rcv, "\n");
+
+ KLIPS_PRINT(debug_rcv && !(skb->dev && dev && (skb->dev == dev)),
+ "klips_debug:ipsec_rcv: "
+ "Informational -- **if this happens, find out why** skb->dev:%s is not equal to dev:%s\n",
+ skb->dev ? (skb->dev->name ? skb->dev->name : "NULL") : "NULL",
+ dev ? (dev->name ? dev->name : "NULL") : "NULL");
+
+ protoc = ipp->protocol;
+#ifndef NET_21
+ if((!protocol) || (protocol->protocol != protoc)) {
+ KLIPS_PRINT(debug_rcv & DB_RX_IPSA,
+ "klips_debug:ipsec_rcv: "
+ "protocol arg is NULL or unequal to the packet contents, this is odd, using value in packet.\n");
+ }
+#endif /* !NET_21 */
+
+ if( (protoc != IPPROTO_AH) &&
+#ifdef CONFIG_IPSEC_IPCOMP_disabled_until_we_register_IPCOMP_HANDLER
+ (protoc != IPPROTO_COMP) &&
+#endif /* CONFIG_IPSEC_IPCOMP */
+ (protoc != IPPROTO_ESP) ) {
+ KLIPS_PRINT(debug_rcv & DB_RX_IPSA,
+ "klips_debug:ipsec_rcv: Why the hell is someone "
+ "passing me a non-ipsec protocol = %d packet? -- dropped.\n",
+ protoc);
+ goto rcvleave;
+ }
+
+ if(skb->dev) {
+ for(i = 0; i < IPSEC_NUM_IF; i++) {
+ sprintf(name, IPSEC_DEV_FORMAT, i);
+ if(!strcmp(name, skb->dev->name)) {
+ prv = (struct ipsecpriv *)(skb->dev->priv);
+ if(prv) {
+ stats = (struct net_device_stats *) &(prv->mystats);
+ }
+ ipsecdev = skb->dev;
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "Info -- pkt already proc'ed a group of ipsec headers, processing next group of ipsec headers.\n");
+ break;
+ }
+ if((ipsecdev = __ipsec_dev_get(name)) == NULL) {
+ KLIPS_PRINT(debug_rcv,
+ "klips_error:ipsec_rcv: "
+ "device %s does not exist\n",
+ name);
+ }
+ prv = ipsecdev ? (struct ipsecpriv *)(ipsecdev->priv) : NULL;
+ prvdev = prv ? (struct device *)(prv->dev) : NULL;
+
+#if 0
+ KLIPS_PRINT(debug_rcv && prvdev,
+ "klips_debug:ipsec_rcv: "
+ "physical device for device %s is %s\n",
+ name,
+ prvdev->name);
+#endif
+ if(prvdev && skb->dev &&
+ !strcmp(prvdev->name, skb->dev->name)) {
+ stats = prv ? ((struct net_device_stats *) &(prv->mystats)) : NULL;
+ skb->dev = ipsecdev;
+ KLIPS_PRINT(debug_rcv && prvdev,
+ "klips_debug:ipsec_rcv: "
+ "assigning packet ownership to virtual device %s from physical device %s.\n",
+ name, prvdev->name);
+ if(stats) {
+ stats->rx_packets++;
+ }
+ break;
+ }
+ }
+ } else {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "device supplied with skb is NULL\n");
+ }
+
+ if(stats == NULL) {
+ KLIPS_PRINT((debug_rcv),
+ "klips_error:ipsec_rcv: "
+ "packet received from physical I/F (%s) not connected to ipsec I/F. Cannot record stats. May not have SA for decoding. Is IPSEC traffic expected on this I/F? Check routing.\n",
+ skb->dev ? (skb->dev->name ? skb->dev->name : "NULL") : "NULL");
+ }
+
+ KLIPS_IP_PRINT(debug_rcv, ipp);
+
+ /* begin decapsulating loop here */
+
+ /*
+ The spinlock is to prevent any other process from
+ accessing or deleting the ipsec_sa hash table or any of the
+ ipsec_sa s while we are using and updating them.
+
+ This is not optimal, but was relatively straightforward
+ at the time. A better way to do it has been planned for
+ more than a year, to lock the hash table and put reference
+ counts on each ipsec_sa instead. This is not likely to happen
+ in KLIPS1 unless a volunteer contributes it, but will be
+ designed into KLIPS2.
+ */
+ spin_lock(&tdb_lock);
+
+ /* set up for decap loop */
+ irs.stats= stats;
+ irs.ipp = ipp;
+ irs.ipsp = NULL;
+ irs.ilen = 0;
+ irs.authlen=0;
+ irs.authfuncs=NULL;
+ irs.skb = skb;
+
+ do {
+ int decap_stat;
+
+ decap_stat = ipsec_rcv_decap_once(&irs);
+
+ if(decap_stat != IPSEC_RCV_OK) {
+ spin_unlock(&tdb_lock);
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: decap_once failed: %d\n",
+ decap_stat);
+
+ goto rcvleave;
+ }
+ /* end decapsulation loop here */
+ } while( (irs.ipp->protocol == IPPROTO_ESP )
+ || (irs.ipp->protocol == IPPROTO_AH )
+#ifdef CONFIG_IPSEC_IPCOMP
+ || (irs.ipp->protocol == IPPROTO_COMP)
+#endif /* CONFIG_IPSEC_IPCOMP */
+ );
+
+ /* set up for decap loop */
+ ipp =irs.ipp;
+ ipsp =irs.ipsp;
+ ipsnext = ipsp->ips_inext;
+ skb = irs.skb;
+
+ /* if there is an IPCOMP, but we don't have an IPPROTO_COMP,
+ * then we can just skip it
+ */
+#ifdef CONFIG_IPSEC_IPCOMP
+ if(ipsnext && ipsnext->ips_said.proto == IPPROTO_COMP) {
+ ipsp = ipsnext;
+ ipsnext = ipsp->ips_inext;
+ }
+#endif /* CONFIG_IPSEC_IPCOMP */
+
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ if ((irs.natt_type) && (ipp->protocol != IPPROTO_IPIP)) {
+ /**
+ * NAT-Traversal and Transport Mode:
+ * we need to correct TCP/UDP checksum
+ *
+ * If we've got NAT-OA, we can fix checksum without recalculation.
+ */
+ __u32 natt_oa = ipsp->ips_natt_oa ?
+ ((struct sockaddr_in*)(ipsp->ips_natt_oa))->sin_addr.s_addr : 0;
+ __u16 pkt_len = skb->tail - (unsigned char *)ipp;
+ __u16 data_len = pkt_len - (ipp->ihl << 2);
+
+ switch (ipp->protocol) {
+ case IPPROTO_TCP:
+ if (data_len >= sizeof(struct tcphdr)) {
+ struct tcphdr *tcp = (struct tcphdr *)((__u32 *)ipp+ipp->ihl);
+ if (natt_oa) {
+ __u32 buff[2] = { ~natt_oa, ipp->saddr };
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "NAT-T & TRANSPORT: "
+ "fix TCP checksum using NAT-OA\n");
+ tcp->check = csum_fold(
+ csum_partial((unsigned char *)buff, sizeof(buff),
+ tcp->check^0xffff));
+ }
+ else {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "NAT-T & TRANSPORT: recalc TCP checksum\n");
+ if (pkt_len > (ntohs(ipp->tot_len)))
+ data_len -= (pkt_len - ntohs(ipp->tot_len));
+ tcp->check = 0;
+ tcp->check = csum_tcpudp_magic(ipp->saddr, ipp->daddr,
+ data_len, IPPROTO_TCP,
+ csum_partial((unsigned char *)tcp, data_len, 0));
+ }
+ }
+ else {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "NAT-T & TRANSPORT: can't fix TCP checksum\n");
+ }
+ break;
+ case IPPROTO_UDP:
+ if (data_len >= sizeof(struct udphdr)) {
+ struct udphdr *udp = (struct udphdr *)((__u32 *)ipp+ipp->ihl);
+ if (udp->check == 0) {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "NAT-T & TRANSPORT: UDP checksum already 0\n");
+ }
+ else if (natt_oa) {
+ __u32 buff[2] = { ~natt_oa, ipp->saddr };
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "NAT-T & TRANSPORT: "
+ "fix UDP checksum using NAT-OA\n");
+ udp->check = csum_fold(
+ csum_partial((unsigned char *)buff, sizeof(buff),
+ udp->check^0xffff));
+ }
+ else {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "NAT-T & TRANSPORT: zero UDP checksum\n");
+ udp->check = 0;
+ }
+ }
+ else {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "NAT-T & TRANSPORT: can't fix UDP checksum\n");
+ }
+ break;
+ default:
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "NAT-T & TRANSPORT: non TCP/UDP packet -- do nothing\n");
+ break;
+ }
+ }
+#endif
+
+ /*
+ * XXX this needs to be locked from when it was first looked
+ * up in the decapsulation loop. Perhaps it is better to put
+ * the IPIP decap inside the loop.
+ */
+ if(ipsnext) {
+ ipsp = ipsnext;
+ irs.sa_len = satoa(irs.said, 0, irs.sa, SATOA_BUF);
+ if(ipp->protocol != IPPROTO_IPIP) {
+ spin_unlock(&tdb_lock);
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "SA:%s, Hey! How did this get through? Dropped.\n",
+ irs.sa_len ? irs.sa : " (error)");
+ if(stats) {
+ stats->rx_dropped++;
+ }
+ goto rcvleave;
+ }
+ if(sysctl_ipsec_inbound_policy_check) {
+ if((ipsnext = ipsp->ips_inext)) {
+ char sa2[SATOA_BUF];
+ size_t sa_len2;
+ sa_len2 = satoa(ipsnext->ips_said, 0, sa2, SATOA_BUF);
+ spin_unlock(&tdb_lock);
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "unexpected SA:%s after IPIP SA:%s\n",
+ sa_len2 ? sa2 : " (error)",
+ irs.sa_len ? irs.sa : " (error)");
+ if(stats) {
+ stats->rx_dropped++;
+ }
+ goto rcvleave;
+ }
+ if(ipp->saddr != ((struct sockaddr_in*)(ipsp->ips_addr_s))->sin_addr.s_addr) {
+ spin_unlock(&tdb_lock);
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "SA:%s, src=%s of pkt does not agree with expected SA source address policy.\n",
+ irs.sa_len ? irs.sa : " (error)",
+ irs.ipsaddr_txt);
+ if(stats) {
+ stats->rx_dropped++;
+ }
+ goto rcvleave;
+ }
+ }
+
+ /*
+ * XXX this needs to be locked from when it was first looked
+ * up in the decapsulation loop. Perhaps it is better to put
+ * the IPIP decap inside the loop.
+ */
+ ipsp->ips_life.ipl_bytes.ipl_count += skb->len;
+ ipsp->ips_life.ipl_bytes.ipl_last = skb->len;
+
+ if(!ipsp->ips_life.ipl_usetime.ipl_count) {
+ ipsp->ips_life.ipl_usetime.ipl_count = jiffies / HZ;
+ }
+ ipsp->ips_life.ipl_usetime.ipl_last = jiffies / HZ;
+ ipsp->ips_life.ipl_packets.ipl_count += 1;
+
+ if(skb->len < irs.iphlen) {
+ spin_unlock(&tdb_lock);
+ printk(KERN_WARNING "klips_debug:ipsec_rcv: "
+ "tried to skb_pull iphlen=%d, %d available. This should never happen, please report.\n",
+ irs.iphlen,
+ (int)(skb->len));
+
+ goto rcvleave;
+ }
+ skb_pull(skb, irs.iphlen);
+
+#ifdef NET_21
+ skb->nh.raw = skb->data;
+ ipp = (struct iphdr *)skb->nh.raw;
+ skb->h.raw = skb->nh.raw + (skb->nh.iph->ihl << 2);
+
+ memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
+#else /* NET_21 */
+ ipp = skb->ip_hdr = skb->h.iph = (struct iphdr *)skb->data;
+
+ memset(skb->proto_priv, 0, sizeof(struct options));
+#endif /* NET_21 */
+ ipsaddr.s_addr = ipp->saddr;
+ addrtoa(ipsaddr, 0, irs.ipsaddr_txt, sizeof(irs.ipsaddr_txt));
+ ipdaddr.s_addr = ipp->daddr;
+ addrtoa(ipdaddr, 0, irs.ipdaddr_txt, sizeof(irs.ipdaddr_txt));
+
+ skb->protocol = htons(ETH_P_IP);
+ skb->ip_summed = 0;
+ KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
+ "klips_debug:ipsec_rcv: "
+ "IPIP tunnel stripped.\n");
+ KLIPS_IP_PRINT(debug_rcv & DB_RX_PKTRX, ipp);
+
+ if(sysctl_ipsec_inbound_policy_check
+ /*
+ Note: "xor" (^) logically replaces "not equal"
+ (!=) and "bitwise or" (|) logically replaces
+ "boolean or" (||). This is done to speed up
+ execution by doing only bitwise operations and
+ no branch operations
+ */
+ && (((ipp->saddr & ipsp->ips_mask_s.u.v4.sin_addr.s_addr)
+ ^ ipsp->ips_flow_s.u.v4.sin_addr.s_addr)
+ | ((ipp->daddr & ipsp->ips_mask_d.u.v4.sin_addr.s_addr)
+ ^ ipsp->ips_flow_d.u.v4.sin_addr.s_addr)) )
+ {
+ char sflow_txt[SUBNETTOA_BUF], dflow_txt[SUBNETTOA_BUF];
+
+ subnettoa(ipsp->ips_flow_s.u.v4.sin_addr,
+ ipsp->ips_mask_s.u.v4.sin_addr,
+ 0, sflow_txt, sizeof(sflow_txt));
+ subnettoa(ipsp->ips_flow_d.u.v4.sin_addr,
+ ipsp->ips_mask_d.u.v4.sin_addr,
+ 0, dflow_txt, sizeof(dflow_txt));
+ spin_unlock(&tdb_lock);
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "SA:%s, inner tunnel policy [%s -> %s] does not agree with pkt contents [%s -> %s].\n",
+ irs.sa_len ? irs.sa : " (error)",
+ sflow_txt,
+ dflow_txt,
+ irs.ipsaddr_txt,
+ irs.ipdaddr_txt);
+ if(stats) {
+ stats->rx_dropped++;
+ }
+ goto rcvleave;
+ }
+#ifdef CONFIG_NETFILTER
+ skb->nfmark = (skb->nfmark & (~(IPsecSAref2NFmark(IPSEC_SA_REF_TABLE_MASK))))
+ | IPsecSAref2NFmark(IPsecSA2SAref(ipsp));
+ KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
+ "klips_debug:ipsec_rcv: "
+ "IPIP SA sets skb->nfmark=0x%x.\n",
+ (unsigned)skb->nfmark);
+#endif /* CONFIG_NETFILTER */
+ }
+
+ spin_unlock(&tdb_lock);
+
+#ifdef NET_21
+ if(stats) {
+ stats->rx_bytes += skb->len;
+ }
+ if(skb->dst) {
+ dst_release(skb->dst);
+ skb->dst = NULL;
+ }
+ skb->pkt_type = PACKET_HOST;
+ if(irs.hard_header_len &&
+ (skb->mac.raw != (skb->data - irs.hard_header_len)) &&
+ (irs.hard_header_len <= skb_headroom(skb))) {
+ /* copy back original MAC header */
+ memmove(skb->data - irs.hard_header_len, skb->mac.raw, irs.hard_header_len);
+ skb->mac.raw = skb->data - irs.hard_header_len;
+ }
+#endif /* NET_21 */
+
+#ifdef CONFIG_IPSEC_IPCOMP
+ if(ipp->protocol == IPPROTO_COMP) {
+ unsigned int flags = 0;
+
+ if(sysctl_ipsec_inbound_policy_check) {
+ KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
+ "klips_debug:ipsec_rcv: "
+ "inbound policy checking enabled, IPCOMP follows IPIP, dropped.\n");
+ if (stats) {
+ stats->rx_errors++;
+ }
+ goto rcvleave;
+ }
+ /*
+ XXX need a ipsec_sa for updating ratio counters but it is not
+ following policy anyways so it is not a priority
+ */
+ skb = skb_decompress(skb, NULL, &flags);
+ if (!skb || flags) {
+ KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
+ "klips_debug:ipsec_rcv: "
+ "skb_decompress() returned error flags: %d, dropped.\n",
+ flags);
+ if (stats) {
+ stats->rx_errors++;
+ }
+ goto rcvleave;
+ }
+ }
+#endif /* CONFIG_IPSEC_IPCOMP */
+
+#ifdef SKB_RESET_NFCT
+ nf_conntrack_put(skb->nfct);
+ skb->nfct = NULL;
+#ifdef CONFIG_NETFILTER_DEBUG
+ skb->nf_debug = 0;
+#endif /* CONFIG_NETFILTER_DEBUG */
+#endif /* SKB_RESET_NFCT */
+ KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
+ "klips_debug:ipsec_rcv: "
+ "netif_rx() called.\n");
+ netif_rx(skb);
+
+ MOD_DEC_USE_COUNT;
+ return(0);
+
+ rcvleave:
+ if(skb) {
+ ipsec_kfree_skb(skb);
+ }
+
+ MOD_DEC_USE_COUNT;
+ return(0);
+}
+
+struct inet_protocol ah_protocol =
+{
+ ipsec_rcv, /* AH handler */
+ NULL, /* TUNNEL error control */
+#ifdef NETDEV_25
+ 1, /* no policy */
+#else
+ 0, /* next */
+ IPPROTO_AH, /* protocol ID */
+ 0, /* copy */
+ NULL, /* data */
+ "AH" /* name */
+#endif
+};
+
+struct inet_protocol esp_protocol =
+{
+ ipsec_rcv, /* ESP handler */
+ NULL, /* TUNNEL error control */
+#ifdef NETDEV_25
+ 1, /* no policy */
+#else
+ 0, /* next */
+ IPPROTO_ESP, /* protocol ID */
+ 0, /* copy */
+ NULL, /* data */
+ "ESP" /* name */
+#endif
+};
+
+#if 0
+/* We probably don't want to install a pure IPCOMP protocol handler, but
+ only want to handle IPCOMP if it is encapsulated inside an ESP payload
+ (which is already handled) */
+#ifdef CONFIG_IPSEC_IPCOMP
+struct inet_protocol comp_protocol =
+{
+ ipsec_rcv, /* COMP handler */
+ NULL, /* COMP error control */
+#ifdef NETDEV_25
+ 1, /* no policy */
+#else
+ 0, /* next */
+ IPPROTO_COMP, /* protocol ID */
+ 0, /* copy */
+ NULL, /* data */
+ "COMP" /* name */
+#endif
+};
+#endif /* CONFIG_IPSEC_IPCOMP */
+#endif
diff --git a/linux/net/ipsec/ipsec_sa.c b/linux/net/ipsec/ipsec_sa.c
new file mode 100644
index 000000000..4f73b92f2
--- /dev/null
+++ b/linux/net/ipsec/ipsec_sa.c
@@ -0,0 +1,1031 @@
+/*
+ * Common routines for IPsec SA maintenance routines.
+ *
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 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: ipsec_sa.c,v 1.3 2004/06/13 19:57:50 as Exp $
+ *
+ * This is the file formerly known as "ipsec_xform.h"
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/kernel.h> /* printk() */
+
+#include "freeswan/ipsec_param.h"
+
+#ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+#else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+#endif /* MALLOC_SLAB */
+#include <linux/vmalloc.h> /* vmalloc() */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/interrupt.h> /* mark_bh */
+
+#include <linux/netdevice.h> /* struct device, and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/ip.h> /* struct iphdr */
+#include <linux/skbuff.h>
+#include <freeswan.h>
+#ifdef SPINLOCK
+#ifdef SPINLOCK_23
+#include <linux/spinlock.h> /* *lock* */
+#else /* SPINLOCK_23 */
+#include <asm/spinlock.h> /* *lock* */
+#endif /* SPINLOCK_23 */
+#endif /* SPINLOCK */
+#ifdef NET_21
+#include <asm/uaccess.h>
+#include <linux/in6.h>
+#endif
+#include <asm/checksum.h>
+#include <net/ip.h>
+
+#include "freeswan/radij.h"
+
+#include "freeswan/ipsec_stats.h"
+#include "freeswan/ipsec_life.h"
+#include "freeswan/ipsec_sa.h"
+#include "freeswan/ipsec_xform.h"
+
+#include "freeswan/ipsec_encap.h"
+#include "freeswan/ipsec_radij.h"
+#include "freeswan/ipsec_xform.h"
+#include "freeswan/ipsec_ipe4.h"
+#include "freeswan/ipsec_ah.h"
+#include "freeswan/ipsec_esp.h"
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "freeswan/ipsec_proto.h"
+#include "freeswan/ipsec_alg.h"
+
+
+#ifdef CONFIG_IPSEC_DEBUG
+int debug_xform = 0;
+#endif /* CONFIG_IPSEC_DEBUG */
+
+#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0)
+
+struct ipsec_sa *ipsec_sadb_hash[SADB_HASHMOD];
+#ifdef SPINLOCK
+spinlock_t tdb_lock = SPIN_LOCK_UNLOCKED;
+#else /* SPINLOCK */
+spinlock_t tdb_lock;
+#endif /* SPINLOCK */
+
+struct ipsec_sadb ipsec_sadb;
+
+#if IPSEC_SA_REF_CODE
+
+/* the sub table must be narrower (or equal) in bits than the variable type
+ in the main table to count the number of unused entries in it. */
+typedef struct {
+ int testSizeOf_refSubTable :
+ ((sizeof(IPsecRefTableUnusedCount) * 8) < IPSEC_SA_REF_SUBTABLE_IDX_WIDTH ? -1 : 1);
+} dummy;
+
+
+/* The field where the saref will be hosted in the skb must be wide enough to
+ accomodate the information it needs to store. */
+typedef struct {
+ int testSizeOf_refField :
+ (IPSEC_SA_REF_HOST_FIELD_WIDTH < IPSEC_SA_REF_TABLE_IDX_WIDTH ? -1 : 1 );
+} dummy2;
+
+
+void
+ipsec_SAtest(void)
+{
+ IPsecSAref_t SAref = 258;
+ struct ipsec_sa ips;
+ ips.ips_ref = 772;
+
+ printk("klips_debug:ipsec_SAtest: "
+ "IPSEC_SA_REF_SUBTABLE_IDX_WIDTH=%u\n"
+ "IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES=%u\n"
+ "IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES=%u\n"
+ "IPSEC_SA_REF_HOST_FIELD_WIDTH=%lu\n"
+ "IPSEC_SA_REF_TABLE_MASK=%x\n"
+ "IPSEC_SA_REF_ENTRY_MASK=%x\n"
+ "IPsecSAref2table(%d)=%u\n"
+ "IPsecSAref2entry(%d)=%u\n"
+ "IPsecSAref2NFmark(%d)=%u\n"
+ "IPsecSAref2SA(%d)=%p\n"
+ "IPsecSA2SAref(%p)=%d\n"
+ ,
+ IPSEC_SA_REF_SUBTABLE_IDX_WIDTH,
+ IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES,
+ IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES,
+ (unsigned long) IPSEC_SA_REF_HOST_FIELD_WIDTH,
+ IPSEC_SA_REF_TABLE_MASK,
+ IPSEC_SA_REF_ENTRY_MASK,
+ SAref, IPsecSAref2table(SAref),
+ SAref, IPsecSAref2entry(SAref),
+ SAref, IPsecSAref2NFmark(SAref),
+ SAref, IPsecSAref2SA(SAref),
+ (&ips), IPsecSA2SAref((&ips))
+ );
+ return;
+}
+
+int
+ipsec_SAref_recycle(void)
+{
+ int table;
+ int entry;
+ int error = 0;
+
+ ipsec_sadb.refFreeListHead = -1;
+ ipsec_sadb.refFreeListTail = -1;
+
+ if(ipsec_sadb.refFreeListCont == IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES * IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES) {
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_SAref_recycle: "
+ "end of table reached, continuing at start..\n");
+ ipsec_sadb.refFreeListCont = 0;
+ }
+
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_SAref_recycle: "
+ "recycling, continuing from SAref=%d (0p%p), table=%d, entry=%d.\n",
+ ipsec_sadb.refFreeListCont,
+ (ipsec_sadb.refTable[IPsecSAref2table(ipsec_sadb.refFreeListCont)] != NULL) ? IPsecSAref2SA(ipsec_sadb.refFreeListCont) : NULL,
+ IPsecSAref2table(ipsec_sadb.refFreeListCont),
+ IPsecSAref2entry(ipsec_sadb.refFreeListCont));
+
+ for(table = IPsecSAref2table(ipsec_sadb.refFreeListCont);
+ table < IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES;
+ table++) {
+ if(ipsec_sadb.refTable[table] == NULL) {
+ error = ipsec_SArefSubTable_alloc(table);
+ if(error) {
+ return error;
+ }
+ }
+ for(entry = IPsecSAref2entry(ipsec_sadb.refFreeListCont);
+ entry < IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES;
+ entry++) {
+ if(ipsec_sadb.refTable[table]->entry[entry] == NULL) {
+ ipsec_sadb.refFreeList[++ipsec_sadb.refFreeListTail] = IPsecSArefBuild(table, entry);
+ if(ipsec_sadb.refFreeListTail == (IPSEC_SA_REF_FREELIST_NUM_ENTRIES - 1)) {
+ ipsec_sadb.refFreeListHead = 0;
+ ipsec_sadb.refFreeListCont = ipsec_sadb.refFreeList[ipsec_sadb.refFreeListTail] + 1;
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_SAref_recycle: "
+ "SArefFreeList refilled.\n");
+ return 0;
+ }
+ }
+ }
+ }
+
+ if(ipsec_sadb.refFreeListTail == -1) {
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_SAref_recycle: "
+ "out of room in the SArefTable.\n");
+
+ return(-ENOSPC);
+ }
+
+ ipsec_sadb.refFreeListHead = 0;
+ ipsec_sadb.refFreeListCont = ipsec_sadb.refFreeList[ipsec_sadb.refFreeListTail] + 1;
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_SAref_recycle: "
+ "SArefFreeList partly refilled to %d of %d.\n",
+ ipsec_sadb.refFreeListTail,
+ IPSEC_SA_REF_FREELIST_NUM_ENTRIES);
+ return 0;
+}
+
+int
+ipsec_SArefSubTable_alloc(unsigned table)
+{
+ unsigned entry;
+ struct IPsecSArefSubTable* SArefsub;
+
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_SArefSubTable_alloc: "
+ "allocating %lu bytes for table %u of %u.\n",
+ (unsigned long) (IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES * sizeof(struct ipsec_sa *)),
+ table,
+ IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES);
+
+ /* allocate another sub-table */
+ SArefsub = vmalloc(IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES * sizeof(struct ipsec_sa *));
+ if(SArefsub == NULL) {
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_SArefSubTable_alloc: "
+ "error allocating memory for table %u of %u!\n",
+ table,
+ IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES);
+ return -ENOMEM;
+ }
+
+ /* add this sub-table to the main table */
+ ipsec_sadb.refTable[table] = SArefsub;
+
+ /* initialise each element to NULL */
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_SArefSubTable_alloc: "
+ "initialising %u elements (2 ^ %u) of table %u.\n",
+ IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES,
+ IPSEC_SA_REF_SUBTABLE_IDX_WIDTH,
+ table);
+ for(entry = 0; entry < IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES; entry++) {
+ SArefsub->entry[entry] = NULL;
+ }
+
+ return 0;
+}
+#endif /* IPSEC_SA_REF_CODE */
+
+int
+ipsec_saref_freelist_init(void)
+{
+ int i;
+
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_saref_freelist_init: "
+ "initialising %u elements of FreeList.\n",
+ IPSEC_SA_REF_FREELIST_NUM_ENTRIES);
+
+ for(i = 0; i < IPSEC_SA_REF_FREELIST_NUM_ENTRIES; i++) {
+ ipsec_sadb.refFreeList[i] = IPSEC_SAREF_NULL;
+ }
+ ipsec_sadb.refFreeListHead = -1;
+ ipsec_sadb.refFreeListCont = 0;
+ ipsec_sadb.refFreeListTail = -1;
+
+ return 0;
+}
+
+int
+ipsec_sadb_init(void)
+{
+ int error = 0;
+ unsigned i;
+
+ for(i = 0; i < SADB_HASHMOD; i++) {
+ ipsec_sadb_hash[i] = NULL;
+ }
+ /* parts above are for the old style SADB hash table */
+
+
+#if IPSEC_SA_REF_CODE
+ /* initialise SA reference table */
+
+ /* initialise the main table */
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sadb_init: "
+ "initialising main table of size %u (2 ^ %u).\n",
+ IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES,
+ IPSEC_SA_REF_MAINTABLE_IDX_WIDTH);
+ {
+ unsigned table;
+ for(table = 0; table < IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES; table++) {
+ ipsec_sadb.refTable[table] = NULL;
+ }
+ }
+
+ /* allocate the first sub-table */
+ error = ipsec_SArefSubTable_alloc(0);
+ if(error) {
+ return error;
+ }
+
+ error = ipsec_saref_freelist_init();
+#endif /* IPSEC_SA_REF_CODE */
+ return error;
+}
+
+#if IPSEC_SA_REF_CODE
+IPsecSAref_t
+ipsec_SAref_alloc(int*error) /* pass in error var by pointer */
+{
+ IPsecSAref_t SAref;
+
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_SAref_alloc: "
+ "SAref requested... head=%d, cont=%d, tail=%d, listsize=%d.\n",
+ ipsec_sadb.refFreeListHead,
+ ipsec_sadb.refFreeListCont,
+ ipsec_sadb.refFreeListTail,
+ IPSEC_SA_REF_FREELIST_NUM_ENTRIES);
+
+ if(ipsec_sadb.refFreeListHead == -1) {
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_SAref_alloc: "
+ "FreeList empty, recycling...\n");
+ *error = ipsec_SAref_recycle();
+ if(*error) {
+ return IPSEC_SAREF_NULL;
+ }
+ }
+
+ SAref = ipsec_sadb.refFreeList[ipsec_sadb.refFreeListHead];
+ if(SAref == IPSEC_SAREF_NULL) {
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_SAref_alloc: "
+ "unexpected error, refFreeListHead = %d points to invalid entry.\n",
+ ipsec_sadb.refFreeListHead);
+ *error = -ESPIPE;
+ return IPSEC_SAREF_NULL;
+ }
+
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_SAref_alloc: "
+ "allocating SAref=%d, table=%u, entry=%u of %u.\n",
+ SAref,
+ IPsecSAref2table(SAref),
+ IPsecSAref2entry(SAref),
+ IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES * IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES);
+
+ ipsec_sadb.refFreeList[ipsec_sadb.refFreeListHead] = IPSEC_SAREF_NULL;
+ ipsec_sadb.refFreeListHead++;
+ if(ipsec_sadb.refFreeListHead > ipsec_sadb.refFreeListTail) {
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_SAref_alloc: "
+ "last FreeList entry allocated, resetting list head to empty.\n");
+ ipsec_sadb.refFreeListHead = -1;
+ }
+
+ return SAref;
+}
+#endif /* IPSEC_SA_REF_CODE */
+
+int
+ipsec_sa_print(struct ipsec_sa *ips)
+{
+ char sa[SATOA_BUF];
+ size_t sa_len;
+
+ printk(KERN_INFO "klips_debug: SA:");
+ if(ips == NULL) {
+ printk("NULL\n");
+ return -ENOENT;
+ }
+ printk(" ref=%d", ips->ips_ref);
+ printk(" refcount=%d", atomic_read(&ips->ips_refcount));
+ if(ips->ips_hnext != NULL) {
+ printk(" hnext=0p%p", ips->ips_hnext);
+ }
+ if(ips->ips_inext != NULL) {
+ printk(" inext=0p%p", ips->ips_inext);
+ }
+ if(ips->ips_onext != NULL) {
+ printk(" onext=0p%p", ips->ips_onext);
+ }
+ sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
+ printk(" said=%s", sa_len ? sa : " (error)");
+ if(ips->ips_seq) {
+ printk(" seq=%u", ips->ips_seq);
+ }
+ if(ips->ips_pid) {
+ printk(" pid=%u", ips->ips_pid);
+ }
+ if(ips->ips_authalg) {
+ printk(" authalg=%u", ips->ips_authalg);
+ }
+ if(ips->ips_encalg) {
+ printk(" encalg=%u", ips->ips_encalg);
+ }
+ printk(" XFORM=%s%s%s", IPS_XFORM_NAME(ips));
+ if(ips->ips_replaywin) {
+ printk(" ooowin=%u", ips->ips_replaywin);
+ }
+ if(ips->ips_flags) {
+ printk(" flags=%u", ips->ips_flags);
+ }
+ if(ips->ips_addr_s) {
+ char buf[SUBNETTOA_BUF];
+ addrtoa(((struct sockaddr_in*)(ips->ips_addr_s))->sin_addr,
+ 0, buf, sizeof(buf));
+ printk(" src=%s", buf);
+ }
+ if(ips->ips_addr_d) {
+ char buf[SUBNETTOA_BUF];
+ addrtoa(((struct sockaddr_in*)(ips->ips_addr_s))->sin_addr,
+ 0, buf, sizeof(buf));
+ printk(" dst=%s", buf);
+ }
+ if(ips->ips_addr_p) {
+ char buf[SUBNETTOA_BUF];
+ addrtoa(((struct sockaddr_in*)(ips->ips_addr_p))->sin_addr,
+ 0, buf, sizeof(buf));
+ printk(" proxy=%s", buf);
+ }
+ if(ips->ips_key_bits_a) {
+ printk(" key_bits_a=%u", ips->ips_key_bits_a);
+ }
+ if(ips->ips_key_bits_e) {
+ printk(" key_bits_e=%u", ips->ips_key_bits_e);
+ }
+
+ printk("\n");
+ return 0;
+}
+
+struct ipsec_sa*
+ipsec_sa_alloc(int*error) /* pass in error var by pointer */
+{
+ struct ipsec_sa* ips;
+
+ if((ips = kmalloc(sizeof(*ips), GFP_ATOMIC) ) == NULL) {
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sa_alloc: "
+ "memory allocation error\n");
+ *error = -ENOMEM;
+ return NULL;
+ }
+ memset((caddr_t)ips, 0, sizeof(*ips));
+#if IPSEC_SA_REF_CODE
+ ips->ips_ref = ipsec_SAref_alloc(error); /* pass in error return by pointer */
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sa_alloc: "
+ "allocated %lu bytes for ipsec_sa struct=0p%p ref=%d.\n",
+ (unsigned long) sizeof(*ips),
+ ips,
+ ips->ips_ref);
+ if(ips->ips_ref == IPSEC_SAREF_NULL) {
+ kfree(ips);
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sa_alloc: "
+ "SAref allocation error\n");
+ return NULL;
+ }
+
+ atomic_inc(&ips->ips_refcount);
+ IPsecSAref2SA(ips->ips_ref) = ips;
+#endif /* IPSEC_SA_REF_CODE */
+
+ *error = 0;
+ return(ips);
+}
+
+int
+ipsec_sa_free(struct ipsec_sa* ips)
+{
+ return ipsec_sa_wipe(ips);
+}
+
+struct ipsec_sa *
+ipsec_sa_getbyid(struct sa_id *said)
+{
+ int hashval;
+ struct ipsec_sa *ips;
+ char sa[SATOA_BUF];
+ size_t sa_len;
+
+ if(said == NULL) {
+ KLIPS_PRINT(debug_xform,
+ "klips_error:ipsec_sa_getbyid: "
+ "null pointer passed in!\n");
+ return NULL;
+ }
+
+ sa_len = satoa(*said, 0, sa, SATOA_BUF);
+
+ hashval = (said->spi+said->dst.s_addr+said->proto) % SADB_HASHMOD;
+
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sa_getbyid: "
+ "linked entry in ipsec_sa table for hash=%d of SA:%s requested.\n",
+ hashval,
+ sa_len ? sa : " (error)");
+
+ if((ips = ipsec_sadb_hash[hashval]) == NULL) {
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sa_getbyid: "
+ "no entries in ipsec_sa table for hash=%d of SA:%s.\n",
+ hashval,
+ sa_len ? sa : " (error)");
+ return NULL;
+ }
+
+ for (; ips; ips = ips->ips_hnext) {
+ if ((ips->ips_said.spi == said->spi) &&
+ (ips->ips_said.dst.s_addr == said->dst.s_addr) &&
+ (ips->ips_said.proto == said->proto)) {
+ atomic_inc(&ips->ips_refcount);
+ return ips;
+ }
+ }
+
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sa_getbyid: "
+ "no entry in linked list for hash=%d of SA:%s.\n",
+ hashval,
+ sa_len ? sa : " (error)");
+ return NULL;
+}
+
+int
+ipsec_sa_put(struct ipsec_sa *ips)
+{
+ char sa[SATOA_BUF];
+ size_t sa_len;
+
+ if(ips == NULL) {
+ KLIPS_PRINT(debug_xform,
+ "klips_error:ipsec_sa_put: "
+ "null pointer passed in!\n");
+ return -1;
+ }
+
+ sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
+
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sa_put: "
+ "ipsec_sa SA:%s, ref:%d reference count decremented.\n",
+ sa_len ? sa : " (error)",
+ ips->ips_ref);
+
+ atomic_dec(&ips->ips_refcount);
+
+ return 0;
+}
+
+/*
+ The ipsec_sa table better *NOT* be locked before it is handed in, or SMP locks will happen
+*/
+int
+ipsec_sa_add(struct ipsec_sa *ips)
+{
+ int error = 0;
+ unsigned int hashval;
+
+ if(ips == NULL) {
+ KLIPS_PRINT(debug_xform,
+ "klips_error:ipsec_sa_add: "
+ "null pointer passed in!\n");
+ return -ENODATA;
+ }
+ hashval = ((ips->ips_said.spi + ips->ips_said.dst.s_addr + ips->ips_said.proto) % SADB_HASHMOD);
+
+ atomic_inc(&ips->ips_refcount);
+ spin_lock_bh(&tdb_lock);
+
+ ips->ips_hnext = ipsec_sadb_hash[hashval];
+ ipsec_sadb_hash[hashval] = ips;
+
+ spin_unlock_bh(&tdb_lock);
+
+ return error;
+}
+
+/*
+ The ipsec_sa table better be locked before it is handed in, or races might happen
+*/
+int
+ipsec_sa_del(struct ipsec_sa *ips)
+{
+ unsigned int hashval;
+ struct ipsec_sa *ipstp;
+ char sa[SATOA_BUF];
+ size_t sa_len;
+
+ if(ips == NULL) {
+ KLIPS_PRINT(debug_xform,
+ "klips_error:ipsec_sa_del: "
+ "null pointer passed in!\n");
+ return -ENODATA;
+ }
+
+ sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
+ if(ips->ips_inext || ips->ips_onext) {
+ KLIPS_PRINT(debug_xform,
+ "klips_error:ipsec_sa_del: "
+ "SA:%s still linked!\n",
+ sa_len ? sa : " (error)");
+ return -EMLINK;
+ }
+
+ hashval = ((ips->ips_said.spi + ips->ips_said.dst.s_addr + ips->ips_said.proto) % SADB_HASHMOD);
+
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sa_del: "
+ "deleting SA:%s, hashval=%d.\n",
+ sa_len ? sa : " (error)",
+ hashval);
+ if(ipsec_sadb_hash[hashval] == NULL) {
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sa_del: "
+ "no entries in ipsec_sa table for hash=%d of SA:%s.\n",
+ hashval,
+ sa_len ? sa : " (error)");
+ return -ENOENT;
+ }
+
+ if (ips == ipsec_sadb_hash[hashval]) {
+ ipsec_sadb_hash[hashval] = ipsec_sadb_hash[hashval]->ips_hnext;
+ ips->ips_hnext = NULL;
+ atomic_dec(&ips->ips_refcount);
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sa_del: "
+ "successfully deleted first ipsec_sa in chain.\n");
+ return 0;
+ } else {
+ for (ipstp = ipsec_sadb_hash[hashval];
+ ipstp;
+ ipstp = ipstp->ips_hnext) {
+ if (ipstp->ips_hnext == ips) {
+ ipstp->ips_hnext = ips->ips_hnext;
+ ips->ips_hnext = NULL;
+ atomic_dec(&ips->ips_refcount);
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sa_del: "
+ "successfully deleted link in ipsec_sa chain.\n");
+ return 0;
+ }
+ }
+ }
+
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sa_del: "
+ "no entries in linked list for hash=%d of SA:%s.\n",
+ hashval,
+ sa_len ? sa : " (error)");
+ return -ENOENT;
+}
+
+/*
+ The ipsec_sa table better be locked before it is handed in, or races
+ might happen
+*/
+int
+ipsec_sa_delchain(struct ipsec_sa *ips)
+{
+ struct ipsec_sa *ipsdel;
+ int error = 0;
+ char sa[SATOA_BUF];
+ size_t sa_len;
+
+ if(ips == NULL) {
+ KLIPS_PRINT(debug_xform,
+ "klips_error:ipsec_sa_delchain: "
+ "null pointer passed in!\n");
+ return -ENODATA;
+ }
+
+ sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sa_delchain: "
+ "passed SA:%s\n",
+ sa_len ? sa : " (error)");
+ while(ips->ips_onext != NULL) {
+ ips = ips->ips_onext;
+ }
+
+ while(ips) {
+ /* XXX send a pfkey message up to advise of deleted ipsec_sa */
+ sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sa_delchain: "
+ "unlinking and delting SA:%s",
+ sa_len ? sa : " (error)");
+ ipsdel = ips;
+ ips = ips->ips_inext;
+ if(ips != NULL) {
+ sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
+ KLIPS_PRINT(debug_xform,
+ ", inext=%s",
+ sa_len ? sa : " (error)");
+ atomic_dec(&ipsdel->ips_refcount);
+ ipsdel->ips_inext = NULL;
+ atomic_dec(&ips->ips_refcount);
+ ips->ips_onext = NULL;
+ }
+ KLIPS_PRINT(debug_xform,
+ ".\n");
+ if((error = ipsec_sa_del(ipsdel))) {
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sa_delchain: "
+ "ipsec_sa_del returned error %d.\n", -error);
+ return error;
+ }
+ if((error = ipsec_sa_wipe(ipsdel))) {
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sa_delchain: "
+ "ipsec_sa_wipe returned error %d.\n", -error);
+ return error;
+ }
+ }
+ return error;
+}
+
+int
+ipsec_sadb_cleanup(__u8 proto)
+{
+ unsigned i;
+ int error = 0;
+ struct ipsec_sa *ips, **ipsprev, *ipsdel;
+ char sa[SATOA_BUF];
+ size_t sa_len;
+
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sadb_cleanup: "
+ "cleaning up proto=%d.\n",
+ proto);
+
+ spin_lock_bh(&tdb_lock);
+
+ for (i = 0; i < SADB_HASHMOD; i++) {
+ ipsprev = &(ipsec_sadb_hash[i]);
+ ips = ipsec_sadb_hash[i];
+ if(ips != NULL) {
+ atomic_inc(&ips->ips_refcount);
+ }
+ for(; ips != NULL;) {
+ sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sadb_cleanup: "
+ "checking SA:%s, hash=%d, ref=%d",
+ sa_len ? sa : " (error)",
+ i,
+ ips->ips_ref);
+ ipsdel = ips;
+ ips = ipsdel->ips_hnext;
+ if(ips != NULL) {
+ atomic_inc(&ips->ips_refcount);
+ sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
+ KLIPS_PRINT(debug_xform,
+ ", hnext=%s",
+ sa_len ? sa : " (error)");
+ }
+ if(*ipsprev != NULL) {
+ sa_len = satoa((*ipsprev)->ips_said, 0, sa, SATOA_BUF);
+ KLIPS_PRINT(debug_xform,
+ ", *ipsprev=%s",
+ sa_len ? sa : " (error)");
+ if((*ipsprev)->ips_hnext) {
+ sa_len = satoa((*ipsprev)->ips_hnext->ips_said, 0, sa, SATOA_BUF);
+ KLIPS_PRINT(debug_xform,
+ ", *ipsprev->ips_hnext=%s",
+ sa_len ? sa : " (error)");
+ }
+ }
+ KLIPS_PRINT(debug_xform,
+ ".\n");
+ if(proto == 0 || (proto == ipsdel->ips_said.proto)) {
+ sa_len = satoa(ipsdel->ips_said, 0, sa, SATOA_BUF);
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sadb_cleanup: "
+ "deleting SA chain:%s.\n",
+ sa_len ? sa : " (error)");
+ if((error = ipsec_sa_delchain(ipsdel))) {
+ SENDERR(-error);
+ }
+ ipsprev = &(ipsec_sadb_hash[i]);
+ ips = ipsec_sadb_hash[i];
+
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sadb_cleanup: "
+ "deleted SA chain:%s",
+ sa_len ? sa : " (error)");
+ if(ips != NULL) {
+ sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
+ KLIPS_PRINT(debug_xform,
+ ", ipsec_sadb_hash[%d]=%s",
+ i,
+ sa_len ? sa : " (error)");
+ }
+ if(*ipsprev != NULL) {
+ sa_len = satoa((*ipsprev)->ips_said, 0, sa, SATOA_BUF);
+ KLIPS_PRINT(debug_xform,
+ ", *ipsprev=%s",
+ sa_len ? sa : " (error)");
+ if((*ipsprev)->ips_hnext != NULL) {
+ sa_len = satoa((*ipsprev)->ips_hnext->ips_said, 0, sa, SATOA_BUF);
+ KLIPS_PRINT(debug_xform,
+ ", *ipsprev->ips_hnext=%s",
+ sa_len ? sa : " (error)");
+ }
+ }
+ KLIPS_PRINT(debug_xform,
+ ".\n");
+ } else {
+ ipsprev = &ipsdel;
+ }
+ if(ipsdel != NULL) {
+ ipsec_sa_put(ipsdel);
+ }
+ }
+ }
+ errlab:
+
+ spin_unlock_bh(&tdb_lock);
+
+
+#if IPSEC_SA_REF_CODE
+ /* clean up SA reference table */
+
+ /* go through the ref table and clean out all the SAs */
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sadb_cleanup: "
+ "removing SAref entries and tables.");
+ {
+ unsigned table, entry;
+ for(table = 0; table < IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES; table++) {
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sadb_cleanup: "
+ "cleaning SAref table=%u.\n",
+ table);
+ if(ipsec_sadb.refTable[table] == NULL) {
+ printk("\n");
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sadb_cleanup: "
+ "cleaned %u used refTables.\n",
+ table);
+ break;
+ }
+ for(entry = 0; entry < IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES; entry++) {
+ if(ipsec_sadb.refTable[table]->entry[entry] != NULL) {
+ ipsec_sa_delchain(ipsec_sadb.refTable[table]->entry[entry]);
+ ipsec_sadb.refTable[table]->entry[entry] = NULL;
+ }
+ }
+ }
+ }
+#endif /* IPSEC_SA_REF_CODE */
+
+ return(error);
+}
+
+int
+ipsec_sadb_free(void)
+{
+ int error = 0;
+
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sadb_free: "
+ "freeing SArefTable memory.\n");
+
+ /* clean up SA reference table */
+
+ /* go through the ref table and clean out all the SAs if any are
+ left and free table memory */
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sadb_free: "
+ "removing SAref entries and tables.\n");
+ {
+ unsigned table, entry;
+ for(table = 0; table < IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES; table++) {
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sadb_free: "
+ "removing SAref table=%u.\n",
+ table);
+ if(ipsec_sadb.refTable[table] == NULL) {
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sadb_free: "
+ "removed %u used refTables.\n",
+ table);
+ break;
+ }
+ for(entry = 0; entry < IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES; entry++) {
+ if(ipsec_sadb.refTable[table]->entry[entry] != NULL) {
+ ipsec_sa_delchain(ipsec_sadb.refTable[table]->entry[entry]);
+ ipsec_sadb.refTable[table]->entry[entry] = NULL;
+ }
+ }
+ vfree(ipsec_sadb.refTable[table]);
+ ipsec_sadb.refTable[table] = NULL;
+ }
+ }
+
+ return(error);
+}
+
+int
+ipsec_sa_wipe(struct ipsec_sa *ips)
+{
+ if(ips == NULL) {
+ return -ENODATA;
+ }
+
+ /* if(atomic_dec_and_test(ips)) {
+ }; */
+
+#if IPSEC_SA_REF_CODE
+ /* remove me from the SArefTable */
+ {
+ char sa[SATOA_BUF];
+ size_t sa_len;
+ sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sa_wipe: "
+ "removing SA=%s(0p%p), SAref=%d, table=%d(0p%p), entry=%d from the refTable.\n",
+ sa_len ? sa : " (error)",
+ ips,
+ ips->ips_ref,
+ IPsecSAref2table(IPsecSA2SAref(ips)),
+ ipsec_sadb.refTable[IPsecSAref2table(IPsecSA2SAref(ips))],
+ IPsecSAref2entry(IPsecSA2SAref(ips)));
+ }
+ if(ips->ips_ref == IPSEC_SAREF_NULL) {
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sa_wipe: "
+ "why does this SA not have a valid SAref?.\n");
+ }
+ ipsec_sadb.refTable[IPsecSAref2table(IPsecSA2SAref(ips))]->entry[IPsecSAref2entry(IPsecSA2SAref(ips))] = NULL;
+ ips->ips_ref = IPSEC_SAREF_NULL;
+ ipsec_sa_put(ips);
+#endif /* IPSEC_SA_REF_CODE */
+
+ /* paranoid clean up */
+ if(ips->ips_addr_s != NULL) {
+ memset((caddr_t)(ips->ips_addr_s), 0, ips->ips_addr_s_size);
+ kfree(ips->ips_addr_s);
+ }
+ ips->ips_addr_s = NULL;
+
+ if(ips->ips_addr_d != NULL) {
+ memset((caddr_t)(ips->ips_addr_d), 0, ips->ips_addr_d_size);
+ kfree(ips->ips_addr_d);
+ }
+ ips->ips_addr_d = NULL;
+
+ if(ips->ips_addr_p != NULL) {
+ memset((caddr_t)(ips->ips_addr_p), 0, ips->ips_addr_p_size);
+ kfree(ips->ips_addr_p);
+ }
+ ips->ips_addr_p = NULL;
+
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ if(ips->ips_natt_oa) {
+ memset((caddr_t)(ips->ips_natt_oa), 0, ips->ips_natt_oa_size);
+ kfree(ips->ips_natt_oa);
+ }
+ ips->ips_natt_oa = NULL;
+#endif
+
+ if(ips->ips_key_a != NULL) {
+ memset((caddr_t)(ips->ips_key_a), 0, ips->ips_key_a_size);
+ kfree(ips->ips_key_a);
+ }
+ ips->ips_key_a = NULL;
+
+ if(ips->ips_key_e != NULL) {
+#ifdef CONFIG_IPSEC_ALG
+ if (ips->ips_alg_enc&&ips->ips_alg_enc->ixt_e_destroy_key) {
+ ips->ips_alg_enc->ixt_e_destroy_key(ips->ips_alg_enc,
+ ips->ips_key_e);
+ } else {
+#endif /* CONFIG_IPSEC_ALG */
+ memset((caddr_t)(ips->ips_key_e), 0, ips->ips_key_e_size);
+ kfree(ips->ips_key_e);
+#ifdef CONFIG_IPSEC_ALG
+ }
+#endif /* CONFIG_IPSEC_ALG */
+ }
+ ips->ips_key_e = NULL;
+
+ if(ips->ips_iv != NULL) {
+ memset((caddr_t)(ips->ips_iv), 0, ips->ips_iv_size);
+ kfree(ips->ips_iv);
+ }
+ ips->ips_iv = NULL;
+
+ if(ips->ips_ident_s.data != NULL) {
+ memset((caddr_t)(ips->ips_ident_s.data),
+ 0,
+ ips->ips_ident_s.len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident));
+ kfree(ips->ips_ident_s.data);
+ }
+ ips->ips_ident_s.data = NULL;
+
+ if(ips->ips_ident_d.data != NULL) {
+ memset((caddr_t)(ips->ips_ident_d.data),
+ 0,
+ ips->ips_ident_d.len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident));
+ kfree(ips->ips_ident_d.data);
+ }
+ ips->ips_ident_d.data = NULL;
+
+#ifdef CONFIG_IPSEC_ALG
+ if (ips->ips_alg_enc||ips->ips_alg_auth) {
+ ipsec_alg_sa_wipe(ips);
+ }
+#endif /* CONFIG_IPSEC_ALG */
+
+ memset((caddr_t)ips, 0, sizeof(*ips));
+ kfree(ips);
+ ips = NULL;
+
+ return 0;
+}
diff --git a/linux/net/ipsec/ipsec_sha1.c b/linux/net/ipsec/ipsec_sha1.c
new file mode 100644
index 000000000..389a55b06
--- /dev/null
+++ b/linux/net/ipsec/ipsec_sha1.c
@@ -0,0 +1,219 @@
+/*
+ * RCSID $Id: ipsec_sha1.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+
+/*
+ * The rest of the code is derived from sha1.c by Steve Reid, which is
+ * public domain.
+ * Minor cosmetic changes to accomodate it in the Linux kernel by ji.
+ */
+
+#include <asm/byteorder.h>
+#include <linux/string.h>
+
+#include "freeswan/ipsec_sha1.h"
+
+#if defined(rol)
+#undef rol
+#endif
+
+#define SHA1HANDSOFF
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/* blk0() and blk() perform the initial expand. */
+/* I got the idea of expanding during the round function from SSLeay */
+#ifdef __LITTLE_ENDIAN
+#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
+ |(rol(block->l[i],8)&0x00FF00FF))
+#else
+#define blk0(i) block->l[i]
+#endif
+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+ ^block->l[(i+2)&15]^block->l[i&15],1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+
+void SHA1Transform(__u32 state[5], __u8 buffer[64])
+{
+__u32 a, b, c, d, e;
+typedef union {
+ unsigned char c[64];
+ __u32 l[16];
+} CHAR64LONG16;
+CHAR64LONG16* block;
+#ifdef SHA1HANDSOFF
+static unsigned char workspace[64];
+ block = (CHAR64LONG16*)workspace;
+ memcpy(block, buffer, 64);
+#else
+ block = (CHAR64LONG16*)buffer;
+#endif
+ /* Copy context->state[] to working vars */
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+ /* 4 rounds of 20 operations each. Loop unrolled. */
+ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+ R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+ R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+ R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+ R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+ R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+ R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+ R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+ R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+ R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+ R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+ R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+ R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+ R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+ R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+ R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+ R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+ R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+ R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+ R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+ /* Add the working vars back into context.state[] */
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+ /* Wipe variables */
+ a = b = c = d = e = 0;
+}
+
+
+/* SHA1Init - Initialize new context */
+
+void SHA1Init(void *vcontext)
+{
+ SHA1_CTX* context = vcontext;
+
+ /* SHA1 initialization constants */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xEFCDAB89;
+ context->state[2] = 0x98BADCFE;
+ context->state[3] = 0x10325476;
+ context->state[4] = 0xC3D2E1F0;
+ context->count[0] = context->count[1] = 0;
+}
+
+
+/* Run your data through this. */
+
+void SHA1Update(void *vcontext, unsigned char* data, __u32 len)
+{
+ SHA1_CTX* context = vcontext;
+ __u32 i, j;
+
+ j = context->count[0];
+ if ((context->count[0] += len << 3) < j)
+ context->count[1]++;
+ context->count[1] += (len>>29);
+ j = (j >> 3) & 63;
+ if ((j + len) > 63) {
+ memcpy(&context->buffer[j], data, (i = 64-j));
+ SHA1Transform(context->state, context->buffer);
+ for ( ; i + 63 < len; i += 64) {
+ SHA1Transform(context->state, &data[i]);
+ }
+ j = 0;
+ }
+ else i = 0;
+ memcpy(&context->buffer[j], &data[i], len - i);
+}
+
+
+/* Add padding and return the message digest. */
+
+void SHA1Final(unsigned char digest[20], void *vcontext)
+{
+ __u32 i, j;
+ unsigned char finalcount[8];
+ SHA1_CTX* context = vcontext;
+
+ for (i = 0; i < 8; i++) {
+ finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
+ >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
+ }
+ SHA1Update(context, (unsigned char *)"\200", 1);
+ while ((context->count[0] & 504) != 448) {
+ SHA1Update(context, (unsigned char *)"\0", 1);
+ }
+ SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
+ for (i = 0; i < 20; i++) {
+ digest[i] = (unsigned char)
+ ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+ }
+ /* Wipe variables */
+ i = j = 0;
+ memset(context->buffer, 0, 64);
+ memset(context->state, 0, 20);
+ memset(context->count, 0, 8);
+ memset(&finalcount, 0, 8);
+#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite its own static vars */
+ SHA1Transform(context->state, context->buffer);
+#endif
+}
+
+
+/*
+ * $Log: ipsec_sha1.c,v $
+ * Revision 1.1 2004/03/15 20:35:26 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.8 2002/09/10 01:45:14 mcr
+ * changed type of MD5_CTX and SHA1_CTX to void * so that
+ * the function prototypes would match, and could be placed
+ * into a pointer to a function.
+ *
+ * Revision 1.7 2002/04/24 07:55:32 mcr
+ * #include patches and Makefiles for post-reorg compilation.
+ *
+ * Revision 1.6 2002/04/24 07:36:30 mcr
+ * Moved from ./klips/net/ipsec/ipsec_sha1.c,v
+ *
+ * Revision 1.5 1999/12/13 13:59:13 rgb
+ * Quick fix to argument size to Update bugs.
+ *
+ * Revision 1.4 1999/04/11 00:29:00 henry
+ * GPL boilerplate
+ *
+ * Revision 1.3 1999/04/06 04:54:27 rgb
+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+ * patch shell fixes.
+ *
+ * Revision 1.2 1999/01/22 06:55:50 rgb
+ * 64-bit clean-up.
+ *
+ * Revision 1.1 1998/06/18 21:27:50 henry
+ * move sources from klips/src to klips/net/ipsec, to keep stupid
+ * kernel-build scripts happier in the presence of symlinks
+ *
+ * Revision 1.2 1998/04/23 20:54:04 rgb
+ * Fixed md5 and sha1 include file nesting issues, to be cleaned up when
+ * verified.
+ *
+ * Revision 1.1 1998/04/09 03:06:11 henry
+ * sources moved up from linux/net/ipsec
+ *
+ * Revision 1.1.1.1 1998/04/08 05:35:05 henry
+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
+ *
+ * Revision 0.4 1997/01/15 01:28:15 ji
+ * New transform
+ *
+ *
+ */
diff --git a/linux/net/ipsec/ipsec_tunnel.c b/linux/net/ipsec/ipsec_tunnel.c
new file mode 100644
index 000000000..de86843bb
--- /dev/null
+++ b/linux/net/ipsec/ipsec_tunnel.c
@@ -0,0 +1,1671 @@
+/*
+ * IPSEC Tunneling code. Heavily based on drivers/net/new_tunnel.c
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Richard Guy Briggs.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+char ipsec_tunnel_c_version[] = "RCSID $Id: ipsec_tunnel.c,v 1.4 2005/06/16 21:21:02 as Exp $";
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/config.h> /* for CONFIG_IP_FORWARD */
+#include <linux/version.h>
+#include <linux/kernel.h> /* printk() */
+
+#include "freeswan/ipsec_param.h"
+
+#ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+#else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+#endif /* MALLOC_SLAB */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/interrupt.h> /* mark_bh */
+
+#include <linux/netdevice.h> /* struct device, struct net_device_stats, dev_queue_xmit() and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/ip.h> /* struct iphdr */
+#include <linux/tcp.h> /* struct tcphdr */
+#include <linux/udp.h> /* struct udphdr */
+#include <linux/skbuff.h>
+#include <freeswan.h>
+#ifdef NET_21
+# include <asm/uaccess.h>
+# include <linux/in6.h>
+# define ip_chk_addr inet_addr_type
+# define IS_MYADDR RTN_LOCAL
+# include <net/dst.h>
+# undef dev_kfree_skb
+# define dev_kfree_skb(a,b) kfree_skb(a)
+# define PHYSDEV_TYPE
+#endif /* NET_21 */
+#include <asm/checksum.h>
+#include <net/icmp.h> /* icmp_send() */
+#include <net/ip.h>
+#ifdef NETDEV_23
+# include <linux/netfilter_ipv4.h>
+#endif /* NETDEV_23 */
+
+#include <linux/if_arp.h>
+
+#include "freeswan/radij.h"
+#include "freeswan/ipsec_life.h"
+#include "freeswan/ipsec_xform.h"
+#include "freeswan/ipsec_eroute.h"
+#include "freeswan/ipsec_encap.h"
+#include "freeswan/ipsec_radij.h"
+#include "freeswan/ipsec_sa.h"
+#include "freeswan/ipsec_tunnel.h"
+#include "freeswan/ipsec_xmit.h"
+#include "freeswan/ipsec_ipe4.h"
+#include "freeswan/ipsec_ah.h"
+#include "freeswan/ipsec_esp.h"
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "freeswan/ipsec_proto.h"
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+#include <linux/udp.h>
+#endif
+
+static __u32 zeroes[64];
+
+#ifdef CONFIG_IPSEC_DEBUG
+int debug_tunnel = 0;
+#endif /* CONFIG_IPSEC_DEBUG */
+
+DEBUG_NO_STATIC int
+ipsec_tunnel_open(struct device *dev)
+{
+ struct ipsecpriv *prv = dev->priv;
+
+ /*
+ * Can't open until attached.
+ */
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_open: "
+ "dev = %s, prv->dev = %s\n",
+ dev->name, prv->dev?prv->dev->name:"NONE");
+
+ if (prv->dev == NULL)
+ return -ENODEV;
+
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+DEBUG_NO_STATIC int
+ipsec_tunnel_close(struct device *dev)
+{
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+#ifdef NETDEV_23
+static inline int ipsec_tunnel_xmit2(struct sk_buff *skb)
+{
+#ifdef NETDEV_25 /* 2.6 kernels */
+ return dst_output(skb);
+#else
+ return ip_send(skb);
+#endif
+}
+#endif /* NETDEV_23 */
+
+enum ipsec_xmit_value
+ipsec_tunnel_strip_hard_header(struct ipsec_xmit_state *ixs)
+{
+ /* ixs->physdev->hard_header_len is unreliable and should not be used */
+ ixs->hard_header_len = (unsigned char *)(ixs->iph) - ixs->skb->data;
+
+ if(ixs->hard_header_len < 0) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_error:ipsec_xmit_strip_hard_header: "
+ "Negative hard_header_len (%d)?!\n", ixs->hard_header_len);
+ ixs->stats->tx_dropped++;
+ return IPSEC_XMIT_BADHHLEN;
+ }
+
+ /* while ixs->physdev->hard_header_len is unreliable and
+ * should not be trusted, it accurate and required for ATM, GRE and
+ * some other interfaces to work. Thanks to Willy Tarreau
+ * <willy@w.ods.org>.
+ */
+ if(ixs->hard_header_len == 0) { /* no hard header present */
+ ixs->hard_header_stripped = 1;
+ ixs->hard_header_len = ixs->physdev->hard_header_len;
+ }
+
+#ifdef CONFIG_IPSEC_DEBUG
+ if (debug_tunnel & DB_TN_XMIT) {
+ int i;
+ char c;
+
+ printk(KERN_INFO "klips_debug:ipsec_xmit_strip_hard_header: "
+ ">>> skb->len=%ld hard_header_len:%d",
+ (unsigned long int)ixs->skb->len, ixs->hard_header_len);
+ c = ' ';
+ for (i=0; i < ixs->hard_header_len; i++) {
+ printk("%c%02x", c, ixs->skb->data[i]);
+ c = ':';
+ }
+ printk(" \n");
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+
+ KLIPS_IP_PRINT(debug_tunnel & DB_TN_XMIT, ixs->iph);
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_debug:ipsec_xmit_strip_hard_header: "
+ "Original head,tailroom: %d,%d\n",
+ skb_headroom(ixs->skb), skb_tailroom(ixs->skb));
+
+ return IPSEC_XMIT_OK;
+}
+
+enum ipsec_xmit_value
+ipsec_tunnel_SAlookup(struct ipsec_xmit_state *ixs)
+{
+ /*
+ * First things first -- look us up in the erouting tables.
+ */
+ ixs->matcher.sen_len = sizeof (struct sockaddr_encap);
+ ixs->matcher.sen_family = AF_ENCAP;
+ ixs->matcher.sen_type = SENT_IP4;
+ ixs->matcher.sen_ip_src.s_addr = ixs->iph->saddr;
+ ixs->matcher.sen_ip_dst.s_addr = ixs->iph->daddr;
+ ixs->matcher.sen_proto = ixs->iph->protocol;
+ ipsec_extract_ports(ixs->iph, &ixs->matcher);
+
+ /*
+ * The spinlock is to prevent any other process from accessing or deleting
+ * the eroute while we are using and updating it.
+ */
+ spin_lock(&eroute_lock);
+
+ ixs->eroute = ipsec_findroute(&ixs->matcher);
+
+ if(ixs->iph->protocol == IPPROTO_UDP) {
+ if(ixs->skb->sk) {
+ ixs->sport=ntohs(ixs->skb->sk->sport);
+ ixs->dport=ntohs(ixs->skb->sk->dport);
+ } else if((ntohs(ixs->iph->frag_off) & IP_OFFSET) == 0 &&
+ ((ixs->skb->len - ixs->hard_header_len) >=
+ ((ixs->iph->ihl << 2) + sizeof(struct udphdr)))) {
+ ixs->sport=ntohs(((struct udphdr*)((caddr_t)ixs->iph+(ixs->iph->ihl<<2)))->source);
+ ixs->dport=ntohs(((struct udphdr*)((caddr_t)ixs->iph + (ixs->iph->ihl<<2)))->dest);
+ } else {
+ ixs->sport=0; ixs->dport=0;
+ }
+ }
+
+ /* default to a %drop eroute */
+ ixs->outgoing_said.proto = IPPROTO_INT;
+ ixs->outgoing_said.spi = htonl(SPI_DROP);
+ ixs->outgoing_said.dst.s_addr = INADDR_ANY;
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_SAlookup: "
+ "checking for local udp/500 IKE packet "
+ "saddr=%x, er=0p%p, daddr=%x, er_dst=%x, proto=%d sport=%d dport=%d\n",
+ ntohl((unsigned int)ixs->iph->saddr),
+ ixs->eroute,
+ ntohl((unsigned int)ixs->iph->daddr),
+ ixs->eroute ? ntohl((unsigned int)ixs->eroute->er_said.dst.s_addr) : 0,
+ ixs->iph->protocol,
+ ixs->sport,
+ ixs->dport);
+
+ /*
+ * Quick cheat for now...are we udp/500 or udp/4500? If so, let it through
+ * without interference since it is most likely an IKE packet.
+ */
+
+ if (ip_chk_addr((unsigned long)ixs->iph->saddr) == IS_MYADDR
+ && (!ixs->eroute
+ || ixs->iph->daddr == ixs->eroute->er_said.dst.s_addr
+ || INADDR_ANY == ixs->eroute->er_said.dst.s_addr)
+ && ((ixs->sport == 500) || (ixs->sport == 4500))) {
+ /* Whatever the eroute, this is an IKE message
+ * from us (i.e. not being forwarded).
+ * Furthermore, if there is a tunnel eroute,
+ * the destination is the peer for this eroute.
+ * So %pass the packet: modify the default %drop.
+ */
+ ixs->outgoing_said.spi = htonl(SPI_PASS);
+ if(!(ixs->skb->sk) && ((ntohs(ixs->iph->frag_off) & IP_MF) != 0)) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_SAlookup: "
+ "local UDP/500 (probably IKE) passthrough: base fragment, rest of fragments will probably get filtered.\n");
+ }
+ } else if (ixs->eroute) {
+ ixs->eroute->er_count++;
+ ixs->eroute->er_lasttime = jiffies/HZ;
+ if(ixs->eroute->er_said.proto==IPPROTO_INT
+ && ixs->eroute->er_said.spi==htonl(SPI_HOLD)) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_SAlookup: "
+ "shunt SA of HOLD: skb stored in HOLD.\n");
+ if(ixs->eroute->er_last != NULL) {
+ kfree_skb(ixs->eroute->er_last);
+ }
+ ixs->eroute->er_last = ixs->skb;
+ ixs->skb = NULL;
+ ixs->stats->tx_dropped++;
+ spin_unlock(&eroute_lock);
+ return IPSEC_XMIT_STOLEN;
+ }
+ ixs->outgoing_said = ixs->eroute->er_said;
+ ixs->eroute_pid = ixs->eroute->er_pid;
+ /* Copy of the ident for the TRAP/TRAPSUBNET eroutes */
+ if(ixs->outgoing_said.proto==IPPROTO_INT
+ && (ixs->outgoing_said.spi==htonl(SPI_TRAP)
+ || (ixs->outgoing_said.spi==htonl(SPI_TRAPSUBNET)))) {
+ int len;
+
+ ixs->ips.ips_ident_s.type = ixs->eroute->er_ident_s.type;
+ ixs->ips.ips_ident_s.id = ixs->eroute->er_ident_s.id;
+ ixs->ips.ips_ident_s.len = ixs->eroute->er_ident_s.len;
+ if (ixs->ips.ips_ident_s.len) {
+ len = ixs->ips.ips_ident_s.len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident);
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_SAlookup: "
+ "allocating %d bytes for ident_s shunt SA of HOLD: skb stored in HOLD.\n",
+ len);
+ if ((ixs->ips.ips_ident_s.data = kmalloc(len, GFP_ATOMIC)) == NULL) {
+ printk(KERN_WARNING "klips_debug:ipsec_xmit_SAlookup: "
+ "Failed, tried to allocate %d bytes for source ident.\n",
+ len);
+ ixs->stats->tx_dropped++;
+ spin_unlock(&eroute_lock);
+ return IPSEC_XMIT_ERRMEMALLOC;
+ }
+ memcpy(ixs->ips.ips_ident_s.data, ixs->eroute->er_ident_s.data, len);
+ }
+ ixs->ips.ips_ident_d.type = ixs->eroute->er_ident_d.type;
+ ixs->ips.ips_ident_d.id = ixs->eroute->er_ident_d.id;
+ ixs->ips.ips_ident_d.len = ixs->eroute->er_ident_d.len;
+ if (ixs->ips.ips_ident_d.len) {
+ len = ixs->ips.ips_ident_d.len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident);
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_SAlookup: "
+ "allocating %d bytes for ident_d shunt SA of HOLD: skb stored in HOLD.\n",
+ len);
+ if ((ixs->ips.ips_ident_d.data = kmalloc(len, GFP_ATOMIC)) == NULL) {
+ printk(KERN_WARNING "klips_debug:ipsec_xmit_SAlookup: "
+ "Failed, tried to allocate %d bytes for dest ident.\n",
+ len);
+ ixs->stats->tx_dropped++;
+ spin_unlock(&eroute_lock);
+ return IPSEC_XMIT_ERRMEMALLOC;
+ }
+ memcpy(ixs->ips.ips_ident_d.data, ixs->eroute->er_ident_d.data, len);
+ }
+ }
+ }
+
+ spin_unlock(&eroute_lock);
+ return IPSEC_XMIT_OK;
+}
+
+enum ipsec_xmit_value
+ipsec_tunnel_restore_hard_header(struct ipsec_xmit_state*ixs)
+{
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_debug:ipsec_xmit_restore_hard_header: "
+ "After recursive xforms -- head,tailroom: %d,%d\n",
+ skb_headroom(ixs->skb),
+ skb_tailroom(ixs->skb));
+
+ if(ixs->saved_header) {
+ if(skb_headroom(ixs->skb) < ixs->hard_header_len) {
+ printk(KERN_WARNING
+ "klips_error:ipsec_xmit_restore_hard_header: "
+ "tried to skb_push hhlen=%d, %d available. This should never happen, please report.\n",
+ ixs->hard_header_len,
+ skb_headroom(ixs->skb));
+ ixs->stats->tx_errors++;
+ return IPSEC_XMIT_PUSHPULLERR;
+
+ }
+ skb_push(ixs->skb, ixs->hard_header_len);
+ {
+ int i;
+ for (i = 0; i < ixs->hard_header_len; i++) {
+ ixs->skb->data[i] = ixs->saved_header[i];
+ }
+ }
+ }
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ if (ixs->natt_type && ixs->natt_head) {
+ struct iphdr *ipp = ixs->skb->nh.iph;
+ struct udphdr *udp;
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_tunnel_start_xmit: "
+ "encapsulating packet into UDP (NAT-Traversal) (%d %d)\n",
+ ixs->natt_type, ixs->natt_head);
+ ixs->iphlen = ipp->ihl << 2;
+ ipp->tot_len =
+ htons(ntohs(ipp->tot_len) + ixs->natt_head);
+ if(skb_tailroom(ixs->skb) < ixs->natt_head) {
+ printk(KERN_WARNING "klips_error:ipsec_tunnel_start_xmit: "
+ "tried to skb_put %d, %d available. "
+ "This should never happen, please report.\n",
+ ixs->natt_head,
+ skb_tailroom(ixs->skb));
+ ixs->stats->tx_errors++;
+ return IPSEC_XMIT_ESPUDP;
+ }
+ skb_put(ixs->skb, ixs->natt_head);
+ udp = (struct udphdr *)((char *)ipp + ixs->iphlen);
+ /* move ESP hdr after UDP hdr */
+ memmove((void *)((char *)udp + ixs->natt_head),
+ (void *)(udp),
+ ntohs(ipp->tot_len) - ixs->iphlen - ixs->natt_head);
+ /* clear UDP & Non-IKE Markers (if any) */
+ memset(udp, 0, ixs->natt_head);
+ /* fill UDP with usefull informations ;-) */
+ udp->source = htons(ixs->natt_sport);
+ udp->dest = htons(ixs->natt_dport);
+ udp->len = htons(ntohs(ipp->tot_len) - ixs->iphlen);
+ /* set protocol */
+ ipp->protocol = IPPROTO_UDP;
+ /* fix IP checksum */
+ ipp->check = 0;
+ ipp->check = ip_fast_csum((unsigned char *)ipp, ipp->ihl);
+ }
+#endif
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_debug:ipsec_xmit_restore_hard_header: "
+ "With hard_header, final head,tailroom: %d,%d\n",
+ skb_headroom(ixs->skb),
+ skb_tailroom(ixs->skb));
+
+ return IPSEC_XMIT_OK;
+}
+
+enum ipsec_xmit_value
+ipsec_tunnel_send(struct ipsec_xmit_state*ixs)
+{
+#ifdef NETDEV_25
+ struct flowi fl;
+#endif
+
+#ifdef NET_21 /* 2.2 and 2.4 kernels */
+ /* new route/dst cache code from James Morris */
+ ixs->skb->dev = ixs->physdev;
+#ifdef NETDEV_25
+ fl.oif = ixs->physdev->iflink;
+ fl.nl_u.ip4_u.daddr = ixs->skb->nh.iph->daddr;
+ fl.nl_u.ip4_u.saddr = ixs->pass ? 0 : ixs->skb->nh.iph->saddr;
+ fl.nl_u.ip4_u.tos = RT_TOS(ixs->skb->nh.iph->tos);
+ fl.proto = ixs->skb->nh.iph->protocol;
+ if ((ixs->error = ip_route_output_key(&ixs->route, &fl))) {
+#else
+ /*skb_orphan(ixs->skb);*/
+ if((ixs->error = ip_route_output(&ixs->route,
+ ixs->skb->nh.iph->daddr,
+ ixs->pass ? 0 : ixs->skb->nh.iph->saddr,
+ RT_TOS(ixs->skb->nh.iph->tos),
+ /* mcr->rgb: should this be 0 instead? */
+ ixs->physdev->iflink))) {
+#endif
+ ixs->stats->tx_errors++;
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_send: "
+ "ip_route_output failed with error code %d, rt->u.dst.dev=%s, dropped\n",
+ ixs->error,
+ ixs->route->u.dst.dev->name);
+ return IPSEC_XMIT_ROUTEERR;
+ }
+ if(ixs->dev == ixs->route->u.dst.dev) {
+ ip_rt_put(ixs->route);
+ /* This is recursion, drop it. */
+ ixs->stats->tx_errors++;
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_send: "
+ "suspect recursion, dev=rt->u.dst.dev=%s, dropped\n",
+ ixs->dev->name);
+ return IPSEC_XMIT_RECURSDETECT;
+ }
+ dst_release(ixs->skb->dst);
+ ixs->skb->dst = &ixs->route->u.dst;
+ ixs->stats->tx_bytes += ixs->skb->len;
+ if(ixs->skb->len < ixs->skb->nh.raw - ixs->skb->data) {
+ ixs->stats->tx_errors++;
+ printk(KERN_WARNING
+ "klips_error:ipsec_xmit_send: "
+ "tried to __skb_pull nh-data=%ld, %d available. This should never happen, please report.\n",
+ (unsigned long)(ixs->skb->nh.raw - ixs->skb->data),
+ ixs->skb->len);
+ return IPSEC_XMIT_PUSHPULLERR;
+ }
+ __skb_pull(ixs->skb, ixs->skb->nh.raw - ixs->skb->data);
+#ifdef SKB_RESET_NFCT
+ if(!ixs->pass) {
+ nf_conntrack_put(ixs->skb->nfct);
+ ixs->skb->nfct = NULL;
+ }
+#ifdef CONFIG_NETFILTER_DEBUG
+ ixs->skb->nf_debug = 0;
+#endif /* CONFIG_NETFILTER_DEBUG */
+#endif /* SKB_RESET_NFCT */
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_send: "
+ "...done, calling ip_send() on device:%s\n",
+ ixs->skb->dev ? ixs->skb->dev->name : "NULL");
+ KLIPS_IP_PRINT(debug_tunnel & DB_TN_XMIT, ixs->skb->nh.iph);
+#ifdef NETDEV_23 /* 2.4 kernels */
+ {
+ int err;
+
+ err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, ixs->skb, NULL, ixs->route->u.dst.dev,
+ ipsec_tunnel_xmit2);
+ if(err != NET_XMIT_SUCCESS && err != NET_XMIT_CN) {
+ if(net_ratelimit())
+ printk(KERN_ERR
+ "klips_error:ipsec_xmit_send: "
+ "ip_send() failed, err=%d\n",
+ -err);
+ ixs->stats->tx_errors++;
+ ixs->stats->tx_aborted_errors++;
+ ixs->skb = NULL;
+ return IPSEC_XMIT_IPSENDFAILURE;
+ }
+ }
+#else /* NETDEV_23 */ /* 2.2 kernels */
+ ip_send(ixs->skb);
+#endif /* NETDEV_23 */
+#else /* NET_21 */ /* 2.0 kernels */
+ ixs->skb->arp = 1;
+ /* ISDN/ASYNC PPP from Matjaz Godec. */
+ /* skb->protocol = htons(ETH_P_IP); */
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_send: "
+ "...done, calling dev_queue_xmit() or ip_fragment().\n");
+ IP_SEND(ixs->skb, ixs->physdev);
+#endif /* NET_21 */
+ ixs->stats->tx_packets++;
+
+ ixs->skb = NULL;
+
+ return IPSEC_XMIT_OK;
+}
+
+void
+ipsec_tunnel_cleanup(struct ipsec_xmit_state*ixs)
+{
+#if defined(HAS_NETIF_QUEUE) || defined (HAVE_NETIF_QUEUE)
+ netif_wake_queue(ixs->dev);
+#else /* defined(HAS_NETIF_QUEUE) || defined (HAVE_NETIF_QUEUE) */
+ ixs->dev->tbusy = 0;
+#endif /* defined(HAS_NETIF_QUEUE) || defined (HAVE_NETIF_QUEUE) */
+ if(ixs->saved_header) {
+ kfree(ixs->saved_header);
+ }
+ if(ixs->skb) {
+ dev_kfree_skb(ixs->skb, FREE_WRITE);
+ }
+ if(ixs->oskb) {
+ dev_kfree_skb(ixs->oskb, FREE_WRITE);
+ }
+ if (ixs->ips.ips_ident_s.data) {
+ kfree(ixs->ips.ips_ident_s.data);
+ }
+ if (ixs->ips.ips_ident_d.data) {
+ kfree(ixs->ips.ips_ident_d.data);
+ }
+}
+
+/*
+ * This function assumes it is being called from dev_queue_xmit()
+ * and that skb is filled properly by that function.
+ */
+int
+ipsec_tunnel_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+ struct ipsec_xmit_state ixs_mem;
+ struct ipsec_xmit_state *ixs = &ixs_mem;
+ enum ipsec_xmit_value stat;
+
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ ixs->natt_type = 0, ixs->natt_head = 0;
+ ixs->natt_sport = 0, ixs->natt_dport = 0;
+#endif
+
+ memset((caddr_t)ixs, 0, sizeof(*ixs));
+ ixs->oskb = NULL;
+ ixs->saved_header = NULL; /* saved copy of the hard header */
+ ixs->route = NULL;
+ memset((caddr_t)&(ixs->ips), 0, sizeof(ixs->ips));
+ ixs->dev = dev;
+ ixs->skb = skb;
+
+ stat = ipsec_xmit_sanity_check_dev(ixs);
+ if(stat != IPSEC_XMIT_OK) {
+ goto cleanup;
+ }
+
+ stat = ipsec_xmit_sanity_check_skb(ixs);
+ if(stat != IPSEC_XMIT_OK) {
+ goto cleanup;
+ }
+
+ stat = ipsec_tunnel_strip_hard_header(ixs);
+ if(stat != IPSEC_XMIT_OK) {
+ goto cleanup;
+ }
+
+ stat = ipsec_tunnel_SAlookup(ixs);
+ if(stat != IPSEC_XMIT_OK) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_tunnel_start_xmit: SAlookup failed: %d\n",
+ stat);
+ goto cleanup;
+ }
+
+ ixs->innersrc = ixs->iph->saddr;
+ /* start encapsulation loop here XXX */
+ do {
+ stat = ipsec_xmit_encap_bundle(ixs);
+ if(stat != IPSEC_XMIT_OK) {
+ if(stat == IPSEC_XMIT_PASS) {
+ goto bypass;
+ }
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_tunnel_start_xmit: encap_bundle failed: %d\n",
+ stat);
+ goto cleanup;
+ }
+
+ ixs->matcher.sen_ip_src.s_addr = ixs->iph->saddr;
+ ixs->matcher.sen_ip_dst.s_addr = ixs->iph->daddr;
+ ixs->matcher.sen_proto = ixs->iph->protocol;
+ ipsec_extract_ports(ixs->iph, &ixs->matcher);
+
+ spin_lock(&eroute_lock);
+ ixs->eroute = ipsec_findroute(&ixs->matcher);
+ if(ixs->eroute) {
+ ixs->outgoing_said = ixs->eroute->er_said;
+ ixs->eroute_pid = ixs->eroute->er_pid;
+ ixs->eroute->er_count++;
+ ixs->eroute->er_lasttime = jiffies/HZ;
+ }
+ spin_unlock(&eroute_lock);
+
+ KLIPS_PRINT((debug_tunnel & DB_TN_XMIT) &&
+ /* ((ixs->orgdst != ixs->newdst) || (ixs->orgsrc != ixs->newsrc)) */
+ (ixs->orgedst != ixs->outgoing_said.dst.s_addr) &&
+ ixs->outgoing_said.dst.s_addr &&
+ ixs->eroute,
+ "klips_debug:ipsec_tunnel_start_xmit: "
+ "We are recursing here.\n");
+
+ } while(/*((ixs->orgdst != ixs->newdst) || (ixs->orgsrc != ixs->newsrc))*/
+ (ixs->orgedst != ixs->outgoing_said.dst.s_addr) &&
+ ixs->outgoing_said.dst.s_addr &&
+ ixs->eroute);
+
+ stat = ipsec_tunnel_restore_hard_header(ixs);
+ if(stat != IPSEC_XMIT_OK) {
+ goto cleanup;
+ }
+
+ bypass:
+ stat = ipsec_tunnel_send(ixs);
+
+ cleanup:
+ ipsec_tunnel_cleanup(ixs);
+
+ return 0;
+}
+
+DEBUG_NO_STATIC struct net_device_stats *
+ipsec_tunnel_get_stats(struct device *dev)
+{
+ return &(((struct ipsecpriv *)(dev->priv))->mystats);
+}
+
+/*
+ * Revectored calls.
+ * For each of these calls, a field exists in our private structure.
+ */
+
+DEBUG_NO_STATIC int
+ipsec_tunnel_hard_header(struct sk_buff *skb, struct device *dev,
+ unsigned short type, void *daddr, void *saddr, unsigned len)
+{
+ struct ipsecpriv *prv = dev->priv;
+ struct device *tmp;
+ int ret;
+ struct net_device_stats *stats; /* This device's statistics */
+
+ if(skb == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_hard_header: "
+ "no skb...\n");
+ return -ENODATA;
+ }
+
+ if(dev == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_hard_header: "
+ "no device...\n");
+ return -ENODEV;
+ }
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_hard_header: "
+ "skb->dev=%s dev=%s.\n",
+ skb->dev ? skb->dev->name : "NULL",
+ dev->name);
+
+ if(prv == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_hard_header: "
+ "no private space associated with dev=%s\n",
+ dev->name ? dev->name : "NULL");
+ return -ENODEV;
+ }
+
+ stats = (struct net_device_stats *) &(prv->mystats);
+
+ if(prv->dev == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_hard_header: "
+ "no physical device associated with dev=%s\n",
+ dev->name ? dev->name : "NULL");
+ stats->tx_dropped++;
+ return -ENODEV;
+ }
+
+ /* check if we have to send a IPv6 packet. It might be a Router
+ Solicitation, where the building of the packet happens in
+ reverse order:
+ 1. ll hdr,
+ 2. IPv6 hdr,
+ 3. ICMPv6 hdr
+ -> skb->nh.raw is still uninitialized when this function is
+ called!! If this is no IPv6 packet, we can print debugging
+ messages, otherwise we skip all debugging messages and just
+ build the ll header */
+ if(type != ETH_P_IPV6) {
+ /* execute this only, if we don't have to build the
+ header for a IPv6 packet */
+ if(!prv->hard_header) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_hard_header: "
+ "physical device has been detached, packet dropped 0p%p->0p%p len=%d type=%d dev=%s->NULL ",
+ saddr,
+ daddr,
+ len,
+ type,
+ dev->name);
+#ifdef NET_21
+ KLIPS_PRINTMORE(debug_tunnel & DB_TN_REVEC,
+ "ip=%08x->%08x\n",
+ (__u32)ntohl(skb->nh.iph->saddr),
+ (__u32)ntohl(skb->nh.iph->daddr) );
+#else /* NET_21 */
+ KLIPS_PRINTMORE(debug_tunnel & DB_TN_REVEC,
+ "ip=%08x->%08x\n",
+ (__u32)ntohl(skb->ip_hdr->saddr),
+ (__u32)ntohl(skb->ip_hdr->daddr) );
+#endif /* NET_21 */
+ stats->tx_dropped++;
+ return -ENODEV;
+ }
+
+#define da ((struct device *)(prv->dev))->dev_addr
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_hard_header: "
+ "Revectored 0p%p->0p%p len=%d type=%d dev=%s->%s dev_addr=%02x:%02x:%02x:%02x:%02x:%02x ",
+ saddr,
+ daddr,
+ len,
+ type,
+ dev->name,
+ prv->dev->name,
+ da[0], da[1], da[2], da[3], da[4], da[5]);
+#ifdef NET_21
+ KLIPS_PRINTMORE(debug_tunnel & DB_TN_REVEC,
+ "ip=%08x->%08x\n",
+ (__u32)ntohl(skb->nh.iph->saddr),
+ (__u32)ntohl(skb->nh.iph->daddr) );
+#else /* NET_21 */
+ KLIPS_PRINTMORE(debug_tunnel & DB_TN_REVEC,
+ "ip=%08x->%08x\n",
+ (__u32)ntohl(skb->ip_hdr->saddr),
+ (__u32)ntohl(skb->ip_hdr->daddr) );
+#endif /* NET_21 */
+ } else {
+ KLIPS_PRINT(debug_tunnel,
+ "klips_debug:ipsec_tunnel_hard_header: "
+ "is IPv6 packet, skip debugging messages, only revector and build linklocal header.\n");
+ }
+ tmp = skb->dev;
+ skb->dev = prv->dev;
+ ret = prv->hard_header(skb, prv->dev, type, (void *)daddr, (void *)saddr, len);
+ skb->dev = tmp;
+ return ret;
+}
+
+DEBUG_NO_STATIC int
+#ifdef NET_21
+ipsec_tunnel_rebuild_header(struct sk_buff *skb)
+#else /* NET_21 */
+ipsec_tunnel_rebuild_header(void *buff, struct device *dev,
+ unsigned long raddr, struct sk_buff *skb)
+#endif /* NET_21 */
+{
+ struct ipsecpriv *prv = skb->dev->priv;
+ struct device *tmp;
+ int ret;
+ struct net_device_stats *stats; /* This device's statistics */
+
+ if(skb->dev == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_rebuild_header: "
+ "no device...");
+ return -ENODEV;
+ }
+
+ if(prv == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_rebuild_header: "
+ "no private space associated with dev=%s",
+ skb->dev->name ? skb->dev->name : "NULL");
+ return -ENODEV;
+ }
+
+ stats = (struct net_device_stats *) &(prv->mystats);
+
+ if(prv->dev == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_rebuild_header: "
+ "no physical device associated with dev=%s",
+ skb->dev->name ? skb->dev->name : "NULL");
+ stats->tx_dropped++;
+ return -ENODEV;
+ }
+
+ if(!prv->rebuild_header) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_rebuild_header: "
+ "physical device has been detached, packet dropped skb->dev=%s->NULL ",
+ skb->dev->name);
+#ifdef NET_21
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "ip=%08x->%08x\n",
+ (__u32)ntohl(skb->nh.iph->saddr),
+ (__u32)ntohl(skb->nh.iph->daddr) );
+#else /* NET_21 */
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "ip=%08x->%08x\n",
+ (__u32)ntohl(skb->ip_hdr->saddr),
+ (__u32)ntohl(skb->ip_hdr->daddr) );
+#endif /* NET_21 */
+ stats->tx_dropped++;
+ return -ENODEV;
+ }
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel: "
+ "Revectored rebuild_header dev=%s->%s ",
+ skb->dev->name, prv->dev->name);
+#ifdef NET_21
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "ip=%08x->%08x\n",
+ (__u32)ntohl(skb->nh.iph->saddr),
+ (__u32)ntohl(skb->nh.iph->daddr) );
+#else /* NET_21 */
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "ip=%08x->%08x\n",
+ (__u32)ntohl(skb->ip_hdr->saddr),
+ (__u32)ntohl(skb->ip_hdr->daddr) );
+#endif /* NET_21 */
+ tmp = skb->dev;
+ skb->dev = prv->dev;
+
+#ifdef NET_21
+ ret = prv->rebuild_header(skb);
+#else /* NET_21 */
+ ret = prv->rebuild_header(buff, prv->dev, raddr, skb);
+#endif /* NET_21 */
+ skb->dev = tmp;
+ return ret;
+}
+
+DEBUG_NO_STATIC int
+ipsec_tunnel_set_mac_address(struct device *dev, void *addr)
+{
+ struct ipsecpriv *prv = dev->priv;
+
+ struct net_device_stats *stats; /* This device's statistics */
+
+ if(dev == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_set_mac_address: "
+ "no device...");
+ return -ENODEV;
+ }
+
+ if(prv == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_set_mac_address: "
+ "no private space associated with dev=%s",
+ dev->name ? dev->name : "NULL");
+ return -ENODEV;
+ }
+
+ stats = (struct net_device_stats *) &(prv->mystats);
+
+ if(prv->dev == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_set_mac_address: "
+ "no physical device associated with dev=%s",
+ dev->name ? dev->name : "NULL");
+ stats->tx_dropped++;
+ return -ENODEV;
+ }
+
+ if(!prv->set_mac_address) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_set_mac_address: "
+ "physical device has been detached, cannot set - skb->dev=%s->NULL\n",
+ dev->name);
+ return -ENODEV;
+ }
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_set_mac_address: "
+ "Revectored dev=%s->%s addr=0p%p\n",
+ dev->name, prv->dev->name, addr);
+ return prv->set_mac_address(prv->dev, addr);
+
+}
+
+#ifndef NET_21
+DEBUG_NO_STATIC void
+ipsec_tunnel_cache_bind(struct hh_cache **hhp, struct device *dev,
+ unsigned short htype, __u32 daddr)
+{
+ struct ipsecpriv *prv = dev->priv;
+
+ struct net_device_stats *stats; /* This device's statistics */
+
+ if(dev == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_cache_bind: "
+ "no device...");
+ return;
+ }
+
+ if(prv == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_cache_bind: "
+ "no private space associated with dev=%s",
+ dev->name ? dev->name : "NULL");
+ return;
+ }
+
+ stats = (struct net_device_stats *) &(prv->mystats);
+
+ if(prv->dev == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_cache_bind: "
+ "no physical device associated with dev=%s",
+ dev->name ? dev->name : "NULL");
+ stats->tx_dropped++;
+ return;
+ }
+
+ if(!prv->header_cache_bind) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_cache_bind: "
+ "physical device has been detached, cannot set - skb->dev=%s->NULL\n",
+ dev->name);
+ stats->tx_dropped++;
+ return;
+ }
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_cache_bind: "
+ "Revectored \n");
+ prv->header_cache_bind(hhp, prv->dev, htype, daddr);
+ return;
+}
+#endif /* !NET_21 */
+
+
+DEBUG_NO_STATIC void
+ipsec_tunnel_cache_update(struct hh_cache *hh, struct device *dev, unsigned char * haddr)
+{
+ struct ipsecpriv *prv = dev->priv;
+
+ struct net_device_stats *stats; /* This device's statistics */
+
+ if(dev == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_cache_update: "
+ "no device...");
+ return;
+ }
+
+ if(prv == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_cache_update: "
+ "no private space associated with dev=%s",
+ dev->name ? dev->name : "NULL");
+ return;
+ }
+
+ stats = (struct net_device_stats *) &(prv->mystats);
+
+ if(prv->dev == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_cache_update: "
+ "no physical device associated with dev=%s",
+ dev->name ? dev->name : "NULL");
+ stats->tx_dropped++;
+ return;
+ }
+
+ if(!prv->header_cache_update) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_cache_update: "
+ "physical device has been detached, cannot set - skb->dev=%s->NULL\n",
+ dev->name);
+ return;
+ }
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel: "
+ "Revectored cache_update\n");
+ prv->header_cache_update(hh, prv->dev, haddr);
+ return;
+}
+
+#ifdef NET_21
+DEBUG_NO_STATIC int
+ipsec_tunnel_neigh_setup(struct neighbour *n)
+{
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_neigh_setup:\n");
+
+ if (n->nud_state == NUD_NONE) {
+ n->ops = &arp_broken_ops;
+ n->output = n->ops->output;
+ }
+ return 0;
+}
+
+DEBUG_NO_STATIC int
+ipsec_tunnel_neigh_setup_dev(struct device *dev, struct neigh_parms *p)
+{
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_neigh_setup_dev: "
+ "setting up %s\n",
+ dev ? dev->name : "NULL");
+
+ if (p->tbl->family == AF_INET) {
+ p->neigh_setup = ipsec_tunnel_neigh_setup;
+ p->ucast_probes = 0;
+ p->mcast_probes = 0;
+ }
+ return 0;
+}
+#endif /* NET_21 */
+
+/*
+ * We call the attach routine to attach another device.
+ */
+
+DEBUG_NO_STATIC int
+ipsec_tunnel_attach(struct device *dev, struct device *physdev)
+{
+ int i;
+ struct ipsecpriv *prv = dev->priv;
+
+ if(dev == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_attach: "
+ "no device...");
+ return -ENODEV;
+ }
+
+ if(prv == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_attach: "
+ "no private space associated with dev=%s",
+ dev->name ? dev->name : "NULL");
+ return -ENODATA;
+ }
+
+ prv->dev = physdev;
+ prv->hard_start_xmit = physdev->hard_start_xmit;
+ prv->get_stats = physdev->get_stats;
+
+ if (physdev->hard_header) {
+ prv->hard_header = physdev->hard_header;
+ dev->hard_header = ipsec_tunnel_hard_header;
+ } else
+ dev->hard_header = NULL;
+
+ if (physdev->rebuild_header) {
+ prv->rebuild_header = physdev->rebuild_header;
+ dev->rebuild_header = ipsec_tunnel_rebuild_header;
+ } else
+ dev->rebuild_header = NULL;
+
+ if (physdev->set_mac_address) {
+ prv->set_mac_address = physdev->set_mac_address;
+ dev->set_mac_address = ipsec_tunnel_set_mac_address;
+ } else
+ dev->set_mac_address = NULL;
+
+#ifndef NET_21
+ if (physdev->header_cache_bind) {
+ prv->header_cache_bind = physdev->header_cache_bind;
+ dev->header_cache_bind = ipsec_tunnel_cache_bind;
+ } else
+ dev->header_cache_bind = NULL;
+#endif /* !NET_21 */
+
+ if (physdev->header_cache_update) {
+ prv->header_cache_update = physdev->header_cache_update;
+ dev->header_cache_update = ipsec_tunnel_cache_update;
+ } else
+ dev->header_cache_update = NULL;
+
+ dev->hard_header_len = physdev->hard_header_len;
+
+#ifdef NET_21
+/* prv->neigh_setup = physdev->neigh_setup; */
+ dev->neigh_setup = ipsec_tunnel_neigh_setup_dev;
+#endif /* NET_21 */
+ dev->mtu = 16260; /* 0xfff0; */ /* dev->mtu; */
+ prv->mtu = physdev->mtu;
+
+#ifdef PHYSDEV_TYPE
+ dev->type = physdev->type; /* ARPHRD_TUNNEL; */
+#endif /* PHYSDEV_TYPE */
+
+ dev->addr_len = physdev->addr_len;
+ for (i=0; i<dev->addr_len; i++) {
+ dev->dev_addr[i] = physdev->dev_addr[i];
+ }
+#ifdef CONFIG_IPSEC_DEBUG
+ if(debug_tunnel & DB_TN_INIT) {
+ printk(KERN_INFO "klips_debug:ipsec_tunnel_attach: "
+ "physical device %s being attached has HW address: %2x",
+ physdev->name, physdev->dev_addr[0]);
+ for (i=1; i < physdev->addr_len; i++) {
+ printk(":%02x", physdev->dev_addr[i]);
+ }
+ printk("\n");
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+
+ return 0;
+}
+
+/*
+ * We call the detach routine to detach the ipsec tunnel from another device.
+ */
+
+DEBUG_NO_STATIC int
+ipsec_tunnel_detach(struct device *dev)
+{
+ int i;
+ struct ipsecpriv *prv = dev->priv;
+
+ if(dev == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_detach: "
+ "no device...");
+ return -ENODEV;
+ }
+
+ if(prv == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_detach: "
+ "no private space associated with dev=%s",
+ dev->name ? dev->name : "NULL");
+ return -ENODATA;
+ }
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_detach: "
+ "physical device %s being detached from virtual device %s\n",
+ prv->dev ? prv->dev->name : "NULL",
+ dev->name);
+
+ ipsec_dev_put(prv->dev);
+ prv->dev = NULL;
+ prv->hard_start_xmit = NULL;
+ prv->get_stats = NULL;
+
+ prv->hard_header = NULL;
+#ifdef DETACH_AND_DOWN
+ dev->hard_header = NULL;
+#endif /* DETACH_AND_DOWN */
+
+ prv->rebuild_header = NULL;
+#ifdef DETACH_AND_DOWN
+ dev->rebuild_header = NULL;
+#endif /* DETACH_AND_DOWN */
+
+ prv->set_mac_address = NULL;
+#ifdef DETACH_AND_DOWN
+ dev->set_mac_address = NULL;
+#endif /* DETACH_AND_DOWN */
+
+#ifndef NET_21
+ prv->header_cache_bind = NULL;
+#ifdef DETACH_AND_DOWN
+ dev->header_cache_bind = NULL;
+#endif /* DETACH_AND_DOWN */
+#endif /* !NET_21 */
+
+ prv->header_cache_update = NULL;
+#ifdef DETACH_AND_DOWN
+ dev->header_cache_update = NULL;
+#endif /* DETACH_AND_DOWN */
+
+#ifdef NET_21
+/* prv->neigh_setup = NULL; */
+#ifdef DETACH_AND_DOWN
+ dev->neigh_setup = NULL;
+#endif /* DETACH_AND_DOWN */
+#endif /* NET_21 */
+ dev->hard_header_len = 0;
+#ifdef DETACH_AND_DOWN
+ dev->mtu = 0;
+#endif /* DETACH_AND_DOWN */
+ prv->mtu = 0;
+ for (i=0; i<MAX_ADDR_LEN; i++) {
+ dev->dev_addr[i] = 0;
+ }
+ dev->addr_len = 0;
+#ifdef PHYSDEV_TYPE
+ dev->type = ARPHRD_VOID; /* ARPHRD_TUNNEL; */
+#endif /* PHYSDEV_TYPE */
+
+ return 0;
+}
+
+/*
+ * We call the clear routine to detach all ipsec tunnels from other devices.
+ */
+DEBUG_NO_STATIC int
+ipsec_tunnel_clear(void)
+{
+ int i;
+ struct device *ipsecdev = NULL, *prvdev;
+ struct ipsecpriv *prv;
+ char name[9];
+ int ret;
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_clear: .\n");
+
+ for(i = 0; i < IPSEC_NUM_IF; i++) {
+ ipsecdev = ipsecdevices[i];
+ if(ipsecdev != NULL) {
+ if((prv = (struct ipsecpriv *)(ipsecdev->priv))) {
+ prvdev = (struct device *)(prv->dev);
+ if(prvdev) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_clear: "
+ "physical device for device %s is %s\n",
+ name, prvdev->name);
+ if((ret = ipsec_tunnel_detach(ipsecdev))) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_clear: "
+ "error %d detatching device %s from device %s.\n",
+ ret, name, prvdev->name);
+ return ret;
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+DEBUG_NO_STATIC int
+ipsec_tunnel_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
+{
+ struct ipsectunnelconf *cf = (struct ipsectunnelconf *)&ifr->ifr_data;
+ struct ipsecpriv *prv = dev->priv;
+ struct device *them; /* physical device */
+#ifdef CONFIG_IP_ALIAS
+ char *colon;
+ char realphysname[IFNAMSIZ];
+#endif /* CONFIG_IP_ALIAS */
+
+ if(dev == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_ioctl: "
+ "device not supplied.\n");
+ return -ENODEV;
+ }
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_ioctl: "
+ "tncfg service call #%d for dev=%s\n",
+ cmd,
+ dev->name ? dev->name : "NULL");
+ switch (cmd) {
+ /* attach a virtual ipsec? device to a physical device */
+ case IPSEC_SET_DEV:
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_ioctl: "
+ "calling ipsec_tunnel_attatch...\n");
+#ifdef CONFIG_IP_ALIAS
+ /* If this is an IP alias interface, get its real physical name */
+ strncpy(realphysname, cf->cf_name, IFNAMSIZ);
+ realphysname[IFNAMSIZ-1] = 0;
+ colon = strchr(realphysname, ':');
+ if (colon) *colon = 0;
+ them = ipsec_dev_get(realphysname);
+#else /* CONFIG_IP_ALIAS */
+ them = ipsec_dev_get(cf->cf_name);
+#endif /* CONFIG_IP_ALIAS */
+
+ if (them == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_ioctl: "
+ "physical device %s requested is null\n",
+ cf->cf_name);
+ return -ENXIO;
+ }
+
+#if 0
+ if (them->flags & IFF_UP) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_ioctl: "
+ "physical device %s requested is not up.\n",
+ cf->cf_name);
+ ipsec_dev_put(them);
+ return -ENXIO;
+ }
+#endif
+
+ if (prv && prv->dev) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_ioctl: "
+ "virtual device is already connected to %s.\n",
+ prv->dev->name ? prv->dev->name : "NULL");
+ ipsec_dev_put(them);
+ return -EBUSY;
+ }
+ return ipsec_tunnel_attach(dev, them);
+
+ case IPSEC_DEL_DEV:
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_ioctl: "
+ "calling ipsec_tunnel_detatch.\n");
+ if (! prv->dev) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_ioctl: "
+ "physical device not connected.\n");
+ return -ENODEV;
+ }
+ return ipsec_tunnel_detach(dev);
+
+ case IPSEC_CLR_DEV:
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_ioctl: "
+ "calling ipsec_tunnel_clear.\n");
+ return ipsec_tunnel_clear();
+
+ default:
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_ioctl: "
+ "unknown command %d.\n",
+ cmd);
+ return -EOPNOTSUPP;
+ }
+}
+
+int
+ipsec_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
+{
+ struct device *dev = ptr;
+ struct device *ipsec_dev;
+ struct ipsecpriv *priv;
+ int i;
+
+ if (dev == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_device_event: "
+ "dev=NULL for event type %ld.\n",
+ event);
+ return(NOTIFY_DONE);
+ }
+
+ /* check for loopback devices */
+ if (dev && (dev->flags & IFF_LOOPBACK)) {
+ return(NOTIFY_DONE);
+ }
+
+ switch (event) {
+ case NETDEV_DOWN:
+ /* look very carefully at the scope of these compiler
+ directives before changing anything... -- RGB */
+#ifdef NET_21
+ case NETDEV_UNREGISTER:
+ switch (event) {
+ case NETDEV_DOWN:
+#endif /* NET_21 */
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_device_event: "
+ "NETDEV_DOWN dev=%s flags=%x\n",
+ dev->name,
+ dev->flags);
+ if(strncmp(dev->name, "ipsec", strlen("ipsec")) == 0) {
+ printk(KERN_CRIT "IPSEC EVENT: KLIPS device %s shut down.\n",
+ dev->name);
+ }
+#ifdef NET_21
+ break;
+ case NETDEV_UNREGISTER:
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_device_event: "
+ "NETDEV_UNREGISTER dev=%s flags=%x\n",
+ dev->name,
+ dev->flags);
+ break;
+ }
+#endif /* NET_21 */
+
+ /* find the attached physical device and detach it. */
+ for(i = 0; i < IPSEC_NUM_IF; i++) {
+ ipsec_dev = ipsecdevices[i];
+
+ if(ipsec_dev) {
+ priv = (struct ipsecpriv *)(ipsec_dev->priv);
+ if(priv) {
+ ;
+ if(((struct device *)(priv->dev)) == dev) {
+ /* dev_close(ipsec_dev); */
+ /* return */ ipsec_tunnel_detach(ipsec_dev);
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_device_event: "
+ "device '%s' has been detached.\n",
+ ipsec_dev->name);
+ break;
+ }
+ } else {
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_device_event: "
+ "device '%s' has no private data space!\n",
+ ipsec_dev->name);
+ }
+ }
+ }
+ break;
+ case NETDEV_UP:
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_device_event: "
+ "NETDEV_UP dev=%s\n",
+ dev->name);
+ break;
+#ifdef NET_21
+ case NETDEV_REBOOT:
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_device_event: "
+ "NETDEV_REBOOT dev=%s\n",
+ dev->name);
+ break;
+ case NETDEV_CHANGE:
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_device_event: "
+ "NETDEV_CHANGE dev=%s flags=%x\n",
+ dev->name,
+ dev->flags);
+ break;
+ case NETDEV_REGISTER:
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_device_event: "
+ "NETDEV_REGISTER dev=%s\n",
+ dev->name);
+ break;
+ case NETDEV_CHANGEMTU:
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_device_event: "
+ "NETDEV_CHANGEMTU dev=%s to mtu=%d\n",
+ dev->name,
+ dev->mtu);
+ break;
+ case NETDEV_CHANGEADDR:
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_device_event: "
+ "NETDEV_CHANGEADDR dev=%s\n",
+ dev->name);
+ break;
+ case NETDEV_GOING_DOWN:
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_device_event: "
+ "NETDEV_GOING_DOWN dev=%s\n",
+ dev->name);
+ break;
+ case NETDEV_CHANGENAME:
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_device_event: "
+ "NETDEV_CHANGENAME dev=%s\n",
+ dev->name);
+ break;
+#endif /* NET_21 */
+ default:
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_device_event: "
+ "event type %ld unrecognised for dev=%s\n",
+ event,
+ dev->name);
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
+/*
+ * Called when an ipsec tunnel device is initialized.
+ * The ipsec tunnel device structure is passed to us.
+ */
+
+int
+ipsec_tunnel_init(struct device *dev)
+{
+ int i;
+
+ KLIPS_PRINT(debug_tunnel,
+ "klips_debug:ipsec_tunnel_init: "
+ "allocating %lu bytes initialising device: %s\n",
+ (unsigned long) sizeof(struct ipsecpriv),
+ dev->name ? dev->name : "NULL");
+
+ /* Add our tunnel functions to the device */
+ dev->open = ipsec_tunnel_open;
+ dev->stop = ipsec_tunnel_close;
+ dev->hard_start_xmit = ipsec_tunnel_start_xmit;
+ dev->get_stats = ipsec_tunnel_get_stats;
+
+ dev->priv = kmalloc(sizeof(struct ipsecpriv), GFP_KERNEL);
+ if (dev->priv == NULL)
+ return -ENOMEM;
+ memset((caddr_t)(dev->priv), 0, sizeof(struct ipsecpriv));
+
+ for(i = 0; i < sizeof(zeroes); i++) {
+ ((__u8*)(zeroes))[i] = 0;
+ }
+
+#ifndef NET_21
+ /* Initialize the tunnel device structure */
+ for (i = 0; i < DEV_NUMBUFFS; i++)
+ skb_queue_head_init(&dev->buffs[i]);
+#endif /* !NET_21 */
+
+ dev->set_multicast_list = NULL;
+ dev->do_ioctl = ipsec_tunnel_ioctl;
+ dev->hard_header = NULL;
+ dev->rebuild_header = NULL;
+ dev->set_mac_address = NULL;
+#ifndef NET_21
+ dev->header_cache_bind = NULL;
+#endif /* !NET_21 */
+ dev->header_cache_update= NULL;
+
+#ifdef NET_21
+/* prv->neigh_setup = NULL; */
+ dev->neigh_setup = ipsec_tunnel_neigh_setup_dev;
+#endif /* NET_21 */
+ dev->hard_header_len = 0;
+ dev->mtu = 0;
+ dev->addr_len = 0;
+ dev->type = ARPHRD_VOID; /* ARPHRD_TUNNEL; */ /* ARPHRD_ETHER; */
+ dev->tx_queue_len = 10; /* Small queue */
+ memset((caddr_t)(dev->broadcast),0xFF, ETH_ALEN); /* what if this is not attached to ethernet? */
+
+ /* New-style flags. */
+ dev->flags = IFF_NOARP /* 0 */ /* Petr Novak */;
+#ifdef NET_21
+ dev_init_buffers(dev);
+#else /* NET_21 */
+ dev->family = AF_INET;
+ dev->pa_addr = 0;
+ dev->pa_brdaddr = 0;
+ dev->pa_mask = 0;
+ dev->pa_alen = 4;
+#endif /* NET_21 */
+
+ /* We're done. Have I forgotten anything? */
+ return 0;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* Module specific interface (but it links with the rest of IPSEC) */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int
+ipsec_tunnel_probe(struct device *dev)
+{
+ ipsec_tunnel_init(dev);
+ return 0;
+}
+
+struct device *ipsecdevices[IPSEC_NUM_IF];
+
+int
+ipsec_tunnel_init_devices(void)
+{
+ int i;
+ char name[IFNAMSIZ];
+ struct device *dev_ipsec;
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_init_devices: "
+ "creating and registering IPSEC_NUM_IF=%u devices, allocating %lu per device, IFNAMSIZ=%u.\n",
+ IPSEC_NUM_IF,
+ (unsigned long) (sizeof(struct device) + IFNAMSIZ),
+ IFNAMSIZ);
+
+ for(i = 0; i < IPSEC_NUM_IF; i++) {
+ sprintf(name, IPSEC_DEV_FORMAT, i);
+ dev_ipsec = (struct device*)kmalloc(sizeof(struct device), GFP_KERNEL);
+ if (dev_ipsec == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_init_devices: "
+ "failed to allocate memory for device %s, quitting device init.\n",
+ name);
+ return -ENOMEM;
+ }
+ memset((caddr_t)dev_ipsec, 0, sizeof(struct device));
+#ifdef NETDEV_23
+ strncpy(dev_ipsec->name, name, sizeof(dev_ipsec->name));
+#else /* NETDEV_23 */
+ dev_ipsec->name = (char*)kmalloc(IFNAMSIZ, GFP_KERNEL);
+ if (dev_ipsec->name == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_init_devices: "
+ "failed to allocate memory for device %s name, quitting device init.\n",
+ name);
+ return -ENOMEM;
+ }
+ memset((caddr_t)dev_ipsec->name, 0, IFNAMSIZ);
+ strncpy(dev_ipsec->name, name, IFNAMSIZ);
+#endif /* NETDEV_23 */
+ dev_ipsec->next = NULL;
+ dev_ipsec->init = &ipsec_tunnel_probe;
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_init_devices: "
+ "registering device %s\n",
+ dev_ipsec->name);
+
+ /* reference and hold the device reference */
+ dev_hold(dev_ipsec);
+ ipsecdevices[i]=dev_ipsec;
+
+ if (register_netdev(dev_ipsec) != 0) {
+ KLIPS_PRINT(1 || debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_init_devices: "
+ "registering device %s failed, quitting device init.\n",
+ dev_ipsec->name);
+ return -EIO;
+ } else {
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_init_devices: "
+ "registering device %s succeeded, continuing...\n",
+ dev_ipsec->name);
+ }
+ }
+ return 0;
+}
+
+/* void */
+int
+ipsec_tunnel_cleanup_devices(void)
+{
+ int error = 0;
+ int i;
+ char name[32];
+ struct device *dev_ipsec;
+
+ for(i = 0; i < IPSEC_NUM_IF; i++) {
+ dev_ipsec = ipsecdevices[i];
+ if(dev_ipsec == NULL) {
+ continue;
+ }
+
+ /* release reference */
+ ipsecdevices[i]=NULL;
+ ipsec_dev_put(dev_ipsec);
+
+ KLIPS_PRINT(debug_tunnel, "Unregistering %s (refcnt=%d)\n",
+ name,
+ atomic_read(&dev_ipsec->refcnt));
+ unregister_netdev(dev_ipsec);
+ KLIPS_PRINT(debug_tunnel, "Unregisted %s\n", name);
+#ifndef NETDEV_23
+ kfree(dev_ipsec->name);
+ dev_ipsec->name=NULL;
+#endif /* !NETDEV_23 */
+ kfree(dev_ipsec->priv);
+ dev_ipsec->priv=NULL;
+ }
+ return error;
+}
diff --git a/linux/net/ipsec/ipsec_xform.c b/linux/net/ipsec/ipsec_xform.c
new file mode 100644
index 000000000..677f83aaf
--- /dev/null
+++ b/linux/net/ipsec/ipsec_xform.c
@@ -0,0 +1,73 @@
+/*
+ * Common routines for IPSEC transformations.
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 1998, 1999, 2000, 2001 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: ipsec_xform.c,v 1.2 2004/06/13 19:57:50 as Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/kernel.h> /* printk() */
+
+#include "freeswan/ipsec_param.h"
+
+#ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+#else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+#endif /* MALLOC_SLAB */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/interrupt.h> /* mark_bh */
+
+#include <linux/netdevice.h> /* struct device, and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/ip.h> /* struct iphdr */
+#include <linux/skbuff.h>
+#include <linux/random.h> /* get_random_bytes() */
+#include <freeswan.h>
+#ifdef SPINLOCK
+# ifdef SPINLOCK_23
+# include <linux/spinlock.h> /* *lock* */
+# else /* SPINLOCK_23 */
+# include <asm/spinlock.h> /* *lock* */
+# endif /* SPINLOCK_23 */
+#endif /* SPINLOCK */
+#ifdef NET_21
+# include <asm/uaccess.h>
+# include <linux/in6.h>
+#endif
+#include <asm/checksum.h>
+#include <net/ip.h>
+
+#include "freeswan/radij.h"
+#include "freeswan/ipsec_encap.h"
+#include "freeswan/ipsec_radij.h"
+#include "freeswan/ipsec_xform.h"
+#include "freeswan/ipsec_ipe4.h"
+#include "freeswan/ipsec_ah.h"
+#include "freeswan/ipsec_esp.h"
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#ifdef CONFIG_IPSEC_DEBUG
+int debug_xform = 0;
+#endif /* CONFIG_IPSEC_DEBUG */
+
+#ifdef SPINLOCK
+spinlock_t tdb_lock = SPIN_LOCK_UNLOCKED;
+#else /* SPINLOCK */
+spinlock_t tdb_lock;
+#endif /* SPINLOCK */
diff --git a/linux/net/ipsec/ipsec_xmit.c b/linux/net/ipsec/ipsec_xmit.c
new file mode 100644
index 000000000..bb390bcf9
--- /dev/null
+++ b/linux/net/ipsec/ipsec_xmit.c
@@ -0,0 +1,1782 @@
+/*
+ * IPSEC Transmit code.
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Richard Guy Briggs.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+char ipsec_xmit_c_version[] = "RCSID $Id: ipsec_xmit.c,v 1.3 2004/06/13 19:37:23 as Exp $";
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/config.h> /* for CONFIG_IP_FORWARD */
+#include <linux/version.h>
+#include <linux/kernel.h> /* printk() */
+
+#include "freeswan/ipsec_param.h"
+
+#ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+#else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+#endif /* MALLOC_SLAB */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/interrupt.h> /* mark_bh */
+
+#include <linux/netdevice.h> /* struct device, struct net_device_stats, dev_queue_xmit() and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/ip.h> /* struct iphdr */
+#include <linux/tcp.h> /* struct tcphdr */
+#include <linux/udp.h> /* struct udphdr */
+#include <linux/skbuff.h>
+#include <freeswan.h>
+#ifdef NET_21
+# define MSS_HACK_ /* experimental */
+# include <asm/uaccess.h>
+# include <linux/in6.h>
+# include <net/dst.h>
+# define proto_priv cb
+#endif /* NET_21 */
+#include <asm/checksum.h>
+#include <net/icmp.h> /* icmp_send() */
+#include <net/ip.h>
+#ifdef NETDEV_23
+# include <linux/netfilter_ipv4.h>
+#endif /* NETDEV_23 */
+
+#include <linux/if_arp.h>
+#ifdef MSS_HACK
+# include <net/tcp.h> /* TCP options */
+#endif /* MSS_HACK */
+
+#include "freeswan/radij.h"
+#include "freeswan/ipsec_life.h"
+#include "freeswan/ipsec_xform.h"
+#include "freeswan/ipsec_eroute.h"
+#include "freeswan/ipsec_encap.h"
+#include "freeswan/ipsec_radij.h"
+#include "freeswan/ipsec_xmit.h"
+#include "freeswan/ipsec_sa.h"
+#include "freeswan/ipsec_tunnel.h"
+#include "freeswan/ipsec_ipe4.h"
+#include "freeswan/ipsec_ah.h"
+#include "freeswan/ipsec_esp.h"
+
+#ifdef CONFIG_IPSEC_IPCOMP
+#include "freeswan/ipcomp.h"
+#endif /* CONFIG_IPSEC_IPCOMP */
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "freeswan/ipsec_proto.h"
+#include "freeswan/ipsec_alg.h"
+
+
+/*
+ * Stupid kernel API differences in APIs. Not only do some
+ * kernels not have ip_select_ident, but some have differing APIs,
+ * and SuSE has one with one parameter, but no way of checking to
+ * see what is really what.
+ */
+
+#ifdef SUSE_LINUX_2_4_19_IS_STUPID
+#define KLIPS_IP_SELECT_IDENT(iph, skb) ip_select_ident(iph)
+#else
+
+/* simplest case, nothing */
+#if !defined(IP_SELECT_IDENT)
+#define KLIPS_IP_SELECT_IDENT(iph, skb) do { iph->id = htons(ip_id_count++); } while(0)
+#endif
+
+/* kernels > 2.3.37-ish */
+#if defined(IP_SELECT_IDENT) && !defined(IP_SELECT_IDENT_NEW)
+#define KLIPS_IP_SELECT_IDENT(iph, skb) ip_select_ident(iph, skb->dst)
+#endif
+
+/* kernels > 2.4.2 */
+#if defined(IP_SELECT_IDENT) && defined(IP_SELECT_IDENT_NEW)
+#define KLIPS_IP_SELECT_IDENT(iph, skb) ip_select_ident(iph, skb->dst, NULL)
+#endif
+
+#endif /* SUSE_LINUX_2_4_19_IS_STUPID */
+
+
+static __u32 zeroes[64];
+
+#ifdef CONFIG_IPSEC_DEBUG
+int sysctl_ipsec_debug_verbose = 0;
+#endif /* CONFIG_IPSEC_DEBUG */
+
+int ipsec_xmit_trap_count = 0;
+int ipsec_xmit_trap_sendcount = 0;
+
+int sysctl_ipsec_icmp = 0;
+int sysctl_ipsec_tos = 0;
+
+/*
+ * If the IP packet (iph) is a carrying TCP/UDP, then set the encaps
+ * source and destination ports to those from the TCP/UDP header.
+ */
+void ipsec_extract_ports(struct iphdr * iph, struct sockaddr_encap * er)
+{
+ struct udphdr *udp;
+
+ switch (iph->protocol) {
+ case IPPROTO_UDP:
+ case IPPROTO_TCP:
+ /*
+ * The ports are at the same offsets in a TCP and UDP
+ * header so hack it ...
+ */
+ udp = (struct udphdr*)(((char*)iph)+(iph->ihl<<2));
+ er->sen_sport = udp->source;
+ er->sen_dport = udp->dest;
+ break;
+ default:
+ er->sen_sport = 0;
+ er->sen_dport = 0;
+ break;
+ }
+}
+
+/*
+ * A TRAP eroute is installed and we want to replace it with a HOLD
+ * eroute.
+ */
+static int create_hold_eroute(struct sk_buff * skb, struct iphdr * iph,
+ uint32_t eroute_pid)
+{
+ struct eroute hold_eroute;
+ struct sa_id hold_said;
+ struct sk_buff *first, *last;
+ int error;
+
+ first = last = NULL;
+ memset((caddr_t)&hold_eroute, 0, sizeof(hold_eroute));
+ memset((caddr_t)&hold_said, 0, sizeof(hold_said));
+
+ hold_said.proto = IPPROTO_INT;
+ hold_said.spi = htonl(SPI_HOLD);
+ hold_said.dst.s_addr = INADDR_ANY;
+
+ hold_eroute.er_eaddr.sen_len = sizeof(struct sockaddr_encap);
+ hold_eroute.er_emask.sen_len = sizeof(struct sockaddr_encap);
+ hold_eroute.er_eaddr.sen_family = AF_ENCAP;
+ hold_eroute.er_emask.sen_family = AF_ENCAP;
+ hold_eroute.er_eaddr.sen_type = SENT_IP4;
+ hold_eroute.er_emask.sen_type = 255;
+
+ hold_eroute.er_eaddr.sen_ip_src.s_addr = iph->saddr;
+ hold_eroute.er_eaddr.sen_ip_dst.s_addr = iph->daddr;
+ hold_eroute.er_emask.sen_ip_src.s_addr = INADDR_BROADCAST;
+ hold_eroute.er_emask.sen_ip_dst.s_addr = INADDR_BROADCAST;
+ hold_eroute.er_emask.sen_sport = ~0;
+ hold_eroute.er_emask.sen_dport = ~0;
+ hold_eroute.er_pid = eroute_pid;
+ hold_eroute.er_count = 0;
+ hold_eroute.er_lasttime = jiffies/HZ;
+
+ hold_eroute.er_eaddr.sen_proto = iph->protocol;
+ ipsec_extract_ports(iph, &hold_eroute.er_eaddr);
+
+#ifdef CONFIG_IPSEC_DEBUG
+ if (debug_pfkey) {
+ char buf1[64], buf2[64];
+ subnettoa(hold_eroute.er_eaddr.sen_ip_src,
+ hold_eroute.er_emask.sen_ip_src, 0, buf1, sizeof(buf1));
+ subnettoa(hold_eroute.er_eaddr.sen_ip_dst,
+ hold_eroute.er_emask.sen_ip_dst, 0, buf2, sizeof(buf2));
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:ipsec_tunnel_start_xmit: "
+ "calling breakeroute and makeroute for %s:%d->%s:%d %d HOLD eroute.\n",
+ buf1, ntohs(hold_eroute.er_eaddr.sen_sport),
+ buf2, ntohs(hold_eroute.er_eaddr.sen_dport),
+ hold_eroute.er_eaddr.sen_proto);
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+
+ if (ipsec_breakroute(&(hold_eroute.er_eaddr), &(hold_eroute.er_emask),
+ &first, &last)) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:ipsec_tunnel_start_xmit: "
+ "HOLD breakeroute found nothing.\n");
+ } else {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:ipsec_tunnel_start_xmit: "
+ "HOLD breakroute deleted %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u %u\n",
+ NIPQUAD(hold_eroute.er_eaddr.sen_ip_src),
+ ntohs(hold_eroute.er_eaddr.sen_sport),
+ NIPQUAD(hold_eroute.er_eaddr.sen_ip_dst),
+ ntohs(hold_eroute.er_eaddr.sen_dport),
+ hold_eroute.er_eaddr.sen_proto);
+ }
+ if (first != NULL)
+ kfree_skb(first);
+ if (last != NULL)
+ kfree_skb(last);
+
+ error = ipsec_makeroute(&(hold_eroute.er_eaddr),
+ &(hold_eroute.er_emask),
+ hold_said, eroute_pid, skb, NULL, NULL);
+ if (error) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:ipsec_tunnel_start_xmit: "
+ "HOLD makeroute returned %d, failed.\n", error);
+ } else {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:ipsec_tunnel_start_xmit: "
+ "HOLD makeroute call successful.\n");
+ }
+ return (error == 0);
+}
+
+#ifdef CONFIG_IPSEC_DEBUG_
+DEBUG_NO_STATIC void
+dmp(char *s, caddr_t bb, int len)
+{
+ int i;
+ unsigned char *b = bb;
+
+ if (debug_tunnel) {
+ printk(KERN_INFO "klips_debug:ipsec_tunnel_:dmp: "
+ "at %s, len=%d:",
+ s,
+ len);
+ for (i=0; i < len; i++) {
+ if(!(i%16)){
+ printk("\nklips_debug: ");
+ }
+ printk(" %02x", *b++);
+ }
+ printk("\n");
+ }
+}
+#else /* CONFIG_IPSEC_DEBUG */
+#define dmp(_x, _y, _z)
+#endif /* CONFIG_IPSEC_DEBUG */
+
+#ifndef SKB_COPY_EXPAND
+/*
+ * This is mostly skbuff.c:skb_copy().
+ */
+struct sk_buff *
+skb_copy_expand(struct sk_buff *skb, int headroom, int tailroom, int priority)
+{
+ struct sk_buff *n;
+ unsigned long offset;
+
+ /*
+ * Do sanity checking
+ */
+ if((headroom < 0) || (tailroom < 0) || ((headroom+tailroom) < 0)) {
+ printk(KERN_WARNING
+ "klips_error:skb_copy_expand: "
+ "Illegal negative head,tailroom %d,%d\n",
+ headroom,
+ tailroom);
+ return NULL;
+ }
+ /*
+ * Allocate the copy buffer
+ */
+
+#ifndef NET_21
+ IS_SKB(skb);
+#endif /* !NET_21 */
+
+
+ n=alloc_skb(skb->end - skb->head + headroom + tailroom, priority);
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_debug:skb_copy_expand: "
+ "allocating %d bytes, head=0p%p data=0p%p tail=0p%p end=0p%p end-head=%d tail-data=%d\n",
+ skb->end - skb->head + headroom + tailroom,
+ skb->head,
+ skb->data,
+ skb->tail,
+ skb->end,
+ skb->end - skb->head,
+ skb->tail - skb->data);
+
+ if(n==NULL)
+ return NULL;
+
+ /*
+ * Shift between the two data areas in bytes
+ */
+
+ /* Set the data pointer */
+ skb_reserve(n,skb->data-skb->head+headroom);
+ /* Set the tail pointer and length */
+ if(skb_tailroom(n) < skb->len) {
+ printk(KERN_WARNING "klips_error:skb_copy_expand: "
+ "tried to skb_put %ld, %d available. This should never happen, please report.\n",
+ (unsigned long int)skb->len,
+ skb_tailroom(n));
+ ipsec_kfree_skb(n);
+ return NULL;
+ }
+ skb_put(n,skb->len);
+
+ offset=n->head + headroom - skb->head;
+
+ /* Copy the bytes */
+ memcpy(n->head + headroom, skb->head,skb->end-skb->head);
+#ifdef NET_21
+ n->csum=skb->csum;
+ n->priority=skb->priority;
+ n->dst=dst_clone(skb->dst);
+ if(skb->nh.raw)
+ n->nh.raw=skb->nh.raw+offset;
+#ifndef NETDEV_23
+ n->is_clone=0;
+#endif /* NETDEV_23 */
+ atomic_set(&n->users, 1);
+ n->destructor = NULL;
+ n->security=skb->security;
+#else /* NET_21 */
+ n->link3=NULL;
+ n->when=skb->when;
+ if(skb->ip_hdr)
+ n->ip_hdr=(struct iphdr *)(((char *)skb->ip_hdr)+offset);
+ n->saddr=skb->saddr;
+ n->daddr=skb->daddr;
+ n->raddr=skb->raddr;
+ n->seq=skb->seq;
+ n->end_seq=skb->end_seq;
+ n->ack_seq=skb->ack_seq;
+ n->acked=skb->acked;
+ n->free=1;
+ n->arp=skb->arp;
+ n->tries=0;
+ n->lock=0;
+ n->users=0;
+#endif /* NET_21 */
+ n->protocol=skb->protocol;
+ n->list=NULL;
+ n->sk=NULL;
+ n->dev=skb->dev;
+ if(skb->h.raw)
+ n->h.raw=skb->h.raw+offset;
+ if(skb->mac.raw)
+ n->mac.raw=skb->mac.raw+offset;
+ memcpy(n->proto_priv, skb->proto_priv, sizeof(skb->proto_priv));
+#ifndef NETDEV_23
+ n->used=skb->used;
+#endif /* !NETDEV_23 */
+ n->pkt_type=skb->pkt_type;
+ n->stamp=skb->stamp;
+
+#ifndef NET_21
+ IS_SKB(n);
+#endif /* !NET_21 */
+ return n;
+}
+#endif /* !SKB_COPY_EXPAND */
+
+#ifdef CONFIG_IPSEC_DEBUG
+void
+ipsec_print_ip(struct iphdr *ip)
+{
+ char buf[ADDRTOA_BUF];
+
+ printk(KERN_INFO "klips_debug: IP:");
+ printk(" ihl:%d", ip->ihl << 2);
+ printk(" ver:%d", ip->version);
+ printk(" tos:%d", ip->tos);
+ printk(" tlen:%d", ntohs(ip->tot_len));
+ printk(" id:%d", ntohs(ip->id));
+ printk(" %s%s%sfrag_off:%d",
+ ip->frag_off & __constant_htons(IP_CE) ? "CE " : "",
+ ip->frag_off & __constant_htons(IP_DF) ? "DF " : "",
+ ip->frag_off & __constant_htons(IP_MF) ? "MF " : "",
+ (ntohs(ip->frag_off) & IP_OFFSET) << 3);
+ printk(" ttl:%d", ip->ttl);
+ printk(" proto:%d", ip->protocol);
+ if(ip->protocol == IPPROTO_UDP)
+ printk(" (UDP)");
+ if(ip->protocol == IPPROTO_TCP)
+ printk(" (TCP)");
+ if(ip->protocol == IPPROTO_ICMP)
+ printk(" (ICMP)");
+ printk(" chk:%d", ntohs(ip->check));
+ addrtoa(*((struct in_addr*)(&ip->saddr)), 0, buf, sizeof(buf));
+ printk(" saddr:%s", buf);
+ if(ip->protocol == IPPROTO_UDP)
+ printk(":%d",
+ ntohs(((struct udphdr*)((caddr_t)ip + (ip->ihl << 2)))->source));
+ if(ip->protocol == IPPROTO_TCP)
+ printk(":%d",
+ ntohs(((struct tcphdr*)((caddr_t)ip + (ip->ihl << 2)))->source));
+ addrtoa(*((struct in_addr*)(&ip->daddr)), 0, buf, sizeof(buf));
+ printk(" daddr:%s", buf);
+ if(ip->protocol == IPPROTO_UDP)
+ printk(":%d",
+ ntohs(((struct udphdr*)((caddr_t)ip + (ip->ihl << 2)))->dest));
+ if(ip->protocol == IPPROTO_TCP)
+ printk(":%d",
+ ntohs(((struct tcphdr*)((caddr_t)ip + (ip->ihl << 2)))->dest));
+ if(ip->protocol == IPPROTO_ICMP)
+ printk(" type:code=%d:%d",
+ ((struct icmphdr*)((caddr_t)ip + (ip->ihl << 2)))->type,
+ ((struct icmphdr*)((caddr_t)ip + (ip->ihl << 2)))->code);
+ printk("\n");
+
+ if(sysctl_ipsec_debug_verbose) {
+ __u8 *c;
+ int i;
+
+ c = ((__u8*)ip) + ip->ihl*4;
+ for(i = 0; i < ntohs(ip->tot_len) - ip->ihl*4; i++ /*, c++*/) {
+ if(!(i % 16)) {
+ printk(KERN_INFO
+ "klips_debug: @%03x:",
+ i);
+ }
+ printk(" %02x", /***/c[i]);
+ if(!((i + 1) % 16)) {
+ printk("\n");
+ }
+ }
+ if(i % 16) {
+ printk("\n");
+ }
+ }
+}
+#endif /* CONFIG_IPSEC_DEBUG */
+
+#ifdef MSS_HACK
+/*
+ * Issues:
+ * 1) Fragments arriving in the tunnel should probably be rejected.
+ * 2) How does this affect syncookies, mss_cache, dst cache ?
+ * 3) Path MTU discovery handling needs to be reviewed. For example,
+ * if we receive an ICMP 'packet too big' message from an intermediate
+ * router specifying it's next hop MTU, our stack may process this and
+ * adjust the MSS without taking our AH/ESP overheads into account.
+ */
+
+
+/*
+ * Recaclulate checksum using differences between changed datum,
+ * borrowed from netfilter.
+ */
+DEBUG_NO_STATIC u_int16_t
+ipsec_fast_csum(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck)
+{
+ u_int32_t diffs[] = { oldvalinv, newval };
+ return csum_fold(csum_partial((char *)diffs, sizeof(diffs),
+ oldcheck^0xFFFF));
+}
+
+/*
+ * Determine effective MSS.
+ *
+ * Note that we assume that there is always an MSS option for our own
+ * SYN segments, which is mentioned in tcp_syn_build_options(), kernel 2.2.x.
+ * This could change, and we should probably parse TCP options instead.
+ *
+ */
+DEBUG_NO_STATIC u_int8_t
+ipsec_adjust_mss(struct sk_buff *skb, struct tcphdr *tcph, u_int16_t mtu)
+{
+ u_int16_t oldmss, newmss;
+ u_int32_t *mssp;
+ struct sock *sk = skb->sk;
+
+ newmss = tcp_sync_mss(sk, mtu);
+ printk(KERN_INFO "klips: setting mss to %u\n", newmss);
+ mssp = (u_int32_t *)tcph + sizeof(struct tcphdr) / sizeof(u_int32_t);
+ oldmss = ntohl(*mssp) & 0x0000FFFF;
+ *mssp = htonl((TCPOPT_MSS << 24) | (TCPOLEN_MSS << 16) | newmss);
+ tcph->check = ipsec_fast_csum(htons(~oldmss),
+ htons(newmss), tcph->check);
+ return 1;
+}
+#endif /* MSS_HACK */
+
+/*
+ * Sanity checks
+ */
+enum ipsec_xmit_value
+ipsec_xmit_sanity_check_dev(struct ipsec_xmit_state *ixs)
+{
+
+ if (ixs->dev == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_error:ipsec_xmit_sanity_check_dev: "
+ "No device associated with skb!\n" );
+ return IPSEC_XMIT_NODEV;
+ }
+
+ ixs->prv = ixs->dev->priv;
+ if (ixs->prv == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_error:ipsec_xmit_sanity_check_dev: "
+ "Device has no private structure!\n" );
+ return IPSEC_XMIT_NOPRIVDEV;
+ }
+
+ ixs->physdev = ixs->prv->dev;
+ if (ixs->physdev == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_error:ipsec_xmit_sanity_check_dev: "
+ "Device is not attached to physical device!\n" );
+ return IPSEC_XMIT_NOPHYSDEV;
+ }
+
+ ixs->physmtu = ixs->physdev->mtu;
+
+ ixs->stats = (struct net_device_stats *) &(ixs->prv->mystats);
+
+ return IPSEC_XMIT_OK;
+}
+
+enum ipsec_xmit_value
+ipsec_xmit_sanity_check_skb(struct ipsec_xmit_state *ixs)
+{
+ /*
+ * Return if there is nothing to do. (Does this ever happen?) XXX
+ */
+ if (ixs->skb == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_error:ipsec_xmit_sanity_check_skb: "
+ "Nothing to do!\n" );
+ return IPSEC_XMIT_NOSKB;
+ }
+#ifdef NET_21
+ /* if skb was cloned (most likely due to a packet sniffer such as
+ tcpdump being momentarily attached to the interface), make
+ a copy of our own to modify */
+ if(skb_cloned(ixs->skb)) {
+ if
+#ifdef SKB_COW_NEW
+ (skb_cow(ixs->skb, skb_headroom(ixs->skb)) != 0)
+#else /* SKB_COW_NEW */
+ ((ixs->skb = skb_cow(ixs->skb, skb_headroom(ixs->skb))) == NULL)
+#endif /* SKB_COW_NEW */
+ {
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_error:ipsec_xmit_sanity_check_skb: "
+ "skb_cow failed to allocate buffer, dropping.\n" );
+ ixs->stats->tx_dropped++;
+ return IPSEC_XMIT_ERRSKBALLOC;
+ }
+ }
+#endif /* NET_21 */
+
+#ifdef NET_21
+ ixs->iph = ixs->skb->nh.iph;
+#else /* NET_21 */
+ ixs->iph = ixs->skb->ip_hdr;
+#endif /* NET_21 */
+
+ /* sanity check for IP version as we can't handle IPv6 right now */
+ if (ixs->iph->version != 4) {
+ KLIPS_PRINT(debug_tunnel,
+ "klips_debug:ipsec_xmit_sanity_check_skb: "
+ "found IP Version %d but cannot process other IP versions than v4.\n",
+ ixs->iph->version); /* XXX */
+ ixs->stats->tx_dropped++;
+ return IPSEC_XMIT_NOIPV6;
+ }
+
+#if IPSEC_DISALLOW_IPOPTIONS
+ if ((ixs->iph->ihl << 2) != sizeof (struct iphdr)) {
+ KLIPS_PRINT(debug_tunnel,
+ "klips_debug:ipsec_xmit_sanity_check_skb: "
+ "cannot process IP header options yet. May be mal-formed packet.\n"); /* XXX */
+ ixs->stats->tx_dropped++;
+ return IPSEC_XMIT_NOIPOPTIONS;
+ }
+#endif /* IPSEC_DISALLOW_IPOPTIONS */
+
+#ifndef NET_21
+ if (ixs->iph->ttl <= 0) {
+ /* Tell the sender its packet died... */
+ ICMP_SEND(ixs->skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0, ixs->physdev);
+
+ KLIPS_PRINT(debug_tunnel, "klips_debug:ipsec_xmit_sanity_check_skb: "
+ "TTL=0, too many hops!\n");
+ ixs->stats->tx_dropped++;
+ return IPSEC_XMIT_TTLEXPIRED;
+ }
+#endif /* !NET_21 */
+
+ return IPSEC_XMIT_OK;
+}
+
+enum ipsec_xmit_value
+ipsec_xmit_encap_once(struct ipsec_xmit_state *ixs)
+{
+#ifdef CONFIG_IPSEC_ESP
+ struct esphdr *espp;
+#ifdef CONFIG_IPSEC_ENC_3DES
+ __u32 iv[ESP_IV_MAXSZ_INT];
+#endif /* !CONFIG_IPSEC_ENC_3DES */
+ unsigned char *idat, *pad;
+ int authlen = 0, padlen = 0, i;
+#endif /* !CONFIG_IPSEC_ESP */
+#ifdef CONFIG_IPSEC_AH
+ struct iphdr ipo;
+ struct ahhdr *ahp;
+#endif /* CONFIG_IPSEC_AH */
+#if defined(CONFIG_IPSEC_AUTH_HMAC_MD5) || defined(CONFIG_IPSEC_AUTH_HMAC_SHA1)
+ union {
+#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
+ MD5_CTX md5;
+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
+#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
+ SHA1_CTX sha1;
+#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
+ } tctx;
+ __u8 hash[AH_AMAX];
+#endif /* defined(CONFIG_IPSEC_AUTH_HMAC_MD5) || defined(CONFIG_IPSEC_AUTH_HMAC_SHA1) */
+ int headroom = 0, tailroom = 0, ilen = 0, len = 0;
+ unsigned char *dat;
+ int blocksize = 8; /* XXX: should be inside ixs --jjo */
+#ifdef CONFIG_IPSEC_ALG
+ struct ipsec_alg_enc *ixt_e = NULL;
+ struct ipsec_alg_auth *ixt_a = NULL;
+#endif /* CONFIG_IPSEC_ALG */
+
+ ixs->iphlen = ixs->iph->ihl << 2;
+ ixs->pyldsz = ntohs(ixs->iph->tot_len) - ixs->iphlen;
+ ixs->sa_len = satoa(ixs->ipsp->ips_said, 0, ixs->sa_txt, SATOA_BUF);
+ KLIPS_PRINT(debug_tunnel & DB_TN_OXFS,
+ "klips_debug:ipsec_xmit_encap_once: "
+ "calling output for <%s%s%s>, SA:%s\n",
+ IPS_XFORM_NAME(ixs->ipsp),
+ ixs->sa_len ? ixs->sa_txt : " (error)");
+
+ switch(ixs->ipsp->ips_said.proto) {
+#ifdef CONFIG_IPSEC_AH
+ case IPPROTO_AH:
+ headroom += sizeof(struct ahhdr);
+ break;
+#endif /* CONFIG_IPSEC_AH */
+#ifdef CONFIG_IPSEC_ESP
+ case IPPROTO_ESP:
+#ifdef CONFIG_IPSEC_ALG
+ if ((ixt_e=ixs->ipsp->ips_alg_enc)) {
+ blocksize = ixt_e->ixt_blocksize;
+ headroom += ESP_HEADER_LEN + ixt_e->ixt_ivlen/8;
+ } else
+#endif /* CONFIG_IPSEC_ALG */
+ switch(ixs->ipsp->ips_encalg) {
+#ifdef CONFIG_IPSEC_ENC_3DES
+ case ESP_3DES:
+ headroom += sizeof(struct esphdr);
+ break;
+#endif /* CONFIG_IPSEC_ENC_3DES */
+ default:
+ ixs->stats->tx_errors++;
+ return IPSEC_XMIT_ESP_BADALG;
+ }
+#ifdef CONFIG_IPSEC_ALG
+ if ((ixt_a=ixs->ipsp->ips_alg_auth)) {
+ tailroom += AHHMAC_HASHLEN;
+ } else
+#endif /* CONFIG_IPSEC_ALG */
+ switch(ixs->ipsp->ips_authalg) {
+#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
+ case AH_MD5:
+ authlen = AHHMAC_HASHLEN;
+ break;
+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
+#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
+ case AH_SHA:
+ authlen = AHHMAC_HASHLEN;
+ break;
+#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
+ case AH_NONE:
+ break;
+ default:
+ ixs->stats->tx_errors++;
+ return IPSEC_XMIT_ESP_BADALG;
+ }
+#ifdef CONFIG_IPSEC_ALG
+ tailroom += blocksize != 1 ?
+ ((blocksize - ((ixs->pyldsz + 2) % blocksize)) % blocksize) + 2 :
+ ((4 - ((ixs->pyldsz + 2) % 4)) % 4) + 2;
+#else
+ tailroom += ((8 - ((ixs->pyldsz + 2 * sizeof(unsigned char)) % 8)) % 8) + 2;
+#endif /* CONFIG_IPSEC_ALG */
+ tailroom += authlen;
+ break;
+#endif /* !CONFIG_IPSEC_ESP */
+#ifdef CONFIG_IPSEC_IPIP
+ case IPPROTO_IPIP:
+ headroom += sizeof(struct iphdr);
+ ixs->iphlen = sizeof(struct iphdr);
+ break;
+#endif /* !CONFIG_IPSEC_IPIP */
+#ifdef CONFIG_IPSEC_IPCOMP
+ case IPPROTO_COMP:
+ break;
+#endif /* CONFIG_IPSEC_IPCOMP */
+ default:
+ ixs->stats->tx_errors++;
+ return IPSEC_XMIT_BADPROTO;
+ }
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_debug:ipsec_xmit_encap_once: "
+ "pushing %d bytes, putting %d, proto %d.\n",
+ headroom, tailroom, ixs->ipsp->ips_said.proto);
+ if(skb_headroom(ixs->skb) < headroom) {
+ printk(KERN_WARNING
+ "klips_error:ipsec_xmit_encap_once: "
+ "tried to skb_push headroom=%d, %d available. This should never happen, please report.\n",
+ headroom, skb_headroom(ixs->skb));
+ ixs->stats->tx_errors++;
+ return IPSEC_XMIT_ESP_PUSHPULLERR;
+ }
+ dat = skb_push(ixs->skb, headroom);
+ ilen = ixs->skb->len - tailroom;
+ if(skb_tailroom(ixs->skb) < tailroom) {
+ printk(KERN_WARNING
+ "klips_error:ipsec_xmit_encap_once: "
+ "tried to skb_put %d, %d available. This should never happen, please report.\n",
+ tailroom, skb_tailroom(ixs->skb));
+ ixs->stats->tx_errors++;
+ return IPSEC_XMIT_ESP_PUSHPULLERR;
+ }
+ skb_put(ixs->skb, tailroom);
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_debug:ipsec_xmit_encap_once: "
+ "head,tailroom: %d,%d before xform.\n",
+ skb_headroom(ixs->skb), skb_tailroom(ixs->skb));
+ len = ixs->skb->len;
+ if(len > 0xfff0) {
+ printk(KERN_WARNING "klips_error:ipsec_xmit_encap_once: "
+ "tot_len (%d) > 65520. This should never happen, please report.\n",
+ len);
+ ixs->stats->tx_errors++;
+ return IPSEC_XMIT_BADLEN;
+ }
+ memmove((void *)dat, (void *)(dat + headroom), ixs->iphlen);
+ ixs->iph = (struct iphdr *)dat;
+ ixs->iph->tot_len = htons(ixs->skb->len);
+
+ switch(ixs->ipsp->ips_said.proto) {
+#ifdef CONFIG_IPSEC_ESP
+ case IPPROTO_ESP:
+ espp = (struct esphdr *)(dat + ixs->iphlen);
+ espp->esp_spi = ixs->ipsp->ips_said.spi;
+ espp->esp_rpl = htonl(++(ixs->ipsp->ips_replaywin_lastseq));
+
+#ifdef CONFIG_IPSEC_ALG
+ if (!ixt_e)
+#endif /* CONFIG_IPSEC_ALG */
+ switch(ixs->ipsp->ips_encalg) {
+#if defined(CONFIG_IPSEC_ENC_3DES)
+#ifdef CONFIG_IPSEC_ENC_3DES
+ case ESP_3DES:
+#endif /* CONFIG_IPSEC_ENC_3DES */
+ iv[0] = *((__u32*)&(espp->esp_iv) ) =
+ ((__u32*)(ixs->ipsp->ips_iv))[0];
+ iv[1] = *((__u32*)&(espp->esp_iv) + 1) =
+ ((__u32*)(ixs->ipsp->ips_iv))[1];
+ break;
+#endif /* defined(CONFIG_IPSEC_ENC_3DES) */
+ default:
+ ixs->stats->tx_errors++;
+ return IPSEC_XMIT_ESP_BADALG;
+ }
+
+ idat = dat + ixs->iphlen + headroom;
+ ilen = len - (ixs->iphlen + headroom + authlen);
+
+ /* Self-describing padding */
+ pad = &dat[len - tailroom];
+ padlen = tailroom - 2 - authlen;
+ for (i = 0; i < padlen; i++) {
+ pad[i] = i + 1;
+ }
+ dat[len - authlen - 2] = padlen;
+
+ dat[len - authlen - 1] = ixs->iph->protocol;
+ ixs->iph->protocol = IPPROTO_ESP;
+
+#ifdef CONFIG_IPSEC_ALG
+ /* Do all operations here:
+ * copy IV->ESP, encrypt, update ips IV
+ */
+ if (ixt_e) {
+ int ret;
+ memcpy(espp->esp_iv,
+ ixs->ipsp->ips_iv,
+ ixt_e->ixt_ivlen/8);
+ ret=ipsec_alg_esp_encrypt(ixs->ipsp,
+ idat, ilen, espp->esp_iv,
+ IPSEC_ALG_ENCRYPT);
+ memcpy(ixs->ipsp->ips_iv,
+ idat + ilen - ixt_e->ixt_ivlen/8,
+ ixt_e->ixt_ivlen/8);
+ } else
+#endif /* CONFIG_IPSEC_ALG */
+ switch(ixs->ipsp->ips_encalg) {
+#ifdef CONFIG_IPSEC_ENC_3DES
+ case ESP_3DES:
+ des_ede3_cbc_encrypt((des_cblock *)idat,
+ (des_cblock *)idat,
+ ilen,
+ ((struct des_eks *)(ixs->ipsp->ips_key_e))[0].ks,
+ ((struct des_eks *)(ixs->ipsp->ips_key_e))[1].ks,
+ ((struct des_eks *)(ixs->ipsp->ips_key_e))[2].ks,
+ (des_cblock *)iv, 1);
+ break;
+#endif /* CONFIG_IPSEC_ENC_3DES */
+ default:
+ ixs->stats->tx_errors++;
+ return IPSEC_XMIT_ESP_BADALG;
+ }
+
+#ifdef CONFIG_IPSEC_ALG
+ if (!ixt_e)
+#endif /* CONFIG_IPSEC_ALG */
+ switch(ixs->ipsp->ips_encalg) {
+#if defined(CONFIG_IPSEC_ENC_3DES)
+#ifdef CONFIG_IPSEC_ENC_3DES
+ case ESP_3DES:
+#endif /* CONFIG_IPSEC_ENC_3DES */
+ /* XXX update IV with the last 8 octets of the encryption */
+#if KLIPS_IMPAIRMENT_ESPIV_CBC_ATTACK
+ ((__u32*)(ixs->ipsp->ips_iv))[0] =
+ ((__u32 *)(idat))[(ilen >> 2) - 2];
+ ((__u32*)(ixs->ipsp->ips_iv))[1] =
+ ((__u32 *)(idat))[(ilen >> 2) - 1];
+#else /* KLIPS_IMPAIRMENT_ESPIV_CBC_ATTACK */
+ prng_bytes(&ipsec_prng, (char *)ixs->ipsp->ips_iv, EMT_ESPDES_IV_SZ);
+#endif /* KLIPS_IMPAIRMENT_ESPIV_CBC_ATTACK */
+ break;
+#endif /* defined(CONFIG_IPSEC_ENC_3DES) */
+ default:
+ ixs->stats->tx_errors++;
+ return IPSEC_XMIT_ESP_BADALG;
+ }
+
+#ifdef CONFIG_IPSEC_ALG
+ if (ixt_a) {
+ ipsec_alg_sa_esp_hash(ixs->ipsp,
+ (caddr_t)espp, len - ixs->iphlen - authlen,
+ &(dat[len - authlen]), authlen);
+
+ } else
+#endif /* CONFIG_IPSEC_ALG */
+ switch(ixs->ipsp->ips_authalg) {
+#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
+ case AH_MD5:
+ dmp("espp", (char*)espp, len - ixs->iphlen - authlen);
+ tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->ictx;
+ dmp("ictx", (char*)&tctx.md5, sizeof(tctx.md5));
+ MD5Update(&tctx.md5, (caddr_t)espp, len - ixs->iphlen - authlen);
+ dmp("ictx+dat", (char*)&tctx.md5, sizeof(tctx.md5));
+ MD5Final(hash, &tctx.md5);
+ dmp("ictx hash", (char*)&hash, sizeof(hash));
+ tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->octx;
+ dmp("octx", (char*)&tctx.md5, sizeof(tctx.md5));
+ MD5Update(&tctx.md5, hash, AHMD596_ALEN);
+ dmp("octx+hash", (char*)&tctx.md5, sizeof(tctx.md5));
+ MD5Final(hash, &tctx.md5);
+ dmp("octx hash", (char*)&hash, sizeof(hash));
+ memcpy(&(dat[len - authlen]), hash, authlen);
+
+ /* paranoid */
+ memset((caddr_t)&tctx.md5, 0, sizeof(tctx.md5));
+ memset((caddr_t)hash, 0, sizeof(*hash));
+ break;
+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
+#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
+ case AH_SHA:
+ tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->ictx;
+ SHA1Update(&tctx.sha1, (caddr_t)espp, len - ixs->iphlen - authlen);
+ SHA1Final(hash, &tctx.sha1);
+ tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->octx;
+ SHA1Update(&tctx.sha1, hash, AHSHA196_ALEN);
+ SHA1Final(hash, &tctx.sha1);
+ memcpy(&(dat[len - authlen]), hash, authlen);
+
+ /* paranoid */
+ memset((caddr_t)&tctx.sha1, 0, sizeof(tctx.sha1));
+ memset((caddr_t)hash, 0, sizeof(*hash));
+ break;
+#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
+ case AH_NONE:
+ break;
+ default:
+ ixs->stats->tx_errors++;
+ return IPSEC_XMIT_AH_BADALG;
+ }
+#ifdef NET_21
+ ixs->skb->h.raw = (unsigned char*)espp;
+#endif /* NET_21 */
+ break;
+#endif /* !CONFIG_IPSEC_ESP */
+#ifdef CONFIG_IPSEC_AH
+ case IPPROTO_AH:
+ ahp = (struct ahhdr *)(dat + ixs->iphlen);
+ ahp->ah_spi = ixs->ipsp->ips_said.spi;
+ ahp->ah_rpl = htonl(++(ixs->ipsp->ips_replaywin_lastseq));
+ ahp->ah_rv = 0;
+ ahp->ah_nh = ixs->iph->protocol;
+ ahp->ah_hl = (headroom >> 2) - sizeof(__u64)/sizeof(__u32);
+ ixs->iph->protocol = IPPROTO_AH;
+ dmp("ahp", (char*)ahp, sizeof(*ahp));
+
+ ipo = *ixs->iph;
+ ipo.tos = 0;
+ ipo.frag_off = 0;
+ ipo.ttl = 0;
+ ipo.check = 0;
+ dmp("ipo", (char*)&ipo, sizeof(ipo));
+
+ switch(ixs->ipsp->ips_authalg) {
+#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
+ case AH_MD5:
+ tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->ictx;
+ dmp("ictx", (char*)&tctx.md5, sizeof(tctx.md5));
+ MD5Update(&tctx.md5, (unsigned char *)&ipo, sizeof (struct iphdr));
+ dmp("ictx+ipo", (char*)&tctx.md5, sizeof(tctx.md5));
+ MD5Update(&tctx.md5, (unsigned char *)ahp, headroom - sizeof(ahp->ah_data));
+ dmp("ictx+ahp", (char*)&tctx.md5, sizeof(tctx.md5));
+ MD5Update(&tctx.md5, (unsigned char *)zeroes, AHHMAC_HASHLEN);
+ dmp("ictx+zeroes", (char*)&tctx.md5, sizeof(tctx.md5));
+ MD5Update(&tctx.md5, dat + ixs->iphlen + headroom, len - ixs->iphlen - headroom);
+ dmp("ictx+dat", (char*)&tctx.md5, sizeof(tctx.md5));
+ MD5Final(hash, &tctx.md5);
+ dmp("ictx hash", (char*)&hash, sizeof(hash));
+ tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->octx;
+ dmp("octx", (char*)&tctx.md5, sizeof(tctx.md5));
+ MD5Update(&tctx.md5, hash, AHMD596_ALEN);
+ dmp("octx+hash", (char*)&tctx.md5, sizeof(tctx.md5));
+ MD5Final(hash, &tctx.md5);
+ dmp("octx hash", (char*)&hash, sizeof(hash));
+
+ memcpy(ahp->ah_data, hash, AHHMAC_HASHLEN);
+
+ /* paranoid */
+ memset((caddr_t)&tctx.md5, 0, sizeof(tctx.md5));
+ memset((caddr_t)hash, 0, sizeof(*hash));
+ break;
+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
+#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
+ case AH_SHA:
+ tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->ictx;
+ SHA1Update(&tctx.sha1, (unsigned char *)&ipo, sizeof (struct iphdr));
+ SHA1Update(&tctx.sha1, (unsigned char *)ahp, headroom - sizeof(ahp->ah_data));
+ SHA1Update(&tctx.sha1, (unsigned char *)zeroes, AHHMAC_HASHLEN);
+ SHA1Update(&tctx.sha1, dat + ixs->iphlen + headroom, len - ixs->iphlen - headroom);
+ SHA1Final(hash, &tctx.sha1);
+ tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->octx;
+ SHA1Update(&tctx.sha1, hash, AHSHA196_ALEN);
+ SHA1Final(hash, &tctx.sha1);
+
+ memcpy(ahp->ah_data, hash, AHHMAC_HASHLEN);
+
+ /* paranoid */
+ memset((caddr_t)&tctx.sha1, 0, sizeof(tctx.sha1));
+ memset((caddr_t)hash, 0, sizeof(*hash));
+ break;
+#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
+ default:
+ ixs->stats->tx_errors++;
+ return IPSEC_XMIT_AH_BADALG;
+ }
+#ifdef NET_21
+ ixs->skb->h.raw = (unsigned char*)ahp;
+#endif /* NET_21 */
+ break;
+#endif /* CONFIG_IPSEC_AH */
+#ifdef CONFIG_IPSEC_IPIP
+ case IPPROTO_IPIP:
+ ixs->iph->version = 4;
+ switch(sysctl_ipsec_tos) {
+ case 0:
+#ifdef NET_21
+ ixs->iph->tos = ixs->skb->nh.iph->tos;
+#else /* NET_21 */
+ ixs->iph->tos = ixs->skb->ip_hdr->tos;
+#endif /* NET_21 */
+ break;
+ case 1:
+ ixs->iph->tos = 0;
+ break;
+ default:
+ break;
+ }
+#ifdef NET_21
+#ifdef NETDEV_23
+ ixs->iph->ttl = sysctl_ip_default_ttl;
+#else /* NETDEV_23 */
+ ixs->iph->ttl = ip_statistics.IpDefaultTTL;
+#endif /* NETDEV_23 */
+#else /* NET_21 */
+ ixs->iph->ttl = 64; /* ip_statistics.IpDefaultTTL; */
+#endif /* NET_21 */
+ ixs->iph->frag_off = 0;
+ ixs->iph->saddr = ((struct sockaddr_in*)(ixs->ipsp->ips_addr_s))->sin_addr.s_addr;
+ ixs->iph->daddr = ((struct sockaddr_in*)(ixs->ipsp->ips_addr_d))->sin_addr.s_addr;
+ ixs->iph->protocol = IPPROTO_IPIP;
+ ixs->iph->ihl = sizeof(struct iphdr) >> 2;
+
+ KLIPS_IP_SELECT_IDENT(ixs->iph, ixs->skb);
+
+ ixs->newdst = (__u32)ixs->iph->daddr;
+ ixs->newsrc = (__u32)ixs->iph->saddr;
+
+#ifdef NET_21
+ ixs->skb->h.ipiph = ixs->skb->nh.iph;
+#endif /* NET_21 */
+ break;
+#endif /* !CONFIG_IPSEC_IPIP */
+#ifdef CONFIG_IPSEC_IPCOMP
+ case IPPROTO_COMP:
+ {
+ unsigned int flags = 0;
+#ifdef CONFIG_IPSEC_DEBUG
+ unsigned int old_tot_len = ntohs(ixs->iph->tot_len);
+#endif /* CONFIG_IPSEC_DEBUG */
+ ixs->ipsp->ips_comp_ratio_dbytes += ntohs(ixs->iph->tot_len);
+
+ ixs->skb = skb_compress(ixs->skb, ixs->ipsp, &flags);
+
+#ifdef NET_21
+ ixs->iph = ixs->skb->nh.iph;
+#else /* NET_21 */
+ ixs->iph = ixs->skb->ip_hdr;
+#endif /* NET_21 */
+
+ ixs->ipsp->ips_comp_ratio_cbytes += ntohs(ixs->iph->tot_len);
+
+#ifdef CONFIG_IPSEC_DEBUG
+ if (debug_tunnel & DB_TN_CROUT)
+ {
+ if (old_tot_len > ntohs(ixs->iph->tot_len))
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_debug:ipsec_xmit_encap_once: "
+ "packet shrunk from %d to %d bytes after compression, cpi=%04x (should be from spi=%08x, spi&0xffff=%04x.\n",
+ old_tot_len, ntohs(ixs->iph->tot_len),
+ ntohs(((struct ipcomphdr*)(((char*)ixs->iph) + ((ixs->iph->ihl) << 2)))->ipcomp_cpi),
+ ntohl(ixs->ipsp->ips_said.spi),
+ (__u16)(ntohl(ixs->ipsp->ips_said.spi) & 0x0000ffff));
+ else
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_debug:ipsec_xmit_encap_once: "
+ "packet did not compress (flags = %d).\n",
+ flags);
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+ }
+ break;
+#endif /* CONFIG_IPSEC_IPCOMP */
+ default:
+ ixs->stats->tx_errors++;
+ return IPSEC_XMIT_BADPROTO;
+ }
+
+#ifdef NET_21
+ ixs->skb->nh.raw = ixs->skb->data;
+#else /* NET_21 */
+ ixs->skb->ip_hdr = ixs->skb->h.iph = (struct iphdr *) ixs->skb->data;
+#endif /* NET_21 */
+ ixs->iph->check = 0;
+ ixs->iph->check = ip_fast_csum((unsigned char *)ixs->iph, ixs->iph->ihl);
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_encap_once: "
+ "after <%s%s%s>, SA:%s:\n",
+ IPS_XFORM_NAME(ixs->ipsp),
+ ixs->sa_len ? ixs->sa_txt : " (error)");
+ KLIPS_IP_PRINT(debug_tunnel & DB_TN_XMIT, ixs->iph);
+
+ ixs->ipsp->ips_life.ipl_bytes.ipl_count += len;
+ ixs->ipsp->ips_life.ipl_bytes.ipl_last = len;
+
+ if(!ixs->ipsp->ips_life.ipl_usetime.ipl_count) {
+ ixs->ipsp->ips_life.ipl_usetime.ipl_count = jiffies / HZ;
+ }
+ ixs->ipsp->ips_life.ipl_usetime.ipl_last = jiffies / HZ;
+ ixs->ipsp->ips_life.ipl_packets.ipl_count++;
+
+ ixs->ipsp = ixs->ipsp->ips_onext;
+
+ return IPSEC_XMIT_OK;
+}
+
+enum ipsec_xmit_value
+ipsec_xmit_encap_bundle(struct ipsec_xmit_state *ixs)
+{
+#ifdef CONFIG_IPSEC_ALG
+ struct ipsec_alg_enc *ixt_e = NULL;
+ struct ipsec_alg_auth *ixt_a = NULL;
+ int blocksize = 8;
+#endif /* CONFIG_IPSEC_ALG */
+ enum ipsec_xmit_value bundle_stat = IPSEC_XMIT_OK;
+
+ ixs->newdst = ixs->orgdst = ixs->iph->daddr;
+ ixs->newsrc = ixs->orgsrc = ixs->iph->saddr;
+ ixs->orgedst = ixs->outgoing_said.dst.s_addr;
+ ixs->iphlen = ixs->iph->ihl << 2;
+ ixs->pyldsz = ntohs(ixs->iph->tot_len) - ixs->iphlen;
+ ixs->max_headroom = ixs->max_tailroom = 0;
+
+ if (ixs->outgoing_said.proto == IPPROTO_INT) {
+ switch (ntohl(ixs->outgoing_said.spi)) {
+ case SPI_DROP:
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "shunt SA of DROP or no eroute: dropping.\n");
+ ixs->stats->tx_dropped++;
+ break;
+
+ case SPI_REJECT:
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "shunt SA of REJECT: notifying and dropping.\n");
+ ICMP_SEND(ixs->skb,
+ ICMP_DEST_UNREACH,
+ ICMP_PKT_FILTERED,
+ 0,
+ ixs->physdev);
+ ixs->stats->tx_dropped++;
+ break;
+
+ case SPI_PASS:
+#ifdef NET_21
+ ixs->pass = 1;
+#endif /* NET_21 */
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "PASS: calling dev_queue_xmit\n");
+ return IPSEC_XMIT_PASS;
+ goto cleanup;
+
+#if 1 /* now moved up to finderoute so we don't need to lock it longer */
+ case SPI_HOLD:
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "shunt SA of HOLD: this does not make sense here, dropping.\n");
+ ixs->stats->tx_dropped++;
+ break;
+#endif
+ case SPI_TRAP:
+ case SPI_TRAPSUBNET:
+ {
+ struct sockaddr_in src, dst;
+#ifdef CONFIG_IPSEC_DEBUG
+ char bufsrc[ADDRTOA_BUF], bufdst[ADDRTOA_BUF];
+#endif /* CONFIG_IPSEC_DEBUG */
+
+ /* Signal all listening KMds with a PF_KEY ACQUIRE */
+ ixs->ips.ips_said.proto = ixs->iph->protocol;
+ src.sin_family = AF_INET;
+ dst.sin_family = AF_INET;
+ src.sin_addr.s_addr = ixs->iph->saddr;
+ dst.sin_addr.s_addr = ixs->iph->daddr;
+ src.sin_port =
+ (ixs->iph->protocol == IPPROTO_UDP
+ ? ((struct udphdr*) (((caddr_t)ixs->iph) + (ixs->iph->ihl << 2)))->source
+ : (ixs->iph->protocol == IPPROTO_TCP
+ ? ((struct tcphdr*)((caddr_t)ixs->iph + (ixs->iph->ihl << 2)))->source
+ : 0));
+ dst.sin_port =
+ (ixs->iph->protocol == IPPROTO_UDP
+ ? ((struct udphdr*) (((caddr_t)ixs->iph) + (ixs->iph->ihl << 2)))->dest
+ : (ixs->iph->protocol == IPPROTO_TCP
+ ? ((struct tcphdr*)((caddr_t)ixs->iph + (ixs->iph->ihl << 2)))->dest
+ : 0));
+ {
+ int i;
+ for(i = 0;
+ i < sizeof(struct sockaddr_in)
+ - offsetof(struct sockaddr_in, sin_zero);
+ i++) {
+ src.sin_zero[i] = 0;
+ dst.sin_zero[i] = 0;
+ }
+ }
+
+ ixs->ips.ips_addr_s = (struct sockaddr*)(&src);
+ ixs->ips.ips_addr_d = (struct sockaddr*)(&dst);
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "SADB_ACQUIRE sent with src=%s:%d, dst=%s:%d, proto=%d.\n",
+ addrtoa(((struct sockaddr_in*)(ixs->ips.ips_addr_s))->sin_addr, 0, bufsrc, sizeof(bufsrc)) <= ADDRTOA_BUF ? bufsrc : "BAD_ADDR",
+ ntohs(((struct sockaddr_in*)(ixs->ips.ips_addr_s))->sin_port),
+ addrtoa(((struct sockaddr_in*)(ixs->ips.ips_addr_d))->sin_addr, 0, bufdst, sizeof(bufdst)) <= ADDRTOA_BUF ? bufdst : "BAD_ADDR",
+ ntohs(((struct sockaddr_in*)(ixs->ips.ips_addr_d))->sin_port),
+ ixs->ips.ips_said.proto);
+
+ /* increment count of total traps needed */
+ ipsec_xmit_trap_count++;
+
+ if (pfkey_acquire(&ixs->ips) == 0) {
+
+ /* note that we succeeded */
+ ipsec_xmit_trap_sendcount++;
+
+ if (ixs->outgoing_said.spi==htonl(SPI_TRAPSUBNET)) {
+ /*
+ * The spinlock is to prevent any other
+ * process from accessing or deleting
+ * the eroute while we are using and
+ * updating it.
+ */
+ spin_lock(&eroute_lock);
+ ixs->eroute = ipsec_findroute(&ixs->matcher);
+ if(ixs->eroute) {
+ ixs->eroute->er_said.spi = htonl(SPI_HOLD);
+ ixs->eroute->er_first = ixs->skb;
+ ixs->skb = NULL;
+ }
+ spin_unlock(&eroute_lock);
+ } else if (create_hold_eroute(ixs->skb, ixs->iph, ixs->eroute_pid)) {
+ ixs->skb = NULL;
+ }
+ }
+ ixs->stats->tx_dropped++;
+ }
+ default:
+ /* XXX what do we do with an unknown shunt spi? */
+ break;
+ } /* switch (ntohl(ixs->outgoing_said.spi)) */
+ return IPSEC_XMIT_STOLEN;
+ } /* if (ixs->outgoing_said.proto == IPPROTO_INT) */
+
+ /*
+ The spinlock is to prevent any other process from
+ accessing or deleting the ipsec_sa hash table or any of the
+ ipsec_sa s while we are using and updating them.
+
+ This is not optimal, but was relatively straightforward
+ at the time. A better way to do it has been planned for
+ more than a year, to lock the hash table and put reference
+ counts on each ipsec_sa instead. This is not likely to happen
+ in KLIPS1 unless a volunteer contributes it, but will be
+ designed into KLIPS2.
+ */
+ spin_lock(&tdb_lock);
+
+ ixs->ipsp = ipsec_sa_getbyid(&ixs->outgoing_said);
+ ixs->sa_len = satoa(ixs->outgoing_said, 0, ixs->sa_txt, SATOA_BUF);
+
+ if (ixs->ipsp == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "no ipsec_sa for SA%s: outgoing packet with no SA, dropped.\n",
+ ixs->sa_len ? ixs->sa_txt : " (error)");
+ ixs->stats->tx_dropped++;
+ bundle_stat = IPSEC_XMIT_SAIDNOTFOUND;
+ goto cleanup;
+ }
+
+ ipsec_sa_put(ixs->ipsp); /* incomplete */
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "found ipsec_sa -- SA:<%s%s%s> %s\n",
+ IPS_XFORM_NAME(ixs->ipsp),
+ ixs->sa_len ? ixs->sa_txt : " (error)");
+
+ /*
+ * How much headroom do we need to be able to apply
+ * all the grouped transforms?
+ */
+ ixs->ipsq = ixs->ipsp; /* save the head of the ipsec_sa chain */
+ while (ixs->ipsp) {
+ ixs->sa_len = satoa(ixs->ipsp->ips_said, 0, ixs->sa_txt, SATOA_BUF);
+ if(ixs->sa_len == 0) {
+ strcpy(ixs->sa_txt, "(error)");
+ }
+
+ /* If it is in larval state, drop the packet, we cannot process yet. */
+ if(ixs->ipsp->ips_state == SADB_SASTATE_LARVAL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "ipsec_sa in larval state for SA:<%s%s%s> %s, cannot be used yet, dropping packet.\n",
+ IPS_XFORM_NAME(ixs->ipsp),
+ ixs->sa_len ? ixs->sa_txt : " (error)");
+ ixs->stats->tx_errors++;
+ bundle_stat = IPSEC_XMIT_SAIDNOTLIVE;
+ goto cleanup;
+ }
+
+ if(ixs->ipsp->ips_state == SADB_SASTATE_DEAD) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "ipsec_sa in dead state for SA:<%s%s%s> %s, can no longer be used, dropping packet.\n",
+ IPS_XFORM_NAME(ixs->ipsp),
+ ixs->sa_len ? ixs->sa_txt : " (error)");
+ ixs->stats->tx_errors++;
+ bundle_stat = IPSEC_XMIT_SAIDNOTLIVE;
+ goto cleanup;
+ }
+
+ /* If the replay window counter == -1, expire SA, it will roll */
+ if(ixs->ipsp->ips_replaywin && ixs->ipsp->ips_replaywin_lastseq == -1) {
+ pfkey_expire(ixs->ipsp, 1);
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "replay window counter rolled for SA:<%s%s%s> %s, packet dropped, expiring SA.\n",
+ IPS_XFORM_NAME(ixs->ipsp),
+ ixs->sa_len ? ixs->sa_txt : " (error)");
+ ipsec_sa_delchain(ixs->ipsp);
+ ixs->stats->tx_errors++;
+ bundle_stat = IPSEC_XMIT_REPLAYROLLED;
+ goto cleanup;
+ }
+
+ /*
+ * if this is the first time we are using this SA, mark start time,
+ * and offset hard/soft counters by "now" for later checking.
+ */
+#if 0
+ if(ixs->ipsp->ips_life.ipl_usetime.count == 0) {
+ ixs->ipsp->ips_life.ipl_usetime.count = jiffies;
+ ixs->ipsp->ips_life.ipl_usetime.hard += jiffies;
+ ixs->ipsp->ips_life.ipl_usetime.soft += jiffies;
+ }
+#endif
+
+
+ if(ipsec_lifetime_check(&ixs->ipsp->ips_life.ipl_bytes, "bytes", ixs->sa_txt,
+ ipsec_life_countbased, ipsec_outgoing, ixs->ipsp) == ipsec_life_harddied ||
+ ipsec_lifetime_check(&ixs->ipsp->ips_life.ipl_addtime, "addtime",ixs->sa_txt,
+ ipsec_life_timebased, ipsec_outgoing, ixs->ipsp) == ipsec_life_harddied ||
+ ipsec_lifetime_check(&ixs->ipsp->ips_life.ipl_usetime, "usetime",ixs->sa_txt,
+ ipsec_life_timebased, ipsec_outgoing, ixs->ipsp) == ipsec_life_harddied ||
+ ipsec_lifetime_check(&ixs->ipsp->ips_life.ipl_packets, "packets",ixs->sa_txt,
+ ipsec_life_countbased, ipsec_outgoing, ixs->ipsp) == ipsec_life_harddied) {
+
+ ipsec_sa_delchain(ixs->ipsp);
+ ixs->stats->tx_errors++;
+ bundle_stat = IPSEC_XMIT_LIFETIMEFAILED;
+ goto cleanup;
+ }
+
+
+ ixs->headroom = ixs->tailroom = 0;
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "calling room for <%s%s%s>, SA:%s\n",
+ IPS_XFORM_NAME(ixs->ipsp),
+ ixs->sa_len ? ixs->sa_txt : " (error)");
+ switch(ixs->ipsp->ips_said.proto) {
+#ifdef CONFIG_IPSEC_AH
+ case IPPROTO_AH:
+ ixs->headroom += sizeof(struct ahhdr);
+ break;
+#endif /* CONFIG_IPSEC_AH */
+#ifdef CONFIG_IPSEC_ESP
+ case IPPROTO_ESP:
+#ifdef CONFIG_IPSEC_ALG
+ if ((ixt_e=ixs->ipsp->ips_alg_enc)) {
+ blocksize = ixt_e->ixt_blocksize;
+ ixs->headroom += ESP_HEADER_LEN + ixt_e->ixt_ivlen/8;
+ } else
+#endif /* CONFIG_IPSEC_ALG */
+ switch(ixs->ipsp->ips_encalg) {
+#ifdef CONFIG_IPSEC_ENC_3DES
+ case ESP_3DES:
+ ixs->headroom += sizeof(struct esphdr);
+ break;
+#endif /* CONFIG_IPSEC_ENC_3DES */
+ default:
+ ixs->stats->tx_errors++;
+ bundle_stat = IPSEC_XMIT_ESP_BADALG;
+ goto cleanup;
+ }
+#ifdef CONFIG_IPSEC_ALG
+ if ((ixt_a=ixs->ipsp->ips_alg_auth)) {
+ ixs->tailroom += AHHMAC_HASHLEN;
+ } else
+#endif /* CONFIG_IPSEC_ALG */
+ switch(ixs->ipsp->ips_authalg) {
+#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
+ case AH_MD5:
+ ixs->tailroom += AHHMAC_HASHLEN;
+ break;
+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
+#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
+ case AH_SHA:
+ ixs->tailroom += AHHMAC_HASHLEN;
+ break;
+#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
+ case AH_NONE:
+ break;
+ default:
+ ixs->stats->tx_errors++;
+ bundle_stat = IPSEC_XMIT_AH_BADALG;
+ goto cleanup;
+ }
+#ifdef CONFIG_IPSEC_ALG
+ ixs->tailroom += blocksize != 1 ?
+ ((blocksize - ((ixs->pyldsz + 2) % blocksize)) % blocksize) + 2 :
+ ((4 - ((ixs->pyldsz + 2) % 4)) % 4) + 2;
+#else
+ ixs->tailroom += ((8 - ((ixs->pyldsz + 2 * sizeof(unsigned char)) % 8)) % 8) + 2;
+#endif /* CONFIG_IPSEC_ALG */
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ if ((ixs->ipsp->ips_natt_type) && (!ixs->natt_type)) {
+ ixs->natt_type = ixs->ipsp->ips_natt_type;
+ ixs->natt_sport = ixs->ipsp->ips_natt_sport;
+ ixs->natt_dport = ixs->ipsp->ips_natt_dport;
+ switch (ixs->natt_type) {
+ case ESPINUDP_WITH_NON_IKE:
+ ixs->natt_head = sizeof(struct udphdr)+(2*sizeof(__u32));
+ break;
+ case ESPINUDP_WITH_NON_ESP:
+ ixs->natt_head = sizeof(struct udphdr);
+ break;
+ default:
+ ixs->natt_head = 0;
+ break;
+ }
+ ixs->tailroom += ixs->natt_head;
+ }
+#endif
+ break;
+#endif /* !CONFIG_IPSEC_ESP */
+#ifdef CONFIG_IPSEC_IPIP
+ case IPPROTO_IPIP:
+ ixs->headroom += sizeof(struct iphdr);
+ break;
+#endif /* !CONFIG_IPSEC_IPIP */
+ case IPPROTO_COMP:
+#ifdef CONFIG_IPSEC_IPCOMP
+ /*
+ We can't predict how much the packet will
+ shrink without doing the actual compression.
+ We could do it here, if we were the first
+ encapsulation in the chain. That might save
+ us a skb_copy_expand, since we might fit
+ into the existing skb then. However, this
+ would be a bit unclean (and this hack has
+ bit us once), so we better not do it. After
+ all, the skb_copy_expand is cheap in
+ comparison to the actual compression.
+ At least we know the packet will not grow.
+ */
+ break;
+#endif /* CONFIG_IPSEC_IPCOMP */
+ default:
+ ixs->stats->tx_errors++;
+ bundle_stat = IPSEC_XMIT_BADPROTO;
+ goto cleanup;
+ }
+ ixs->ipsp = ixs->ipsp->ips_onext;
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "Required head,tailroom: %d,%d\n",
+ ixs->headroom, ixs->tailroom);
+ ixs->max_headroom += ixs->headroom;
+ ixs->max_tailroom += ixs->tailroom;
+ ixs->pyldsz += (ixs->headroom + ixs->tailroom);
+ }
+ ixs->ipsp = ixs->ipsq; /* restore the head of the ipsec_sa chain */
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "existing head,tailroom: %d,%d before applying xforms with head,tailroom: %d,%d .\n",
+ skb_headroom(ixs->skb), skb_tailroom(ixs->skb),
+ ixs->max_headroom, ixs->max_tailroom);
+
+ ixs->tot_headroom += ixs->max_headroom;
+ ixs->tot_tailroom += ixs->max_tailroom;
+
+ ixs->mtudiff = ixs->prv->mtu + ixs->tot_headroom + ixs->tot_tailroom - ixs->physmtu;
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "mtu:%d physmtu:%d tothr:%d tottr:%d mtudiff:%d ippkttotlen:%d\n",
+ ixs->prv->mtu, ixs->physmtu,
+ ixs->tot_headroom, ixs->tot_tailroom, ixs->mtudiff, ntohs(ixs->iph->tot_len));
+ if(ixs->mtudiff > 0) {
+ int newmtu = ixs->physmtu - (ixs->tot_headroom + ((ixs->tot_tailroom + 2) & ~7) + 5);
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_info:ipsec_xmit_encap_bundle: "
+ "dev %s mtu of %d decreased by %d to %d\n",
+ ixs->dev->name,
+ ixs->prv->mtu,
+ ixs->prv->mtu - newmtu,
+ newmtu);
+ ixs->prv->mtu = newmtu;
+#ifdef NET_21
+#if 0
+ ixs->skb->dst->pmtu = ixs->prv->mtu; /* RGB */
+#endif /* 0 */
+#else /* NET_21 */
+#if 0
+ ixs->dev->mtu = ixs->prv->mtu; /* RGB */
+#endif /* 0 */
+#endif /* NET_21 */
+ }
+
+ /*
+ If the sender is doing PMTU discovery, and the
+ packet doesn't fit within ixs->prv->mtu, notify him
+ (unless it was an ICMP packet, or it was not the
+ zero-offset packet) and send it anyways.
+
+ Note: buggy firewall configuration may prevent the
+ ICMP packet from getting back.
+ */
+ if(sysctl_ipsec_icmp
+ && ixs->prv->mtu < ntohs(ixs->iph->tot_len)
+ && (ixs->iph->frag_off & __constant_htons(IP_DF)) ) {
+ int notify = ixs->iph->protocol != IPPROTO_ICMP
+ && (ixs->iph->frag_off & __constant_htons(IP_OFFSET)) == 0;
+
+#ifdef IPSEC_obey_DF
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "fragmentation needed and DF set; %sdropping packet\n",
+ notify ? "sending ICMP and " : "");
+ if (notify)
+ ICMP_SEND(ixs->skb,
+ ICMP_DEST_UNREACH,
+ ICMP_FRAG_NEEDED,
+ ixs->prv->mtu,
+ ixs->physdev);
+ ixs->stats->tx_errors++;
+ bundle_stat = IPSEC_XMIT_CANNOTFRAG;
+ goto cleanup;
+#else /* IPSEC_obey_DF */
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "fragmentation needed and DF set; %spassing packet\n",
+ notify ? "sending ICMP and " : "");
+ if (notify)
+ ICMP_SEND(ixs->skb,
+ ICMP_DEST_UNREACH,
+ ICMP_FRAG_NEEDED,
+ ixs->prv->mtu,
+ ixs->physdev);
+#endif /* IPSEC_obey_DF */
+ }
+
+#ifdef MSS_HACK
+ /*
+ * If this is a transport mode TCP packet with
+ * SYN set, determine an effective MSS based on
+ * AH/ESP overheads determined above.
+ */
+ if (ixs->iph->protocol == IPPROTO_TCP
+ && ixs->outgoing_said.proto != IPPROTO_IPIP) {
+ struct tcphdr *tcph = ixs->skb->h.th;
+ if (tcph->syn && !tcph->ack) {
+ if(!ipsec_adjust_mss(ixs->skb, tcph, ixs->prv->mtu)) {
+ printk(KERN_WARNING
+ "klips_warning:ipsec_xmit_encap_bundle: "
+ "ipsec_adjust_mss() failed\n");
+ ixs->stats->tx_errors++;
+ bundle_stat = IPSEC_XMIT_MSSERR;
+ goto cleanup;
+ }
+ }
+ }
+#endif /* MSS_HACK */
+
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ if ((ixs->natt_type) && (ixs->outgoing_said.proto != IPPROTO_IPIP)) {
+ /**
+ * NAT-Traversal and Transport Mode:
+ * we need to correct TCP/UDP checksum
+ *
+ * If we've got NAT-OA, we can fix checksum without recalculation.
+ * If we don't we can zero udp checksum.
+ */
+ __u32 natt_oa = ixs->ipsp->ips_natt_oa ?
+ ((struct sockaddr_in*)(ixs->ipsp->ips_natt_oa))->sin_addr.s_addr : 0;
+ __u16 pkt_len = ixs->skb->tail - (unsigned char *)ixs->iph;
+ __u16 data_len = pkt_len - (ixs->iph->ihl << 2);
+ switch (ixs->iph->protocol) {
+ case IPPROTO_TCP:
+ if (data_len >= sizeof(struct tcphdr)) {
+ struct tcphdr *tcp = (struct tcphdr *)((__u32 *)ixs->iph+ixs->iph->ihl);
+ if (natt_oa) {
+ __u32 buff[2] = { ~ixs->iph->daddr, natt_oa };
+ KLIPS_PRINT(debug_tunnel,
+ "klips_debug:ipsec_tunnel_start_xmit: "
+ "NAT-T & TRANSPORT: "
+ "fix TCP checksum using NAT-OA\n");
+ tcp->check = csum_fold(
+ csum_partial((unsigned char *)buff, sizeof(buff),
+ tcp->check^0xffff));
+ }
+ else {
+ KLIPS_PRINT(debug_tunnel,
+ "klips_debug:ipsec_tunnel_start_xmit: "
+ "NAT-T & TRANSPORT: do not recalc TCP checksum\n");
+ }
+ }
+ else {
+ KLIPS_PRINT(debug_tunnel,
+ "klips_debug:ipsec_tunnel_start_xmit: "
+ "NAT-T & TRANSPORT: can't fix TCP checksum\n");
+ }
+ break;
+ case IPPROTO_UDP:
+ if (data_len >= sizeof(struct udphdr)) {
+ struct udphdr *udp = (struct udphdr *)((__u32 *)ixs->iph+ixs->iph->ihl);
+ if (udp->check == 0) {
+ KLIPS_PRINT(debug_tunnel,
+ "klips_debug:ipsec_tunnel_start_xmit: "
+ "NAT-T & TRANSPORT: UDP checksum already 0\n");
+ }
+ else if (natt_oa) {
+ __u32 buff[2] = { ~ixs->iph->daddr, natt_oa };
+ KLIPS_PRINT(debug_tunnel,
+ "klips_debug:ipsec_tunnel_start_xmit: "
+ "NAT-T & TRANSPORT: "
+ "fix UDP checksum using NAT-OA\n");
+ udp->check = csum_fold(
+ csum_partial((unsigned char *)buff, sizeof(buff),
+ udp->check^0xffff));
+ }
+ else {
+ KLIPS_PRINT(debug_tunnel,
+ "klips_debug:ipsec_tunnel_start_xmit: "
+ "NAT-T & TRANSPORT: zero UDP checksum\n");
+ udp->check = 0;
+ }
+ }
+ else {
+ KLIPS_PRINT(debug_tunnel,
+ "klips_debug:ipsec_tunnel_start_xmit: "
+ "NAT-T & TRANSPORT: can't fix UDP checksum\n");
+ }
+ break;
+ default:
+ KLIPS_PRINT(debug_tunnel,
+ "klips_debug:ipsec_tunnel_start_xmit: "
+ "NAT-T & TRANSPORT: non TCP/UDP packet -- do nothing\n");
+ break;
+ }
+ }
+#endif /* CONFIG_IPSEC_NAT_TRAVERSAL */
+
+ if(!ixs->hard_header_stripped) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "allocating %d bytes for hardheader.\n",
+ ixs->hard_header_len);
+ if((ixs->saved_header = kmalloc(ixs->hard_header_len, GFP_ATOMIC)) == NULL) {
+ printk(KERN_WARNING "klips_debug:ipsec_xmit_encap_bundle: "
+ "Failed, tried to allocate %d bytes for temp hard_header.\n",
+ ixs->hard_header_len);
+ ixs->stats->tx_errors++;
+ bundle_stat = IPSEC_XMIT_ERRMEMALLOC;
+ goto cleanup;
+ }
+ {
+ int i;
+ for (i = 0; i < ixs->hard_header_len; i++) {
+ ixs->saved_header[i] = ixs->skb->data[i];
+ }
+ }
+ if(ixs->skb->len < ixs->hard_header_len) {
+ printk(KERN_WARNING "klips_error:ipsec_xmit_encap_bundle: "
+ "tried to skb_pull hhlen=%d, %d available. This should never happen, please report.\n",
+ ixs->hard_header_len, (int)(ixs->skb->len));
+ ixs->stats->tx_errors++;
+ bundle_stat = IPSEC_XMIT_ESP_PUSHPULLERR;
+ goto cleanup;
+ }
+ skb_pull(ixs->skb, ixs->hard_header_len);
+ ixs->hard_header_stripped = 1;
+
+/* ixs->iph = (struct iphdr *) (ixs->skb->data); */
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "head,tailroom: %d,%d after hard_header stripped.\n",
+ skb_headroom(ixs->skb), skb_tailroom(ixs->skb));
+ KLIPS_IP_PRINT(debug_tunnel & DB_TN_CROUT, ixs->iph);
+ } else {
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "hard header already stripped.\n");
+ }
+
+ ixs->ll_headroom = (ixs->hard_header_len + 15) & ~15;
+
+ if ((skb_headroom(ixs->skb) >= ixs->max_headroom + 2 * ixs->ll_headroom) &&
+ (skb_tailroom(ixs->skb) >= ixs->max_tailroom)
+#ifndef NET_21
+ && ixs->skb->free
+#endif /* !NET_21 */
+ ) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "data fits in existing skb\n");
+ } else {
+ struct sk_buff* tskb;
+
+ if(!ixs->oskb) {
+ ixs->oskb = ixs->skb;
+ }
+
+ tskb = skb_copy_expand(ixs->skb,
+ /* The need for 2 * link layer length here remains unexplained...RGB */
+ ixs->max_headroom + 2 * ixs->ll_headroom,
+ ixs->max_tailroom,
+ GFP_ATOMIC);
+#ifdef NET_21
+ if(tskb && ixs->skb->sk) {
+ skb_set_owner_w(tskb, ixs->skb->sk);
+ }
+#endif /* NET_21 */
+ if(ixs->skb != ixs->oskb) {
+ ipsec_kfree_skb(ixs->skb);
+ }
+ ixs->skb = tskb;
+ if (!ixs->skb) {
+ printk(KERN_WARNING
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "Failed, tried to allocate %d head and %d tailroom\n",
+ ixs->max_headroom, ixs->max_tailroom);
+ ixs->stats->tx_errors++;
+ bundle_stat = IPSEC_XMIT_ERRSKBALLOC;
+ goto cleanup;
+ }
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "head,tailroom: %d,%d after allocation\n",
+ skb_headroom(ixs->skb), skb_tailroom(ixs->skb));
+ }
+
+ /*
+ * Apply grouped transforms to packet
+ */
+ while (ixs->ipsp) {
+ enum ipsec_xmit_value encap_stat = IPSEC_XMIT_OK;
+
+ encap_stat = ipsec_xmit_encap_once(ixs);
+ if(encap_stat != IPSEC_XMIT_OK) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_encap_bundle: encap_once failed: %d\n",
+ encap_stat);
+
+ bundle_stat = IPSEC_XMIT_ENCAPFAIL;
+ goto cleanup;
+ }
+ }
+ /* end encapsulation loop here XXX */
+ cleanup:
+ spin_unlock(&tdb_lock);
+ return bundle_stat;
+}
diff --git a/linux/net/ipsec/pfkey_v2.c b/linux/net/ipsec/pfkey_v2.c
new file mode 100644
index 000000000..a78aaf26e
--- /dev/null
+++ b/linux/net/ipsec/pfkey_v2.c
@@ -0,0 +1,2125 @@
+/*
+ * @(#) RFC2367 PF_KEYv2 Key management API domain socket I/F
+ * Copyright (C) 1999, 2000, 2001 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.c,v 1.4 2004/09/29 22:27:41 as Exp $
+ */
+
+/*
+ * Template from /usr/src/linux-2.0.36/net/unix/af_unix.c.
+ * Hints from /usr/src/linux-2.0.36/net/ipv4/udp.c.
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+
+#include "freeswan/ipsec_param.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>
+#ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+#else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+#endif /* MALLOC_SLAB */
+#include <asm/segment.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <net/sock.h> /* struct sock */
+/* #include <net/tcp.h> */
+#include <net/af_unix.h>
+#ifdef CONFIG_PROC_FS
+# include <linux/proc_fs.h>
+#endif /* CONFIG_PROC_FS */
+
+#include <linux/types.h>
+
+#include <freeswan.h>
+#ifdef NET_21
+# include <asm/uaccess.h>
+# include <linux/in6.h>
+#endif /* NET_21 */
+
+#include "freeswan/radij.h"
+#include "freeswan/ipsec_encap.h"
+#include "freeswan/ipsec_sa.h"
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "freeswan/ipsec_proto.h"
+
+#ifdef CONFIG_IPSEC_DEBUG
+int debug_pfkey = 0;
+extern int sysctl_ipsec_debug_verbose;
+#endif /* CONFIG_IPSEC_DEBUG */
+
+#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0)
+
+#ifndef SOCKOPS_WRAPPED
+#define SOCKOPS_WRAPPED(name) name
+#endif /* SOCKOPS_WRAPPED */
+
+extern struct proto_ops pfkey_ops;
+struct sock *pfkey_sock_list = NULL;
+struct supported_list *pfkey_supported_list[SADB_SATYPE_MAX+1];
+
+struct socket_list *pfkey_open_sockets = NULL;
+struct socket_list *pfkey_registered_sockets[SADB_SATYPE_MAX+1];
+
+int pfkey_msg_interp(struct sock *, struct sadb_msg *, struct sadb_msg **);
+
+int
+pfkey_list_remove_socket(struct socket *socketp, struct socket_list **sockets)
+{
+ struct socket_list *socket_listp,*prev;
+
+ if(!socketp) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_list_remove_socket: "
+ "NULL socketp handed in, failed.\n");
+ return -EINVAL;
+ }
+
+ if(!sockets) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_list_remove_socket: "
+ "NULL sockets list handed in, failed.\n");
+ return -EINVAL;
+ }
+
+ socket_listp = *sockets;
+ prev = NULL;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_list_remove_socket: "
+ "removing sock=0p%p\n",
+ socketp);
+
+ while(socket_listp != NULL) {
+ if(socket_listp->socketp == socketp) {
+ if(prev != NULL) {
+ prev->next = socket_listp->next;
+ } else {
+ *sockets = socket_listp->next;
+ }
+
+ kfree((void*)socket_listp);
+
+ break;
+ }
+ prev = socket_listp;
+ socket_listp = socket_listp->next;
+ }
+
+ return 0;
+}
+
+int
+pfkey_list_insert_socket(struct socket *socketp, struct socket_list **sockets)
+{
+ struct socket_list *socket_listp;
+
+ if(!socketp) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_list_insert_socket: "
+ "NULL socketp handed in, failed.\n");
+ return -EINVAL;
+ }
+
+ if(!sockets) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_list_insert_socket: "
+ "NULL sockets list handed in, failed.\n");
+ return -EINVAL;
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_list_insert_socket: "
+ "allocating %lu bytes for socketp=0p%p\n",
+ (unsigned long) sizeof(struct socket_list),
+ socketp);
+
+ if((socket_listp = (struct socket_list *)kmalloc(sizeof(struct socket_list), GFP_KERNEL)) == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_list_insert_socket: "
+ "memory allocation error.\n");
+ return -ENOMEM;
+ }
+
+ socket_listp->socketp = socketp;
+ socket_listp->next = *sockets;
+ *sockets = socket_listp;
+
+ return 0;
+}
+
+int
+pfkey_list_remove_supported(struct supported *supported, struct supported_list **supported_list)
+{
+ struct supported_list *supported_listp = *supported_list, *prev = NULL;
+
+ if(!supported) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_list_remove_supported: "
+ "NULL supported handed in, failed.\n");
+ return -EINVAL;
+ }
+
+ if(!supported_list) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_list_remove_supported: "
+ "NULL supported_list handed in, failed.\n");
+ return -EINVAL;
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_list_remove_supported: "
+ "removing supported=0p%p\n",
+ supported);
+
+ while(supported_listp != NULL) {
+ if(supported_listp->supportedp == supported) {
+ if(prev != NULL) {
+ prev->next = supported_listp->next;
+ } else {
+ *supported_list = supported_listp->next;
+ }
+
+ kfree((void*)supported_listp);
+
+ break;
+ }
+ prev = supported_listp;
+ supported_listp = supported_listp->next;
+ }
+
+ return 0;
+}
+
+int
+pfkey_list_insert_supported(struct supported *supported, struct supported_list **supported_list)
+{
+ struct supported_list *supported_listp;
+
+ if(!supported) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_list_insert_supported: "
+ "NULL supported handed in, failed.\n");
+ return -EINVAL;
+ }
+
+ if(!supported_list) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_list_insert_supported: "
+ "NULL supported_list handed in, failed.\n");
+ return -EINVAL;
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_list_insert_supported: "
+ "allocating %lu bytes for incoming, supported=0p%p, supported_list=0p%p\n",
+ (unsigned long) sizeof(struct supported_list),
+ supported,
+ supported_list);
+
+ supported_listp = (struct supported_list *)kmalloc(sizeof(struct supported_list), GFP_KERNEL);
+ if(supported_listp == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_list_insert_supported: "
+ "memory allocation error.\n");
+ return -ENOMEM;
+ }
+
+ supported_listp->supportedp = supported;
+ supported_listp->next = *supported_list;
+ *supported_list = supported_listp;
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_list_insert_supported: "
+ "outgoing, supported=0p%p, supported_list=0p%p\n",
+ supported,
+ supported_list);
+
+ return 0;
+}
+
+#ifndef NET_21
+DEBUG_NO_STATIC void
+pfkey_state_change(struct sock *sk)
+{
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_state_change: .\n");
+ if(!sk->dead) {
+ wake_up_interruptible(sk->sleep);
+ }
+}
+#endif /* !NET_21 */
+
+#ifndef NET_21
+DEBUG_NO_STATIC void
+pfkey_data_ready(struct sock *sk, int len)
+{
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_data_ready: "
+ "sk=0p%p len=%d\n",
+ sk,
+ len);
+ if(!sk->dead) {
+ wake_up_interruptible(sk->sleep);
+ sock_wake_async(sk->socket, 1);
+ }
+}
+
+DEBUG_NO_STATIC void
+pfkey_write_space(struct sock *sk)
+{
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_write_space: .\n");
+ if(!sk->dead) {
+ wake_up_interruptible(sk->sleep);
+ sock_wake_async(sk->socket, 2);
+ }
+}
+#endif /* !NET_21 */
+
+DEBUG_NO_STATIC void
+pfkey_insert_socket(struct sock *sk)
+{
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_insert_socket: "
+ "sk=0p%p\n",
+ sk);
+ cli();
+ sk->next=pfkey_sock_list;
+ pfkey_sock_list=sk;
+ sti();
+}
+
+DEBUG_NO_STATIC void
+pfkey_remove_socket(struct sock *sk)
+{
+ struct sock **s;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_remove_socket: .\n");
+ cli();
+ s=&pfkey_sock_list;
+
+ while(*s!=NULL) {
+ if(*s==sk) {
+ *s=sk->next;
+ sk->next=NULL;
+ sti();
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_remove_socket: "
+ "succeeded.\n");
+ return;
+ }
+ s=&((*s)->next);
+ }
+ sti();
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_remove_socket: "
+ "not found.\n");
+ return;
+}
+
+DEBUG_NO_STATIC void
+pfkey_destroy_socket(struct sock *sk)
+{
+ struct sk_buff *skb;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_destroy_socket: .\n");
+ pfkey_remove_socket(sk);
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_destroy_socket: "
+ "pfkey_remove_socket called.\n");
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_destroy_socket: "
+ "sk(0p%p)->(&0p%p)receive_queue.{next=0p%p,prev=0p%p}.\n",
+ sk,
+ &(sk->receive_queue),
+ sk->receive_queue.next,
+ sk->receive_queue.prev);
+ while(sk && ((skb=skb_dequeue(&(sk->receive_queue)))!=NULL)) {
+#ifdef NET_21
+#ifdef CONFIG_IPSEC_DEBUG
+ if(debug_pfkey && sysctl_ipsec_debug_verbose) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_destroy_socket: "
+ "skb=0p%p dequeued.\n", skb);
+ printk(KERN_INFO "klips_debug:pfkey_destroy_socket: "
+ "pfkey_skb contents:");
+ printk(" next:0p%p", skb->next);
+ printk(" prev:0p%p", skb->prev);
+ printk(" list:0p%p", skb->list);
+ printk(" sk:0p%p", skb->sk);
+ printk(" stamp:%ld.%ld", skb->stamp.tv_sec, skb->stamp.tv_usec);
+ printk(" dev:0p%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:0p%p", skb->h.raw);
+ printk(" nh:0p%p", skb->nh.raw);
+ printk(" mac:0p%p", skb->mac.raw);
+ printk(" dst:0p%p", skb->dst);
+ if(sysctl_ipsec_debug_verbose) {
+ 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);
+#ifndef NETDEV_23
+ printk(" used:%d", skb->used);
+ printk(" is_clone:%d", skb->is_clone);
+#endif /* NETDEV_23 */
+ 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:0p%p", skb->head);
+ printk(" data:0p%p", skb->data);
+ printk(" tail:0p%p", skb->tail);
+ printk(" end:0p%p", skb->end);
+ if(sysctl_ipsec_debug_verbose) {
+ unsigned char* i;
+ printk(" data");
+ for(i = skb->head; i < skb->end; i++) {
+ printk(":%2x", (unsigned char)(*(i)));
+ }
+ }
+ printk(" destructor:0p%p", skb->destructor);
+ printk("\n");
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+#endif /* NET_21 */
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_destroy_socket: "
+ "skb=0p%p freed.\n",
+ skb);
+ ipsec_kfree_skb(skb);
+ }
+
+ sk->dead = 1;
+ sk_free(sk);
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_destroy_socket: destroyed.\n");
+}
+
+int
+pfkey_upmsg(struct socket *sock, struct sadb_msg *pfkey_msg)
+{
+ int error = 0;
+ struct sk_buff * skb = NULL;
+ struct sock *sk;
+
+ if(sock == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_upmsg: "
+ "NULL socket passed in.\n");
+ return -EINVAL;
+ }
+
+ if(pfkey_msg == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_upmsg: "
+ "NULL pfkey_msg passed in.\n");
+ return -EINVAL;
+ }
+
+#ifdef NET_21
+ sk = sock->sk;
+#else /* NET_21 */
+ sk = sock->data;
+#endif /* NET_21 */
+
+ if(sk == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_upmsg: "
+ "NULL sock passed in.\n");
+ return -EINVAL;
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_upmsg: "
+ "allocating %d bytes...\n",
+ (int)(pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN));
+ if(!(skb = alloc_skb(pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN, GFP_ATOMIC) )) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_upmsg: "
+ "no buffers left to send up a message.\n");
+ return -ENOBUFS;
+ }
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_upmsg: "
+ "...allocated at 0p%p.\n",
+ skb);
+
+ 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));
+ ipsec_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);
+
+#ifndef NET_21
+ skb->free = 1;
+#endif /* !NET_21 */
+
+ if((error = sock_queue_rcv_skb(sk, skb)) < 0) {
+ skb->sk=NULL;
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_upmsg: "
+ "error=%d calling sock_queue_rcv_skb with skb=0p%p.\n",
+ error,
+ skb);
+ ipsec_kfree_skb(skb);
+ return error;
+ }
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_create(struct socket *sock, int protocol)
+{
+ struct sock *sk;
+
+ if(sock == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_create: "
+ "socket NULL.\n");
+ return -EINVAL;
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_create: "
+ "sock=0p%p type:%d state:%d flags:%ld protocol:%d\n",
+ sock,
+ sock->type,
+ (unsigned int)(sock->state),
+ sock->flags, protocol);
+
+ if(sock->type != SOCK_RAW) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_create: "
+ "only SOCK_RAW supported.\n");
+ return -ESOCKTNOSUPPORT;
+ }
+
+ if(protocol != PF_KEY_V2) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_create: "
+ "protocol not PF_KEY_V2.\n");
+ return -EPROTONOSUPPORT;
+ }
+
+ if((current->uid != 0)) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_create: "
+ "must be root to open pfkey sockets.\n");
+ return -EACCES;
+ }
+
+#ifdef NET_21
+ sock->state = SS_UNCONNECTED;
+#endif /* NET_21 */
+ MOD_INC_USE_COUNT;
+#ifdef NET_21
+ if((sk=(struct sock *)sk_alloc(PF_KEY, GFP_KERNEL, 1)) == NULL)
+#else /* NET_21 */
+ if((sk=(struct sock *)sk_alloc(GFP_KERNEL)) == NULL)
+#endif /* NET_21 */
+ {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_create: "
+ "Out of memory trying to allocate.\n");
+ MOD_DEC_USE_COUNT;
+ return -ENOMEM;
+ }
+
+#ifndef NET_21
+ memset(sk, 0, sizeof(*sk));
+#endif /* !NET_21 */
+
+#ifdef NET_21
+ sock_init_data(sock, sk);
+
+ sk->destruct = NULL;
+ sk->reuse = 1;
+ sock->ops = &pfkey_ops;
+
+ sk->zapped=0;
+ sk->family = PF_KEY;
+/* sk->num = protocol; */
+ sk->protocol = protocol;
+ key_pid(sk) = current->pid;
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_create: "
+ "sock->fasync_list=0p%p sk->sleep=0p%p.\n",
+ sock->fasync_list,
+ sk->sleep);
+#else /* NET_21 */
+ sk->type=sock->type;
+ init_timer(&sk->timer);
+ skb_queue_head_init(&sk->write_queue);
+ skb_queue_head_init(&sk->receive_queue);
+ skb_queue_head_init(&sk->back_log);
+ sk->rcvbuf=SK_RMEM_MAX;
+ sk->sndbuf=SK_WMEM_MAX;
+ sk->allocation=GFP_KERNEL;
+ sk->state=TCP_CLOSE;
+ sk->priority=SOPRI_NORMAL;
+ sk->state_change=pfkey_state_change;
+ sk->data_ready=pfkey_data_ready;
+ sk->write_space=pfkey_write_space;
+ sk->error_report=pfkey_state_change;
+ sk->mtu=4096;
+ sk->socket=sock;
+ sock->data=(void *)sk;
+ sk->sleep=sock->wait;
+#endif /* NET_21 */
+
+ pfkey_insert_socket(sk);
+ pfkey_list_insert_socket(sock, &pfkey_open_sockets);
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_create: "
+ "Socket sock=0p%p sk=0p%p initialised.\n", sock, sk);
+ return 0;
+}
+
+#ifndef NET_21
+DEBUG_NO_STATIC int
+pfkey_dup(struct socket *newsock, struct socket *oldsock)
+{
+ struct sock *sk;
+
+ if(newsock==NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_dup: "
+ "No new socket attached.\n");
+ return -EINVAL;
+ }
+
+ if(oldsock==NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_dup: "
+ "No old socket attached.\n");
+ return -EINVAL;
+ }
+
+#ifdef NET_21
+ sk=oldsock->sk;
+#else /* NET_21 */
+ sk=oldsock->data;
+#endif /* NET_21 */
+
+ /* May not have data attached */
+ if(sk==NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_dup: "
+ "No sock attached to old socket.\n");
+ return -EINVAL;
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_dup: .\n");
+
+ return pfkey_create(newsock, sk->protocol);
+}
+#endif /* !NET_21 */
+
+DEBUG_NO_STATIC int
+#ifdef NETDEV_23
+pfkey_release(struct socket *sock)
+#else /* NETDEV_23 */
+pfkey_release(struct socket *sock, struct socket *peersock)
+#endif /* NETDEV_23 */
+{
+ struct sock *sk;
+ int i;
+
+ if(sock==NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_release: "
+ "No socket attached.\n");
+ return 0; /* -EINVAL; */
+ }
+
+#ifdef NET_21
+ sk=sock->sk;
+#else /* NET_21 */
+ sk=sock->data;
+#endif /* NET_21 */
+
+ /* May not have data attached */
+ if(sk==NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_release: "
+ "No sk attached to sock=0p%p.\n", sock);
+ return 0; /* -EINVAL; */
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_release: "
+ "sock=0p%p sk=0p%p\n", sock, sk);
+
+#ifdef NET_21
+ if(!sk->dead)
+#endif /* NET_21 */
+ if(sk->state_change) {
+ sk->state_change(sk);
+ }
+
+#ifdef NET_21
+ sock->sk = NULL;
+#else /* NET_21 */
+ sock->data = NULL;
+#endif /* NET_21 */
+
+ /* Try to flush out this socket. Throw out buffers at least */
+ 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]));
+ }
+
+ MOD_DEC_USE_COUNT;
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_release: "
+ "succeeded.\n");
+
+ return 0;
+}
+
+#ifndef NET_21
+DEBUG_NO_STATIC int
+pfkey_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
+{
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_bind: "
+ "operation not supported.\n");
+ return -EINVAL;
+}
+
+DEBUG_NO_STATIC int
+pfkey_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags)
+{
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_connect: "
+ "operation not supported.\n");
+ return -EINVAL;
+}
+
+DEBUG_NO_STATIC int
+pfkey_socketpair(struct socket *a, struct socket *b)
+{
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_socketpair: "
+ "operation not supported.\n");
+ return -EINVAL;
+}
+
+DEBUG_NO_STATIC int
+pfkey_accept(struct socket *sock, struct socket *newsock, int flags)
+{
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_aaccept: "
+ "operation not supported.\n");
+ return -EINVAL;
+}
+
+DEBUG_NO_STATIC int
+pfkey_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len,
+ int peer)
+{
+ struct sockaddr *ska = (struct sockaddr*)uaddr;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_getname: .\n");
+ ska->sa_family = PF_KEY;
+ *uaddr_len = sizeof(*ska);
+ return 0;
+}
+
+DEBUG_NO_STATIC int
+pfkey_select(struct socket *sock, int sel_type, select_table *wait)
+{
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_select: "
+ ".sock=0p%p sk=0p%p sel_type=%d\n",
+ sock,
+ sock->data,
+ sel_type);
+ if(sock == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_select: "
+ "Null socket passed in.\n");
+ return -EINVAL;
+ }
+ return datagram_select(sock->data, sel_type, wait);
+}
+
+DEBUG_NO_STATIC int
+pfkey_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ioctl: "
+ "not supported.\n");
+ return -EINVAL;
+}
+
+DEBUG_NO_STATIC int
+pfkey_listen(struct socket *sock, int backlog)
+{
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_listen: "
+ "not supported.\n");
+ return -EINVAL;
+}
+#endif /* !NET_21 */
+
+DEBUG_NO_STATIC int
+pfkey_shutdown(struct socket *sock, int mode)
+{
+ struct sock *sk;
+
+ if(sock == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_shutdown: "
+ "NULL socket passed in.\n");
+ return -EINVAL;
+ }
+
+#ifdef NET_21
+ sk=sock->sk;
+#else /* NET_21 */
+ sk=sock->data;
+#endif /* NET_21 */
+
+ if(sk == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_shutdown: "
+ "No sock attached to socket.\n");
+ return -EINVAL;
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_shutdown: "
+ "mode=%x.\n", mode);
+ mode++;
+
+ if(mode&SEND_SHUTDOWN) {
+ sk->shutdown|=SEND_SHUTDOWN;
+ sk->state_change(sk);
+ }
+
+ if(mode&RCV_SHUTDOWN) {
+ sk->shutdown|=RCV_SHUTDOWN;
+ sk->state_change(sk);
+ }
+ return 0;
+}
+
+#ifndef NET_21
+DEBUG_NO_STATIC int
+pfkey_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
+{
+#ifndef NET_21
+ struct sock *sk;
+
+ if(sock == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_setsockopt: "
+ "Null socket passed in.\n");
+ return -EINVAL;
+ }
+
+ sk=sock->data;
+
+ if(sk == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_setsockopt: "
+ "Null sock passed in.\n");
+ return -EINVAL;
+ }
+#endif /* !NET_21 */
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_setsockopt: .\n");
+ if(level!=SOL_SOCKET) {
+ return -EOPNOTSUPP;
+ }
+#ifdef NET_21
+ return sock_setsockopt(sock, level, optname, optval, optlen);
+#else /* NET_21 */
+ return sock_setsockopt(sk, level, optname, optval, optlen);
+#endif /* NET_21 */
+}
+
+DEBUG_NO_STATIC int
+pfkey_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
+{
+#ifndef NET_21
+ struct sock *sk;
+
+ if(sock == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_setsockopt: "
+ "Null socket passed in.\n");
+ return -EINVAL;
+ }
+
+ sk=sock->data;
+
+ if(sk == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_setsockopt: "
+ "Null sock passed in.\n");
+ return -EINVAL;
+ }
+#endif /* !NET_21 */
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_getsockopt: .\n");
+ if(level!=SOL_SOCKET) {
+ return -EOPNOTSUPP;
+ }
+#ifdef NET_21
+ return sock_getsockopt(sock, level, optname, optval, optlen);
+#else /* NET_21 */
+ return sock_getsockopt(sk, level, optname, optval, optlen);
+#endif /* NET_21 */
+}
+
+DEBUG_NO_STATIC int
+pfkey_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_fcntl: "
+ "not supported.\n");
+ return -EINVAL;
+}
+#endif /* !NET_21 */
+
+/*
+ * Send PF_KEY data down.
+ */
+
+DEBUG_NO_STATIC int
+#ifdef NET_21
+pfkey_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
+#else /* NET_21 */
+pfkey_sendmsg(struct socket *sock, struct msghdr *msg, int len, int nonblock, int flags)
+#endif /* NET_21 */
+{
+ struct sock *sk;
+ int error = 0;
+ struct sadb_msg *pfkey_msg = NULL, *pfkey_reply = NULL;
+
+ if(sock == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "Null socket passed in.\n");
+ SENDERR(EINVAL);
+ }
+
+#ifdef NET_21
+ sk = sock->sk;
+#else /* NET_21 */
+ sk = sock->data;
+#endif /* NET_21 */
+
+ if(sk == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "Null sock passed in.\n");
+ SENDERR(EINVAL);
+ }
+
+ if(msg == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "Null msghdr passed in.\n");
+ SENDERR(EINVAL);
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: .\n");
+ if(sk->err) {
+ error = sock_error(sk);
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "sk->err is non-zero, returns %d.\n",
+ error);
+ SENDERR(-error);
+ }
+
+ if((current->uid != 0)) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "must be root to send messages to pfkey sockets.\n");
+ SENDERR(EACCES);
+ }
+
+#ifdef NET_21
+ if(msg->msg_control)
+#else /* NET_21 */
+ if(flags || msg->msg_control)
+#endif /* NET_21 */
+ {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "can't set flags or set msg_control.\n");
+ SENDERR(EINVAL);
+ }
+
+ if(sk->shutdown & SEND_SHUTDOWN) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "shutdown.\n");
+ send_sig(SIGPIPE, current, 0);
+ SENDERR(EPIPE);
+ }
+
+ if(len < sizeof(struct sadb_msg)) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "bogus msg len of %d, too small.\n", len);
+ SENDERR(EMSGSIZE);
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "allocating %d bytes for downward message.\n",
+ len);
+ if((pfkey_msg = (struct sadb_msg*)kmalloc(len, GFP_KERNEL)) == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "memory allocation error.\n");
+ SENDERR(ENOBUFS);
+ }
+
+ memcpy_fromiovec((void *)pfkey_msg, msg->msg_iov, len);
+
+ if(pfkey_msg->sadb_msg_version != PF_KEY_V2) {
+ KLIPS_PRINT(1 || debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "not PF_KEY_V2 msg, found %d, should be %d.\n",
+ pfkey_msg->sadb_msg_version,
+ PF_KEY_V2);
+ kfree((void*)pfkey_msg);
+ return -EINVAL;
+ }
+
+ if(len != pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "bogus msg len of %d, not %d byte aligned.\n",
+ len, (int)IPSEC_PFKEYv2_ALIGN);
+ SENDERR(EMSGSIZE);
+ }
+
+#if 0
+ /* This check is questionable, since a downward message could be
+ the result of an ACQUIRE either from kernel (PID==0) or
+ userspace (some other PID). */
+ /* check PID */
+ if(pfkey_msg->sadb_msg_pid != current->pid) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "pid (%d) does not equal sending process pid (%d).\n",
+ pfkey_msg->sadb_msg_pid, current->pid);
+ SENDERR(EINVAL);
+ }
+#endif
+
+ if(pfkey_msg->sadb_msg_reserved) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "reserved field must be zero, set to %d.\n",
+ pfkey_msg->sadb_msg_reserved);
+ SENDERR(EINVAL);
+ }
+
+ if((pfkey_msg->sadb_msg_type > SADB_MAX) || (!pfkey_msg->sadb_msg_type)){
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "msg type too large or small:%d.\n",
+ pfkey_msg->sadb_msg_type);
+ SENDERR(EINVAL);
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "msg sent for parsing.\n");
+
+ if((error = pfkey_msg_interp(sk, pfkey_msg, &pfkey_reply))) {
+ struct socket_list *pfkey_socketsp;
+
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: "
+ "pfkey_msg_parse returns %d.\n",
+ error);
+
+ if((pfkey_reply = (struct sadb_msg*)kmalloc(sizeof(struct sadb_msg), GFP_KERNEL)) == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "memory allocation error.\n");
+ SENDERR(ENOBUFS);
+ }
+ memcpy((void*)pfkey_reply, (void*)pfkey_msg, sizeof(struct sadb_msg));
+ pfkey_reply->sadb_msg_errno = -error;
+ pfkey_reply->sadb_msg_len = sizeof(struct sadb_msg) / IPSEC_PFKEYv2_ALIGN;
+
+ for(pfkey_socketsp = pfkey_open_sockets;
+ pfkey_socketsp;
+ pfkey_socketsp = pfkey_socketsp->next) {
+ int error_upmsg = 0;
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: "
+ "sending up error=%d message=0p%p to socket=0p%p.\n",
+ error,
+ pfkey_reply,
+ pfkey_socketsp->socketp);
+ if((error_upmsg = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: "
+ "sending up error message to socket=0p%p failed with error=%d.\n",
+ pfkey_socketsp->socketp,
+ error_upmsg);
+ /* pfkey_msg_free(&pfkey_reply); */
+ /* SENDERR(-error); */
+ }
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: "
+ "sending up error message to socket=0p%p succeeded.\n",
+ pfkey_socketsp->socketp);
+ }
+
+ pfkey_msg_free(&pfkey_reply);
+
+ SENDERR(-error);
+ }
+
+ errlab:
+ if (pfkey_msg) {
+ kfree((void*)pfkey_msg);
+ }
+
+ if(error) {
+ return error;
+ } else {
+ return len;
+ }
+}
+
+/*
+ * Receive PF_KEY data up.
+ */
+
+DEBUG_NO_STATIC int
+#ifdef NET_21
+pfkey_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags, struct scm_cookie *scm)
+#else /* NET_21 */
+pfkey_recvmsg(struct socket *sock, struct msghdr *msg, int size, int noblock, int flags, int *addr_len)
+#endif /* NET_21 */
+{
+ struct sock *sk;
+#ifdef NET_21
+ int noblock = flags & MSG_DONTWAIT;
+#endif /* NET_21 */
+ struct sk_buff *skb;
+ int error;
+
+ if(sock == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_recvmsg: "
+ "Null socket passed in.\n");
+ return -EINVAL;
+ }
+
+#ifdef NET_21
+ sk = sock->sk;
+#else /* NET_21 */
+ sk = sock->data;
+#endif /* NET_21 */
+
+ if(sk == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_recvmsg: "
+ "Null sock passed in for sock=0p%p.\n", sock);
+ return -EINVAL;
+ }
+
+ if(msg == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_recvmsg: "
+ "Null msghdr passed in for sock=0p%p, sk=0p%p.\n",
+ sock, sk);
+ return -EINVAL;
+ }
+
+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
+ "klips_debug:pfkey_recvmsg: sock=0p%p sk=0p%p msg=0p%p size=%d.\n",
+ sock, sk, msg, size);
+ if(flags & ~MSG_PEEK) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "flags (%d) other than MSG_PEEK not supported.\n",
+ flags);
+ return -EOPNOTSUPP;
+ }
+
+#ifdef NET_21
+ msg->msg_namelen = 0; /* sizeof(*ska); */
+#else /* NET_21 */
+ if(addr_len) {
+ *addr_len = 0; /* sizeof(*ska); */
+ }
+#endif /* NET_21 */
+
+ if(sk->err) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "sk->err=%d.\n", sk->err);
+ return sock_error(sk);
+ }
+
+ if((skb = skb_recv_datagram(sk, flags, noblock, &error) ) == NULL) {
+ return error;
+ }
+
+ if(size > skb->len) {
+ size = skb->len;
+ }
+#ifdef NET_21
+ else if(size <skb->len) {
+ msg->msg_flags |= MSG_TRUNC;
+ }
+#endif /* NET_21 */
+
+ skb_copy_datagram_iovec(skb, 0, msg->msg_iov, size);
+ sk->stamp=skb->stamp;
+
+ skb_free_datagram(sk, skb);
+ return size;
+}
+
+#ifdef NET_21
+struct net_proto_family pfkey_family_ops = {
+ PF_KEY,
+ pfkey_create
+};
+
+struct proto_ops SOCKOPS_WRAPPED(pfkey_ops) = {
+#ifdef NETDEV_23
+ 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,
+#else /* NETDEV_23 */
+ PF_KEY,
+ sock_no_dup,
+ pfkey_release,
+ sock_no_bind,
+ sock_no_connect,
+ sock_no_socketpair,
+ sock_no_accept,
+ sock_no_getname,
+ datagram_poll,
+ sock_no_ioctl,
+ sock_no_listen,
+ pfkey_shutdown,
+ sock_no_setsockopt,
+ sock_no_getsockopt,
+ sock_no_fcntl,
+ pfkey_sendmsg,
+ pfkey_recvmsg
+#endif /* NETDEV_23 */
+};
+
+#ifdef NETDEV_23
+#include <linux/smp_lock.h>
+SOCKOPS_WRAP(pfkey, PF_KEY);
+#endif /* NETDEV_23 */
+
+#else /* NET_21 */
+struct proto_ops pfkey_proto_ops = {
+ PF_KEY,
+ pfkey_create,
+ pfkey_dup,
+ pfkey_release,
+ pfkey_bind,
+ pfkey_connect,
+ pfkey_socketpair,
+ pfkey_accept,
+ pfkey_getname,
+ pfkey_select,
+ pfkey_ioctl,
+ pfkey_listen,
+ pfkey_shutdown,
+ pfkey_setsockopt,
+ pfkey_getsockopt,
+ pfkey_fcntl,
+ pfkey_sendmsg,
+ pfkey_recvmsg
+};
+#endif /* NET_21 */
+
+#ifdef CONFIG_PROC_FS
+#ifndef PROC_FS_2325
+DEBUG_NO_STATIC
+#endif /* PROC_FS_2325 */
+int
+pfkey_get_info(char *buffer, char **start, off_t offset, int length
+#ifndef PROC_NO_DUMMY
+, int dummy
+#endif /* !PROC_NO_DUMMY */
+)
+{
+ const int max_content = length > 0? length-1 : 0;
+
+ off_t begin=0;
+ int len=0;
+ struct sock *sk=pfkey_sock_list;
+
+#ifdef CONFIG_IPSEC_DEBUG
+ if(!sysctl_ipsec_debug_verbose) {
+#endif /* CONFIG_IPSEC_DEBUG */
+ len+= snprintf(buffer,length,
+ " sock pid socket next prev e n p sndbf Flags Type St\n");
+#ifdef CONFIG_IPSEC_DEBUG
+ } else {
+ len+= snprintf(buffer,length,
+ " sock pid d sleep socket next prev e r z n p sndbf stamp Flags Type St\n");
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+
+ while(sk!=NULL) {
+#ifdef CONFIG_IPSEC_DEBUG
+ if(!sysctl_ipsec_debug_verbose) {
+#endif /* CONFIG_IPSEC_DEBUG */
+ len += ipsec_snprintf(buffer+len, length-len,
+ "%8p %5d %8p %8p %8p %d %d %d %5d %08lX %8X %2X\n",
+ sk,
+ key_pid(sk),
+ sk->socket,
+ sk->next,
+ sk->prev,
+ sk->err,
+ sk->num,
+ sk->protocol,
+ sk->sndbuf,
+ sk->socket->flags,
+ sk->socket->type,
+ sk->socket->state);
+#ifdef CONFIG_IPSEC_DEBUG
+ } else {
+ len += ipsec_snprintf(buffer+len, length-len,
+ "%8p %5d %d %8p %8p %8p %8p %d %d %d %d %d %5d %d.%06d %08lX %8X %2X\n",
+ sk,
+ key_pid(sk),
+ sk->dead,
+ sk->sleep,
+ sk->socket,
+ sk->next,
+ sk->prev,
+ sk->err,
+ sk->reuse,
+ sk->zapped,
+ sk->num,
+ sk->protocol,
+ sk->sndbuf,
+ (unsigned int)sk->stamp.tv_sec,
+ (unsigned int)sk->stamp.tv_usec,
+ sk->socket->flags,
+ sk->socket->type,
+ sk->socket->state);
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+
+ if (len >= max_content) {
+ /* we've done all that can fit -- stop loop */
+ len = max_content; /* truncate crap */
+ break;
+ } else {
+ const off_t pos = begin + len; /* file position of end of what we've generated */
+
+ if (pos <= offset) {
+ /* all is before first interesting character:
+ * discard, but note where we are.
+ */
+ len = 0;
+ begin = pos;
+ }
+ }
+ sk=sk->next;
+ }
+
+ *start = buffer + (offset - begin); /* Start of wanted data */
+ return len - (offset - begin);
+}
+
+#ifndef PROC_FS_2325
+DEBUG_NO_STATIC
+#endif /* PROC_FS_2325 */
+int
+pfkey_supported_get_info(char *buffer, char **start, off_t offset, int length
+#ifndef PROC_NO_DUMMY
+, int dummy
+#endif /* !PROC_NO_DUMMY */
+)
+{
+ const int max_content = length > 0? length-1 : 0;
+
+ off_t begin=0;
+ int len=0;
+ int satype;
+ struct supported_list *pfkey_supported_p;
+
+ len += ipsec_snprintf(buffer, length,
+ "satype exttype alg_id ivlen minbits maxbits\n");
+
+ for(satype = SADB_SATYPE_UNSPEC; satype <= SADB_SATYPE_MAX; satype++) {
+ pfkey_supported_p = pfkey_supported_list[satype];
+ while(pfkey_supported_p) {
+ len += ipsec_snprintf(buffer+len, length-len,
+ " %2d %2d %2d %3d %3d %3d\n",
+ satype,
+ pfkey_supported_p->supportedp->supported_alg_exttype,
+ pfkey_supported_p->supportedp->supported_alg_id,
+ pfkey_supported_p->supportedp->supported_alg_ivlen,
+ pfkey_supported_p->supportedp->supported_alg_minbits,
+ pfkey_supported_p->supportedp->supported_alg_maxbits);
+
+ if (len >= max_content) {
+ /* we've done all that can fit -- stop loop */
+ len = max_content; /* truncate crap */
+ break;
+ } else {
+ const off_t pos = begin + len; /* file position of end of what we've generated */
+
+ if (pos <= offset) {
+ /* all is before first interesting character:
+ * discard, but note where we are.
+ */
+ len = 0;
+ begin = pos;
+ }
+ }
+
+ pfkey_supported_p = pfkey_supported_p->next;
+ }
+ }
+
+ *start = buffer + (offset - begin); /* Start of wanted data */
+ return len - (offset - begin);
+}
+
+#ifndef PROC_FS_2325
+DEBUG_NO_STATIC
+#endif /* PROC_FS_2325 */
+int
+pfkey_registered_get_info(char *buffer, char **start, off_t offset, int length
+#ifndef PROC_NO_DUMMY
+, int dummy
+#endif /* !PROC_NO_DUMMY */
+)
+{
+ const int max_content = length > 0? length-1 : 0;
+
+ off_t begin=0;
+ int len=0;
+ int satype;
+ struct socket_list *pfkey_sockets;
+
+ len += ipsec_snprintf(buffer, length,
+ "satype socket pid sk\n");
+
+ for(satype = SADB_SATYPE_UNSPEC; satype <= SADB_SATYPE_MAX; satype++) {
+ pfkey_sockets = pfkey_registered_sockets[satype];
+ while(pfkey_sockets) {
+#ifdef NET_21
+ len += ipsec_snprintf(buffer+len, length-len,
+ " %2d %8p %5d %8p\n",
+ satype,
+ pfkey_sockets->socketp,
+ key_pid(pfkey_sockets->socketp->sk),
+ pfkey_sockets->socketp->sk);
+#else /* NET_21 */
+ len += ipsec_snprintf(buffer+len, length-len,
+ " %2d %8p N/A %8p\n",
+ satype,
+ pfkey_sockets->socketp,
+#if 0
+ key_pid((pfkey_sockets->socketp)->data),
+#endif
+ (pfkey_sockets->socketp)->data);
+#endif /* NET_21 */
+
+ if (len >= max_content) {
+ /* we've done all that can fit -- stop loop (could stop two) */
+ len = max_content; /* truncate crap */
+ break;
+ } else {
+ const off_t pos = begin + len; /* file position of end of what we've generated */
+
+ if (pos <= offset) {
+ /* all is before first interesting character:
+ * discard, but note where we are.
+ */
+ len = 0;
+ begin = pos;
+ }
+ }
+
+ pfkey_sockets = pfkey_sockets->next;
+ }
+ }
+
+ *start = buffer + (offset - begin); /* Start of wanted data */
+ return len - (offset - begin);
+}
+
+#ifndef PROC_FS_2325
+struct proc_dir_entry proc_net_pfkey =
+{
+ 0,
+ 6, "pf_key",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ pfkey_get_info
+};
+struct proc_dir_entry proc_net_pfkey_supported =
+{
+ 0,
+ 16, "pf_key_supported",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ pfkey_supported_get_info
+};
+struct proc_dir_entry proc_net_pfkey_registered =
+{
+ 0,
+ 17, "pf_key_registered",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ pfkey_registered_get_info
+};
+#endif /* !PROC_FS_2325 */
+#endif /* CONFIG_PROC_FS */
+
+DEBUG_NO_STATIC int
+supported_add_all(int satype, struct supported supported[], int size)
+{
+ int i;
+ int error = 0;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:init_pfkey: "
+ "sizeof(supported_init_<satype=%d>)[%d]/sizeof(struct supported)[%d]=%d.\n",
+ satype,
+ size,
+ (int)sizeof(struct supported),
+ (int)(size/sizeof(struct supported)));
+
+ for(i = 0; i < size / sizeof(struct supported); i++) {
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:init_pfkey: "
+ "i=%d inserting satype=%d exttype=%d id=%d ivlen=%d minbits=%d maxbits=%d.\n",
+ i,
+ satype,
+ supported[i].supported_alg_exttype,
+ supported[i].supported_alg_id,
+ supported[i].supported_alg_ivlen,
+ supported[i].supported_alg_minbits,
+ supported[i].supported_alg_maxbits);
+
+ error |= pfkey_list_insert_supported(&(supported[i]),
+ &(pfkey_supported_list[satype]));
+ }
+ return error;
+}
+
+DEBUG_NO_STATIC int
+supported_remove_all(int satype)
+{
+ int error = 0;
+ struct supported*supportedp;
+
+ while(pfkey_supported_list[satype]) {
+ supportedp = pfkey_supported_list[satype]->supportedp;
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:init_pfkey: "
+ "removing satype=%d exttype=%d id=%d ivlen=%d minbits=%d maxbits=%d.\n",
+ satype,
+ supportedp->supported_alg_exttype,
+ supportedp->supported_alg_id,
+ supportedp->supported_alg_ivlen,
+ supportedp->supported_alg_minbits,
+ supportedp->supported_alg_maxbits);
+
+ error |= pfkey_list_remove_supported(supportedp,
+ &(pfkey_supported_list[satype]));
+ }
+ return error;
+}
+
+int
+pfkey_init(void)
+{
+ int error = 0;
+ int i;
+
+ static struct supported supported_init_ah[] = {
+#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
+ {SADB_EXT_SUPPORTED_AUTH, SADB_AALG_MD5_HMAC, 0, 128, 128},
+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
+#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
+ {SADB_EXT_SUPPORTED_AUTH, SADB_AALG_SHA1_HMAC, 0, 160, 160}
+#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
+ };
+ static struct supported supported_init_esp[] = {
+#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
+ {SADB_EXT_SUPPORTED_AUTH, SADB_AALG_MD5_HMAC, 0, 128, 128},
+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
+#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
+ {SADB_EXT_SUPPORTED_AUTH, SADB_AALG_SHA1_HMAC, 0, 160, 160},
+#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
+#ifdef CONFIG_IPSEC_ENC_3DES
+ {SADB_EXT_SUPPORTED_ENCRYPT, SADB_EALG_3DES_CBC, 64, 168, 168},
+#endif /* CONFIG_IPSEC_ENC_3DES */
+ };
+ static struct supported supported_init_ipip[] = {
+ {SADB_EXT_SUPPORTED_ENCRYPT, SADB_X_TALG_IPv4_in_IPv4, 0, 32, 32}
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ , {SADB_EXT_SUPPORTED_ENCRYPT, SADB_X_TALG_IPv6_in_IPv4, 0, 128, 32}
+ , {SADB_EXT_SUPPORTED_ENCRYPT, SADB_X_TALG_IPv4_in_IPv6, 0, 32, 128}
+ , {SADB_EXT_SUPPORTED_ENCRYPT, SADB_X_TALG_IPv6_in_IPv6, 0, 128, 128}
+#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
+ };
+#ifdef CONFIG_IPSEC_IPCOMP
+ static struct supported supported_init_ipcomp[] = {
+ {SADB_EXT_SUPPORTED_ENCRYPT, SADB_X_CALG_DEFLATE, 0, 1, 1}
+ };
+#endif /* CONFIG_IPSEC_IPCOMP */
+
+#if 0
+ printk(KERN_INFO
+ "klips_info:pfkey_init: "
+ "FreeS/WAN: initialising PF_KEYv2 domain sockets.\n");
+#endif
+
+ for(i = SADB_SATYPE_UNSPEC; i <= SADB_SATYPE_MAX; i++) {
+ pfkey_registered_sockets[i] = NULL;
+ pfkey_supported_list[i] = NULL;
+ }
+
+ error |= supported_add_all(SADB_SATYPE_AH, supported_init_ah, sizeof(supported_init_ah));
+ error |= supported_add_all(SADB_SATYPE_ESP, supported_init_esp, sizeof(supported_init_esp));
+#ifdef CONFIG_IPSEC_IPCOMP
+ error |= supported_add_all(SADB_X_SATYPE_COMP, supported_init_ipcomp, sizeof(supported_init_ipcomp));
+#endif /* CONFIG_IPSEC_IPCOMP */
+ error |= supported_add_all(SADB_X_SATYPE_IPIP, supported_init_ipip, sizeof(supported_init_ipip));
+
+#ifdef NET_21
+ error |= sock_register(&pfkey_family_ops);
+#else /* NET_21 */
+ error |= sock_register(pfkey_proto_ops.family, &pfkey_proto_ops);
+#endif /* NET_21 */
+
+#ifdef CONFIG_PROC_FS
+# ifndef PROC_FS_2325
+# ifdef PROC_FS_21
+ error |= proc_register(proc_net, &proc_net_pfkey);
+ error |= proc_register(proc_net, &proc_net_pfkey_supported);
+ error |= proc_register(proc_net, &proc_net_pfkey_registered);
+# else /* PROC_FS_21 */
+ error |= proc_register_dynamic(&proc_net, &proc_net_pfkey);
+ error |= proc_register_dynamic(&proc_net, &proc_net_pfkey_supported);
+ error |= proc_register_dynamic(&proc_net, &proc_net_pfkey_registered);
+# endif /* PROC_FS_21 */
+# else /* !PROC_FS_2325 */
+ proc_net_create ("pf_key", 0, pfkey_get_info);
+ proc_net_create ("pf_key_supported", 0, pfkey_supported_get_info);
+ proc_net_create ("pf_key_registered", 0, pfkey_registered_get_info);
+# endif /* !PROC_FS_2325 */
+#endif /* CONFIG_PROC_FS */
+
+ return error;
+}
+
+int
+pfkey_cleanup(void)
+{
+ int error = 0;
+
+ printk(KERN_INFO "klips_info:pfkey_cleanup: "
+ "shutting down PF_KEY domain sockets.\n");
+#ifdef NET_21
+ error |= sock_unregister(PF_KEY);
+#else /* NET_21 */
+ error |= sock_unregister(pfkey_proto_ops.family);
+#endif /* NET_21 */
+
+ error |= supported_remove_all(SADB_SATYPE_AH);
+ error |= supported_remove_all(SADB_SATYPE_ESP);
+#ifdef CONFIG_IPSEC_IPCOMP
+ error |= supported_remove_all(SADB_X_SATYPE_COMP);
+#endif /* CONFIG_IPSEC_IPCOMP */
+ error |= supported_remove_all(SADB_X_SATYPE_IPIP);
+
+#ifdef CONFIG_PROC_FS
+# ifndef PROC_FS_2325
+ if (proc_net_unregister(proc_net_pfkey.low_ino) != 0)
+ printk("klips_debug:pfkey_cleanup: "
+ "cannot unregister /proc/net/pf_key\n");
+ if (proc_net_unregister(proc_net_pfkey_supported.low_ino) != 0)
+ printk("klips_debug:pfkey_cleanup: "
+ "cannot unregister /proc/net/pf_key_supported\n");
+ if (proc_net_unregister(proc_net_pfkey_registered.low_ino) != 0)
+ printk("klips_debug:pfkey_cleanup: "
+ "cannot unregister /proc/net/pf_key_registered\n");
+# else /* !PROC_FS_2325 */
+ proc_net_remove ("pf_key");
+ proc_net_remove ("pf_key_supported");
+ proc_net_remove ("pf_key_registered");
+# endif /* !PROC_FS_2325 */
+#endif /* CONFIG_PROC_FS */
+
+ /* other module unloading cleanup happens here */
+ return error;
+}
+
+#ifdef MODULE
+#if 0
+int
+init_module(void)
+{
+ pfkey_init();
+ return 0;
+}
+
+void
+cleanup_module(void)
+{
+ pfkey_cleanup();
+}
+#endif /* 0 */
+#else /* MODULE */
+void
+pfkey_proto_init(struct net_proto *pro)
+{
+ pfkey_init();
+}
+#endif /* MODULE */
+
+/*
+ * $Log: pfkey_v2.c,v $
+ * Revision 1.4 2004/09/29 22:27:41 as
+ * changed SADB identifiers
+ *
+ * Revision 1.3 2004/04/28 08:06:22 as
+ * added dhr's freeswan-2.06 changes
+ *
+ * Revision 1.2 2004/03/22 21:53:19 as
+ * merged alg-0.8.1 branch with HEAD
+ *
+ * Revision 1.1.4.1 2004/03/16 09:48:20 as
+ * alg-0.8.1rc12 patch merged
+ *
+ * Revision 1.1 2004/03/15 20:35:26 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.78 2003/04/03 17:38:09 rgb
+ * Centralised ipsec_kfree_skb and ipsec_dev_{get,put}.
+ *
+ * Revision 1.77 2002/10/17 16:49:36 mcr
+ * sock->ops should reference the unwrapped options so that
+ * we get hacked in locking on SMP systems.
+ *
+ * Revision 1.76 2002/10/12 23:11:53 dhr
+ *
+ * [KenB + DHR] more 64-bit cleanup
+ *
+ * Revision 1.75 2002/09/20 05:01:57 rgb
+ * Added memory allocation debugging.
+ *
+ * Revision 1.74 2002/09/19 02:42:50 mcr
+ * do not define the pfkey_ops function for now.
+ *
+ * Revision 1.73 2002/09/17 17:29:23 mcr
+ * #if 0 out some dead code - pfkey_ops is never used as written.
+ *
+ * Revision 1.72 2002/07/24 18:44:54 rgb
+ * Type fiddling to tame ia64 compiler.
+ *
+ * Revision 1.71 2002/05/23 07:14:11 rgb
+ * Cleaned up %p variants to 0p%p for test suite cleanup.
+ *
+ * Revision 1.70 2002/04/24 07:55:32 mcr
+ * #include patches and Makefiles for post-reorg compilation.
+ *
+ * Revision 1.69 2002/04/24 07:36:33 mcr
+ * Moved from ./klips/net/ipsec/pfkey_v2.c,v
+ *
+ * Revision 1.68 2002/03/08 01:15:17 mcr
+ * put some internal structure only debug messages behind
+ * && sysctl_ipsec_debug_verbose.
+ *
+ * Revision 1.67 2002/01/29 17:17:57 mcr
+ * moved include of ipsec_param.h to after include of linux/kernel.h
+ * otherwise, it seems that some option that is set in ipsec_param.h
+ * screws up something subtle in the include path to kernel.h, and
+ * it complains on the snprintf() prototype.
+ *
+ * Revision 1.66 2002/01/29 04:00:54 mcr
+ * more excise of kversions.h header.
+ *
+ * Revision 1.65 2002/01/29 02:13:18 mcr
+ * introduction of ipsec_kversion.h means that include of
+ * ipsec_param.h must preceed any decisions about what files to
+ * include to deal with differences in kernel source.
+ *
+ * Revision 1.64 2001/11/26 09:23:51 rgb
+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
+ *
+ * Revision 1.61.2.1 2001/09/25 02:28:44 mcr
+ * cleaned up includes.
+ *
+ * Revision 1.63 2001/11/12 19:38:00 rgb
+ * Continue trying other sockets even if one fails and return only original
+ * error.
+ *
+ * Revision 1.62 2001/10/18 04:45:22 rgb
+ * 2.4.9 kernel deprecates linux/malloc.h in favour of linux/slab.h,
+ * lib/freeswan.h version macros moved to lib/kversions.h.
+ * Other compiler directive cleanups.
+ *
+ * Revision 1.61 2001/09/20 15:32:59 rgb
+ * Min/max cleanup.
+ *
+ * Revision 1.60 2001/06/14 19:35:12 rgb
+ * Update copyright date.
+ *
+ * Revision 1.59 2001/06/13 15:35:48 rgb
+ * Fixed #endif comments.
+ *
+ * Revision 1.58 2001/05/04 16:37:24 rgb
+ * Remove erroneous checking of return codes for proc_net_* in 2.4.
+ *
+ * Revision 1.57 2001/05/03 19:43:36 rgb
+ * Initialise error return variable.
+ * Check error return codes in startup and shutdown.
+ * Standardise on SENDERR() macro.
+ *
+ * Revision 1.56 2001/04/21 23:05:07 rgb
+ * Define out skb->used for 2.4 kernels.
+ *
+ * Revision 1.55 2001/02/28 05:03:28 rgb
+ * Clean up and rationalise startup messages.
+ *
+ * Revision 1.54 2001/02/27 22:24:55 rgb
+ * Re-formatting debug output (line-splitting, joining, 1arg/line).
+ * Check for satoa() return codes.
+ *
+ * Revision 1.53 2001/02/27 06:48:18 rgb
+ * Fixed pfkey socket unregister log message to reflect type and function.
+ *
+ * Revision 1.52 2001/02/26 22:34:38 rgb
+ * Fix error return code that was getting overwritten by the error return
+ * code of an upmsg.
+ *
+ * Revision 1.51 2001/01/30 23:42:47 rgb
+ * Allow pfkey msgs from pid other than user context required for ACQUIRE
+ * and subsequent ADD or UDATE.
+ *
+ * Revision 1.50 2001/01/23 20:22:59 rgb
+ * 2.4 fix to remove removed is_clone member.
+ *
+ * Revision 1.49 2000/11/06 04:33:47 rgb
+ * Changed non-exported functions to DEBUG_NO_STATIC.
+ *
+ * Revision 1.48 2000/09/29 19:47:41 rgb
+ * Update copyright.
+ *
+ * Revision 1.47 2000/09/22 04:23:04 rgb
+ * Added more debugging to pfkey_upmsg() call from pfkey_sendmsg() error.
+ *
+ * Revision 1.46 2000/09/21 04:20:44 rgb
+ * Fixed array size off-by-one error. (Thanks Svenning!)
+ *
+ * Revision 1.45 2000/09/20 04:01:26 rgb
+ * Changed static functions to DEBUG_NO_STATIC for revealing function names
+ * in oopsen.
+ *
+ * Revision 1.44 2000/09/19 00:33:17 rgb
+ * 2.0 fixes.
+ *
+ * Revision 1.43 2000/09/16 01:28:13 rgb
+ * Fixed use of 0 in p format warning.
+ *
+ * Revision 1.42 2000/09/16 01:09:41 rgb
+ * Fixed debug format warning for pointers that was expecting ints.
+ *
+ * Revision 1.41 2000/09/13 15:54:00 rgb
+ * Rewrote pfkey_get_info(), added pfkey_{supported,registered}_get_info().
+ * Moved supported algos add and remove to functions.
+ *
+ * Revision 1.40 2000/09/12 18:49:28 rgb
+ * Added IPIP tunnel and IPCOMP register support.
+ *
+ * Revision 1.39 2000/09/12 03:23:49 rgb
+ * Converted #if0 debugs to sysctl.
+ * Removed debug_pfkey initialisations that prevented no_debug loading or
+ * linking.
+ *
+ * Revision 1.38 2000/09/09 06:38:02 rgb
+ * Return positive errno in pfkey_reply error message.
+ *
+ * Revision 1.37 2000/09/08 19:19:09 rgb
+ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
+ * Clean-up of long-unused crud...
+ * Create pfkey error message on on failure.
+ * Give pfkey_list_{insert,remove}_{socket,supported}() some error
+ * checking.
+ *
+ * Revision 1.36 2000/09/01 18:49:38 rgb
+ * Reap experimental NET_21_ bits.
+ * Turned registered sockets list into an array of one list per satype.
+ * Remove references to deprecated sklist_{insert,remove}_socket.
+ * Removed leaking socket debugging code.
+ * Removed duplicate pfkey_insert_socket in pfkey_create.
+ * Removed all references to pfkey msg->msg_name, since it is not used for
+ * pfkey.
+ * 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.
+ * Only send pfkey_expire() messages to sockets registered for that satype.
+ *
+ * Revision 1.35 2000/08/24 17:03:00 rgb
+ * Corrected message size error return code for PF_KEYv2.
+ * Removed downward error prohibition.
+ *
+ * Revision 1.34 2000/08/21 16:32:26 rgb
+ * Re-formatted for cosmetic consistency and readability.
+ *
+ * Revision 1.33 2000/08/20 21:38:24 rgb
+ * Added a pfkey_reply parameter to pfkey_msg_interp(). (Momchil)
+ * Extended the upward message initiation of pfkey_sendmsg(). (Momchil)
+ *
+ * Revision 1.32 2000/07/28 14:58:31 rgb
+ * Changed kfree_s to kfree, eliminating extra arg to fix 2.4.0-test5.
+ *
+ * Revision 1.31 2000/05/16 03:04:00 rgb
+ * Updates for 2.3.99pre8 from MB.
+ *
+ * Revision 1.30 2000/05/10 19:22:21 rgb
+ * Use sklist private functions for 2.3.xx compatibility.
+ *
+ * Revision 1.29 2000/03/22 16:17:03 rgb
+ * Fixed SOCKOPS_WRAPPED macro for SMP (MB).
+ *
+ * Revision 1.28 2000/02/21 19:30:45 rgb
+ * Removed references to pkt_bridged for 2.3.47 compatibility.
+ *
+ * Revision 1.27 2000/02/14 21:07:00 rgb
+ * Fixed /proc/net/pf-key legend spacing.
+ *
+ * Revision 1.26 2000/01/22 03:46:59 rgb
+ * Fixed pfkey error return mechanism so that we are able to free the
+ * local copy of the pfkey_msg, plugging a memory leak and silencing
+ * the bad object free complaints.
+ *
+ * Revision 1.25 2000/01/21 06:19:44 rgb
+ * Moved pfkey_list_remove_socket() calls to before MOD_USE_DEC_COUNT.
+ * Added debugging to pfkey_upmsg.
+ *
+ * Revision 1.24 2000/01/10 16:38:23 rgb
+ * MB fixups for 2.3.x.
+ *
+ * Revision 1.23 1999/12/09 23:22:16 rgb
+ * Added more instrumentation for debugging 2.0 socket
+ * selection/reading.
+ * Removed erroneous 2.0 wait==NULL check bug in select.
+ *
+ * Revision 1.22 1999/12/08 20:32:16 rgb
+ * Tidied up 2.0.xx support, after major pfkey work, eliminating
+ * msg->msg_name twiddling in the process, since it is not defined
+ * for PF_KEYv2.
+ *
+ * Revision 1.21 1999/12/01 22:17:19 rgb
+ * Set skb->dev to zero on new skb in case it is a reused skb.
+ * Added check for skb_put overflow and freeing to avoid upmsg on error.
+ * Added check for wrong pfkey version and freeing to avoid upmsg on
+ * error.
+ * Shut off content dumping in pfkey_destroy.
+ * Added debugging message for size of buffer allocated for upmsg.
+ *
+ * Revision 1.20 1999/11/27 12:11:00 rgb
+ * Minor clean-up, enabling quiet operation of pfkey if desired.
+ *
+ * Revision 1.19 1999/11/25 19:04:21 rgb
+ * Update proc_fs code for pfkey to use dynamic registration.
+ *
+ * Revision 1.18 1999/11/25 09:07:17 rgb
+ * Implemented SENDERR macro for propagating error codes.
+ * Fixed error return code bug.
+ *
+ * Revision 1.17 1999/11/23 23:07:20 rgb
+ * Change name of pfkey_msg_parser to pfkey_msg_interp since it no longer
+ * parses. (PJO)
+ * Sort out pfkey and freeswan headers, putting them in a library path.
+ *
+ * Revision 1.16 1999/11/20 22:00:22 rgb
+ * Moved socketlist type declarations and prototypes for shared use.
+ * Renamed reformatted and generically extended for use by other socket
+ * lists pfkey_{del,add}_open_socket to pfkey_list_{remove,insert}_socket.
+ *
+ * Revision 1.15 1999/11/18 04:15:09 rgb
+ * Make pfkey_data_ready temporarily available for 2.2.x testing.
+ * Clean up pfkey_destroy_socket() debugging statements.
+ * Add Peter Onion's code to send messages up to all listening sockets.
+ * Changed all occurrences of #include "../../../lib/freeswan.h"
+ * to #include <freeswan.h> which works due to -Ilibfreeswan in the
+ * klips/net/ipsec/Makefile.
+ * Replaced all kernel version macros to shorter, readable form.
+ * Added CONFIG_PROC_FS compiler directives in case it is shut off.
+ *
+ * Revision 1.14 1999/11/17 16:01:00 rgb
+ * Make pfkey_data_ready temporarily available for 2.2.x testing.
+ * Clean up pfkey_destroy_socket() debugging statements.
+ * Add Peter Onion's code to send messages up to all listening sockets.
+ * Changed #include "../../../lib/freeswan.h" to #include <freeswan.h>
+ * which works due to -Ilibfreeswan in the klips/net/ipsec/Makefile.
+ *
+ * Revision 1.13 1999/10/27 19:59:51 rgb
+ * Removed af_unix comments that are no longer relevant.
+ * Added debug prink statements.
+ * Added to the /proc output in pfkey_get_info.
+ * Made most functions non-static to enable oops tracing.
+ * Re-enable skb dequeueing and freeing.
+ * Fix skb_alloc() and skb_put() size bug in pfkey_upmsg().
+ *
+ * Revision 1.12 1999/10/26 17:05:42 rgb
+ * Complete re-ordering based on proto_ops structure order.
+ * Separated out proto_ops structures for 2.0.x and 2.2.x for clarity.
+ * Simplification to use built-in socket ops where possible for 2.2.x.
+ * Add shorter macros for compiler directives to visually clean-up.
+ * Add lots of sk skb dequeueing debugging statements.
+ * Added to the /proc output in pfkey_get_info.
+ *
+ * Revision 1.11 1999/09/30 02:55:10 rgb
+ * Bogus skb detection.
+ * Fix incorrect /proc/net/ipsec-eroute printk message.
+ *
+ * Revision 1.10 1999/09/21 15:22:13 rgb
+ * Temporary fix while I figure out the right way to destroy sockets.
+ *
+ * Revision 1.9 1999/07/08 19:19:44 rgb
+ * Fix pointer format warning.
+ * Fix missing member error under 2.0.xx kernels.
+ *
+ * Revision 1.8 1999/06/13 07:24:04 rgb
+ * Add more debugging.
+ *
+ * Revision 1.7 1999/06/10 05:24:17 rgb
+ * Clarified compiler directives.
+ * Renamed variables to reduce confusion.
+ * Used sklist_*_socket() kernel functions to simplify 2.2.x socket support.
+ * Added lots of sanity checking.
+ *
+ * Revision 1.6 1999/06/03 18:59:50 rgb
+ * More updates to 2.2.x socket support. Almost works, oops at end of call.
+ *
+ * Revision 1.5 1999/05/25 22:44:05 rgb
+ * Start fixing 2.2 sockets.
+ *
+ * Revision 1.4 1999/04/29 15:21:34 rgb
+ * Move log to the end of the file.
+ * Eliminate min/max redefinition in #include <net/tcp.h>.
+ * Correct path for pfkey #includes
+ * Standardise an error return method.
+ * Add debugging instrumentation.
+ * Move message type checking to pfkey_msg_parse().
+ * Add check for errno incorrectly set.
+ * Add check for valid PID.
+ * Add check for reserved illegally set.
+ * Add check for message out of bounds.
+ *
+ * Revision 1.3 1999/04/15 17:58:07 rgb
+ * Add RCSID labels.
+ *
+ * Revision 1.2 1999/04/15 15:37:26 rgb
+ * Forward check changes from POST1_00 branch.
+ *
+ * Revision 1.1.2.2 1999/04/13 20:37:12 rgb
+ * Header Title correction.
+ *
+ * Revision 1.1.2.1 1999/03/26 20:58:55 rgb
+ * Add pfkeyv2 support to KLIPS.
+ *
+ *
+ * RFC 2367
+ * PF_KEY_v2 Key Management API
+ */
diff --git a/linux/net/ipsec/pfkey_v2_ext_process.c b/linux/net/ipsec/pfkey_v2_ext_process.c
new file mode 100644
index 000000000..9269bd59e
--- /dev/null
+++ b/linux/net/ipsec/pfkey_v2_ext_process.c
@@ -0,0 +1,851 @@
+/*
+ * @(#) RFC2367 PF_KEYv2 Key management API message parser
+ * Copyright (C) 1999, 2000, 2001 Richard Guy Briggs <rgb@freeswan.org>
+ *
+ * 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_process.c,v 1.3 2004/06/13 19:57:50 as Exp $
+ */
+
+/*
+ * Template from klips/net/ipsec/ipsec/ipsec_netlink.c.
+ */
+
+char pfkey_v2_ext_process_c_version[] = "$Id: pfkey_v2_ext_process.c,v 1.3 2004/06/13 19:57:50 as Exp $";
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/kernel.h> /* printk() */
+
+#include "freeswan/ipsec_param.h"
+
+#ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+#else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+#endif /* MALLOC_SLAB */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/interrupt.h> /* mark_bh */
+
+#include <linux/netdevice.h> /* struct device, and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/ip.h> /* struct iphdr */
+#include <linux/skbuff.h>
+
+#include <freeswan.h>
+
+#include <crypto/des.h>
+
+#ifdef SPINLOCK
+# ifdef SPINLOCK_23
+# include <linux/spinlock.h> /* *lock* */
+# else /* SPINLOCK_23 */
+# include <asm/spinlock.h> /* *lock* */
+# endif /* SPINLOCK_23 */
+#endif /* SPINLOCK */
+#ifdef NET_21
+# include <asm/uaccess.h>
+# include <linux/in6.h>
+# define ip_chk_addr inet_addr_type
+# define IS_MYADDR RTN_LOCAL
+#endif
+#include <asm/checksum.h>
+#include <net/ip.h>
+#ifdef NETLINK_SOCK
+# include <linux/netlink.h>
+#else
+# include <net/netlink.h>
+#endif
+
+#include <linux/random.h> /* get_random_bytes() */
+
+#include "freeswan/radij.h"
+#include "freeswan/ipsec_encap.h"
+#include "freeswan/ipsec_sa.h"
+
+#include "freeswan/ipsec_radij.h"
+#include "freeswan/ipsec_xform.h"
+#include "freeswan/ipsec_ah.h"
+#include "freeswan/ipsec_esp.h"
+#include "freeswan/ipsec_tunnel.h"
+#include "freeswan/ipsec_rcv.h"
+#include "freeswan/ipcomp.h"
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "freeswan/ipsec_proto.h"
+#include "freeswan/ipsec_alg.h"
+
+#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0)
+
+int
+pfkey_sa_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
+{
+ struct sadb_sa *pfkey_sa = (struct sadb_sa *)pfkey_ext;
+ int error = 0;
+ struct ipsec_sa* ipsp;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sa_process: .\n");
+
+ if(!extr || !extr->ips) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sa_process: "
+ "extr or extr->ips is NULL, fatal\n");
+ SENDERR(EINVAL);
+ }
+
+ switch(pfkey_ext->sadb_ext_type) {
+ case SADB_EXT_SA:
+ ipsp = extr->ips;
+ break;
+ case SADB_X_EXT_SA2:
+ if(extr->ips2 == NULL) {
+ extr->ips2 = ipsec_sa_alloc(&error); /* pass error var by pointer */
+ }
+ if(extr->ips2 == NULL) {
+ SENDERR(-error);
+ }
+ ipsp = extr->ips2;
+ break;
+ default:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sa_process: "
+ "invalid exttype=%d.\n",
+ pfkey_ext->sadb_ext_type);
+ SENDERR(EINVAL);
+ }
+
+ ipsp->ips_said.spi = pfkey_sa->sadb_sa_spi;
+ ipsp->ips_replaywin = pfkey_sa->sadb_sa_replay;
+ ipsp->ips_state = pfkey_sa->sadb_sa_state;
+ ipsp->ips_flags = pfkey_sa->sadb_sa_flags;
+ ipsp->ips_replaywin_lastseq = ipsp->ips_replaywin_bitmap = 0;
+ ipsp->ips_ref_rel = pfkey_sa->sadb_x_sa_ref;
+
+ switch(ipsp->ips_said.proto) {
+ case IPPROTO_AH:
+ ipsp->ips_authalg = pfkey_sa->sadb_sa_auth;
+ ipsp->ips_encalg = SADB_EALG_NONE;
+ break;
+ case IPPROTO_ESP:
+ ipsp->ips_authalg = pfkey_sa->sadb_sa_auth;
+ ipsp->ips_encalg = pfkey_sa->sadb_sa_encrypt;
+#ifdef CONFIG_IPSEC_ALG
+ ipsec_alg_sa_init(ipsp);
+#endif /* CONFIG_IPSEC_ALG */
+ break;
+ case IPPROTO_IPIP:
+ ipsp->ips_authalg = AH_NONE;
+ ipsp->ips_encalg = ESP_NONE;
+ break;
+#ifdef CONFIG_IPSEC_IPCOMP
+ case IPPROTO_COMP:
+ ipsp->ips_authalg = AH_NONE;
+ ipsp->ips_encalg = pfkey_sa->sadb_sa_encrypt;
+ break;
+#endif /* CONFIG_IPSEC_IPCOMP */
+ case IPPROTO_INT:
+ ipsp->ips_authalg = AH_NONE;
+ ipsp->ips_encalg = ESP_NONE;
+ break;
+ case 0:
+ break;
+ default:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sa_process: "
+ "unknown proto=%d.\n",
+ ipsp->ips_said.proto);
+ SENDERR(EINVAL);
+ }
+
+errlab:
+ return error;
+}
+
+int
+pfkey_lifetime_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+ struct sadb_lifetime *pfkey_lifetime = (struct sadb_lifetime *)pfkey_ext;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_lifetime_process: .\n");
+
+ if(!extr || !extr->ips) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_lifetime_process: "
+ "extr or extr->ips is NULL, fatal\n");
+ SENDERR(EINVAL);
+ }
+
+ switch(pfkey_lifetime->sadb_lifetime_exttype) {
+ case SADB_EXT_LIFETIME_CURRENT:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_lifetime_process: "
+ "lifetime_current not supported yet.\n");
+ SENDERR(EINVAL);
+ break;
+ case SADB_EXT_LIFETIME_HARD:
+ ipsec_lifetime_update_hard(&extr->ips->ips_life.ipl_allocations,
+ pfkey_lifetime->sadb_lifetime_allocations);
+
+ ipsec_lifetime_update_hard(&extr->ips->ips_life.ipl_bytes,
+ pfkey_lifetime->sadb_lifetime_bytes);
+
+ ipsec_lifetime_update_hard(&extr->ips->ips_life.ipl_addtime,
+ pfkey_lifetime->sadb_lifetime_addtime);
+
+ ipsec_lifetime_update_hard(&extr->ips->ips_life.ipl_usetime,
+ pfkey_lifetime->sadb_lifetime_usetime);
+
+ break;
+
+ case SADB_EXT_LIFETIME_SOFT:
+ ipsec_lifetime_update_soft(&extr->ips->ips_life.ipl_allocations,
+ pfkey_lifetime->sadb_lifetime_allocations);
+
+ ipsec_lifetime_update_soft(&extr->ips->ips_life.ipl_bytes,
+ pfkey_lifetime->sadb_lifetime_bytes);
+
+ ipsec_lifetime_update_soft(&extr->ips->ips_life.ipl_addtime,
+ pfkey_lifetime->sadb_lifetime_addtime);
+
+ ipsec_lifetime_update_soft(&extr->ips->ips_life.ipl_usetime,
+ pfkey_lifetime->sadb_lifetime_usetime);
+
+ break;
+ default:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_lifetime_process: "
+ "invalid exttype=%d.\n",
+ pfkey_ext->sadb_ext_type);
+ SENDERR(EINVAL);
+ }
+
+errlab:
+ return error;
+}
+
+int
+pfkey_address_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+ int saddr_len = 0;
+ char ipaddr_txt[ADDRTOA_BUF];
+ unsigned char **sap;
+ unsigned short * portp = 0;
+ struct sadb_address *pfkey_address = (struct sadb_address *)pfkey_ext;
+ struct sockaddr* s = (struct sockaddr*)((char*)pfkey_address + sizeof(*pfkey_address));
+ struct ipsec_sa* ipsp;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process:\n");
+
+ if(!extr || !extr->ips) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process: "
+ "extr or extr->ips is NULL, fatal\n");
+ SENDERR(EINVAL);
+ }
+
+ switch(s->sa_family) {
+ case AF_INET:
+ saddr_len = sizeof(struct sockaddr_in);
+ addrtoa(((struct sockaddr_in*)s)->sin_addr, 0, ipaddr_txt, sizeof(ipaddr_txt));
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process: "
+ "found address family=%d, AF_INET, %s.\n",
+ s->sa_family,
+ ipaddr_txt);
+ break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ case AF_INET6:
+ saddr_len = sizeof(struct sockaddr_in6);
+ break;
+#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
+ default:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process: "
+ "s->sa_family=%d not supported.\n",
+ s->sa_family);
+ SENDERR(EPFNOSUPPORT);
+ }
+
+ switch(pfkey_address->sadb_address_exttype) {
+ case SADB_EXT_ADDRESS_SRC:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process: "
+ "found src address.\n");
+ sap = (unsigned char **)&(extr->ips->ips_addr_s);
+ extr->ips->ips_addr_s_size = saddr_len;
+ break;
+ case SADB_EXT_ADDRESS_DST:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process: "
+ "found dst address.\n");
+ sap = (unsigned char **)&(extr->ips->ips_addr_d);
+ extr->ips->ips_addr_d_size = saddr_len;
+ break;
+ case SADB_EXT_ADDRESS_PROXY:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process: "
+ "found proxy address.\n");
+ sap = (unsigned char **)&(extr->ips->ips_addr_p);
+ extr->ips->ips_addr_p_size = saddr_len;
+ break;
+ case SADB_X_EXT_ADDRESS_DST2:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process: "
+ "found 2nd dst address.\n");
+ if(extr->ips2 == NULL) {
+ extr->ips2 = ipsec_sa_alloc(&error); /* pass error var by pointer */
+ }
+ if(extr->ips2 == NULL) {
+ SENDERR(-error);
+ }
+ sap = (unsigned char **)&(extr->ips2->ips_addr_d);
+ extr->ips2->ips_addr_d_size = saddr_len;
+ break;
+ case SADB_X_EXT_ADDRESS_SRC_FLOW:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process: "
+ "found src flow address.\n");
+ if(pfkey_alloc_eroute(&(extr->eroute)) == ENOMEM) {
+ SENDERR(ENOMEM);
+ }
+ sap = (unsigned char **)&(extr->eroute->er_eaddr.sen_ip_src);
+ portp = &(extr->eroute->er_eaddr.sen_sport);
+ break;
+ case SADB_X_EXT_ADDRESS_DST_FLOW:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process: "
+ "found dst flow address.\n");
+ if(pfkey_alloc_eroute(&(extr->eroute)) == ENOMEM) {
+ SENDERR(ENOMEM);
+ }
+ sap = (unsigned char **)&(extr->eroute->er_eaddr.sen_ip_dst);
+ portp = &(extr->eroute->er_eaddr.sen_dport);
+ break;
+ case SADB_X_EXT_ADDRESS_SRC_MASK:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process: "
+ "found src mask address.\n");
+ if(pfkey_alloc_eroute(&(extr->eroute)) == ENOMEM) {
+ SENDERR(ENOMEM);
+ }
+ sap = (unsigned char **)&(extr->eroute->er_emask.sen_ip_src);
+ portp = &(extr->eroute->er_emask.sen_sport);
+ break;
+ case SADB_X_EXT_ADDRESS_DST_MASK:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process: "
+ "found dst mask address.\n");
+ if(pfkey_alloc_eroute(&(extr->eroute)) == ENOMEM) {
+ SENDERR(ENOMEM);
+ }
+ sap = (unsigned char **)&(extr->eroute->er_emask.sen_ip_dst);
+ portp = &(extr->eroute->er_emask.sen_dport);
+ break;
+#ifdef NAT_TRAVERSAL
+ case SADB_X_EXT_NAT_T_OA:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process: "
+ "found NAT-OA address.\n");
+ sap = (unsigned char **)&(extr->ips->ips_natt_oa);
+ extr->ips->ips_natt_oa_size = saddr_len;
+ break;
+#endif
+ default:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process: "
+ "unrecognised ext_type=%d.\n",
+ pfkey_address->sadb_address_exttype);
+ SENDERR(EINVAL);
+ }
+
+ switch(pfkey_address->sadb_address_exttype) {
+ case SADB_EXT_ADDRESS_SRC:
+ case SADB_EXT_ADDRESS_DST:
+ case SADB_EXT_ADDRESS_PROXY:
+ case SADB_X_EXT_ADDRESS_DST2:
+#ifdef NAT_TRAVERSAL
+ case SADB_X_EXT_NAT_T_OA:
+#endif
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process: "
+ "allocating %d bytes for saddr.\n",
+ saddr_len);
+ if(!(*sap = kmalloc(saddr_len, GFP_KERNEL))) {
+ SENDERR(ENOMEM);
+ }
+ memcpy(*sap, s, saddr_len);
+ break;
+ default:
+ if(s->sa_family != AF_INET) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process: "
+ "s->sa_family=%d not supported.\n",
+ s->sa_family);
+ SENDERR(EPFNOSUPPORT);
+ }
+ (unsigned long)(*sap) = ((struct sockaddr_in*)s)->sin_addr.s_addr;
+ if (portp != 0)
+ *portp = ((struct sockaddr_in*)s)->sin_port;
+#ifdef CONFIG_IPSEC_DEBUG
+ if(extr->eroute) {
+ char buf1[64], buf2[64];
+ if (debug_pfkey) {
+ subnettoa(extr->eroute->er_eaddr.sen_ip_src,
+ extr->eroute->er_emask.sen_ip_src, 0, buf1, sizeof(buf1));
+ subnettoa(extr->eroute->er_eaddr.sen_ip_dst,
+ extr->eroute->er_emask.sen_ip_dst, 0, buf2, sizeof(buf2));
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_parse: "
+ "extr->eroute set to %s:%d->%s:%d\n",
+ buf1,
+ ntohs(extr->eroute->er_eaddr.sen_sport),
+ buf2,
+ ntohs(extr->eroute->er_eaddr.sen_dport));
+ }
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+ }
+
+ ipsp = extr->ips;
+ switch(pfkey_address->sadb_address_exttype) {
+ case SADB_X_EXT_ADDRESS_DST2:
+ ipsp = extr->ips2;
+ case SADB_EXT_ADDRESS_DST:
+ if(s->sa_family == AF_INET) {
+ ipsp->ips_said.dst.s_addr = ((struct sockaddr_in*)(ipsp->ips_addr_d))->sin_addr.s_addr;
+ addrtoa(((struct sockaddr_in*)(ipsp->ips_addr_d))->sin_addr,
+ 0,
+ ipaddr_txt,
+ sizeof(ipaddr_txt));
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process: "
+ "ips_said.dst set to %s.\n",
+ ipaddr_txt);
+ } else {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process: "
+ "uh, ips_said.dst doesn't do address family=%d yet, said will be invalid.\n",
+ s->sa_family);
+ }
+ default:
+ break;
+ }
+
+ /* XXX check if port!=0 */
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process: successful.\n");
+ errlab:
+ return error;
+}
+
+int
+pfkey_key_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+ struct sadb_key *pfkey_key = (struct sadb_key *)pfkey_ext;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_key_process: .\n");
+
+ if(!extr || !extr->ips) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_key_process: "
+ "extr or extr->ips is NULL, fatal\n");
+ SENDERR(EINVAL);
+ }
+
+ switch(pfkey_key->sadb_key_exttype) {
+ case SADB_EXT_KEY_AUTH:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_key_process: "
+ "allocating %d bytes for authkey.\n",
+ DIVUP(pfkey_key->sadb_key_bits, 8));
+ if(!(extr->ips->ips_key_a = kmalloc(DIVUP(pfkey_key->sadb_key_bits, 8), GFP_KERNEL))) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_key_process: "
+ "memory allocation error.\n");
+ SENDERR(ENOMEM);
+ }
+ extr->ips->ips_key_bits_a = pfkey_key->sadb_key_bits;
+ extr->ips->ips_key_a_size = DIVUP(pfkey_key->sadb_key_bits, 8);
+ memcpy(extr->ips->ips_key_a,
+ (char*)pfkey_key + sizeof(struct sadb_key),
+ extr->ips->ips_key_a_size);
+ break;
+ case SADB_EXT_KEY_ENCRYPT: /* Key(s) */
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_key_process: "
+ "allocating %d bytes for enckey.\n",
+ DIVUP(pfkey_key->sadb_key_bits, 8));
+ if(!(extr->ips->ips_key_e = kmalloc(DIVUP(pfkey_key->sadb_key_bits, 8), GFP_KERNEL))) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_key_process: "
+ "memory allocation error.\n");
+ SENDERR(ENOMEM);
+ }
+ extr->ips->ips_key_bits_e = pfkey_key->sadb_key_bits;
+ extr->ips->ips_key_e_size = DIVUP(pfkey_key->sadb_key_bits, 8);
+ memcpy(extr->ips->ips_key_e,
+ (char*)pfkey_key + sizeof(struct sadb_key),
+ extr->ips->ips_key_e_size);
+ break;
+ default:
+ SENDERR(EINVAL);
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_key_process: "
+ "success.\n");
+errlab:
+ return error;
+}
+
+int
+pfkey_ident_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+ struct sadb_ident *pfkey_ident = (struct sadb_ident *)pfkey_ext;
+ int data_len;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ident_process: .\n");
+
+ if(!extr || !extr->ips) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ident_process: "
+ "extr or extr->ips is NULL, fatal\n");
+ SENDERR(EINVAL);
+ }
+
+ switch(pfkey_ident->sadb_ident_exttype) {
+ case SADB_EXT_IDENTITY_SRC:
+ data_len = pfkey_ident->sadb_ident_len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident);
+
+ extr->ips->ips_ident_s.type = pfkey_ident->sadb_ident_type;
+ extr->ips->ips_ident_s.id = pfkey_ident->sadb_ident_id;
+ extr->ips->ips_ident_s.len = pfkey_ident->sadb_ident_len;
+ if(data_len) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ident_process: "
+ "allocating %d bytes for ident_s.\n",
+ data_len);
+ if(!(extr->ips->ips_ident_s.data
+ = kmalloc(data_len, GFP_KERNEL))) {
+ SENDERR(ENOMEM);
+ }
+ memcpy(extr->ips->ips_ident_s.data,
+ (char*)pfkey_ident + sizeof(struct sadb_ident),
+ data_len);
+ } else {
+ extr->ips->ips_ident_s.data = NULL;
+ }
+ break;
+ case SADB_EXT_IDENTITY_DST: /* Identity(ies) */
+ data_len = pfkey_ident->sadb_ident_len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident);
+
+ extr->ips->ips_ident_d.type = pfkey_ident->sadb_ident_type;
+ extr->ips->ips_ident_d.id = pfkey_ident->sadb_ident_id;
+ extr->ips->ips_ident_d.len = pfkey_ident->sadb_ident_len;
+ if(data_len) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ident_process: "
+ "allocating %d bytes for ident_d.\n",
+ data_len);
+ if(!(extr->ips->ips_ident_d.data
+ = kmalloc(data_len, GFP_KERNEL))) {
+ SENDERR(ENOMEM);
+ }
+ memcpy(extr->ips->ips_ident_d.data,
+ (char*)pfkey_ident + sizeof(struct sadb_ident),
+ data_len);
+ } else {
+ extr->ips->ips_ident_d.data = NULL;
+ }
+ break;
+ default:
+ SENDERR(EINVAL);
+ }
+errlab:
+ return error;
+}
+
+int
+pfkey_sens_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sens_process: "
+ "Sorry, I can't process exttype=%d yet.\n",
+ pfkey_ext->sadb_ext_type);
+ SENDERR(EINVAL); /* don't process these yet */
+ errlab:
+ return error;
+}
+
+int
+pfkey_prop_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_prop_process: "
+ "Sorry, I can't process exttype=%d yet.\n",
+ pfkey_ext->sadb_ext_type);
+ SENDERR(EINVAL); /* don't process these yet */
+
+ errlab:
+ return error;
+}
+
+int
+pfkey_supported_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_supported_process: "
+ "Sorry, I can't process exttype=%d yet.\n",
+ pfkey_ext->sadb_ext_type);
+ SENDERR(EINVAL); /* don't process these yet */
+
+errlab:
+ return error;
+}
+
+int
+pfkey_spirange_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_spirange_process: .\n");
+/* errlab: */
+ return error;
+}
+
+int
+pfkey_x_kmprivate_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_kmprivate_process: "
+ "Sorry, I can't process exttype=%d yet.\n",
+ pfkey_ext->sadb_ext_type);
+ SENDERR(EINVAL); /* don't process these yet */
+
+errlab:
+ return error;
+}
+
+int
+pfkey_x_satype_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+ struct sadb_x_satype *pfkey_x_satype = (struct sadb_x_satype *)pfkey_ext;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_satype_process: .\n");
+
+ if(!extr || !extr->ips) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_satype_process: "
+ "extr or extr->ips is NULL, fatal\n");
+ SENDERR(EINVAL);
+ }
+
+ if(extr->ips2 == NULL) {
+ extr->ips2 = ipsec_sa_alloc(&error); /* pass error var by pointer */
+ }
+ if(extr->ips2 == NULL) {
+ SENDERR(-error);
+ }
+ if(!(extr->ips2->ips_said.proto = satype2proto(pfkey_x_satype->sadb_x_satype_satype))) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_satype_process: "
+ "proto lookup from satype=%d failed.\n",
+ pfkey_x_satype->sadb_x_satype_satype);
+ SENDERR(EINVAL);
+ }
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_satype_process: "
+ "protocol==%d decoded from satype==%d(%s).\n",
+ extr->ips2->ips_said.proto,
+ pfkey_x_satype->sadb_x_satype_satype,
+ satype2name(pfkey_x_satype->sadb_x_satype_satype));
+
+errlab:
+ return error;
+}
+
+
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+int
+pfkey_x_nat_t_type_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+ struct sadb_x_nat_t_type *pfkey_x_nat_t_type = (struct sadb_x_nat_t_type *)pfkey_ext;
+
+ if(!pfkey_x_nat_t_type) {
+ printk("klips_debug:pfkey_x_nat_t_type_process: "
+ "null pointer passed in\n");
+ SENDERR(EINVAL);
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_nat_t_type_process: %d.\n",
+ pfkey_x_nat_t_type->sadb_x_nat_t_type_type);
+
+ if(!extr || !extr->ips) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_nat_t_type_process: "
+ "extr or extr->ips is NULL, fatal\n");
+ SENDERR(EINVAL);
+ }
+
+ switch(pfkey_x_nat_t_type->sadb_x_nat_t_type_type) {
+ case ESPINUDP_WITH_NON_IKE: /* with Non-IKE */
+ case ESPINUDP_WITH_NON_ESP: /* with Non-ESP */
+ extr->ips->ips_natt_type = pfkey_x_nat_t_type->sadb_x_nat_t_type_type;
+ break;
+ default:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_nat_t_type_process: "
+ "unknown type %d.\n",
+ pfkey_x_nat_t_type->sadb_x_nat_t_type_type);
+ SENDERR(EINVAL);
+ break;
+ }
+
+errlab:
+ return error;
+}
+
+int
+pfkey_x_nat_t_port_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+ struct sadb_x_nat_t_port *pfkey_x_nat_t_port = (struct sadb_x_nat_t_port *)pfkey_ext;
+
+ if(!pfkey_x_nat_t_port) {
+ printk("klips_debug:pfkey_x_nat_t_port_process: "
+ "null pointer passed in\n");
+ SENDERR(EINVAL);
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_nat_t_port_process: %d/%d.\n",
+ pfkey_x_nat_t_port->sadb_x_nat_t_port_exttype,
+ pfkey_x_nat_t_port->sadb_x_nat_t_port_port);
+
+ if(!extr || !extr->ips) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_nat_t_type_process: "
+ "extr or extr->ips is NULL, fatal\n");
+ SENDERR(EINVAL);
+ }
+
+ switch(pfkey_x_nat_t_port->sadb_x_nat_t_port_exttype) {
+ case SADB_X_EXT_NAT_T_SPORT:
+ extr->ips->ips_natt_sport = pfkey_x_nat_t_port->sadb_x_nat_t_port_port;
+ break;
+ case SADB_X_EXT_NAT_T_DPORT:
+ extr->ips->ips_natt_dport = pfkey_x_nat_t_port->sadb_x_nat_t_port_port;
+ break;
+ default:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_nat_t_port_process: "
+ "unknown exttype %d.\n",
+ pfkey_x_nat_t_port->sadb_x_nat_t_port_exttype);
+ SENDERR(EINVAL);
+ break;
+ }
+
+errlab:
+ return error;
+}
+#endif
+
+int
+pfkey_x_debug_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+ struct sadb_x_debug *pfkey_x_debug = (struct sadb_x_debug *)pfkey_ext;
+
+ if(!pfkey_x_debug) {
+ printk("klips_debug:pfkey_x_debug_process: "
+ "null pointer passed in\n");
+ SENDERR(EINVAL);
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_debug_process: .\n");
+
+#ifdef CONFIG_IPSEC_DEBUG
+ if(pfkey_x_debug->sadb_x_debug_netlink >>
+ (sizeof(pfkey_x_debug->sadb_x_debug_netlink) * 8 - 1)) {
+ pfkey_x_debug->sadb_x_debug_netlink &=
+ ~(1 << (sizeof(pfkey_x_debug->sadb_x_debug_netlink) * 8 -1));
+ debug_tunnel |= pfkey_x_debug->sadb_x_debug_tunnel;
+ debug_netlink |= pfkey_x_debug->sadb_x_debug_netlink;
+ debug_xform |= pfkey_x_debug->sadb_x_debug_xform;
+ debug_eroute |= pfkey_x_debug->sadb_x_debug_eroute;
+ debug_spi |= pfkey_x_debug->sadb_x_debug_spi;
+ debug_radij |= pfkey_x_debug->sadb_x_debug_radij;
+ debug_esp |= pfkey_x_debug->sadb_x_debug_esp;
+ debug_ah |= pfkey_x_debug->sadb_x_debug_ah;
+ debug_rcv |= pfkey_x_debug->sadb_x_debug_rcv;
+ debug_pfkey |= pfkey_x_debug->sadb_x_debug_pfkey;
+#ifdef CONFIG_IPSEC_IPCOMP
+ sysctl_ipsec_debug_ipcomp |= pfkey_x_debug->sadb_x_debug_ipcomp;
+#endif /* CONFIG_IPSEC_IPCOMP */
+ sysctl_ipsec_debug_verbose |= pfkey_x_debug->sadb_x_debug_verbose;
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_debug_process: "
+ "set\n");
+ } else {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_debug_process: "
+ "unset\n");
+ debug_tunnel &= pfkey_x_debug->sadb_x_debug_tunnel;
+ debug_netlink &= pfkey_x_debug->sadb_x_debug_netlink;
+ debug_xform &= pfkey_x_debug->sadb_x_debug_xform;
+ debug_eroute &= pfkey_x_debug->sadb_x_debug_eroute;
+ debug_spi &= pfkey_x_debug->sadb_x_debug_spi;
+ debug_radij &= pfkey_x_debug->sadb_x_debug_radij;
+ debug_esp &= pfkey_x_debug->sadb_x_debug_esp;
+ debug_ah &= pfkey_x_debug->sadb_x_debug_ah;
+ debug_rcv &= pfkey_x_debug->sadb_x_debug_rcv;
+ debug_pfkey &= pfkey_x_debug->sadb_x_debug_pfkey;
+#ifdef CONFIG_IPSEC_IPCOMP
+ sysctl_ipsec_debug_ipcomp &= pfkey_x_debug->sadb_x_debug_ipcomp;
+#endif /* CONFIG_IPSEC_IPCOMP */
+ sysctl_ipsec_debug_verbose &= pfkey_x_debug->sadb_x_debug_verbose;
+ }
+#else /* CONFIG_IPSEC_DEBUG */
+ printk("klips_debug:pfkey_x_debug_process: "
+ "debugging not enabled\n");
+ SENDERR(EINVAL);
+#endif /* CONFIG_IPSEC_DEBUG */
+
+errlab:
+ return error;
+}
diff --git a/linux/net/ipsec/pfkey_v2_parser.c b/linux/net/ipsec/pfkey_v2_parser.c
new file mode 100644
index 000000000..d170ddea5
--- /dev/null
+++ b/linux/net/ipsec/pfkey_v2_parser.c
@@ -0,0 +1,3420 @@
+/*
+ * @(#) RFC2367 PF_KEYv2 Key management API message parser
+ * Copyright (C) 1999, 2000, 2001 Richard Guy Briggs <rgb@freeswan.org>
+ *
+ * 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_parser.c,v 1.4 2004/09/29 22:27:41 as Exp $
+ */
+
+/*
+ * Template from klips/net/ipsec/ipsec/ipsec_netlink.c.
+ */
+
+char pfkey_v2_parser_c_version[] = "$Id: pfkey_v2_parser.c,v 1.4 2004/09/29 22:27:41 as Exp $";
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/kernel.h> /* printk() */
+
+#include "freeswan/ipsec_param.h"
+
+#ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+#else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+#endif /* MALLOC_SLAB */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/interrupt.h> /* mark_bh */
+
+#include <linux/netdevice.h> /* struct device, and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/ip.h> /* struct iphdr */
+#include <linux/skbuff.h>
+
+#include <freeswan.h>
+
+#include <crypto/des.h>
+
+#ifdef SPINLOCK
+# ifdef SPINLOCK_23
+# include <linux/spinlock.h> /* *lock* */
+# else /* SPINLOCK_23 */
+# include <asm/spinlock.h> /* *lock* */
+# endif /* SPINLOCK_23 */
+#endif /* SPINLOCK */
+#ifdef NET_21
+# include <asm/uaccess.h>
+# include <linux/in6.h>
+# define ip_chk_addr inet_addr_type
+# define IS_MYADDR RTN_LOCAL
+#endif
+#include <asm/checksum.h>
+#include <net/ip.h>
+#ifdef NETLINK_SOCK
+# include <linux/netlink.h>
+#else
+# include <net/netlink.h>
+#endif
+
+#include <linux/random.h> /* get_random_bytes() */
+
+#include "freeswan/radij.h"
+#include "freeswan/ipsec_encap.h"
+#include "freeswan/ipsec_sa.h"
+
+#include "freeswan/ipsec_radij.h"
+#include "freeswan/ipsec_xform.h"
+#include "freeswan/ipsec_ah.h"
+#include "freeswan/ipsec_esp.h"
+#include "freeswan/ipsec_tunnel.h"
+#include "freeswan/ipsec_rcv.h"
+#include "freeswan/ipcomp.h"
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "freeswan/ipsec_proto.h"
+#include "freeswan/ipsec_alg.h"
+
+
+#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0)
+
+struct sklist_t {
+ struct socket *sk;
+ struct sklist_t* next;
+} pfkey_sklist_head, *pfkey_sklist, *pfkey_sklist_prev;
+
+__u32 pfkey_msg_seq = 0;
+
+int
+pfkey_alloc_eroute(struct eroute** eroute)
+{
+ int error = 0;
+ if(*eroute) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_alloc_eroute: "
+ "eroute struct already allocated\n");
+ SENDERR(EEXIST);
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_alloc_eroute: "
+ "allocating %lu bytes for an eroute.\n",
+ (unsigned long) sizeof(**eroute));
+ if((*eroute = kmalloc(sizeof(**eroute), GFP_ATOMIC) ) == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_alloc_eroute: "
+ "memory allocation error\n");
+ SENDERR(ENOMEM);
+ }
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_alloc_eroute: "
+ "allocated eroute struct=0p%p.\n", eroute);
+ memset((caddr_t)*eroute, 0, sizeof(**eroute));
+ (*eroute)->er_eaddr.sen_len =
+ (*eroute)->er_emask.sen_len = sizeof(struct sockaddr_encap);
+ (*eroute)->er_eaddr.sen_family =
+ (*eroute)->er_emask.sen_family = AF_ENCAP;
+ (*eroute)->er_eaddr.sen_type = SENT_IP4;
+ (*eroute)->er_emask.sen_type = 255;
+ (*eroute)->er_pid = 0;
+ (*eroute)->er_count = 0;
+ (*eroute)->er_lasttime = jiffies/HZ;
+
+ errlab:
+ return(error);
+}
+
+DEBUG_NO_STATIC int
+pfkey_x_protocol_process(struct sadb_ext *pfkey_ext,
+ struct pfkey_extracted_data *extr)
+{
+ int error = 0;
+ struct sadb_protocol * p = (struct sadb_protocol *)pfkey_ext;
+
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_protocol_process: %p\n", extr);
+
+ if (extr == 0) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_protocol_process:"
+ "extr is NULL, fatal\n");
+ SENDERR(EINVAL);
+ }
+ if (extr->eroute == 0) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_protocol_process:"
+ "extr->eroute is NULL, fatal\n");
+ SENDERR(EINVAL);
+ }
+ extr->eroute->er_eaddr.sen_proto = p->sadb_protocol_proto;
+ extr->eroute->er_emask.sen_proto = p->sadb_protocol_proto ? ~0:0;
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_protocol_process: protocol = %d.\n",
+ p->sadb_protocol_proto);
+ errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_ipsec_sa_init(struct ipsec_sa *ipsp, struct sadb_ext **extensions)
+{
+ int error = 0;
+ char sa[SATOA_BUF];
+ size_t sa_len;
+ char ipaddr_txt[ADDRTOA_BUF];
+ char ipaddr2_txt[ADDRTOA_BUF];
+#if defined (CONFIG_IPSEC_AUTH_HMAC_MD5) || defined (CONFIG_IPSEC_AUTH_HMAC_SHA1)
+ int i;
+ unsigned char kb[AHMD596_BLKLEN];
+#endif
+#ifdef CONFIG_IPSEC_ALG
+ struct ipsec_alg_enc *ixt_e = NULL;
+ struct ipsec_alg_auth *ixt_a = NULL;
+#endif /* CONFIG_IPSEC_ALG */
+
+ if(ipsp == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "ipsp is NULL, fatal\n");
+ SENDERR(EINVAL);
+ }
+
+ sa_len = satoa(ipsp->ips_said, 0, sa, SATOA_BUF);
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "(pfkey defined) called for SA:%s\n",
+ sa_len ? sa : " (error)");
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "calling init routine of %s%s%s\n",
+ IPS_XFORM_NAME(ipsp));
+
+ switch(ipsp->ips_said.proto) {
+
+#ifdef CONFIG_IPSEC_IPIP
+ case IPPROTO_IPIP: {
+ addrtoa(((struct sockaddr_in*)(ipsp->ips_addr_s))->sin_addr,
+ 0,
+ ipaddr_txt, sizeof(ipaddr_txt));
+ addrtoa(((struct sockaddr_in*)(ipsp->ips_addr_d))->sin_addr,
+ 0,
+ ipaddr2_txt, sizeof(ipaddr_txt));
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "(pfkey defined) IPIP ipsec_sa set for %s->%s.\n",
+ ipaddr_txt,
+ ipaddr2_txt);
+ }
+ break;
+#endif /* !CONFIG_IPSEC_IPIP */
+#ifdef CONFIG_IPSEC_AH
+ case IPPROTO_AH:
+ switch(ipsp->ips_authalg) {
+# ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
+ case AH_MD5: {
+ unsigned char *akp;
+ unsigned int aks;
+ MD5_CTX *ictx;
+ MD5_CTX *octx;
+
+ if(ipsp->ips_key_bits_a != (AHMD596_KLEN * 8)) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "incorrect key size: %d bits -- must be %d bits\n"/*octets (bytes)\n"*/,
+ ipsp->ips_key_bits_a, AHMD596_KLEN * 8);
+ SENDERR(EINVAL);
+ }
+
+# if KLIPS_DIVULGE_HMAC_KEY
+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "hmac md5-96 key is 0x%08x %08x %08x %08x\n",
+ ntohl(*(((__u32 *)ipsp->ips_key_a)+0)),
+ ntohl(*(((__u32 *)ipsp->ips_key_a)+1)),
+ ntohl(*(((__u32 *)ipsp->ips_key_a)+2)),
+ ntohl(*(((__u32 *)ipsp->ips_key_a)+3)));
+# endif /* KLIPS_DIVULGE_HMAC_KEY */
+
+ ipsp->ips_auth_bits = AHMD596_ALEN * 8;
+
+ /* save the pointer to the key material */
+ akp = ipsp->ips_key_a;
+ aks = ipsp->ips_key_a_size;
+
+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "allocating %lu bytes for md5_ctx.\n",
+ (unsigned long) sizeof(struct md5_ctx));
+ if((ipsp->ips_key_a = (caddr_t)
+ kmalloc(sizeof(struct md5_ctx), GFP_ATOMIC)) == NULL) {
+ ipsp->ips_key_a = akp;
+ SENDERR(ENOMEM);
+ }
+ ipsp->ips_key_a_size = sizeof(struct md5_ctx);
+
+ for (i = 0; i < DIVUP(ipsp->ips_key_bits_a, 8); i++) {
+ kb[i] = akp[i] ^ HMAC_IPAD;
+ }
+ for (; i < AHMD596_BLKLEN; i++) {
+ kb[i] = HMAC_IPAD;
+ }
+
+ ictx = &(((struct md5_ctx*)(ipsp->ips_key_a))->ictx);
+ MD5Init(ictx);
+ MD5Update(ictx, kb, AHMD596_BLKLEN);
+
+ for (i = 0; i < AHMD596_BLKLEN; i++) {
+ kb[i] ^= (HMAC_IPAD ^ HMAC_OPAD);
+ }
+
+ octx = &(((struct md5_ctx*)(ipsp->ips_key_a))->octx);
+ MD5Init(octx);
+ MD5Update(octx, kb, AHMD596_BLKLEN);
+
+# if KLIPS_DIVULGE_HMAC_KEY
+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "MD5 ictx=0x%08x %08x %08x %08x octx=0x%08x %08x %08x %08x\n",
+ ((__u32*)ictx)[0],
+ ((__u32*)ictx)[1],
+ ((__u32*)ictx)[2],
+ ((__u32*)ictx)[3],
+ ((__u32*)octx)[0],
+ ((__u32*)octx)[1],
+ ((__u32*)octx)[2],
+ ((__u32*)octx)[3] );
+# endif /* KLIPS_DIVULGE_HMAC_KEY */
+
+ /* zero key buffer -- paranoid */
+ memset(akp, 0, aks);
+ kfree(akp);
+ }
+ break;
+# endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
+# ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
+ case AH_SHA: {
+ unsigned char *akp;
+ unsigned int aks;
+ SHA1_CTX *ictx;
+ SHA1_CTX *octx;
+
+ if(ipsp->ips_key_bits_a != (AHSHA196_KLEN * 8)) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "incorrect key size: %d bits -- must be %d bits\n"/*octets (bytes)\n"*/,
+ ipsp->ips_key_bits_a, AHSHA196_KLEN * 8);
+ SENDERR(EINVAL);
+ }
+
+# if KLIPS_DIVULGE_HMAC_KEY
+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "hmac sha1-96 key is 0x%08x %08x %08x %08x\n",
+ ntohl(*(((__u32 *)ipsp->ips_key_a)+0)),
+ ntohl(*(((__u32 *)ipsp->ips_key_a)+1)),
+ ntohl(*(((__u32 *)ipsp->ips_key_a)+2)),
+ ntohl(*(((__u32 *)ipsp->ips_key_a)+3)));
+# endif /* KLIPS_DIVULGE_HMAC_KEY */
+
+ ipsp->ips_auth_bits = AHSHA196_ALEN * 8;
+
+ /* save the pointer to the key material */
+ akp = ipsp->ips_key_a;
+ aks = ipsp->ips_key_a_size;
+
+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "allocating %lu bytes for sha1_ctx.\n",
+ (unsigned long) sizeof(struct sha1_ctx));
+ if((ipsp->ips_key_a = (caddr_t)
+ kmalloc(sizeof(struct sha1_ctx), GFP_ATOMIC)) == NULL) {
+ ipsp->ips_key_a = akp;
+ SENDERR(ENOMEM);
+ }
+ ipsp->ips_key_a_size = sizeof(struct sha1_ctx);
+
+ for (i = 0; i < DIVUP(ipsp->ips_key_bits_a, 8); i++) {
+ kb[i] = akp[i] ^ HMAC_IPAD;
+ }
+ for (; i < AHMD596_BLKLEN; i++) {
+ kb[i] = HMAC_IPAD;
+ }
+
+ ictx = &(((struct sha1_ctx*)(ipsp->ips_key_a))->ictx);
+ SHA1Init(ictx);
+ SHA1Update(ictx, kb, AHSHA196_BLKLEN);
+
+ for (i = 0; i < AHSHA196_BLKLEN; i++) {
+ kb[i] ^= (HMAC_IPAD ^ HMAC_OPAD);
+ }
+
+ octx = &(((struct sha1_ctx*)(ipsp->ips_key_a))->octx);
+ SHA1Init(octx);
+ SHA1Update(octx, kb, AHSHA196_BLKLEN);
+
+# if KLIPS_DIVULGE_HMAC_KEY
+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "SHA1 ictx=0x%08x %08x %08x %08x octx=0x%08x %08x %08x %08x\n",
+ ((__u32*)ictx)[0],
+ ((__u32*)ictx)[1],
+ ((__u32*)ictx)[2],
+ ((__u32*)ictx)[3],
+ ((__u32*)octx)[0],
+ ((__u32*)octx)[1],
+ ((__u32*)octx)[2],
+ ((__u32*)octx)[3] );
+# endif /* KLIPS_DIVULGE_HMAC_KEY */
+ /* zero key buffer -- paranoid */
+ memset(akp, 0, aks);
+ kfree(akp);
+ }
+ break;
+# endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
+ default:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "authalg=%d support not available in the kernel",
+ ipsp->ips_authalg);
+ SENDERR(EINVAL);
+ }
+ break;
+#endif /* CONFIG_IPSEC_AH */
+#ifdef CONFIG_IPSEC_ESP
+ case IPPROTO_ESP: {
+#if defined (CONFIG_IPSEC_AUTH_HMAC_MD5) || defined (CONFIG_IPSEC_AUTH_HMAC_SHA1)
+ unsigned char *akp;
+ unsigned int aks;
+#endif
+#if defined (CONFIG_IPSEC_ENC_3DES)
+ unsigned char *ekp;
+ unsigned int eks;
+#endif
+
+ ipsp->ips_iv_size = 0;
+#ifdef CONFIG_IPSEC_ALG
+ if ((ixt_e=ipsp->ips_alg_enc)) {
+ ipsp->ips_iv_size = ixt_e->ixt_ivlen/8;
+ } else
+#endif /* CONFIG_IPSEC_ALG */
+ switch(ipsp->ips_encalg) {
+# ifdef CONFIG_IPSEC_ENC_3DES
+ case ESP_3DES:
+# endif /* CONFIG_IPSEC_ENC_3DES */
+# if defined(CONFIG_IPSEC_ENC_3DES)
+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "allocating %u bytes for iv.\n",
+ EMT_ESPDES_IV_SZ);
+ if((ipsp->ips_iv = (caddr_t)
+ kmalloc((ipsp->ips_iv_size = EMT_ESPDES_IV_SZ), GFP_ATOMIC)) == NULL) {
+ SENDERR(ENOMEM);
+ }
+ prng_bytes(&ipsec_prng, (char *)ipsp->ips_iv, EMT_ESPDES_IV_SZ);
+ ipsp->ips_iv_bits = ipsp->ips_iv_size * 8;
+ ipsp->ips_iv_size = EMT_ESPDES_IV_SZ;
+ break;
+# endif /* defined(CONFIG_IPSEC_ENC_3DES) */
+ case ESP_NONE:
+ break;
+ default:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "encalg=%d support not available in the kernel",
+ ipsp->ips_encalg);
+ SENDERR(EINVAL);
+ }
+
+ /* Create IV */
+ if (ipsp->ips_iv_size) {
+ if((ipsp->ips_iv = (caddr_t)
+ kmalloc(ipsp->ips_iv_size, GFP_ATOMIC)) == NULL) {
+ SENDERR(ENOMEM);
+ }
+ prng_bytes(&ipsec_prng, (char *)ipsp->ips_iv, ipsp->ips_iv_size);
+ ipsp->ips_iv_bits = ipsp->ips_iv_size * 8;
+ }
+
+#ifdef CONFIG_IPSEC_ALG
+ if (ixt_e) {
+ if ((error=ipsec_alg_enc_key_create(ipsp)) < 0)
+ SENDERR(-error);
+ } else
+#endif /* CONFIG_IPSEC_ALG */
+ switch(ipsp->ips_encalg) {
+# ifdef CONFIG_IPSEC_ENC_3DES
+ case ESP_3DES:
+ if(ipsp->ips_key_bits_e != (EMT_ESP3DES_KEY_SZ * 8)) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "incorrect encryption key size: %d bits -- must be %d bits\n"/*octets (bytes)\n"*/,
+ ipsp->ips_key_bits_e, EMT_ESP3DES_KEY_SZ * 8);
+ SENDERR(EINVAL);
+ }
+
+ /* save encryption key pointer */
+ ekp = ipsp->ips_key_e;
+ eks = ipsp->ips_key_e_size;
+
+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "allocating %lu bytes for 3des.\n",
+ (unsigned long) (3 * sizeof(struct des_eks)));
+ if((ipsp->ips_key_e = (caddr_t)
+ kmalloc(3 * sizeof(struct des_eks), GFP_ATOMIC)) == NULL) {
+ ipsp->ips_key_e = ekp;
+ SENDERR(ENOMEM);
+ }
+ ipsp->ips_key_e_size = 3 * sizeof(struct des_eks);
+
+ for(i = 0; i < 3; i++) {
+#if KLIPS_DIVULGE_CYPHER_KEY
+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "3des key %d/3 is 0x%08x%08x\n",
+ i + 1,
+ ntohl(*((__u32 *)ekp + i * 2)),
+ ntohl(*((__u32 *)ekp + i * 2 + 1)));
+# endif
+#if KLIPS_FIXES_DES_PARITY
+ /* force parity */
+ des_set_odd_parity((des_cblock *)(ekp + EMT_ESPDES_KEY_SZ * i));
+#endif
+ error = des_set_key((des_cblock *)(ekp + EMT_ESPDES_KEY_SZ * i),
+ ((struct des_eks *)(ipsp->ips_key_e))[i].ks);
+ if (error == -1)
+ printk("klips_debug:pfkey_ipsec_sa_init: "
+ "parity error in des key %d/3\n",
+ i + 1);
+ else if (error == -2)
+ printk("klips_debug:pfkey_ipsec_sa_init: "
+ "illegal weak des key %d/3\n", i + 1);
+ if (error) {
+ memset(ekp, 0, eks);
+ kfree(ekp);
+ SENDERR(EINVAL);
+ }
+ }
+
+ /* paranoid */
+ memset(ekp, 0, eks);
+ kfree(ekp);
+ break;
+# endif /* CONFIG_IPSEC_ENC_3DES */
+ case ESP_NONE:
+ break;
+ default:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "encalg=%d support not available in the kernel",
+ ipsp->ips_encalg);
+ SENDERR(EINVAL);
+ }
+
+#ifdef CONFIG_IPSEC_ALG
+ if ((ixt_a=ipsp->ips_alg_auth)) {
+ if ((error=ipsec_alg_auth_key_create(ipsp)) < 0)
+ SENDERR(-error);
+ } else
+#endif /* CONFIG_IPSEC_ALG */
+
+ switch(ipsp->ips_authalg) {
+# ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
+ case AH_MD5: {
+ MD5_CTX *ictx;
+ MD5_CTX *octx;
+
+ if(ipsp->ips_key_bits_a != (AHMD596_KLEN * 8)) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "incorrect authorisation key size: %d bits -- must be %d bits\n"/*octets (bytes)\n"*/,
+ ipsp->ips_key_bits_a,
+ AHMD596_KLEN * 8);
+ SENDERR(EINVAL);
+ }
+
+# if KLIPS_DIVULGE_HMAC_KEY
+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "hmac md5-96 key is 0x%08x %08x %08x %08x\n",
+ ntohl(*(((__u32 *)(ipsp->ips_key_a))+0)),
+ ntohl(*(((__u32 *)(ipsp->ips_key_a))+1)),
+ ntohl(*(((__u32 *)(ipsp->ips_key_a))+2)),
+ ntohl(*(((__u32 *)(ipsp->ips_key_a))+3)));
+# endif /* KLIPS_DIVULGE_HMAC_KEY */
+ ipsp->ips_auth_bits = AHMD596_ALEN * 8;
+
+ /* save the pointer to the key material */
+ akp = ipsp->ips_key_a;
+ aks = ipsp->ips_key_a_size;
+
+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "allocating %lu bytes for md5_ctx.\n",
+ (unsigned long) sizeof(struct md5_ctx));
+ if((ipsp->ips_key_a = (caddr_t)
+ kmalloc(sizeof(struct md5_ctx), GFP_ATOMIC)) == NULL) {
+ ipsp->ips_key_a = akp;
+ SENDERR(ENOMEM);
+ }
+ ipsp->ips_key_a_size = sizeof(struct md5_ctx);
+
+ for (i = 0; i < DIVUP(ipsp->ips_key_bits_a, 8); i++) {
+ kb[i] = akp[i] ^ HMAC_IPAD;
+ }
+ for (; i < AHMD596_BLKLEN; i++) {
+ kb[i] = HMAC_IPAD;
+ }
+
+ ictx = &(((struct md5_ctx*)(ipsp->ips_key_a))->ictx);
+ MD5Init(ictx);
+ MD5Update(ictx, kb, AHMD596_BLKLEN);
+
+ for (i = 0; i < AHMD596_BLKLEN; i++) {
+ kb[i] ^= (HMAC_IPAD ^ HMAC_OPAD);
+ }
+
+ octx = &(((struct md5_ctx*)(ipsp->ips_key_a))->octx);
+ MD5Init(octx);
+ MD5Update(octx, kb, AHMD596_BLKLEN);
+
+# if KLIPS_DIVULGE_HMAC_KEY
+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "MD5 ictx=0x%08x %08x %08x %08x octx=0x%08x %08x %08x %08x\n",
+ ((__u32*)ictx)[0],
+ ((__u32*)ictx)[1],
+ ((__u32*)ictx)[2],
+ ((__u32*)ictx)[3],
+ ((__u32*)octx)[0],
+ ((__u32*)octx)[1],
+ ((__u32*)octx)[2],
+ ((__u32*)octx)[3] );
+# endif /* KLIPS_DIVULGE_HMAC_KEY */
+ /* paranoid */
+ memset(akp, 0, aks);
+ kfree(akp);
+ break;
+ }
+# endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
+# ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
+ case AH_SHA: {
+ SHA1_CTX *ictx;
+ SHA1_CTX *octx;
+
+ if(ipsp->ips_key_bits_a != (AHSHA196_KLEN * 8)) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "incorrect authorisation key size: %d bits -- must be %d bits\n"/*octets (bytes)\n"*/,
+ ipsp->ips_key_bits_a,
+ AHSHA196_KLEN * 8);
+ SENDERR(EINVAL);
+ }
+
+# if KLIPS_DIVULGE_HMAC_KEY
+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "hmac sha1-96 key is 0x%08x %08x %08x %08x\n",
+ ntohl(*(((__u32 *)ipsp->ips_key_a)+0)),
+ ntohl(*(((__u32 *)ipsp->ips_key_a)+1)),
+ ntohl(*(((__u32 *)ipsp->ips_key_a)+2)),
+ ntohl(*(((__u32 *)ipsp->ips_key_a)+3)));
+# endif /* KLIPS_DIVULGE_HMAC_KEY */
+ ipsp->ips_auth_bits = AHSHA196_ALEN * 8;
+
+ /* save the pointer to the key material */
+ akp = ipsp->ips_key_a;
+ aks = ipsp->ips_key_a_size;
+
+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "allocating %lu bytes for sha1_ctx.\n",
+ (unsigned long) sizeof(struct sha1_ctx));
+ if((ipsp->ips_key_a = (caddr_t)
+ kmalloc(sizeof(struct sha1_ctx), GFP_ATOMIC)) == NULL) {
+ ipsp->ips_key_a = akp;
+ SENDERR(ENOMEM);
+ }
+ ipsp->ips_key_a_size = sizeof(struct sha1_ctx);
+
+ for (i = 0; i < DIVUP(ipsp->ips_key_bits_a, 8); i++) {
+ kb[i] = akp[i] ^ HMAC_IPAD;
+ }
+ for (; i < AHMD596_BLKLEN; i++) {
+ kb[i] = HMAC_IPAD;
+ }
+
+ ictx = &(((struct sha1_ctx*)(ipsp->ips_key_a))->ictx);
+ SHA1Init(ictx);
+ SHA1Update(ictx, kb, AHSHA196_BLKLEN);
+
+ for (i = 0; i < AHSHA196_BLKLEN; i++) {
+ kb[i] ^= (HMAC_IPAD ^ HMAC_OPAD);
+ }
+
+ octx = &((struct sha1_ctx*)(ipsp->ips_key_a))->octx;
+ SHA1Init(octx);
+ SHA1Update(octx, kb, AHSHA196_BLKLEN);
+
+# if KLIPS_DIVULGE_HMAC_KEY
+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "SHA1 ictx=0x%08x %08x %08x %08x octx=0x%08x %08x %08x %08x\n",
+ ((__u32*)ictx)[0],
+ ((__u32*)ictx)[1],
+ ((__u32*)ictx)[2],
+ ((__u32*)ictx)[3],
+ ((__u32*)octx)[0],
+ ((__u32*)octx)[1],
+ ((__u32*)octx)[2],
+ ((__u32*)octx)[3] );
+# endif /* KLIPS_DIVULGE_HMAC_KEY */
+ memset(akp, 0, aks);
+ kfree(akp);
+ break;
+ }
+# endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
+ case AH_NONE:
+ break;
+ default:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "authalg=%d support not available in the kernel.\n",
+ ipsp->ips_authalg);
+ SENDERR(EINVAL);
+ }
+ }
+ break;
+#endif /* !CONFIG_IPSEC_ESP */
+#ifdef CONFIG_IPSEC_IPCOMP
+ case IPPROTO_COMP:
+ ipsp->ips_comp_adapt_tries = 0;
+ ipsp->ips_comp_adapt_skip = 0;
+ ipsp->ips_comp_ratio_cbytes = 0;
+ ipsp->ips_comp_ratio_dbytes = 0;
+ break;
+#endif /* CONFIG_IPSEC_IPCOMP */
+ default:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "proto=%d unknown.\n",
+ ipsp->ips_said.proto);
+ SENDERR(EINVAL);
+ }
+
+ errlab:
+ return(error);
+}
+
+
+int
+pfkey_safe_build(int error, struct sadb_ext *extensions[SADB_MAX+1])
+{
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_safe_build: "
+ "error=%d\n",
+ error);
+ if (!error) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_safe_build:"
+ "success.\n");
+ return 1;
+ } else {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_safe_build:"
+ "caught error %d\n",
+ error);
+ pfkey_extensions_free(extensions);
+ return 0;
+ }
+}
+
+
+DEBUG_NO_STATIC int
+pfkey_getspi_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+ ipsec_spi_t minspi = htonl(256), maxspi = htonl(-1L);
+ int found_avail = 0;
+ struct ipsec_sa *ipsq;
+ char sa[SATOA_BUF];
+ size_t sa_len;
+ struct sadb_ext *extensions_reply[SADB_EXT_MAX+1];
+ struct sadb_msg *pfkey_reply = NULL;
+ struct socket_list *pfkey_socketsp;
+ uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_getspi_parse: .\n");
+
+ pfkey_extensions_init(extensions_reply);
+
+ if(extr == NULL || extr->ips == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_getspi_parse: "
+ "error, extr or extr->ipsec_sa pointer NULL\n");
+ SENDERR(EINVAL);
+ }
+
+ if(extensions[SADB_EXT_SPIRANGE]) {
+ minspi = ((struct sadb_spirange *)extensions[SADB_EXT_SPIRANGE])->sadb_spirange_min;
+ maxspi = ((struct sadb_spirange *)extensions[SADB_EXT_SPIRANGE])->sadb_spirange_max;
+ }
+
+ if(maxspi == minspi) {
+ extr->ips->ips_said.spi = maxspi;
+ ipsq = ipsec_sa_getbyid(&(extr->ips->ips_said));
+ if(ipsq != NULL) {
+ sa_len = satoa(extr->ips->ips_said, 0, sa, SATOA_BUF);
+ ipsec_sa_put(ipsq);
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_getspi_parse: "
+ "EMT_GETSPI found an old ipsec_sa for SA: %s, delete it first.\n",
+ sa_len ? sa : " (error)");
+ SENDERR(EEXIST);
+ } else {
+ found_avail = 1;
+ }
+ } else {
+ int i = 0;
+ __u32 rand_val;
+ __u32 spi_diff;
+ while( ( i < (spi_diff = (ntohl(maxspi) - ntohl(minspi)))) && !found_avail ) {
+ prng_bytes(&ipsec_prng, (char *) &(rand_val),
+ ( (spi_diff < (2^8)) ? 1 :
+ ( (spi_diff < (2^16)) ? 2 :
+ ( (spi_diff < (2^24)) ? 3 :
+ 4 ) ) ) );
+ extr->ips->ips_said.spi = htonl(ntohl(minspi) +
+ (rand_val %
+ (spi_diff + 1)));
+ i++;
+ ipsq = ipsec_sa_getbyid(&(extr->ips->ips_said));
+ if(ipsq == NULL) {
+ found_avail = 1;
+ } else {
+ ipsec_sa_put(ipsq);
+ }
+ }
+ }
+
+ sa_len = satoa(extr->ips->ips_said, 0, sa, SATOA_BUF);
+
+ if (!found_avail) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_getspi_parse: "
+ "found an old ipsec_sa for SA: %s, delete it first.\n",
+ sa_len ? sa : " (error)");
+ SENDERR(EEXIST);
+ }
+
+ if(ip_chk_addr((unsigned long)extr->ips->ips_said.dst.s_addr) == IS_MYADDR) {
+ extr->ips->ips_flags |= EMT_INBOUND;
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_getspi_parse: "
+ "existing ipsec_sa not found (this is good) for SA: %s, %s-bound, allocating.\n",
+ sa_len ? sa : " (error)",
+ extr->ips->ips_flags & EMT_INBOUND ? "in" : "out");
+
+ /* XXX extr->ips->ips_rcvif = &(enc_softc[em->em_if].enc_if);*/
+ extr->ips->ips_rcvif = NULL;
+ extr->ips->ips_life.ipl_addtime.ipl_count = jiffies/HZ;
+
+ extr->ips->ips_state = SADB_SASTATE_LARVAL;
+
+ if(!extr->ips->ips_life.ipl_allocations.ipl_count) {
+ extr->ips->ips_life.ipl_allocations.ipl_count += 1;
+ }
+
+ if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
+ SADB_GETSPI,
+ satype,
+ 0,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_seq,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions_reply[SADB_EXT_SA],
+ SADB_EXT_SA,
+ extr->ips->ips_said.spi,
+ 0,
+ SADB_SASTATE_LARVAL,
+ 0,
+ 0,
+ 0,
+ extr->ips->ips_ref),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_SRC],
+ SADB_EXT_ADDRESS_SRC,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ extr->ips->ips_addr_s),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_DST],
+ SADB_EXT_ADDRESS_DST,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ extr->ips->ips_addr_d),
+ extensions_reply) )) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_getspi_parse: "
+ "failed to build the getspi reply message extensions\n");
+ goto errlab;
+ }
+
+ if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_getspi_parse: "
+ "failed to build the getspi reply message\n");
+ SENDERR(-error);
+ }
+ for(pfkey_socketsp = pfkey_open_sockets;
+ pfkey_socketsp;
+ pfkey_socketsp = pfkey_socketsp->next) {
+ if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_getspi_parse: "
+ "sending up getspi reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp,
+ error);
+ SENDERR(-error);
+ }
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_getspi_parse: "
+ "sending up getspi reply message for satype=%d(%s) to socket=0p%p succeeded.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp);
+ }
+
+ if((error = ipsec_sa_add(extr->ips))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_getspi_parse: "
+ "failed to add the larval SA=%s with error=%d.\n",
+ sa_len ? sa : " (error)",
+ error);
+ SENDERR(-error);
+ }
+ extr->ips = NULL;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_getspi_parse: "
+ "successful for SA: %s\n",
+ sa_len ? sa : " (error)");
+
+ errlab:
+ if (pfkey_reply) {
+ pfkey_msg_free(&pfkey_reply);
+ }
+ pfkey_extensions_free(extensions_reply);
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_update_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+ struct ipsec_sa* ipsq;
+ char sa[SATOA_BUF];
+ size_t sa_len;
+ struct sadb_ext *extensions_reply[SADB_EXT_MAX+1];
+ struct sadb_msg *pfkey_reply = NULL;
+ struct socket_list *pfkey_socketsp;
+ uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype;
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ struct ipsec_sa *nat_t_ips_saved = NULL;
+#endif
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_update_parse: .\n");
+
+ pfkey_extensions_init(extensions_reply);
+
+ if(((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state != SADB_SASTATE_MATURE) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_update_parse: "
+ "error, sa_state=%d must be MATURE=%d\n",
+ ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state,
+ SADB_SASTATE_MATURE);
+ SENDERR(EINVAL);
+ }
+
+ if(extr == NULL || extr->ips == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_update_parse: "
+ "error, extr or extr->ips pointer NULL\n");
+ SENDERR(EINVAL);
+ }
+
+ sa_len = satoa(extr->ips->ips_said, 0, sa, SATOA_BUF);
+
+ spin_lock_bh(&tdb_lock);
+
+ ipsq = ipsec_sa_getbyid(&(extr->ips->ips_said));
+ if (ipsq == NULL) {
+ spin_unlock_bh(&tdb_lock);
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_update_parse: "
+ "reserved ipsec_sa for SA: %s not found. Call SADB_GETSPI first or call SADB_ADD instead.\n",
+ sa_len ? sa : " (error)");
+ SENDERR(ENOENT);
+ }
+
+ if(ip_chk_addr((unsigned long)extr->ips->ips_said.dst.s_addr) == IS_MYADDR) {
+ extr->ips->ips_flags |= EMT_INBOUND;
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_update_parse: "
+ "existing ipsec_sa found (this is good) for SA: %s, %s-bound, updating.\n",
+ sa_len ? sa : " (error)",
+ extr->ips->ips_flags & EMT_INBOUND ? "in" : "out");
+
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ if (extr->ips->ips_natt_sport || extr->ips->ips_natt_dport) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_update_parse: only updating NAT-T ports "
+ "(%u:%u -> %u:%u)\n",
+ ipsq->ips_natt_sport, ipsq->ips_natt_dport,
+ extr->ips->ips_natt_sport, extr->ips->ips_natt_dport);
+
+ if (extr->ips->ips_natt_sport) {
+ ipsq->ips_natt_sport = extr->ips->ips_natt_sport;
+ if (ipsq->ips_addr_s->sa_family == AF_INET) {
+ ((struct sockaddr_in *)(ipsq->ips_addr_s))->sin_port = htons(extr->ips->ips_natt_sport);
+ }
+ }
+
+ if (extr->ips->ips_natt_dport) {
+ ipsq->ips_natt_dport = extr->ips->ips_natt_dport;
+ if (ipsq->ips_addr_d->sa_family == AF_INET) {
+ ((struct sockaddr_in *)(ipsq->ips_addr_d))->sin_port = htons(extr->ips->ips_natt_dport);
+ }
+ }
+
+ nat_t_ips_saved = extr->ips;
+ extr->ips = ipsq;
+ }
+ else {
+#endif
+
+ /* XXX extr->ips->ips_rcvif = &(enc_softc[em->em_if].enc_if);*/
+ extr->ips->ips_rcvif = NULL;
+ if ((error = pfkey_ipsec_sa_init(extr->ips, extensions))) {
+ ipsec_sa_put(ipsq);
+ spin_unlock_bh(&tdb_lock);
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_update_parse: "
+ "not successful for SA: %s, deleting.\n",
+ sa_len ? sa : " (error)");
+ SENDERR(-error);
+ }
+
+ extr->ips->ips_life.ipl_addtime.ipl_count = ipsq->ips_life.ipl_addtime.ipl_count;
+ ipsec_sa_put(ipsq);
+ if((error = ipsec_sa_delchain(ipsq))) {
+ spin_unlock_bh(&tdb_lock);
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_update_parse: "
+ "error=%d, trouble deleting intermediate ipsec_sa for SA=%s.\n",
+ error,
+ sa_len ? sa : " (error)");
+ SENDERR(-error);
+ }
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ }
+#endif
+
+ spin_unlock_bh(&tdb_lock);
+
+ if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
+ SADB_UPDATE,
+ satype,
+ 0,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_seq,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions_reply[SADB_EXT_SA],
+ SADB_EXT_SA,
+ extr->ips->ips_said.spi,
+ extr->ips->ips_replaywin,
+ extr->ips->ips_state,
+ extr->ips->ips_authalg,
+ extr->ips->ips_encalg,
+ extr->ips->ips_flags,
+ extr->ips->ips_ref),
+ extensions_reply)
+ /* The 3 lifetime extentions should only be sent if non-zero. */
+ && (extensions[SADB_EXT_LIFETIME_HARD]
+ ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[SADB_EXT_LIFETIME_HARD],
+ SADB_EXT_LIFETIME_HARD,
+ extr->ips->ips_life.ipl_allocations.ipl_hard,
+ extr->ips->ips_life.ipl_bytes.ipl_hard,
+ extr->ips->ips_life.ipl_addtime.ipl_hard,
+ extr->ips->ips_life.ipl_usetime.ipl_hard,
+ extr->ips->ips_life.ipl_packets.ipl_hard),
+ extensions_reply) : 1)
+ && (extensions[SADB_EXT_LIFETIME_SOFT]
+ ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[SADB_EXT_LIFETIME_SOFT],
+ SADB_EXT_LIFETIME_SOFT,
+ extr->ips->ips_life.ipl_allocations.ipl_count,
+ extr->ips->ips_life.ipl_bytes.ipl_count,
+ extr->ips->ips_life.ipl_addtime.ipl_count,
+ extr->ips->ips_life.ipl_usetime.ipl_count,
+ extr->ips->ips_life.ipl_packets.ipl_count),
+ extensions_reply) : 1)
+ && (extr->ips->ips_life.ipl_allocations.ipl_count
+ || extr->ips->ips_life.ipl_bytes.ipl_count
+ || extr->ips->ips_life.ipl_addtime.ipl_count
+ || extr->ips->ips_life.ipl_usetime.ipl_count
+ || extr->ips->ips_life.ipl_packets.ipl_count
+
+ ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[SADB_EXT_LIFETIME_CURRENT],
+ SADB_EXT_LIFETIME_CURRENT,
+ extr->ips->ips_life.ipl_allocations.ipl_count,
+ extr->ips->ips_life.ipl_bytes.ipl_count,
+ extr->ips->ips_life.ipl_addtime.ipl_count,
+ extr->ips->ips_life.ipl_usetime.ipl_count,
+ extr->ips->ips_life.ipl_packets.ipl_count),
+ extensions_reply) : 1)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_SRC],
+ SADB_EXT_ADDRESS_SRC,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ extr->ips->ips_addr_s),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_DST],
+ SADB_EXT_ADDRESS_DST,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ extr->ips->ips_addr_d),
+ extensions_reply)
+ && (extr->ips->ips_ident_s.data
+ ? pfkey_safe_build(error = pfkey_ident_build(&extensions_reply[SADB_EXT_IDENTITY_SRC],
+ SADB_EXT_IDENTITY_SRC,
+ extr->ips->ips_ident_s.type,
+ extr->ips->ips_ident_s.id,
+ extr->ips->ips_ident_s.len,
+ extr->ips->ips_ident_s.data),
+ extensions_reply) : 1)
+ && (extr->ips->ips_ident_d.data
+ ? pfkey_safe_build(error = pfkey_ident_build(&extensions_reply[SADB_EXT_IDENTITY_DST],
+ SADB_EXT_IDENTITY_DST,
+ extr->ips->ips_ident_d.type,
+ extr->ips->ips_ident_d.id,
+ extr->ips->ips_ident_d.len,
+ extr->ips->ips_ident_d.data),
+ extensions_reply) : 1)
+#if 0
+ /* FIXME: This won't work yet because I have not finished
+ it. */
+ && (extr->ips->ips_sens_
+ ? pfkey_safe_build(error = pfkey_sens_build(&extensions_reply[SADB_EXT_SENSITIVITY],
+ extr->ips->ips_sens_dpd,
+ extr->ips->ips_sens_sens_level,
+ extr->ips->ips_sens_sens_len,
+ extr->ips->ips_sens_sens_bitmap,
+ extr->ips->ips_sens_integ_level,
+ extr->ips->ips_sens_integ_len,
+ extr->ips->ips_sens_integ_bitmap),
+ extensions_reply) : 1)
+#endif
+ )) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_update_parse: "
+ "failed to build the update reply message extensions\n");
+ SENDERR(-error);
+ }
+
+ if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_update_parse: "
+ "failed to build the update reply message\n");
+ SENDERR(-error);
+ }
+ for(pfkey_socketsp = pfkey_open_sockets;
+ pfkey_socketsp;
+ pfkey_socketsp = pfkey_socketsp->next) {
+ if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_update_parse: "
+ "sending up update reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp,
+ error);
+ SENDERR(-error);
+ }
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_update_parse: "
+ "sending up update reply message for satype=%d(%s) to socket=0p%p succeeded.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp);
+ }
+
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ if (nat_t_ips_saved) {
+ /**
+ * As we _really_ update existing SA, we keep tdbq and need to delete
+ * parsed ips (nat_t_ips_saved, was extr->ips).
+ *
+ * goto errlab with extr->ips = nat_t_ips_saved will free it.
+ */
+
+ extr->ips = nat_t_ips_saved;
+
+ error = 0;
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_update_parse (NAT-T ports): "
+ "successful for SA: %s\n",
+ sa_len ? sa : " (error)");
+
+ goto errlab;
+ }
+#endif
+
+ if((error = ipsec_sa_add(extr->ips))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_update_parse: "
+ "failed to update the mature SA=%s with error=%d.\n",
+ sa_len ? sa : " (error)",
+ error);
+ SENDERR(-error);
+ }
+ extr->ips = NULL;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_update_parse: "
+ "successful for SA: %s\n",
+ sa_len ? sa : " (error)");
+
+ errlab:
+ if (pfkey_reply) {
+ pfkey_msg_free(&pfkey_reply);
+ }
+ pfkey_extensions_free(extensions_reply);
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_add_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+ struct ipsec_sa* ipsq;
+ char sa[SATOA_BUF];
+ size_t sa_len;
+ struct sadb_ext *extensions_reply[SADB_EXT_MAX+1];
+ struct sadb_msg *pfkey_reply = NULL;
+ struct socket_list *pfkey_socketsp;
+ uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_add_parse: .\n");
+
+ pfkey_extensions_init(extensions_reply);
+
+ if(((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state != SADB_SASTATE_MATURE) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_add_parse: "
+ "error, sa_state=%d must be MATURE=%d\n",
+ ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state,
+ SADB_SASTATE_MATURE);
+ SENDERR(EINVAL);
+ }
+
+ if(!extr || !extr->ips) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_add_parse: "
+ "extr or extr->ips pointer NULL\n");
+ SENDERR(EINVAL);
+ }
+
+ sa_len = satoa(extr->ips->ips_said, 0, sa, SATOA_BUF);
+
+ ipsq = ipsec_sa_getbyid(&(extr->ips->ips_said));
+ if(ipsq != NULL) {
+ ipsec_sa_put(ipsq);
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_add_parse: "
+ "found an old ipsec_sa for SA%s, delete it first.\n",
+ sa_len ? sa : " (error)");
+ SENDERR(EEXIST);
+ }
+
+ if(ip_chk_addr((unsigned long)extr->ips->ips_said.dst.s_addr) == IS_MYADDR) {
+ extr->ips->ips_flags |= EMT_INBOUND;
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_add_parse: "
+ "existing ipsec_sa not found (this is good) for SA%s, %s-bound, allocating.\n",
+ sa_len ? sa : " (error)",
+ extr->ips->ips_flags & EMT_INBOUND ? "in" : "out");
+
+ /* XXX extr->ips->ips_rcvif = &(enc_softc[em->em_if].enc_if);*/
+ extr->ips->ips_rcvif = NULL;
+
+ if ((error = pfkey_ipsec_sa_init(extr->ips, extensions))) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_add_parse: "
+ "not successful for SA: %s, deleting.\n",
+ sa_len ? sa : " (error)");
+ SENDERR(-error);
+ }
+
+ extr->ips->ips_life.ipl_addtime.ipl_count = jiffies / HZ;
+ if(!extr->ips->ips_life.ipl_allocations.ipl_count) {
+ extr->ips->ips_life.ipl_allocations.ipl_count += 1;
+ }
+
+ if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
+ SADB_ADD,
+ satype,
+ 0,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_seq,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions_reply[SADB_EXT_SA],
+ SADB_EXT_SA,
+ extr->ips->ips_said.spi,
+ extr->ips->ips_replaywin,
+ extr->ips->ips_state,
+ extr->ips->ips_authalg,
+ extr->ips->ips_encalg,
+ extr->ips->ips_flags,
+ extr->ips->ips_ref),
+ extensions_reply)
+ /* The 3 lifetime extentions should only be sent if non-zero. */
+ && (extensions[SADB_EXT_LIFETIME_HARD]
+ ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[SADB_EXT_LIFETIME_HARD],
+ SADB_EXT_LIFETIME_HARD,
+ extr->ips->ips_life.ipl_allocations.ipl_hard,
+ extr->ips->ips_life.ipl_bytes.ipl_hard,
+ extr->ips->ips_life.ipl_addtime.ipl_hard,
+ extr->ips->ips_life.ipl_usetime.ipl_hard,
+ extr->ips->ips_life.ipl_packets.ipl_hard),
+ extensions_reply) : 1)
+ && (extensions[SADB_EXT_LIFETIME_SOFT]
+ ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[SADB_EXT_LIFETIME_SOFT],
+ SADB_EXT_LIFETIME_SOFT,
+ extr->ips->ips_life.ipl_allocations.ipl_soft,
+ extr->ips->ips_life.ipl_bytes.ipl_soft,
+ extr->ips->ips_life.ipl_addtime.ipl_soft,
+ extr->ips->ips_life.ipl_usetime.ipl_soft,
+ extr->ips->ips_life.ipl_packets.ipl_soft),
+ extensions_reply) : 1)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_SRC],
+ SADB_EXT_ADDRESS_SRC,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ extr->ips->ips_addr_s),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_DST],
+ SADB_EXT_ADDRESS_DST,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ extr->ips->ips_addr_d),
+ extensions_reply)
+ && (extr->ips->ips_ident_s.data
+ ? pfkey_safe_build(error = pfkey_ident_build(&extensions_reply[SADB_EXT_IDENTITY_SRC],
+ SADB_EXT_IDENTITY_SRC,
+ extr->ips->ips_ident_s.type,
+ extr->ips->ips_ident_s.id,
+ extr->ips->ips_ident_s.len,
+ extr->ips->ips_ident_s.data),
+ extensions_reply) : 1)
+ && (extr->ips->ips_ident_d.data
+ ? pfkey_safe_build(error = pfkey_ident_build(&extensions_reply[SADB_EXT_IDENTITY_DST],
+ SADB_EXT_IDENTITY_DST,
+ extr->ips->ips_ident_d.type,
+ extr->ips->ips_ident_d.id,
+ extr->ips->ips_ident_d.len,
+ extr->ips->ips_ident_d.data),
+ extensions_reply) : 1)
+#if 0
+ /* FIXME: This won't work yet because I have not finished
+ it. */
+ && (extr->ips->ips_sens_
+ ? pfkey_safe_build(error = pfkey_sens_build(&extensions_reply[SADB_EXT_SENSITIVITY],
+ extr->ips->ips_sens_dpd,
+ extr->ips->ips_sens_sens_level,
+ extr->ips->ips_sens_sens_len,
+ extr->ips->ips_sens_sens_bitmap,
+ extr->ips->ips_sens_integ_level,
+ extr->ips->ips_sens_integ_len,
+ extr->ips->ips_sens_integ_bitmap),
+ extensions_reply) : 1)
+#endif
+ )) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_add_parse: "
+ "failed to build the add reply message extensions\n");
+ SENDERR(-error);
+ }
+
+ if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_add_parse: "
+ "failed to build the add reply message\n");
+ SENDERR(-error);
+ }
+ for(pfkey_socketsp = pfkey_open_sockets;
+ pfkey_socketsp;
+ pfkey_socketsp = pfkey_socketsp->next) {
+ if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_add_parse: "
+ "sending up add reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp,
+ error);
+ SENDERR(-error);
+ }
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_add_parse: "
+ "sending up add reply message for satype=%d(%s) to socket=0p%p succeeded.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp);
+ }
+
+ if((error = ipsec_sa_add(extr->ips))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_add_parse: "
+ "failed to add the mature SA=%s with error=%d.\n",
+ sa_len ? sa : " (error)",
+ error);
+ SENDERR(-error);
+ }
+ extr->ips = NULL;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_add_parse: "
+ "successful for SA: %s\n",
+ sa_len ? sa : " (error)");
+
+ errlab:
+ if (pfkey_reply) {
+ pfkey_msg_free(&pfkey_reply);
+ }
+ pfkey_extensions_free(extensions_reply);
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_delete_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
+{
+ struct ipsec_sa *ipsp;
+ char sa[SATOA_BUF];
+ size_t sa_len;
+ int error = 0;
+ struct sadb_ext *extensions_reply[SADB_EXT_MAX+1];
+ struct sadb_msg *pfkey_reply = NULL;
+ struct socket_list *pfkey_socketsp;
+ uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_delete_parse: .\n");
+
+ pfkey_extensions_init(extensions_reply);
+
+ if(!extr || !extr->ips) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_delete_parse: "
+ "extr or extr->ips pointer NULL, fatal\n");
+ SENDERR(EINVAL);
+ }
+
+ sa_len = satoa(extr->ips->ips_said, 0, sa, SATOA_BUF);
+
+ spin_lock_bh(&tdb_lock);
+
+ ipsp = ipsec_sa_getbyid(&(extr->ips->ips_said));
+ if (ipsp == NULL) {
+ spin_unlock_bh(&tdb_lock);
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_delete_parse: "
+ "ipsec_sa not found for SA:%s, could not delete.\n",
+ sa_len ? sa : " (error)");
+ SENDERR(ESRCH);
+ }
+
+ ipsec_sa_put(ipsp);
+ if((error = ipsec_sa_delchain(ipsp))) {
+ spin_unlock_bh(&tdb_lock);
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_delete_parse: "
+ "error=%d returned trying to delete ipsec_sa for SA:%s.\n",
+ error,
+ sa_len ? sa : " (error)");
+ SENDERR(-error);
+ }
+ spin_unlock_bh(&tdb_lock);
+
+ if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
+ SADB_DELETE,
+ satype,
+ 0,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_seq,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions_reply[SADB_EXT_SA],
+ SADB_EXT_SA,
+ extr->ips->ips_said.spi,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ extr->ips->ips_ref),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_SRC],
+ SADB_EXT_ADDRESS_SRC,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ extr->ips->ips_addr_s),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_DST],
+ SADB_EXT_ADDRESS_DST,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ extr->ips->ips_addr_d),
+ extensions_reply)
+ )) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_delete_parse: "
+ "failed to build the delete reply message extensions\n");
+ SENDERR(-error);
+ }
+
+ if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_delete_parse: "
+ "failed to build the delete reply message\n");
+ SENDERR(-error);
+ }
+ for(pfkey_socketsp = pfkey_open_sockets;
+ pfkey_socketsp;
+ pfkey_socketsp = pfkey_socketsp->next) {
+ if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_delete_parse: "
+ "sending up delete reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp,
+ error);
+ SENDERR(-error);
+ }
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_delete_parse: "
+ "sending up delete reply message for satype=%d(%s) to socket=0p%p succeeded.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp);
+ }
+
+ errlab:
+ if (pfkey_reply) {
+ pfkey_msg_free(&pfkey_reply);
+ }
+ pfkey_extensions_free(extensions_reply);
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_get_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+ struct ipsec_sa *ipsp;
+ char sa[SATOA_BUF];
+ size_t sa_len;
+ struct sadb_ext *extensions_reply[SADB_EXT_MAX+1];
+ struct sadb_msg *pfkey_reply = NULL;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_get_parse: .\n");
+
+ pfkey_extensions_init(extensions_reply);
+
+ if(!extr || !extr->ips) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_get_parse: "
+ "extr or extr->ips pointer NULL, fatal\n");
+ SENDERR(EINVAL);
+ }
+
+ sa_len = satoa(extr->ips->ips_said, 0, sa, SATOA_BUF);
+
+ spin_lock_bh(&tdb_lock);
+
+ ipsp = ipsec_sa_getbyid(&(extr->ips->ips_said));
+ if (ipsp == NULL) {
+ spin_unlock_bh(&tdb_lock);
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_get_parse: "
+ "ipsec_sa not found for SA=%s, could not get.\n",
+ sa_len ? sa : " (error)");
+ SENDERR(ESRCH);
+ }
+
+ if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
+ SADB_GET,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype,
+ 0,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_seq,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions_reply[SADB_EXT_SA],
+ SADB_EXT_SA,
+ extr->ips->ips_said.spi,
+ extr->ips->ips_replaywin,
+ extr->ips->ips_state,
+ extr->ips->ips_authalg,
+ extr->ips->ips_encalg,
+ extr->ips->ips_flags,
+ extr->ips->ips_ref),
+ extensions_reply)
+ /* The 3 lifetime extentions should only be sent if non-zero. */
+ && (ipsp->ips_life.ipl_allocations.ipl_count
+ || ipsp->ips_life.ipl_bytes.ipl_count
+ || ipsp->ips_life.ipl_addtime.ipl_count
+ || ipsp->ips_life.ipl_usetime.ipl_count
+ || ipsp->ips_life.ipl_packets.ipl_count
+ ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[SADB_EXT_LIFETIME_CURRENT],
+ SADB_EXT_LIFETIME_CURRENT,
+ ipsp->ips_life.ipl_allocations.ipl_count,
+ ipsp->ips_life.ipl_bytes.ipl_count,
+ ipsp->ips_life.ipl_addtime.ipl_count,
+ ipsp->ips_life.ipl_usetime.ipl_count,
+ ipsp->ips_life.ipl_packets.ipl_count),
+ extensions_reply) : 1)
+ && (ipsp->ips_life.ipl_allocations.ipl_hard
+ || ipsp->ips_life.ipl_bytes.ipl_hard
+ || ipsp->ips_life.ipl_addtime.ipl_hard
+ || ipsp->ips_life.ipl_usetime.ipl_hard
+ || ipsp->ips_life.ipl_packets.ipl_hard
+ ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[SADB_EXT_LIFETIME_HARD],
+ SADB_EXT_LIFETIME_HARD,
+ ipsp->ips_life.ipl_allocations.ipl_hard,
+ ipsp->ips_life.ipl_bytes.ipl_hard,
+ ipsp->ips_life.ipl_addtime.ipl_hard,
+ ipsp->ips_life.ipl_usetime.ipl_hard,
+ ipsp->ips_life.ipl_packets.ipl_hard),
+ extensions_reply) : 1)
+ && (ipsp->ips_life.ipl_allocations.ipl_soft
+ || ipsp->ips_life.ipl_bytes.ipl_soft
+ || ipsp->ips_life.ipl_addtime.ipl_soft
+ || ipsp->ips_life.ipl_usetime.ipl_soft
+ || ipsp->ips_life.ipl_packets.ipl_soft
+ ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[SADB_EXT_LIFETIME_SOFT],
+ SADB_EXT_LIFETIME_SOFT,
+ ipsp->ips_life.ipl_allocations.ipl_soft,
+ ipsp->ips_life.ipl_bytes.ipl_soft,
+ ipsp->ips_life.ipl_addtime.ipl_soft,
+ ipsp->ips_life.ipl_usetime.ipl_soft,
+ ipsp->ips_life.ipl_packets.ipl_soft),
+ extensions_reply) : 1)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_SRC],
+ SADB_EXT_ADDRESS_SRC,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ extr->ips->ips_addr_s),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_DST],
+ SADB_EXT_ADDRESS_DST,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ extr->ips->ips_addr_d),
+ extensions_reply)
+ && (extr->ips->ips_addr_p
+ ? pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_PROXY],
+ SADB_EXT_ADDRESS_PROXY,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ extr->ips->ips_addr_p),
+ extensions_reply) : 1)
+#if 0
+ /* FIXME: This won't work yet because the keys are not
+ stored directly in the ipsec_sa. They are stored as
+ contexts. */
+ && (extr->ips->ips_key_a_size
+ ? pfkey_safe_build(error = pfkey_key_build(&extensions_reply[SADB_EXT_KEY_AUTH],
+ SADB_EXT_KEY_AUTH,
+ extr->ips->ips_key_a_size * 8,
+ extr->ips->ips_key_a),
+ extensions_reply) : 1)
+ /* FIXME: This won't work yet because the keys are not
+ stored directly in the ipsec_sa. They are stored as
+ key schedules. */
+ && (extr->ips->ips_key_e_size
+ ? pfkey_safe_build(error = pfkey_key_build(&extensions_reply[SADB_EXT_KEY_ENCRYPT],
+ SADB_EXT_KEY_ENCRYPT,
+ extr->ips->ips_key_e_size * 8,
+ extr->ips->ips_key_e),
+ extensions_reply) : 1)
+#endif
+ && (extr->ips->ips_ident_s.data
+ ? pfkey_safe_build(error = pfkey_ident_build(&extensions_reply[SADB_EXT_IDENTITY_SRC],
+ SADB_EXT_IDENTITY_SRC,
+ extr->ips->ips_ident_s.type,
+ extr->ips->ips_ident_s.id,
+ extr->ips->ips_ident_s.len,
+ extr->ips->ips_ident_s.data),
+ extensions_reply) : 1)
+ && (extr->ips->ips_ident_d.data
+ ? pfkey_safe_build(error = pfkey_ident_build(&extensions_reply[SADB_EXT_IDENTITY_DST],
+ SADB_EXT_IDENTITY_DST,
+ extr->ips->ips_ident_d.type,
+ extr->ips->ips_ident_d.id,
+ extr->ips->ips_ident_d.len,
+ extr->ips->ips_ident_d.data),
+ extensions_reply) : 1)
+#if 0
+ /* FIXME: This won't work yet because I have not finished
+ it. */
+ && (extr->ips->ips_sens_
+ ? pfkey_safe_build(error = pfkey_sens_build(&extensions_reply[SADB_EXT_SENSITIVITY],
+ extr->ips->ips_sens_dpd,
+ extr->ips->ips_sens_sens_level,
+ extr->ips->ips_sens_sens_len,
+ extr->ips->ips_sens_sens_bitmap,
+ extr->ips->ips_sens_integ_level,
+ extr->ips->ips_sens_integ_len,
+ extr->ips->ips_sens_integ_bitmap),
+ extensions_reply) : 1)
+#endif
+ )) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_get_parse: "
+ "failed to build the get reply message extensions\n");
+ ipsec_sa_put(ipsp);
+ spin_unlock_bh(&tdb_lock);
+ SENDERR(-error);
+ }
+
+ ipsec_sa_put(ipsp);
+ spin_unlock_bh(&tdb_lock);
+
+ if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_get_parse: "
+ "failed to build the get reply message\n");
+ SENDERR(-error);
+ }
+
+ if((error = pfkey_upmsg(sk->socket, pfkey_reply))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_get_parse: "
+ "failed to send the get reply message\n");
+ SENDERR(-error);
+ }
+
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_get_parse: "
+ "succeeded in sending get reply message.\n");
+
+ errlab:
+ if (pfkey_reply) {
+ pfkey_msg_free(&pfkey_reply);
+ }
+ pfkey_extensions_free(extensions_reply);
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_acquire_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+ struct socket_list *pfkey_socketsp;
+ uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_acquire_parse: .\n");
+
+ /* XXX I don't know if we want an upper bound, since userspace may
+ want to register itself for an satype > SADB_SATYPE_MAX. */
+ if((satype == 0) || (satype > SADB_SATYPE_MAX)) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_acquire_parse: "
+ "SATYPE=%d invalid.\n",
+ satype);
+ SENDERR(EINVAL);
+ }
+
+ if(!(pfkey_registered_sockets[satype])) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_acquire_parse: "
+ "no sockets registered for SAtype=%d(%s).\n",
+ satype,
+ satype2name(satype));
+ SENDERR(EPROTONOSUPPORT);
+ }
+
+ for(pfkey_socketsp = pfkey_registered_sockets[satype];
+ pfkey_socketsp;
+ pfkey_socketsp = pfkey_socketsp->next) {
+ if((error = pfkey_upmsg(pfkey_socketsp->socketp,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_acquire_parse: "
+ "sending up acquire reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp,
+ error);
+ SENDERR(-error);
+ }
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_acquire_parse: "
+ "sending up acquire reply message for satype=%d(%s) to socket=0p%p succeeded.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp);
+ }
+
+ errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_register_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+ uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_register_parse: .\n");
+
+ /* XXX I don't know if we want an upper bound, since userspace may
+ want to register itself for an satype > SADB_SATYPE_MAX. */
+ if((satype == 0) || (satype > SADB_SATYPE_MAX)) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_register_parse: "
+ "SATYPE=%d invalid.\n",
+ satype);
+ SENDERR(EINVAL);
+ }
+
+ if(!pfkey_list_insert_socket(sk->socket,
+ &(pfkey_registered_sockets[satype]))) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_register_parse: "
+ "SATYPE=%02d(%s) successfully registered by KMd (pid=%d).\n",
+ satype,
+ satype2name(satype),
+ key_pid(sk));
+ };
+
+ /* send up register msg with supported SATYPE algos */
+
+ error=pfkey_register_reply(satype, (struct sadb_msg*)extensions[SADB_EXT_RESERVED]);
+ errlab:
+ return error;
+}
+int
+pfkey_register_reply(int satype, struct sadb_msg *sadb_msg)
+{
+ struct sadb_ext *extensions_reply[SADB_EXT_MAX+1];
+ struct sadb_msg *pfkey_reply = NULL;
+ struct socket_list *pfkey_socketsp;
+ struct supported_list *pfkey_supported_listp;
+ unsigned int alg_num_a = 0, alg_num_e = 0;
+ struct sadb_alg *alg_a = NULL, *alg_e = NULL, *alg_ap = NULL, *alg_ep = NULL;
+ int error = 0;
+
+ pfkey_extensions_init(extensions_reply);
+
+ if((satype == 0) || (satype > SADB_SATYPE_MAX)) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_reply: "
+ "SAtype=%d unspecified or unknown.\n",
+ satype);
+ SENDERR(EINVAL);
+ }
+ if(!(pfkey_registered_sockets[satype])) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_reply: "
+ "no sockets registered for SAtype=%d(%s).\n",
+ satype,
+ satype2name(satype));
+ SENDERR(EPROTONOSUPPORT);
+ }
+ /* send up register msg with supported SATYPE algos */
+ pfkey_supported_listp = pfkey_supported_list[satype];
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_register_reply: "
+ "pfkey_supported_list[%d]=0p%p\n",
+ satype,
+ pfkey_supported_list[satype]);
+ while(pfkey_supported_listp) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_register_reply: "
+ "checking supported=0p%p\n",
+ pfkey_supported_listp);
+ if(pfkey_supported_listp->supportedp->supported_alg_exttype == SADB_EXT_SUPPORTED_AUTH) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_register_reply: "
+ "adding auth alg.\n");
+ alg_num_a++;
+ }
+ if(pfkey_supported_listp->supportedp->supported_alg_exttype == SADB_EXT_SUPPORTED_ENCRYPT) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_register_reply: "
+ "adding encrypt alg.\n");
+ alg_num_e++;
+ }
+ pfkey_supported_listp = pfkey_supported_listp->next;
+ }
+
+ if(alg_num_a) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_register_reply: "
+ "allocating %lu bytes for auth algs.\n",
+ (unsigned long) (alg_num_a * sizeof(struct sadb_alg)));
+ if((alg_a = kmalloc(alg_num_a * sizeof(struct sadb_alg), GFP_ATOMIC) ) == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_register_reply: "
+ "auth alg memory allocation error\n");
+ SENDERR(ENOMEM);
+ }
+ alg_ap = alg_a;
+ }
+
+ if(alg_num_e) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_register_reply: "
+ "allocating %lu bytes for enc algs.\n",
+ (unsigned long) (alg_num_e * sizeof(struct sadb_alg)));
+ if((alg_e = kmalloc(alg_num_e * sizeof(struct sadb_alg), GFP_ATOMIC) ) == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_register_reply: "
+ "enc alg memory allocation error\n");
+ SENDERR(ENOMEM);
+ }
+ alg_ep = alg_e;
+ }
+
+ pfkey_supported_listp = pfkey_supported_list[satype];
+ while(pfkey_supported_listp) {
+ if(alg_num_a) {
+ if(pfkey_supported_listp->supportedp->supported_alg_exttype == SADB_EXT_SUPPORTED_AUTH) {
+ alg_ap->sadb_alg_id = pfkey_supported_listp->supportedp->supported_alg_id;
+ alg_ap->sadb_alg_ivlen = pfkey_supported_listp->supportedp->supported_alg_ivlen;
+ alg_ap->sadb_alg_minbits = pfkey_supported_listp->supportedp->supported_alg_minbits;
+ alg_ap->sadb_alg_maxbits = pfkey_supported_listp->supportedp->supported_alg_maxbits;
+ alg_ap->sadb_alg_reserved = 0;
+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
+ "klips_debug:pfkey_register_reply: "
+ "adding auth=0p%p\n",
+ alg_ap);
+ alg_ap++;
+ }
+ }
+ if(alg_num_e) {
+ if(pfkey_supported_listp->supportedp->supported_alg_exttype == SADB_EXT_SUPPORTED_ENCRYPT) {
+ alg_ep->sadb_alg_id = pfkey_supported_listp->supportedp->supported_alg_id;
+ alg_ep->sadb_alg_ivlen = pfkey_supported_listp->supportedp->supported_alg_ivlen;
+ alg_ep->sadb_alg_minbits = pfkey_supported_listp->supportedp->supported_alg_minbits;
+ alg_ep->sadb_alg_maxbits = pfkey_supported_listp->supportedp->supported_alg_maxbits;
+ alg_ep->sadb_alg_reserved = 0;
+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
+ "klips_debug:pfkey_register_reply: "
+ "adding encrypt=0p%p\n",
+ alg_ep);
+ alg_ep++;
+ }
+ }
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_register_reply: "
+ "found satype=%d(%s) exttype=%d id=%d ivlen=%d minbits=%d maxbits=%d.\n",
+ satype,
+ satype2name(satype),
+ pfkey_supported_listp->supportedp->supported_alg_exttype,
+ pfkey_supported_listp->supportedp->supported_alg_id,
+ pfkey_supported_listp->supportedp->supported_alg_ivlen,
+ pfkey_supported_listp->supportedp->supported_alg_minbits,
+ pfkey_supported_listp->supportedp->supported_alg_maxbits);
+ pfkey_supported_listp = pfkey_supported_listp->next;
+ }
+ if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
+ SADB_REGISTER,
+ satype,
+ 0,
+ sadb_msg? sadb_msg->sadb_msg_seq : ++pfkey_msg_seq,
+ sadb_msg? sadb_msg->sadb_msg_pid: current->pid),
+ extensions_reply) &&
+ (alg_num_a ? pfkey_safe_build(error = pfkey_supported_build(&extensions_reply[SADB_EXT_SUPPORTED_AUTH],
+ SADB_EXT_SUPPORTED_AUTH,
+ alg_num_a,
+ alg_a),
+ extensions_reply) : 1) &&
+ (alg_num_e ? pfkey_safe_build(error = pfkey_supported_build(&extensions_reply[SADB_EXT_SUPPORTED_ENCRYPT],
+ SADB_EXT_SUPPORTED_ENCRYPT,
+ alg_num_e,
+ alg_e),
+ extensions_reply) : 1))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_reply: "
+ "failed to build the register message extensions_reply\n");
+ SENDERR(-error);
+ }
+
+ if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_reply: "
+ "failed to build the register message\n");
+ SENDERR(-error);
+ }
+ /* this should go to all registered sockets for that satype only */
+ for(pfkey_socketsp = pfkey_registered_sockets[satype];
+ pfkey_socketsp;
+ pfkey_socketsp = pfkey_socketsp->next) {
+ if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_reply: "
+ "sending up acquire message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp,
+ error);
+ SENDERR(-error);
+ }
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_reply: "
+ "sending up register message for satype=%d(%s) to socket=0p%p succeeded.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp);
+ }
+
+ errlab:
+ if(alg_a) {
+ kfree(alg_a);
+ }
+ if(alg_e) {
+ kfree(alg_e);
+ }
+ if (pfkey_reply) {
+ pfkey_msg_free(&pfkey_reply);
+ }
+ pfkey_extensions_free(extensions_reply);
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_expire_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+ struct socket_list *pfkey_socketsp;
+#ifdef CONFIG_IPSEC_DEBUG
+ uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype;
+#endif /* CONFIG_IPSEC_DEBUG */
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_expire_parse: .\n");
+
+ if(pfkey_open_sockets) {
+ for(pfkey_socketsp = pfkey_open_sockets;
+ pfkey_socketsp;
+ pfkey_socketsp = pfkey_socketsp->next) {
+ if((error = pfkey_upmsg(pfkey_socketsp->socketp,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_expire_parse: "
+ "sending up expire reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp,
+ error);
+ SENDERR(-error);
+ }
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_expire_parse: "
+ "sending up expire reply message for satype=%d(%s) to socket=0p%p succeeded.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp);
+ }
+ }
+
+ errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_flush_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+ struct socket_list *pfkey_socketsp;
+ uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype;
+ uint8_t proto = 0;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_flush_parse: "
+ "flushing type %d SAs\n",
+ satype);
+
+ if(satype && !(proto = satype2proto(satype))) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_flush_parse: "
+ "satype %d lookup failed.\n",
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype);
+ SENDERR(EINVAL);
+ }
+
+ if ((error = ipsec_sadb_cleanup(proto))) {
+ SENDERR(-error);
+ }
+
+ if(pfkey_open_sockets) {
+ for(pfkey_socketsp = pfkey_open_sockets;
+ pfkey_socketsp;
+ pfkey_socketsp = pfkey_socketsp->next) {
+ if((error = pfkey_upmsg(pfkey_socketsp->socketp,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_flush_parse: "
+ "sending up flush reply message for satype=%d(%s) (proto=%d) to socket=0p%p failed with error=%d.\n",
+ satype,
+ satype2name(satype),
+ proto,
+ pfkey_socketsp->socketp,
+ error);
+ SENDERR(-error);
+ }
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_flush_parse: "
+ "sending up flush reply message for satype=%d(%s) to socket=0p%p succeeded.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp);
+ }
+ }
+
+ errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_dump_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_dump_parse: .\n");
+
+ SENDERR(ENOSYS);
+ errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_x_promisc_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_promisc_parse: .\n");
+
+ SENDERR(ENOSYS);
+ errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_x_pchange_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_pchange_parse: .\n");
+
+ SENDERR(ENOSYS);
+ errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_x_grpsa_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
+{
+ struct ipsec_sa *ips1p, *ips2p, *ipsp;
+ struct sadb_ext *extensions_reply[SADB_EXT_MAX+1];
+ struct sadb_msg *pfkey_reply = NULL;
+ struct socket_list *pfkey_socketsp;
+ uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype;
+ char sa1[SATOA_BUF], sa2[SATOA_BUF];
+ size_t sa_len1, sa_len2 = 0;
+ int error = 0;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_grpsa_parse: .\n");
+
+ pfkey_extensions_init(extensions_reply);
+
+ if(extr == NULL || extr->ips == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_grpsa_parse: "
+ "extr or extr->ips is NULL, fatal.\n");
+ SENDERR(EINVAL);
+ }
+
+ sa_len1 = satoa(extr->ips->ips_said, 0, sa1, SATOA_BUF);
+ if(extr->ips2 != NULL) {
+ sa_len2 = satoa(extr->ips2->ips_said, 0, sa2, SATOA_BUF);
+ }
+
+ spin_lock_bh(&tdb_lock);
+
+ ips1p = ipsec_sa_getbyid(&(extr->ips->ips_said));
+ if(ips1p == NULL) {
+ spin_unlock_bh(&tdb_lock);
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_grpsa_parse: "
+ "reserved ipsec_sa for SA1: %s not found. Call SADB_ADD/UPDATE first.\n",
+ sa_len1 ? sa1 : " (error)");
+ SENDERR(ENOENT);
+ }
+ if(extr->ips2) { /* GRPSA */
+ ips2p = ipsec_sa_getbyid(&(extr->ips2->ips_said));
+ if(ips2p == NULL) {
+ ipsec_sa_put(ips1p);
+ spin_unlock_bh(&tdb_lock);
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_grpsa_parse: "
+ "reserved ipsec_sa for SA2: %s not found. Call SADB_ADD/UPDATE first.\n",
+ sa_len2 ? sa2 : " (error)");
+ SENDERR(ENOENT);
+ }
+
+ /* Is either one already linked? */
+ if(ips1p->ips_onext) {
+ ipsec_sa_put(ips1p);
+ ipsec_sa_put(ips2p);
+ spin_unlock_bh(&tdb_lock);
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_grpsa_parse: "
+ "ipsec_sa for SA: %s is already linked.\n",
+ sa_len1 ? sa1 : " (error)");
+ SENDERR(EEXIST);
+ }
+ if(ips2p->ips_inext) {
+ ipsec_sa_put(ips1p);
+ ipsec_sa_put(ips2p);
+ spin_unlock_bh(&tdb_lock);
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_grpsa_parse: "
+ "ipsec_sa for SA: %s is already linked.\n",
+ sa_len2 ? sa2 : " (error)");
+ SENDERR(EEXIST);
+ }
+
+ /* Is extr->ips already linked to extr->ips2? */
+ ipsp = ips2p;
+ while(ipsp) {
+ if(ipsp == ips1p) {
+ ipsec_sa_put(ips1p);
+ ipsec_sa_put(ips2p);
+ spin_unlock_bh(&tdb_lock);
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_grpsa_parse: "
+ "ipsec_sa for SA: %s is already linked to %s.\n",
+ sa_len1 ? sa1 : " (error)",
+ sa_len2 ? sa2 : " (error)");
+ SENDERR(EEXIST);
+ }
+ ipsp = ipsp->ips_onext;
+ }
+
+ /* link 'em */
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_grpsa_parse: "
+ "linking ipsec_sa SA: %s with %s.\n",
+ sa_len1 ? sa1 : " (error)",
+ sa_len2 ? sa2 : " (error)");
+ ips1p->ips_onext = ips2p;
+ ips2p->ips_inext = ips1p;
+ } else { /* UNGRPSA */
+ ipsec_sa_put(ips1p);
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_grpsa_parse: "
+ "unlinking ipsec_sa SA: %s.\n",
+ sa_len1 ? sa1 : " (error)");
+ while(ips1p->ips_onext) {
+ ips1p = ips1p->ips_onext;
+ }
+ while(ips1p->ips_inext) {
+ ipsp = ips1p;
+ ips1p = ips1p->ips_inext;
+ ipsec_sa_put(ips1p);
+ ipsp->ips_inext = NULL;
+ ipsec_sa_put(ipsp);
+ ips1p->ips_onext = NULL;
+ }
+ }
+
+ spin_unlock_bh(&tdb_lock);
+
+ if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
+ SADB_X_GRPSA,
+ satype,
+ 0,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_seq,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions_reply[SADB_EXT_SA],
+ SADB_EXT_SA,
+ extr->ips->ips_said.spi,
+ extr->ips->ips_replaywin,
+ extr->ips->ips_state,
+ extr->ips->ips_authalg,
+ extr->ips->ips_encalg,
+ extr->ips->ips_flags,
+ extr->ips->ips_ref),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_DST],
+ SADB_EXT_ADDRESS_DST,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ extr->ips->ips_addr_d),
+ extensions_reply)
+ && (extr->ips2
+ ? (pfkey_safe_build(error = pfkey_x_satype_build(&extensions_reply[SADB_X_EXT_SATYPE2],
+ ((struct sadb_x_satype*)extensions[SADB_X_EXT_SATYPE2])->sadb_x_satype_satype
+ /* proto2satype(extr->ips2->ips_said.proto) */),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions_reply[SADB_X_EXT_SA2],
+ SADB_X_EXT_SA2,
+ extr->ips2->ips_said.spi,
+ extr->ips2->ips_replaywin,
+ extr->ips2->ips_state,
+ extr->ips2->ips_authalg,
+ extr->ips2->ips_encalg,
+ extr->ips2->ips_flags,
+ extr->ips2->ips_ref),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_X_EXT_ADDRESS_DST2],
+ SADB_X_EXT_ADDRESS_DST2,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ extr->ips2->ips_addr_d),
+ extensions_reply) ) : 1 )
+ )) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_grpsa_parse: "
+ "failed to build the x_grpsa reply message extensions\n");
+ SENDERR(-error);
+ }
+
+ if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_grpsa_parse: "
+ "failed to build the x_grpsa reply message\n");
+ SENDERR(-error);
+ }
+
+ for(pfkey_socketsp = pfkey_open_sockets;
+ pfkey_socketsp;
+ pfkey_socketsp = pfkey_socketsp->next) {
+ if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_grpsa_parse: "
+ "sending up x_grpsa reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp,
+ error);
+ SENDERR(-error);
+ }
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_grpsa_parse: "
+ "sending up x_grpsa reply message for satype=%d(%s) to socket=0p%p succeeded.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp);
+ }
+
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_grpsa_parse: "
+ "succeeded in sending x_grpsa reply message.\n");
+
+ errlab:
+ if (pfkey_reply) {
+ pfkey_msg_free(&pfkey_reply);
+ }
+ pfkey_extensions_free(extensions_reply);
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_x_addflow_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+#ifdef CONFIG_IPSEC_DEBUG
+ char buf1[64], buf2[64];
+#endif /* CONFIG_IPSEC_DEBUG */
+ struct sadb_ext *extensions_reply[SADB_EXT_MAX+1];
+ struct sadb_msg *pfkey_reply = NULL;
+ struct socket_list *pfkey_socketsp;
+ uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype;
+ ip_address srcflow, dstflow, srcmask, dstmask;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_addflow_parse: .\n");
+
+ pfkey_extensions_init(extensions_reply);
+
+ memset((caddr_t)&srcflow, 0, sizeof(srcflow));
+ memset((caddr_t)&dstflow, 0, sizeof(dstflow));
+ memset((caddr_t)&srcmask, 0, sizeof(srcmask));
+ memset((caddr_t)&dstmask, 0, sizeof(dstmask));
+
+ if(!extr || !(extr->ips) || !(extr->eroute)) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_addflow_parse: "
+ "missing extr, ipsec_sa or eroute data.\n");
+ SENDERR(EINVAL);
+ }
+
+ srcflow.u.v4.sin_family = AF_INET;
+ dstflow.u.v4.sin_family = AF_INET;
+ srcmask.u.v4.sin_family = AF_INET;
+ dstmask.u.v4.sin_family = AF_INET;
+ srcflow.u.v4.sin_addr = extr->eroute->er_eaddr.sen_ip_src;
+ dstflow.u.v4.sin_addr = extr->eroute->er_eaddr.sen_ip_dst;
+ srcmask.u.v4.sin_addr = extr->eroute->er_emask.sen_ip_src;
+ dstmask.u.v4.sin_addr = extr->eroute->er_emask.sen_ip_dst;
+
+#ifdef CONFIG_IPSEC_DEBUG
+ if (debug_pfkey) {
+ subnettoa(extr->eroute->er_eaddr.sen_ip_src,
+ extr->eroute->er_emask.sen_ip_src, 0, buf1, sizeof(buf1));
+ subnettoa(extr->eroute->er_eaddr.sen_ip_dst,
+ extr->eroute->er_emask.sen_ip_dst, 0, buf2, sizeof(buf2));
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_addflow_parse: "
+ "calling breakeroute and/or makeroute for %s->%s\n",
+ buf1, buf2);
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+ if(extr->ips->ips_flags & SADB_X_SAFLAGS_INFLOW) {
+/* if(ip_chk_addr((unsigned long)extr->ips->ips_said.dst.s_addr) == IS_MYADDR) */
+ struct ipsec_sa *ipsp, *ipsq;
+ char sa[SATOA_BUF];
+ size_t sa_len;
+
+ ipsq = ipsec_sa_getbyid(&(extr->ips->ips_said));
+ if(ipsq == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_addflow_parse: "
+ "ipsec_sa not found, cannot set incoming policy.\n");
+ SENDERR(ENOENT);
+ }
+
+ ipsp = ipsq;
+ while(ipsp && ipsp->ips_said.proto != IPPROTO_IPIP) {
+ ipsp = ipsp->ips_inext;
+ }
+
+ if(ipsp == NULL) {
+ ipsec_sa_put(ipsq);
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_addflow_parse: "
+ "SA chain does not have an IPIP SA, cannot set incoming policy.\n");
+ SENDERR(ENOENT);
+ }
+
+ sa_len = satoa(extr->ips->ips_said, 0, sa, SATOA_BUF);
+
+ ipsp->ips_flags |= SADB_X_SAFLAGS_INFLOW;
+ ipsp->ips_flow_s = srcflow;
+ ipsp->ips_flow_d = dstflow;
+ ipsp->ips_mask_s = srcmask;
+ ipsp->ips_mask_d = dstmask;
+
+ ipsec_sa_put(ipsq);
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_addflow_parse: "
+ "inbound eroute, setting incoming policy information in IPIP ipsec_sa for SA: %s.\n",
+ sa_len ? sa : " (error)");
+ } else {
+ struct sk_buff *first = NULL, *last = NULL;
+
+ if(extr->ips->ips_flags & SADB_X_SAFLAGS_REPLACEFLOW) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_addflow_parse: "
+ "REPLACEFLOW flag set, calling breakeroute.\n");
+ if ((error = ipsec_breakroute(&(extr->eroute->er_eaddr),
+ &(extr->eroute->er_emask),
+ &first, &last))) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_addflow_parse: "
+ "breakeroute returned %d. first=0p%p, last=0p%p\n",
+ error,
+ first,
+ last);
+ if(first != NULL) {
+ ipsec_kfree_skb(first);
+ }
+ if(last != NULL) {
+ ipsec_kfree_skb(last);
+ }
+ SENDERR(-error);
+ }
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_addflow_parse: "
+ "calling makeroute.\n");
+
+ if ((error = ipsec_makeroute(&(extr->eroute->er_eaddr),
+ &(extr->eroute->er_emask),
+ extr->ips->ips_said,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid,
+ NULL,
+ &(extr->ips->ips_ident_s),
+ &(extr->ips->ips_ident_d)))) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_addflow_parse: "
+ "makeroute returned %d.\n", error);
+ SENDERR(-error);
+ }
+ if(first != NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_addflow_parse: "
+ "first=0p%p HOLD packet re-injected.\n",
+ first);
+ DEV_QUEUE_XMIT(first, first->dev, SOPRI_NORMAL);
+ }
+ if(last != NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_addflow_parse: "
+ "last=0p%p HOLD packet re-injected.\n",
+ last);
+ DEV_QUEUE_XMIT(last, last->dev, SOPRI_NORMAL);
+ }
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_addflow_parse: "
+ "makeroute call successful.\n");
+
+ if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
+ SADB_X_ADDFLOW,
+ satype,
+ 0,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_seq,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions_reply[SADB_EXT_SA],
+ SADB_EXT_SA,
+ extr->ips->ips_said.spi,
+ extr->ips->ips_replaywin,
+ extr->ips->ips_state,
+ extr->ips->ips_authalg,
+ extr->ips->ips_encalg,
+ extr->ips->ips_flags,
+ extr->ips->ips_ref),
+ extensions_reply)
+ && (extensions[SADB_EXT_ADDRESS_SRC]
+ ? pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_SRC],
+ SADB_EXT_ADDRESS_SRC,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ extr->ips->ips_addr_s),
+ extensions_reply) : 1)
+ && (extensions[SADB_EXT_ADDRESS_DST]
+ ? pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_DST],
+ SADB_EXT_ADDRESS_DST,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ extr->ips->ips_addr_d),
+ extensions_reply) : 1)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_X_EXT_ADDRESS_SRC_FLOW],
+ SADB_X_EXT_ADDRESS_SRC_FLOW,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ (struct sockaddr*)&srcflow),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_X_EXT_ADDRESS_DST_FLOW],
+ SADB_X_EXT_ADDRESS_DST_FLOW,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ (struct sockaddr*)&dstflow),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_X_EXT_ADDRESS_SRC_MASK],
+ SADB_X_EXT_ADDRESS_SRC_MASK,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ (struct sockaddr*)&srcmask),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_X_EXT_ADDRESS_DST_MASK],
+ SADB_X_EXT_ADDRESS_DST_MASK,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ (struct sockaddr*)&dstmask),
+ extensions_reply)
+ )) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_addflow_parse: "
+ "failed to build the x_addflow reply message extensions\n");
+ SENDERR(-error);
+ }
+
+ if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_addflow_parse: "
+ "failed to build the x_addflow reply message\n");
+ SENDERR(-error);
+ }
+
+ for(pfkey_socketsp = pfkey_open_sockets;
+ pfkey_socketsp;
+ pfkey_socketsp = pfkey_socketsp->next) {
+ if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_addflow_parse: "
+ "sending up x_addflow reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp,
+ error);
+ SENDERR(-error);
+ }
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_addflow_parse: "
+ "sending up x_addflow reply message for satype=%d(%s) (proto=%d) to socket=0p%p succeeded.\n",
+ satype,
+ satype2name(satype),
+ extr->ips->ips_said.proto,
+ pfkey_socketsp->socketp);
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_addflow_parse: "
+ "extr->ips cleaned up and freed.\n");
+
+ errlab:
+ if (pfkey_reply) {
+ pfkey_msg_free(&pfkey_reply);
+ }
+ pfkey_extensions_free(extensions_reply);
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_x_delflow_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+#ifdef CONFIG_IPSEC_DEBUG
+ char buf1[64], buf2[64];
+#endif /* CONFIG_IPSEC_DEBUG */
+ struct sadb_ext *extensions_reply[SADB_EXT_MAX+1];
+ struct sadb_msg *pfkey_reply = NULL;
+ struct socket_list *pfkey_socketsp;
+ uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype;
+ ip_address srcflow, dstflow, srcmask, dstmask;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_delflow_parse: .\n");
+
+ pfkey_extensions_init(extensions_reply);
+
+ memset((caddr_t)&srcflow, 0, sizeof(srcflow));
+ memset((caddr_t)&dstflow, 0, sizeof(dstflow));
+ memset((caddr_t)&srcmask, 0, sizeof(srcmask));
+ memset((caddr_t)&dstmask, 0, sizeof(dstmask));
+
+ if(!extr || !(extr->ips)) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_delflow_parse: "
+ "extr, or extr->ips is NULL, fatal\n");
+ SENDERR(EINVAL);
+ }
+
+ if(extr->ips->ips_flags & SADB_X_SAFLAGS_CLEARFLOW) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_delflow_parse: "
+ "CLEARFLOW flag set, calling cleareroutes.\n");
+ if ((error = ipsec_cleareroutes()))
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_delflow_parse: "
+ "cleareroutes returned %d.\n", error);
+ SENDERR(-error);
+ } else {
+ struct sk_buff *first = NULL, *last = NULL;
+
+ if(!(extr->eroute)) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_delflow_parse: "
+ "extr->eroute is NULL, fatal.\n");
+ SENDERR(EINVAL);
+ }
+
+ srcflow.u.v4.sin_family = AF_INET;
+ dstflow.u.v4.sin_family = AF_INET;
+ srcmask.u.v4.sin_family = AF_INET;
+ dstmask.u.v4.sin_family = AF_INET;
+ srcflow.u.v4.sin_addr = extr->eroute->er_eaddr.sen_ip_src;
+ dstflow.u.v4.sin_addr = extr->eroute->er_eaddr.sen_ip_dst;
+ srcmask.u.v4.sin_addr = extr->eroute->er_emask.sen_ip_src;
+ dstmask.u.v4.sin_addr = extr->eroute->er_emask.sen_ip_dst;
+
+#ifdef CONFIG_IPSEC_DEBUG
+ if (debug_pfkey) {
+ subnettoa(extr->eroute->er_eaddr.sen_ip_src,
+ extr->eroute->er_emask.sen_ip_src, 0, buf1, sizeof(buf1));
+ subnettoa(extr->eroute->er_eaddr.sen_ip_dst,
+ extr->eroute->er_emask.sen_ip_dst, 0, buf2, sizeof(buf2));
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_delflow_parse: "
+ "calling breakeroute for %s->%s\n",
+ buf1, buf2);
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+ error = ipsec_breakroute(&(extr->eroute->er_eaddr),
+ &(extr->eroute->er_emask),
+ &first, &last);
+ if(error) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_delflow_parse: "
+ "breakeroute returned %d. first=0p%p, last=0p%p\n",
+ error,
+ first,
+ last);
+ }
+ if(first != NULL) {
+ ipsec_kfree_skb(first);
+ }
+ if(last != NULL) {
+ ipsec_kfree_skb(last);
+ }
+ if(error) {
+ SENDERR(-error);
+ }
+ }
+
+ if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
+ SADB_X_DELFLOW,
+ satype,
+ 0,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_seq,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions_reply[SADB_EXT_SA],
+ SADB_EXT_SA,
+ extr->ips->ips_said.spi,
+ extr->ips->ips_replaywin,
+ extr->ips->ips_state,
+ extr->ips->ips_authalg,
+ extr->ips->ips_encalg,
+ extr->ips->ips_flags,
+ extr->ips->ips_ref),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_X_EXT_ADDRESS_SRC_FLOW],
+ SADB_X_EXT_ADDRESS_SRC_FLOW,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ (struct sockaddr*)&srcflow),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_X_EXT_ADDRESS_DST_FLOW],
+ SADB_X_EXT_ADDRESS_DST_FLOW,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ (struct sockaddr*)&dstflow),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_X_EXT_ADDRESS_SRC_MASK],
+ SADB_X_EXT_ADDRESS_SRC_MASK,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ (struct sockaddr*)&srcmask),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_X_EXT_ADDRESS_DST_MASK],
+ SADB_X_EXT_ADDRESS_DST_MASK,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ (struct sockaddr*)&dstmask),
+ extensions_reply)
+ )) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_delflow_parse: "
+ "failed to build the x_delflow reply message extensions\n");
+ SENDERR(-error);
+ }
+
+ if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_delflow_parse: "
+ "failed to build the x_delflow reply message\n");
+ SENDERR(-error);
+ }
+
+ for(pfkey_socketsp = pfkey_open_sockets;
+ pfkey_socketsp;
+ pfkey_socketsp = pfkey_socketsp->next) {
+ if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_delflow_parse: "
+ "sending up x_delflow reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp,
+ error);
+ SENDERR(-error);
+ }
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_delflow_parse: "
+ "sending up x_delflow reply message for satype=%d(%s) to socket=0p%p succeeded.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp);
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_delflow_parse: "
+ "extr->ips cleaned up and freed.\n");
+
+ errlab:
+ if (pfkey_reply) {
+ pfkey_msg_free(&pfkey_reply);
+ }
+ pfkey_extensions_free(extensions_reply);
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_x_msg_debug_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_msg_debug_parse: .\n");
+
+/* errlab:*/
+ return error;
+}
+
+/* pfkey_expire expects the ipsec_sa table to be locked before being called. */
+int
+pfkey_expire(struct ipsec_sa *ipsp, int hard)
+{
+ struct sadb_ext *extensions[SADB_EXT_MAX+1];
+ struct sadb_msg *pfkey_msg = NULL;
+ struct socket_list *pfkey_socketsp;
+ int error = 0;
+ uint8_t satype;
+
+ pfkey_extensions_init(extensions);
+
+ if(!(satype = proto2satype(ipsp->ips_said.proto))) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_expire: "
+ "satype lookup for protocol %d lookup failed.\n",
+ ipsp->ips_said.proto);
+ SENDERR(EINVAL);
+ }
+
+ if(!pfkey_open_sockets) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_expire: "
+ "no sockets listening.\n");
+ SENDERR(EPROTONOSUPPORT);
+ }
+
+ if (!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions[0],
+ SADB_EXPIRE,
+ satype,
+ 0,
+ ++pfkey_msg_seq,
+ 0),
+ extensions)
+ && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions[SADB_EXT_SA],
+ SADB_EXT_SA,
+ ipsp->ips_said.spi,
+ ipsp->ips_replaywin,
+ ipsp->ips_state,
+ ipsp->ips_authalg,
+ ipsp->ips_encalg,
+ ipsp->ips_flags,
+ ipsp->ips_ref),
+ extensions)
+ && pfkey_safe_build(error = pfkey_lifetime_build(&extensions[SADB_EXT_LIFETIME_CURRENT],
+ SADB_EXT_LIFETIME_CURRENT,
+ ipsp->ips_life.ipl_allocations.ipl_count,
+ ipsp->ips_life.ipl_bytes.ipl_count,
+ ipsp->ips_life.ipl_addtime.ipl_count,
+ ipsp->ips_life.ipl_usetime.ipl_count,
+ ipsp->ips_life.ipl_packets.ipl_count),
+ extensions)
+ && (hard ?
+ pfkey_safe_build(error = pfkey_lifetime_build(&extensions[SADB_EXT_LIFETIME_HARD],
+ SADB_EXT_LIFETIME_HARD,
+ ipsp->ips_life.ipl_allocations.ipl_hard,
+ ipsp->ips_life.ipl_bytes.ipl_hard,
+ ipsp->ips_life.ipl_addtime.ipl_hard,
+ ipsp->ips_life.ipl_usetime.ipl_hard,
+ ipsp->ips_life.ipl_packets.ipl_hard),
+ extensions)
+ : pfkey_safe_build(error = pfkey_lifetime_build(&extensions[SADB_EXT_LIFETIME_SOFT],
+ SADB_EXT_LIFETIME_SOFT,
+ ipsp->ips_life.ipl_allocations.ipl_soft,
+ ipsp->ips_life.ipl_bytes.ipl_soft,
+ ipsp->ips_life.ipl_addtime.ipl_soft,
+ ipsp->ips_life.ipl_usetime.ipl_soft,
+ ipsp->ips_life.ipl_packets.ipl_soft),
+ extensions))
+ && pfkey_safe_build(error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_SRC],
+ SADB_EXT_ADDRESS_SRC,
+ 0, /* ipsp->ips_said.proto, */
+ 0,
+ ipsp->ips_addr_s),
+ extensions)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_DST],
+ SADB_EXT_ADDRESS_DST,
+ 0, /* ipsp->ips_said.proto, */
+ 0,
+ ipsp->ips_addr_d),
+ extensions))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_expire: "
+ "failed to build the expire message extensions\n");
+ spin_unlock(&tdb_lock);
+ goto errlab;
+ }
+
+ if ((error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_OUT))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_expire: "
+ "failed to build the expire message\n");
+ SENDERR(-error);
+ }
+
+ for(pfkey_socketsp = pfkey_open_sockets;
+ pfkey_socketsp;
+ pfkey_socketsp = pfkey_socketsp->next) {
+ if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_msg))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_expire: "
+ "sending up expire message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp,
+ error);
+ SENDERR(-error);
+ }
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_expire: "
+ "sending up expire message for satype=%d(%s) (proto=%d) to socket=0p%p succeeded.\n",
+ satype,
+ satype2name(satype),
+ ipsp->ips_said.proto,
+ pfkey_socketsp->socketp);
+ }
+
+ errlab:
+ if (pfkey_msg) {
+ pfkey_msg_free(&pfkey_msg);
+ }
+ pfkey_extensions_free(extensions);
+ return error;
+}
+
+int
+pfkey_acquire(struct ipsec_sa *ipsp)
+{
+ struct sadb_ext *extensions[SADB_EXT_MAX+1];
+ struct sadb_msg *pfkey_msg = NULL;
+ struct socket_list *pfkey_socketsp;
+ int error = 0;
+ struct sadb_comb comb[] = {
+ /* auth; encrypt; flags; */
+ /* auth_minbits; auth_maxbits; encrypt_minbits; encrypt_maxbits; */
+ /* reserved; soft_allocations; hard_allocations; soft_bytes; hard_bytes; */
+ /* soft_addtime; hard_addtime; soft_usetime; hard_usetime; */
+ /* soft_packets; hard_packets; */
+ { SADB_AALG_MD5_HMAC, SADB_EALG_3DES_CBC, SADB_SAFLAGS_PFS,
+ 128, 128, 168, 168,
+ 0, 0, 0, 0, 0,
+ 57600, 86400, 57600, 86400,
+ 0, 0 },
+ { SADB_AALG_SHA1_HMAC, SADB_EALG_3DES_CBC, SADB_SAFLAGS_PFS,
+ 160, 160, 168, 168,
+ 0, 0, 0, 0, 0,
+ 57600, 86400, 57600, 86400,
+ 0, 0 }
+ };
+
+ /* XXX This should not be hard-coded. It should be taken from the spdb */
+ uint8_t satype = SADB_SATYPE_ESP;
+
+ pfkey_extensions_init(extensions);
+
+ if((satype == 0) || (satype > SADB_SATYPE_MAX)) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_acquire: "
+ "SAtype=%d unspecified or unknown.\n",
+ satype);
+ SENDERR(EINVAL);
+ }
+
+ if(!(pfkey_registered_sockets[satype])) {
+ KLIPS_PRINT(1|debug_pfkey, "klips_debug:pfkey_acquire: "
+ "no sockets registered for SAtype=%d(%s).\n",
+ satype,
+ satype2name(satype));
+ SENDERR(EPROTONOSUPPORT);
+ }
+
+ if (!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions[0],
+ SADB_ACQUIRE,
+ satype,
+ 0,
+ ++pfkey_msg_seq,
+ 0),
+ extensions)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_SRC],
+ SADB_EXT_ADDRESS_SRC,
+ ipsp->ips_said.proto,
+ 0,
+ ipsp->ips_addr_s),
+ extensions)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_DST],
+ SADB_EXT_ADDRESS_DST,
+ ipsp->ips_said.proto,
+ 0,
+ ipsp->ips_addr_d),
+ extensions)
+#if 0
+ && (ipsp->ips_addr_p
+ ? pfkey_safe_build(error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_PROXY],
+ SADB_EXT_ADDRESS_PROXY,
+ ipsp->ips_said.proto,
+ 0,
+ ipsp->ips_addr_p),
+ extensions) : 1)
+#endif
+ && (ipsp->ips_ident_s.type != SADB_IDENTTYPE_RESERVED
+ ? pfkey_safe_build(error = pfkey_ident_build(&extensions[SADB_EXT_IDENTITY_SRC],
+ SADB_EXT_IDENTITY_SRC,
+ ipsp->ips_ident_s.type,
+ ipsp->ips_ident_s.id,
+ ipsp->ips_ident_s.len,
+ ipsp->ips_ident_s.data),
+ extensions) : 1)
+
+ && (ipsp->ips_ident_d.type != SADB_IDENTTYPE_RESERVED
+ ? pfkey_safe_build(error = pfkey_ident_build(&extensions[SADB_EXT_IDENTITY_DST],
+ SADB_EXT_IDENTITY_DST,
+ ipsp->ips_ident_d.type,
+ ipsp->ips_ident_d.id,
+ ipsp->ips_ident_d.len,
+ ipsp->ips_ident_d.data),
+ extensions) : 1)
+#if 0
+ /* FIXME: This won't work yet because I have not finished
+ it. */
+ && (ipsp->ips_sens_
+ ? pfkey_safe_build(error = pfkey_sens_build(&extensions[SADB_EXT_SENSITIVITY],
+ ipsp->ips_sens_dpd,
+ ipsp->ips_sens_sens_level,
+ ipsp->ips_sens_sens_len,
+ ipsp->ips_sens_sens_bitmap,
+ ipsp->ips_sens_integ_level,
+ ipsp->ips_sens_integ_len,
+ ipsp->ips_sens_integ_bitmap),
+ extensions) : 1)
+#endif
+ && pfkey_safe_build(error = pfkey_prop_build(&extensions[SADB_EXT_PROPOSAL],
+ 64, /* replay */
+ sizeof(comb)/sizeof(struct sadb_comb),
+ &(comb[0])),
+ extensions)
+ )) {
+ KLIPS_PRINT(1|debug_pfkey, "klips_debug:pfkey_acquire: "
+ "failed to build the acquire message extensions\n");
+ SENDERR(-error);
+ }
+
+ if ((error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_OUT))) {
+ KLIPS_PRINT(1|debug_pfkey, "klips_debug:pfkey_acquire: "
+ "failed to build the acquire message\n");
+ SENDERR(-error);
+ }
+
+#if KLIPS_PFKEY_ACQUIRE_LOSSAGE > 0
+ if(sysctl_ipsec_regress_pfkey_lossage) {
+ return(0);
+ }
+#endif
+
+ /* this should go to all registered sockets for that satype only */
+ for(pfkey_socketsp = pfkey_registered_sockets[satype];
+ pfkey_socketsp;
+ pfkey_socketsp = pfkey_socketsp->next) {
+ if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_msg))) {
+ KLIPS_PRINT(1|debug_pfkey, "klips_debug:pfkey_acquire: "
+ "sending up acquire message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp,
+ error);
+ SENDERR(-error);
+ }
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_acquire: "
+ "sending up acquire message for satype=%d(%s) to socket=0p%p succeeded.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp);
+ }
+
+ errlab:
+ if (pfkey_msg) {
+ pfkey_msg_free(&pfkey_msg);
+ }
+ pfkey_extensions_free(extensions);
+ return error;
+}
+
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+int
+pfkey_nat_t_new_mapping(struct ipsec_sa *ipsp, struct sockaddr *ipaddr,
+ __u16 sport)
+{
+ struct sadb_ext *extensions[SADB_EXT_MAX+1];
+ struct sadb_msg *pfkey_msg = NULL;
+ struct socket_list *pfkey_socketsp;
+ int error = 0;
+ uint8_t satype = (ipsp->ips_said.proto==IPPROTO_ESP) ? SADB_SATYPE_ESP : 0;
+
+ /* Construct SADB_X_NAT_T_NEW_MAPPING message */
+
+ pfkey_extensions_init(extensions);
+
+ if((satype == 0) || (satype > SADB_SATYPE_MAX)) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_nat_t_new_mapping: "
+ "SAtype=%d unspecified or unknown.\n",
+ satype);
+ SENDERR(EINVAL);
+ }
+
+ if(!(pfkey_registered_sockets[satype])) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_nat_t_new_mapping: "
+ "no sockets registered for SAtype=%d(%s).\n",
+ satype,
+ satype2name(satype));
+ SENDERR(EPROTONOSUPPORT);
+ }
+
+ if (!(pfkey_safe_build
+ (error = pfkey_msg_hdr_build(&extensions[0], SADB_X_NAT_T_NEW_MAPPING,
+ satype, 0, ++pfkey_msg_seq, 0), extensions)
+ /* SA */
+ && pfkey_safe_build
+ (error = pfkey_sa_build(&extensions[SADB_EXT_SA],
+ SADB_EXT_SA, ipsp->ips_said.spi, 0, 0, 0, 0, 0), extensions)
+ /* ADDRESS_SRC = old addr */
+ && pfkey_safe_build
+ (error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_SRC],
+ SADB_EXT_ADDRESS_SRC, ipsp->ips_said.proto, 0, ipsp->ips_addr_s),
+ extensions)
+ /* NAT_T_SPORT = old port */
+ && pfkey_safe_build
+ (error = pfkey_x_nat_t_port_build(&extensions[SADB_X_EXT_NAT_T_SPORT],
+ SADB_X_EXT_NAT_T_SPORT, ipsp->ips_natt_sport), extensions)
+ /* ADDRESS_DST = new addr */
+ && pfkey_safe_build
+ (error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_DST],
+ SADB_EXT_ADDRESS_DST, ipsp->ips_said.proto, 0, ipaddr), extensions)
+ /* NAT_T_DPORT = new port */
+ && pfkey_safe_build
+ (error = pfkey_x_nat_t_port_build(&extensions[SADB_X_EXT_NAT_T_DPORT],
+ SADB_X_EXT_NAT_T_DPORT, sport), extensions)
+ )) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_nat_t_new_mapping: "
+ "failed to build the nat_t_new_mapping message extensions\n");
+ SENDERR(-error);
+ }
+
+ if ((error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_OUT))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_nat_t_new_mapping: "
+ "failed to build the nat_t_new_mapping message\n");
+ SENDERR(-error);
+ }
+
+ /* this should go to all registered sockets for that satype only */
+ for(pfkey_socketsp = pfkey_registered_sockets[satype];
+ pfkey_socketsp;
+ pfkey_socketsp = pfkey_socketsp->next) {
+ if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_msg))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_nat_t_new_mapping: "
+ "sending up nat_t_new_mapping message for satype=%d(%s) to socket=%p failed with error=%d.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp,
+ error);
+ SENDERR(-error);
+ }
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_nat_t_new_mapping: "
+ "sending up nat_t_new_mapping message for satype=%d(%s) to socket=%p succeeded.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp);
+ }
+
+ errlab:
+ if (pfkey_msg) {
+ pfkey_msg_free(&pfkey_msg);
+ }
+ pfkey_extensions_free(extensions);
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_x_nat_t_new_mapping_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
+{
+ /* SADB_X_NAT_T_NEW_MAPPING not used in kernel */
+ return -EINVAL;
+}
+#endif
+
+DEBUG_NO_STATIC int (*ext_processors[SADB_EXT_MAX+1])(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr) =
+{
+ NULL, /* pfkey_msg_process, */
+ pfkey_sa_process,
+ pfkey_lifetime_process,
+ pfkey_lifetime_process,
+ pfkey_lifetime_process,
+ pfkey_address_process,
+ pfkey_address_process,
+ pfkey_address_process,
+ pfkey_key_process,
+ pfkey_key_process,
+ pfkey_ident_process,
+ pfkey_ident_process,
+ pfkey_sens_process,
+ pfkey_prop_process,
+ pfkey_supported_process,
+ pfkey_supported_process,
+ pfkey_spirange_process,
+ pfkey_x_kmprivate_process,
+ pfkey_x_satype_process,
+ pfkey_sa_process,
+ pfkey_address_process,
+ pfkey_address_process,
+ pfkey_address_process,
+ pfkey_address_process,
+ pfkey_address_process,
+ pfkey_x_debug_process,
+ pfkey_x_protocol_process
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ ,
+ pfkey_x_nat_t_type_process,
+ pfkey_x_nat_t_port_process,
+ pfkey_x_nat_t_port_process,
+ pfkey_address_process
+#endif
+};
+
+
+DEBUG_NO_STATIC int (*msg_parsers[SADB_MAX +1])(struct sock *sk, struct sadb_ext *extensions[], struct pfkey_extracted_data* extr)
+ =
+{
+ NULL, /* RESERVED */
+ pfkey_getspi_parse,
+ pfkey_update_parse,
+ pfkey_add_parse,
+ pfkey_delete_parse,
+ pfkey_get_parse,
+ pfkey_acquire_parse,
+ pfkey_register_parse,
+ pfkey_expire_parse,
+ pfkey_flush_parse,
+ pfkey_dump_parse,
+ pfkey_x_promisc_parse,
+ pfkey_x_pchange_parse,
+ pfkey_x_grpsa_parse,
+ pfkey_x_addflow_parse,
+ pfkey_x_delflow_parse,
+ pfkey_x_msg_debug_parse
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ , pfkey_x_nat_t_new_mapping_parse
+#endif
+};
+
+int
+pfkey_build_reply(struct sadb_msg *pfkey_msg, struct pfkey_extracted_data *extr,
+ struct sadb_msg **pfkey_reply)
+{
+ struct sadb_ext *extensions[SADB_EXT_MAX+1];
+ int error = 0;
+ int msg_type = pfkey_msg->sadb_msg_type;
+ int seq = pfkey_msg->sadb_msg_seq;
+
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_build_reply: "
+ "building reply with type: %d\n",
+ msg_type);
+ pfkey_extensions_init(extensions);
+ if (!extr || !extr->ips) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_build_reply: "
+ "bad ipsec_sa passed\n");
+ return EINVAL;
+ }
+ error = pfkey_safe_build(pfkey_msg_hdr_build(&extensions[0],
+ msg_type,
+ proto2satype(extr->ips->ips_said.proto),
+ 0,
+ seq,
+ pfkey_msg->sadb_msg_pid),
+ extensions) &&
+ (!(extensions_bitmaps[EXT_BITS_OUT][EXT_BITS_REQ][msg_type] &
+ 1 << SADB_EXT_SA)
+ || pfkey_safe_build(pfkey_sa_ref_build(&extensions[SADB_EXT_SA],
+ SADB_EXT_SA,
+ extr->ips->ips_said.spi,
+ extr->ips->ips_replaywin,
+ extr->ips->ips_state,
+ extr->ips->ips_authalg,
+ extr->ips->ips_encalg,
+ extr->ips->ips_flags,
+ extr->ips->ips_ref),
+ extensions)) &&
+ (!(extensions_bitmaps[EXT_BITS_OUT][EXT_BITS_REQ][msg_type] &
+ 1 << SADB_EXT_LIFETIME_CURRENT)
+ || pfkey_safe_build(pfkey_lifetime_build(&extensions
+ [SADB_EXT_LIFETIME_CURRENT],
+ SADB_EXT_LIFETIME_CURRENT,
+ extr->ips->ips_life.ipl_allocations.ipl_count,
+ extr->ips->ips_life.ipl_bytes.ipl_count,
+ extr->ips->ips_life.ipl_addtime.ipl_count,
+ extr->ips->ips_life.ipl_usetime.ipl_count,
+ extr->ips->ips_life.ipl_packets.ipl_count),
+ extensions)) &&
+ (!(extensions_bitmaps[EXT_BITS_OUT][EXT_BITS_REQ][msg_type] &
+ 1 << SADB_EXT_ADDRESS_SRC)
+ || pfkey_safe_build(pfkey_address_build(&extensions[SADB_EXT_ADDRESS_SRC],
+ SADB_EXT_ADDRESS_SRC,
+ extr->ips->ips_said.proto,
+ 0,
+ extr->ips->ips_addr_s),
+ extensions)) &&
+ (!(extensions_bitmaps[EXT_BITS_OUT][EXT_BITS_REQ][msg_type] &
+ 1 << SADB_EXT_ADDRESS_DST)
+ || pfkey_safe_build(pfkey_address_build(&extensions[SADB_EXT_ADDRESS_DST],
+ SADB_EXT_ADDRESS_DST,
+ extr->ips->ips_said.proto,
+ 0,
+ extr->ips->ips_addr_d),
+ extensions));
+
+ if (error == 0) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_build_reply: "
+ "building extensions failed\n");
+ return EINVAL;
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_build_reply: "
+ "built extensions, proceed to build the message\n");
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_build_reply: "
+ "extensions[1]=0p%p\n",
+ extensions[1]);
+ error = pfkey_msg_build(pfkey_reply, extensions, EXT_BITS_OUT);
+ pfkey_extensions_free(extensions);
+
+ return error;
+}
+
+int
+pfkey_msg_interp(struct sock *sk, struct sadb_msg *pfkey_msg,
+ struct sadb_msg **pfkey_reply)
+{
+ int error = 0;
+ int i;
+ struct sadb_ext *extensions[SADB_EXT_MAX+1];
+ struct pfkey_extracted_data extr = {NULL, NULL, NULL};
+
+ pfkey_extensions_init(extensions);
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_msg_interp: "
+ "parsing message ver=%d, type=%d, errno=%d, satype=%d(%s), len=%d, res=%d, seq=%d, pid=%d.\n",
+ pfkey_msg->sadb_msg_version,
+ pfkey_msg->sadb_msg_type,
+ pfkey_msg->sadb_msg_errno,
+ pfkey_msg->sadb_msg_satype,
+ satype2name(pfkey_msg->sadb_msg_satype),
+ pfkey_msg->sadb_msg_len,
+ pfkey_msg->sadb_msg_reserved,
+ pfkey_msg->sadb_msg_seq,
+ pfkey_msg->sadb_msg_pid);
+
+ extr.ips = ipsec_sa_alloc(&error); /* pass in error var by pointer */
+ if(extr.ips == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_msg_interp: "
+ "memory allocation error.\n");
+ SENDERR(-error);
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_msg_interp: "
+ "allocated extr->ips=0p%p.\n",
+ extr.ips);
+
+ if(pfkey_msg->sadb_msg_satype > SADB_SATYPE_MAX) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_msg_interp: "
+ "satype %d > max %d\n",
+ pfkey_msg->sadb_msg_satype,
+ SADB_SATYPE_MAX);
+ SENDERR(EINVAL);
+ }
+
+ switch(pfkey_msg->sadb_msg_type) {
+ case SADB_GETSPI:
+ case SADB_UPDATE:
+ case SADB_ADD:
+ case SADB_DELETE:
+ case SADB_X_GRPSA:
+ case SADB_X_ADDFLOW:
+ if(!(extr.ips->ips_said.proto = satype2proto(pfkey_msg->sadb_msg_satype))) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_msg_interp: "
+ "satype %d lookup failed.\n",
+ pfkey_msg->sadb_msg_satype);
+ SENDERR(EINVAL);
+ } else {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_msg_interp: "
+ "satype %d lookups to proto=%d.\n",
+ pfkey_msg->sadb_msg_satype,
+ extr.ips->ips_said.proto);
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* The NULL below causes the default extension parsers to be used */
+ /* Parse the extensions */
+ if((error = pfkey_msg_parse(pfkey_msg, NULL, extensions, EXT_BITS_IN)))
+ {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_msg_interp: "
+ "message parsing failed with error %d.\n",
+ error);
+ SENDERR(-error);
+ }
+
+ /* Process the extensions */
+ for(i=1; i <= SADB_EXT_MAX;i++) {
+ if(extensions[i] != NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_msg_interp: "
+ "processing ext %d 0p%p with processor 0p%p.\n",
+ i, extensions[i], ext_processors[i]);
+ if((error = ext_processors[i](extensions[i], &extr))) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_msg_interp: "
+ "extension processing for type %d failed with error %d.\n",
+ i,
+ error);
+ SENDERR(-error);
+ }
+
+ }
+
+ }
+
+ /* Parse the message types */
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_msg_interp: "
+ "parsing message type %d(%s) with msg_parser 0p%p.\n",
+ pfkey_msg->sadb_msg_type,
+ pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type),
+ msg_parsers[pfkey_msg->sadb_msg_type]);
+ if((error = msg_parsers[pfkey_msg->sadb_msg_type](sk, extensions, &extr))) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_msg_interp: "
+ "message parsing failed with error %d.\n",
+ error);
+ SENDERR(-error);
+ }
+
+#if 0
+ error = pfkey_build_reply(pfkey_msg, &extr, pfkey_reply);
+ if (error) {
+ *pfkey_reply = NULL;
+ }
+#endif
+ errlab:
+ if(extr.ips != NULL) {
+ ipsec_sa_wipe(extr.ips);
+ }
+ if(extr.ips2 != NULL) {
+ ipsec_sa_wipe(extr.ips2);
+ }
+ if (extr.eroute != NULL) {
+ kfree(extr.eroute);
+ }
+ return(error);
+}
+
diff --git a/linux/net/ipsec/radij.c b/linux/net/ipsec/radij.c
new file mode 100644
index 000000000..7dbec8d37
--- /dev/null
+++ b/linux/net/ipsec/radij.c
@@ -0,0 +1,992 @@
+char radij_c_version[] = "RCSID $Id: radij.c,v 1.2 2004/06/13 19:57:50 as Exp $";
+
+/*
+ * This file is defived from ${SRC}/sys/net/radix.c of BSD 4.4lite
+ *
+ * Variable and procedure names have been modified so that they don't
+ * conflict with the original BSD code, as a small number of modifications
+ * have been introduced and we may want to reuse this code in BSD.
+ *
+ * The `j' in `radij' is pronounced as a voiceless guttural (like a Greek
+ * chi or a German ch sound (as `doch', not as in `milch'), or even a
+ * spanish j as in Juan. It is not as far back in the throat like
+ * the corresponding Hebrew sound, nor is it a soft breath like the English h.
+ * It has nothing to do with the Dutch ij sound.
+ *
+ * Here is the appropriate copyright notice:
+ */
+
+/*
+ * Copyright (c) 1988, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)radix.c 8.2 (Berkeley) 1/4/94
+ */
+
+/*
+ * Routines to build and maintain radix trees for routing lookups.
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/kernel.h> /* printk() */
+
+#include "freeswan/ipsec_param.h"
+
+#ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+#else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+#endif /* MALLOC_SLAB */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/interrupt.h> /* mark_bh */
+
+#include <linux/netdevice.h> /* struct device, and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/ip.h> /* struct iphdr */
+#include <linux/skbuff.h>
+#ifdef NET_21
+# include <asm/uaccess.h>
+# include <linux/in6.h>
+#endif /* NET_21 */
+#include <asm/checksum.h>
+#include <net/ip.h>
+
+#include <freeswan.h>
+
+#include "freeswan/radij.h"
+#include "freeswan/ipsec_encap.h"
+#include "freeswan/ipsec_radij.h"
+
+int maj_keylen;
+struct radij_mask *rj_mkfreelist;
+struct radij_node_head *mask_rjhead;
+static int gotOddMasks;
+static char *maskedKey;
+static char *rj_zeroes, *rj_ones;
+
+#define rj_masktop (mask_rjhead->rnh_treetop)
+#ifdef Bcmp
+# undef Bcmp
+#endif /* Bcmp */
+#define Bcmp(a, b, l) (l == 0 ? 0 : memcmp((caddr_t)(b), (caddr_t)(a), (size_t)l))
+/*
+ * The data structure for the keys is a radix tree with one way
+ * branching removed. The index rj_b at an internal node n represents a bit
+ * position to be tested. The tree is arranged so that all descendants
+ * of a node n have keys whose bits all agree up to position rj_b - 1.
+ * (We say the index of n is rj_b.)
+ *
+ * There is at least one descendant which has a one bit at position rj_b,
+ * and at least one with a zero there.
+ *
+ * A route is determined by a pair of key and mask. We require that the
+ * bit-wise logical and of the key and mask to be the key.
+ * We define the index of a route to associated with the mask to be
+ * the first bit number in the mask where 0 occurs (with bit number 0
+ * representing the highest order bit).
+ *
+ * We say a mask is normal if every bit is 0, past the index of the mask.
+ * If a node n has a descendant (k, m) with index(m) == index(n) == rj_b,
+ * and m is a normal mask, then the route applies to every descendant of n.
+ * If the index(m) < rj_b, this implies the trailing last few bits of k
+ * before bit b are all 0, (and hence consequently true of every descendant
+ * of n), so the route applies to all descendants of the node as well.
+ *
+ * The present version of the code makes no use of normal routes,
+ * but similar logic shows that a non-normal mask m such that
+ * index(m) <= index(n) could potentially apply to many children of n.
+ * Thus, for each non-host route, we attach its mask to a list at an internal
+ * node as high in the tree as we can go.
+ */
+
+struct radij_node *
+rj_search(v_arg, head)
+ void *v_arg;
+ struct radij_node *head;
+{
+ register struct radij_node *x;
+ register caddr_t v;
+
+ for (x = head, v = v_arg; x->rj_b >= 0;) {
+ if (x->rj_bmask & v[x->rj_off])
+ x = x->rj_r;
+ else
+ x = x->rj_l;
+ }
+ return (x);
+};
+
+struct radij_node *
+rj_search_m(v_arg, head, m_arg)
+ struct radij_node *head;
+ void *v_arg, *m_arg;
+{
+ register struct radij_node *x;
+ register caddr_t v = v_arg, m = m_arg;
+
+ for (x = head; x->rj_b >= 0;) {
+ if ((x->rj_bmask & m[x->rj_off]) &&
+ (x->rj_bmask & v[x->rj_off]))
+ x = x->rj_r;
+ else
+ x = x->rj_l;
+ }
+ return x;
+};
+
+int
+rj_refines(m_arg, n_arg)
+ void *m_arg, *n_arg;
+{
+ register caddr_t m = m_arg, n = n_arg;
+ register caddr_t lim, lim2 = lim = n + *(u_char *)n;
+ int longer = (*(u_char *)n++) - (int)(*(u_char *)m++);
+ int masks_are_equal = 1;
+
+ if (longer > 0)
+ lim -= longer;
+ while (n < lim) {
+ if (*n & ~(*m))
+ return 0;
+ if (*n++ != *m++)
+ masks_are_equal = 0;
+
+ }
+ while (n < lim2)
+ if (*n++)
+ return 0;
+ if (masks_are_equal && (longer < 0))
+ for (lim2 = m - longer; m < lim2; )
+ if (*m++)
+ return 1;
+ return (!masks_are_equal);
+}
+
+
+struct radij_node *
+rj_match(v_arg, head)
+ void *v_arg;
+ struct radij_node_head *head;
+{
+ caddr_t v = v_arg;
+ register struct radij_node *t = head->rnh_treetop, *x;
+ register caddr_t cp = v, cp2, cp3;
+ caddr_t cplim, mstart;
+ struct radij_node *saved_t, *top = t;
+ int off = t->rj_off, vlen = *(u_char *)cp, matched_off;
+
+ /*
+ * Open code rj_search(v, top) to avoid overhead of extra
+ * subroutine call.
+ */
+ for (; t->rj_b >= 0; ) {
+ if (t->rj_bmask & cp[t->rj_off])
+ t = t->rj_r;
+ else
+ t = t->rj_l;
+ }
+ /*
+ * See if we match exactly as a host destination
+ */
+ KLIPS_PRINT(debug_radij,
+ "klips_debug:rj_match: "
+ "* See if we match exactly as a host destination\n");
+
+ cp += off; cp2 = t->rj_key + off; cplim = v + vlen;
+ for (; cp < cplim; cp++, cp2++)
+ if (*cp != *cp2)
+ goto on1;
+ /*
+ * This extra grot is in case we are explicitly asked
+ * to look up the default. Ugh!
+ */
+ if ((t->rj_flags & RJF_ROOT) && t->rj_dupedkey)
+ t = t->rj_dupedkey;
+ return t;
+on1:
+ matched_off = cp - v;
+ saved_t = t;
+ KLIPS_PRINT(debug_radij,
+ "klips_debug:rj_match: "
+ "** try to match a leaf, t=0p%p\n", t);
+ do {
+ if (t->rj_mask) {
+ /*
+ * Even if we don't match exactly as a hosts;
+ * we may match if the leaf we wound up at is
+ * a route to a net.
+ */
+ cp3 = matched_off + t->rj_mask;
+ cp2 = matched_off + t->rj_key;
+ for (; cp < cplim; cp++)
+ if ((*cp2++ ^ *cp) & *cp3++)
+ break;
+ if (cp == cplim)
+ return t;
+ cp = matched_off + v;
+ }
+ } while ((t = t->rj_dupedkey));
+ t = saved_t;
+ /* start searching up the tree */
+ KLIPS_PRINT(debug_radij,
+ "klips_debug:rj_match: "
+ "*** start searching up the tree, t=0p%p\n",
+ t);
+ do {
+ register struct radij_mask *m;
+
+ t = t->rj_p;
+ KLIPS_PRINT(debug_radij,
+ "klips_debug:rj_match: "
+ "**** t=0p%p\n",
+ t);
+ if ((m = t->rj_mklist)) {
+ /*
+ * After doing measurements here, it may
+ * turn out to be faster to open code
+ * rj_search_m here instead of always
+ * copying and masking.
+ */
+ /* off = min(t->rj_off, matched_off); */
+ off = t->rj_off;
+ if (matched_off < off)
+ off = matched_off;
+ mstart = maskedKey + off;
+ do {
+ cp2 = mstart;
+ cp3 = m->rm_mask + off;
+ KLIPS_PRINT(debug_radij,
+ "klips_debug:rj_match: "
+ "***** cp2=0p%p cp3=0p%p\n",
+ cp2, cp3);
+ for (cp = v + off; cp < cplim;)
+ *cp2++ = *cp++ & *cp3++;
+ x = rj_search(maskedKey, t);
+ while (x && x->rj_mask != m->rm_mask)
+ x = x->rj_dupedkey;
+ if (x &&
+ (Bcmp(mstart, x->rj_key + off,
+ vlen - off) == 0))
+ return x;
+ } while ((m = m->rm_mklist));
+ }
+ } while (t != top);
+ KLIPS_PRINT(debug_radij,
+ "klips_debug:rj_match: "
+ "***** not found.\n");
+ return 0;
+};
+
+#ifdef RJ_DEBUG
+int rj_nodenum;
+struct radij_node *rj_clist;
+int rj_saveinfo;
+DEBUG_NO_STATIC void traverse(struct radij_node *);
+#ifdef RJ_DEBUG2
+int rj_debug = 1;
+#else
+int rj_debug = 0;
+#endif /* RJ_DEBUG2 */
+#endif /* RJ_DEBUG */
+
+struct radij_node *
+rj_newpair(v, b, nodes)
+ void *v;
+ int b;
+ struct radij_node nodes[2];
+{
+ register struct radij_node *tt = nodes, *t = tt + 1;
+ t->rj_b = b; t->rj_bmask = 0x80 >> (b & 7);
+ t->rj_l = tt; t->rj_off = b >> 3;
+ tt->rj_b = -1; tt->rj_key = (caddr_t)v; tt->rj_p = t;
+ tt->rj_flags = t->rj_flags = RJF_ACTIVE;
+#ifdef RJ_DEBUG
+ tt->rj_info = rj_nodenum++; t->rj_info = rj_nodenum++;
+ tt->rj_twin = t; tt->rj_ybro = rj_clist; rj_clist = tt;
+#endif /* RJ_DEBUG */
+ return t;
+}
+
+struct radij_node *
+rj_insert(v_arg, head, dupentry, nodes)
+ void *v_arg;
+ struct radij_node_head *head;
+ int *dupentry;
+ struct radij_node nodes[2];
+{
+ caddr_t v = v_arg;
+ struct radij_node *top = head->rnh_treetop;
+ int head_off = top->rj_off, vlen = (int)*((u_char *)v);
+ register struct radij_node *t = rj_search(v_arg, top);
+ register caddr_t cp = v + head_off;
+ register int b;
+ struct radij_node *tt;
+ /*
+ *find first bit at which v and t->rj_key differ
+ */
+ {
+ register caddr_t cp2 = t->rj_key + head_off;
+ register int cmp_res;
+ caddr_t cplim = v + vlen;
+
+ while (cp < cplim)
+ if (*cp2++ != *cp++)
+ goto on1;
+ *dupentry = 1;
+ return t;
+on1:
+ *dupentry = 0;
+ cmp_res = (cp[-1] ^ cp2[-1]) & 0xff;
+ for (b = (cp - v) << 3; cmp_res; b--)
+ cmp_res >>= 1;
+ }
+ {
+ register struct radij_node *p, *x = top;
+ cp = v;
+ do {
+ p = x;
+ if (cp[x->rj_off] & x->rj_bmask)
+ x = x->rj_r;
+ else x = x->rj_l;
+ } while (b > (unsigned) x->rj_b); /* x->rj_b < b && x->rj_b >= 0 */
+#ifdef RJ_DEBUG
+ if (rj_debug)
+ printk("klips_debug:rj_insert: Going In:\n"), traverse(p);
+#endif /* RJ_DEBUG */
+ t = rj_newpair(v_arg, b, nodes); tt = t->rj_l;
+ if ((cp[p->rj_off] & p->rj_bmask) == 0)
+ p->rj_l = t;
+ else
+ p->rj_r = t;
+ x->rj_p = t; t->rj_p = p; /* frees x, p as temp vars below */
+ if ((cp[t->rj_off] & t->rj_bmask) == 0) {
+ t->rj_r = x;
+ } else {
+ t->rj_r = tt; t->rj_l = x;
+ }
+#ifdef RJ_DEBUG
+ if (rj_debug)
+ printk("klips_debug:rj_insert: Coming out:\n"), traverse(p);
+#endif /* RJ_DEBUG */
+ }
+ return (tt);
+}
+
+struct radij_node *
+rj_addmask(n_arg, search, skip)
+ int search, skip;
+ void *n_arg;
+{
+ caddr_t netmask = (caddr_t)n_arg;
+ register struct radij_node *x;
+ register caddr_t cp, cplim;
+ register int b, mlen, j;
+ int maskduplicated;
+
+ mlen = *(u_char *)netmask;
+ if (search) {
+ x = rj_search(netmask, rj_masktop);
+ mlen = *(u_char *)netmask;
+ if (Bcmp(netmask, x->rj_key, mlen) == 0)
+ return (x);
+ }
+ R_Malloc(x, struct radij_node *, maj_keylen + 2 * sizeof (*x));
+ if (x == 0)
+ return (0);
+ Bzero(x, maj_keylen + 2 * sizeof (*x));
+ cp = (caddr_t)(x + 2);
+ Bcopy(netmask, cp, mlen);
+ netmask = cp;
+ x = rj_insert(netmask, mask_rjhead, &maskduplicated, x);
+ /*
+ * Calculate index of mask.
+ */
+ cplim = netmask + mlen;
+ for (cp = netmask + skip; cp < cplim; cp++)
+ if (*(u_char *)cp != 0xff)
+ break;
+ b = (cp - netmask) << 3;
+ if (cp != cplim) {
+ if (*cp != 0) {
+ gotOddMasks = 1;
+ for (j = 0x80; j; b++, j >>= 1)
+ if ((j & *cp) == 0)
+ break;
+ }
+ }
+ x->rj_b = -1 - b;
+ return (x);
+}
+
+#if 0
+struct radij_node *
+#endif
+int
+rj_addroute(v_arg, n_arg, head, treenodes)
+ void *v_arg, *n_arg;
+ struct radij_node_head *head;
+ struct radij_node treenodes[2];
+{
+ caddr_t v = (caddr_t)v_arg, netmask = (caddr_t)n_arg;
+ register struct radij_node *t, *x=NULL, *tt;
+ struct radij_node *saved_tt, *top = head->rnh_treetop;
+ short b = 0, b_leaf;
+ int mlen, keyduplicated;
+ caddr_t cplim;
+ struct radij_mask *m, **mp;
+
+ /*
+ * In dealing with non-contiguous masks, there may be
+ * many different routes which have the same mask.
+ * We will find it useful to have a unique pointer to
+ * the mask to speed avoiding duplicate references at
+ * nodes and possibly save time in calculating indices.
+ */
+ if (netmask) {
+ x = rj_search(netmask, rj_masktop);
+ mlen = *(u_char *)netmask;
+ if (Bcmp(netmask, x->rj_key, mlen) != 0) {
+ x = rj_addmask(netmask, 0, top->rj_off);
+ if (x == 0)
+ return -ENOMEM; /* (0) rgb */
+ }
+ netmask = x->rj_key;
+ b = -1 - x->rj_b;
+ }
+ /*
+ * Deal with duplicated keys: attach node to previous instance
+ */
+ saved_tt = tt = rj_insert(v, head, &keyduplicated, treenodes);
+ if (keyduplicated) {
+ do {
+ if (tt->rj_mask == netmask)
+ return -EEXIST; /* -ENXIO; (0) rgb */
+ t = tt;
+ if (netmask == 0 ||
+ (tt->rj_mask && rj_refines(netmask, tt->rj_mask)))
+ break;
+ } while ((tt = tt->rj_dupedkey));
+ /*
+ * If the mask is not duplicated, we wouldn't
+ * find it among possible duplicate key entries
+ * anyway, so the above test doesn't hurt.
+ *
+ * We sort the masks for a duplicated key the same way as
+ * in a masklist -- most specific to least specific.
+ * This may require the unfortunate nuisance of relocating
+ * the head of the list.
+ */
+ if (tt && t == saved_tt) {
+ struct radij_node *xx = x;
+ /* link in at head of list */
+ (tt = treenodes)->rj_dupedkey = t;
+ tt->rj_flags = t->rj_flags;
+ tt->rj_p = x = t->rj_p;
+ if (x->rj_l == t) x->rj_l = tt; else x->rj_r = tt;
+ saved_tt = tt; x = xx;
+ } else {
+ (tt = treenodes)->rj_dupedkey = t->rj_dupedkey;
+ t->rj_dupedkey = tt;
+ }
+#ifdef RJ_DEBUG
+ t=tt+1; tt->rj_info = rj_nodenum++; t->rj_info = rj_nodenum++;
+ tt->rj_twin = t; tt->rj_ybro = rj_clist; rj_clist = tt;
+#endif /* RJ_DEBUG */
+ t = saved_tt;
+ tt->rj_key = (caddr_t) v;
+ tt->rj_b = -1;
+ tt->rj_flags = t->rj_flags & ~RJF_ROOT;
+ }
+ /*
+ * Put mask in tree.
+ */
+ if (netmask) {
+ tt->rj_mask = netmask;
+ tt->rj_b = x->rj_b;
+ }
+ t = saved_tt->rj_p;
+ b_leaf = -1 - t->rj_b;
+ if (t->rj_r == saved_tt) x = t->rj_l; else x = t->rj_r;
+ /* Promote general routes from below */
+ if (x->rj_b < 0) {
+ if (x->rj_mask && (x->rj_b >= b_leaf) && x->rj_mklist == 0) {
+ MKGet(m);
+ if (m) {
+ Bzero(m, sizeof *m);
+ m->rm_b = x->rj_b;
+ m->rm_mask = x->rj_mask;
+ x->rj_mklist = t->rj_mklist = m;
+ }
+ }
+ } else if (x->rj_mklist) {
+ /*
+ * Skip over masks whose index is > that of new node
+ */
+ for (mp = &x->rj_mklist; (m = *mp); mp = &m->rm_mklist)
+ if (m->rm_b >= b_leaf)
+ break;
+ t->rj_mklist = m; *mp = 0;
+ }
+ /* Add new route to highest possible ancestor's list */
+ if ((netmask == 0) || (b > t->rj_b ))
+ return 0; /* tt rgb */ /* can't lift at all */
+ b_leaf = tt->rj_b;
+ do {
+ x = t;
+ t = t->rj_p;
+ } while (b <= t->rj_b && x != top);
+ /*
+ * Search through routes associated with node to
+ * insert new route according to index.
+ * For nodes of equal index, place more specific
+ * masks first.
+ */
+ cplim = netmask + mlen;
+ for (mp = &x->rj_mklist; (m = *mp); mp = &m->rm_mklist) {
+ if (m->rm_b < b_leaf)
+ continue;
+ if (m->rm_b > b_leaf)
+ break;
+ if (m->rm_mask == netmask) {
+ m->rm_refs++;
+ tt->rj_mklist = m;
+ return 0; /* tt rgb */
+ }
+ if (rj_refines(netmask, m->rm_mask))
+ break;
+ }
+ MKGet(m);
+ if (m == 0) {
+ printk("klips_debug:rj_addroute: "
+ "Mask for route not entered\n");
+ return 0; /* (tt) rgb */
+ }
+ Bzero(m, sizeof *m);
+ m->rm_b = b_leaf;
+ m->rm_mask = netmask;
+ m->rm_mklist = *mp;
+ *mp = m;
+ tt->rj_mklist = m;
+ return 0; /* tt rgb */
+}
+
+int
+rj_delete(v_arg, netmask_arg, head, node)
+ void *v_arg, *netmask_arg;
+ struct radij_node_head *head;
+ struct radij_node **node;
+{
+ register struct radij_node *t, *p, *x, *tt;
+ struct radij_mask *m, *saved_m, **mp;
+ struct radij_node *dupedkey, *saved_tt, *top;
+ caddr_t v, netmask;
+ int b, head_off, vlen;
+
+ v = v_arg;
+ netmask = netmask_arg;
+ x = head->rnh_treetop;
+ tt = rj_search(v, x);
+ head_off = x->rj_off;
+ vlen = *(u_char *)v;
+ saved_tt = tt;
+ top = x;
+ if (tt == 0 ||
+ Bcmp(v + head_off, tt->rj_key + head_off, vlen - head_off))
+ return -EFAULT; /* (0) rgb */
+ /*
+ * Delete our route from mask lists.
+ */
+ if ((dupedkey = tt->rj_dupedkey)) {
+ if (netmask)
+ netmask = rj_search(netmask, rj_masktop)->rj_key;
+ while (tt->rj_mask != netmask)
+ if ((tt = tt->rj_dupedkey) == 0)
+ return -ENOENT; /* -ENXIO; (0) rgb */
+ }
+ if (tt->rj_mask == 0 || (saved_m = m = tt->rj_mklist) == 0)
+ goto on1;
+ if (m->rm_mask != tt->rj_mask) {
+ printk("klips_debug:rj_delete: "
+ "inconsistent annotation\n");
+ goto on1;
+ }
+ if (--m->rm_refs >= 0)
+ goto on1;
+ b = -1 - tt->rj_b;
+ t = saved_tt->rj_p;
+ if (b > t->rj_b)
+ goto on1; /* Wasn't lifted at all */
+ do {
+ x = t;
+ t = t->rj_p;
+ } while (b <= t->rj_b && x != top);
+ for (mp = &x->rj_mklist; (m = *mp); mp = &m->rm_mklist)
+ if (m == saved_m) {
+ *mp = m->rm_mklist;
+ MKFree(m);
+ break;
+ }
+ if (m == 0)
+ printk("klips_debug:rj_delete: "
+ "couldn't find our annotation\n");
+on1:
+ /*
+ * Eliminate us from tree
+ */
+ if (tt->rj_flags & RJF_ROOT)
+ return -EFAULT; /* (0) rgb */
+#ifdef RJ_DEBUG
+ /* Get us out of the creation list */
+ for (t = rj_clist; t && t->rj_ybro != tt; t = t->rj_ybro) {}
+ if (t) t->rj_ybro = tt->rj_ybro;
+#endif /* RJ_DEBUG */
+ t = tt->rj_p;
+ if (dupedkey) {
+ if (tt == saved_tt) {
+ x = dupedkey; x->rj_p = t;
+ if (t->rj_l == tt) t->rj_l = x; else t->rj_r = x;
+ } else {
+ for (x = p = saved_tt; p && p->rj_dupedkey != tt;)
+ p = p->rj_dupedkey;
+ if (p) p->rj_dupedkey = tt->rj_dupedkey;
+ else printk("klips_debug:rj_delete: "
+ "couldn't find us\n");
+ }
+ t = tt + 1;
+ if (t->rj_flags & RJF_ACTIVE) {
+#ifndef RJ_DEBUG
+ *++x = *t; p = t->rj_p;
+#else
+ b = t->rj_info; *++x = *t; t->rj_info = b; p = t->rj_p;
+#endif /* RJ_DEBUG */
+ if (p->rj_l == t) p->rj_l = x; else p->rj_r = x;
+ x->rj_l->rj_p = x; x->rj_r->rj_p = x;
+ }
+ goto out;
+ }
+ if (t->rj_l == tt) x = t->rj_r; else x = t->rj_l;
+ p = t->rj_p;
+ if (p->rj_r == t) p->rj_r = x; else p->rj_l = x;
+ x->rj_p = p;
+ /*
+ * Demote routes attached to us.
+ */
+ if (t->rj_mklist) {
+ if (x->rj_b >= 0) {
+ for (mp = &x->rj_mklist; (m = *mp);)
+ mp = &m->rm_mklist;
+ *mp = t->rj_mklist;
+ } else {
+ for (m = t->rj_mklist; m;) {
+ struct radij_mask *mm = m->rm_mklist;
+ if (m == x->rj_mklist && (--(m->rm_refs) < 0)) {
+ x->rj_mklist = 0;
+ MKFree(m);
+ } else
+ printk("klips_debug:rj_delete: "
+ "Orphaned Mask 0p%p at 0p%p\n", m, x);
+ m = mm;
+ }
+ }
+ }
+ /*
+ * We may be holding an active internal node in the tree.
+ */
+ x = tt + 1;
+ if (t != x) {
+#ifndef RJ_DEBUG
+ *t = *x;
+#else
+ b = t->rj_info; *t = *x; t->rj_info = b;
+#endif /* RJ_DEBUG */
+ t->rj_l->rj_p = t; t->rj_r->rj_p = t;
+ p = x->rj_p;
+ if (p->rj_l == x) p->rj_l = t; else p->rj_r = t;
+ }
+out:
+ tt->rj_flags &= ~RJF_ACTIVE;
+ tt[1].rj_flags &= ~RJF_ACTIVE;
+ *node = tt;
+ return 0; /* (tt) rgb */
+}
+
+int
+rj_walktree(h, f, w)
+ struct radij_node_head *h;
+ register int (*f)(struct radij_node *,void *);
+ void *w;
+{
+ int error;
+ struct radij_node *base, *next;
+ register struct radij_node *rn;
+
+ if(!h || !f /* || !w */) {
+ return -ENODATA;
+ }
+
+ rn = h->rnh_treetop;
+ /*
+ * This gets complicated because we may delete the node
+ * while applying the function f to it, so we need to calculate
+ * the successor node in advance.
+ */
+ /* First time through node, go left */
+ while (rn->rj_b >= 0)
+ rn = rn->rj_l;
+ for (;;) {
+#ifdef CONFIG_IPSEC_DEBUG
+ if(debug_radij) {
+ printk("klips_debug:rj_walktree: "
+ "for: rn=0p%p rj_b=%d rj_flags=%x",
+ rn,
+ rn->rj_b,
+ rn->rj_flags);
+ rn->rj_b >= 0 ?
+ printk(" node off=%x\n",
+ rn->rj_off) :
+ printk(" leaf key = %08x->%08x\n",
+ (u_int)ntohl(((struct sockaddr_encap *)rn->rj_key)->sen_ip_src.s_addr),
+ (u_int)ntohl(((struct sockaddr_encap *)rn->rj_key)->sen_ip_dst.s_addr))
+ ;
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+ base = rn;
+ /* If at right child go back up, otherwise, go right */
+ while (rn->rj_p->rj_r == rn && (rn->rj_flags & RJF_ROOT) == 0)
+ rn = rn->rj_p;
+ /* Find the next *leaf* since next node might vanish, too */
+ for (rn = rn->rj_p->rj_r; rn->rj_b >= 0;)
+ rn = rn->rj_l;
+ next = rn;
+#ifdef CONFIG_IPSEC_DEBUG
+ if(debug_radij) {
+ printk("klips_debug:rj_walktree: "
+ "processing leaves, rn=0p%p rj_b=%d rj_flags=%x",
+ rn,
+ rn->rj_b,
+ rn->rj_flags);
+ rn->rj_b >= 0 ?
+ printk(" node off=%x\n",
+ rn->rj_off) :
+ printk(" leaf key = %08x->%08x\n",
+ (u_int)ntohl(((struct sockaddr_encap *)rn->rj_key)->sen_ip_src.s_addr),
+ (u_int)ntohl(((struct sockaddr_encap *)rn->rj_key)->sen_ip_dst.s_addr))
+ ;
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+ /* Process leaves */
+ while ((rn = base)) {
+ base = rn->rj_dupedkey;
+#ifdef CONFIG_IPSEC_DEBUG
+ if(debug_radij) {
+ printk("klips_debug:rj_walktree: "
+ "while: base=0p%p rn=0p%p rj_b=%d rj_flags=%x",
+ base,
+ rn,
+ rn->rj_b,
+ rn->rj_flags);
+ rn->rj_b >= 0 ?
+ printk(" node off=%x\n",
+ rn->rj_off) :
+ printk(" leaf key = %08x->%08x\n",
+ (u_int)ntohl(((struct sockaddr_encap *)rn->rj_key)->sen_ip_src.s_addr),
+ (u_int)ntohl(((struct sockaddr_encap *)rn->rj_key)->sen_ip_dst.s_addr))
+ ;
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+ if (!(rn->rj_flags & RJF_ROOT) && (error = (*f)(rn, w)))
+ return (-error);
+ }
+ rn = next;
+ if (rn->rj_flags & RJF_ROOT)
+ return (0);
+ }
+ /* NOTREACHED */
+}
+
+int
+rj_inithead(head, off)
+ void **head;
+ int off;
+{
+ register struct radij_node_head *rnh;
+ register struct radij_node *t, *tt, *ttt;
+ if (*head)
+ return (1);
+ R_Malloc(rnh, struct radij_node_head *, sizeof (*rnh));
+ if (rnh == NULL)
+ return (0);
+ Bzero(rnh, sizeof (*rnh));
+ *head = rnh;
+ t = rj_newpair(rj_zeroes, off, rnh->rnh_nodes);
+ ttt = rnh->rnh_nodes + 2;
+ t->rj_r = ttt;
+ t->rj_p = t;
+ tt = t->rj_l;
+ tt->rj_flags = t->rj_flags = RJF_ROOT | RJF_ACTIVE;
+ tt->rj_b = -1 - off;
+ *ttt = *tt;
+ ttt->rj_key = rj_ones;
+ rnh->rnh_addaddr = rj_addroute;
+ rnh->rnh_deladdr = rj_delete;
+ rnh->rnh_matchaddr = rj_match;
+ rnh->rnh_walktree = rj_walktree;
+ rnh->rnh_treetop = t;
+ return (1);
+}
+
+void
+rj_init()
+{
+ char *cp, *cplim;
+
+ if (maj_keylen == 0) {
+ printk("klips_debug:rj_init: "
+ "radij functions require maj_keylen be set\n");
+ return;
+ }
+ R_Malloc(rj_zeroes, char *, 3 * maj_keylen);
+ if (rj_zeroes == NULL)
+ panic("rj_init");
+ Bzero(rj_zeroes, 3 * maj_keylen);
+ rj_ones = cp = rj_zeroes + maj_keylen;
+ maskedKey = cplim = rj_ones + maj_keylen;
+ while (cp < cplim)
+ *cp++ = -1;
+ if (rj_inithead((void **)&mask_rjhead, 0) == 0)
+ panic("rj_init 2");
+}
+
+void
+rj_preorder(struct radij_node *rn, int l)
+{
+ int i;
+
+ if (rn == NULL){
+ printk("klips_debug:rj_preorder: "
+ "NULL pointer\n");
+ return;
+ }
+
+ if (rn->rj_b >= 0){
+ rj_preorder(rn->rj_l, l+1);
+ rj_preorder(rn->rj_r, l+1);
+ printk("klips_debug:");
+ for (i=0; i<l; i++)
+ printk("*");
+ printk(" off = %d\n",
+ rn->rj_off);
+ } else {
+ printk("klips_debug:");
+ for (i=0; i<l; i++)
+ printk("@");
+ printk(" flags = %x",
+ (u_int)rn->rj_flags);
+ if (rn->rj_flags & RJF_ACTIVE) {
+ printk(" @key=0p%p",
+ rn->rj_key);
+ printk(" key = %08x->%08x",
+ (u_int)ntohl(((struct sockaddr_encap *)rn->rj_key)->sen_ip_src.s_addr),
+ (u_int)ntohl(((struct sockaddr_encap *)rn->rj_key)->sen_ip_dst.s_addr));
+ printk(" @mask=0p%p",
+ rn->rj_mask);
+ if (rn->rj_mask)
+ printk(" mask = %08x->%08x",
+ (u_int)ntohl(((struct sockaddr_encap *)rn->rj_mask)->sen_ip_src.s_addr),
+ (u_int)ntohl(((struct sockaddr_encap *)rn->rj_mask)->sen_ip_dst.s_addr));
+ if (rn->rj_dupedkey)
+ printk(" dupedkey = 0p%p",
+ rn->rj_dupedkey);
+ }
+ printk("\n");
+ }
+}
+
+#ifdef RJ_DEBUG
+DEBUG_NO_STATIC void traverse(struct radij_node *p)
+{
+ rj_preorder(p, 0);
+}
+#endif /* RJ_DEBUG */
+
+void
+rj_dumptrees(void)
+{
+ rj_preorder(rnh->rnh_treetop, 0);
+}
+
+void
+rj_free_mkfreelist(void)
+{
+ struct radij_mask *mknp, *mknp2;
+
+ mknp = rj_mkfreelist;
+ while(mknp)
+ {
+ mknp2 = mknp;
+ mknp = mknp->rm_mklist;
+ kfree(mknp2);
+ }
+}
+
+int
+radijcleartree(void)
+{
+ return rj_walktree(rnh, ipsec_rj_walker_delete, NULL);
+}
+
+int
+radijcleanup(void)
+{
+ int error = 0;
+
+ error = radijcleartree();
+
+ rj_free_mkfreelist();
+
+/* rj_walktree(mask_rjhead, ipsec_rj_walker_delete, NULL); */
+ if(mask_rjhead) {
+ kfree(mask_rjhead);
+ }
+
+ if(rj_zeroes) {
+ kfree(rj_zeroes);
+ }
+
+ if(rnh) {
+ kfree(rnh);
+ }
+
+ return error;
+}
+
diff --git a/linux/net/ipsec/sysctl_net_ipsec.c b/linux/net/ipsec/sysctl_net_ipsec.c
new file mode 100644
index 000000000..b494329f6
--- /dev/null
+++ b/linux/net/ipsec/sysctl_net_ipsec.c
@@ -0,0 +1,196 @@
+/*
+ * sysctl interface to net IPSEC subsystem.
+ * Copyright (C) 1998, 1999, 2000, 2001 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: sysctl_net_ipsec.c,v 1.1 2004/03/15 20:35:27 as Exp $
+ */
+
+/* -*- linux-c -*-
+ *
+ * Initiated April 3, 1998, Richard Guy Briggs <rgb@conscoop.ottawa.on.ca>
+ */
+
+#include <linux/mm.h>
+#include <linux/sysctl.h>
+
+#include "freeswan/ipsec_param.h"
+
+#ifdef CONFIG_SYSCTL
+
+#define NET_IPSEC 2112 /* Random number */
+#ifdef CONFIG_IPSEC_DEBUG
+extern int debug_ah;
+extern int debug_esp;
+extern int debug_tunnel;
+extern int debug_eroute;
+extern int debug_spi;
+extern int debug_radij;
+extern int debug_netlink;
+extern int debug_xform;
+extern int debug_rcv;
+extern int debug_pfkey;
+extern int sysctl_ipsec_debug_verbose;
+#ifdef CONFIG_IPSEC_IPCOMP
+extern int sysctl_ipsec_debug_ipcomp;
+#endif /* CONFIG_IPSEC_IPCOMP */
+#endif /* CONFIG_IPSEC_DEBUG */
+
+extern int sysctl_ipsec_icmp;
+extern int sysctl_ipsec_inbound_policy_check;
+extern int sysctl_ipsec_tos;
+int sysctl_ipsec_regress_pfkey_lossage;
+
+enum {
+#ifdef CONFIG_IPSEC_DEBUG
+ NET_IPSEC_DEBUG_AH=1,
+ NET_IPSEC_DEBUG_ESP=2,
+ NET_IPSEC_DEBUG_TUNNEL=3,
+ NET_IPSEC_DEBUG_EROUTE=4,
+ NET_IPSEC_DEBUG_SPI=5,
+ NET_IPSEC_DEBUG_RADIJ=6,
+ NET_IPSEC_DEBUG_NETLINK=7,
+ NET_IPSEC_DEBUG_XFORM=8,
+ NET_IPSEC_DEBUG_RCV=9,
+ NET_IPSEC_DEBUG_PFKEY=10,
+ NET_IPSEC_DEBUG_VERBOSE=11,
+ NET_IPSEC_DEBUG_IPCOMP=12,
+#endif /* CONFIG_IPSEC_DEBUG */
+ NET_IPSEC_ICMP=13,
+ NET_IPSEC_INBOUND_POLICY_CHECK=14,
+ NET_IPSEC_TOS=15,
+ NET_IPSEC_REGRESS_PFKEY_LOSSAGE=16,
+};
+
+static ctl_table ipsec_table[] = {
+#ifdef CONFIG_IPSEC_DEBUG
+ { NET_IPSEC_DEBUG_AH, "debug_ah", &debug_ah,
+ sizeof(int), 0644, NULL, &proc_dointvec},
+ { NET_IPSEC_DEBUG_ESP, "debug_esp", &debug_esp,
+ sizeof(int), 0644, NULL, &proc_dointvec},
+ { NET_IPSEC_DEBUG_TUNNEL, "debug_tunnel", &debug_tunnel,
+ sizeof(int), 0644, NULL, &proc_dointvec},
+ { NET_IPSEC_DEBUG_EROUTE, "debug_eroute", &debug_eroute,
+ sizeof(int), 0644, NULL, &proc_dointvec},
+ { NET_IPSEC_DEBUG_SPI, "debug_spi", &debug_spi,
+ sizeof(int), 0644, NULL, &proc_dointvec},
+ { NET_IPSEC_DEBUG_RADIJ, "debug_radij", &debug_radij,
+ sizeof(int), 0644, NULL, &proc_dointvec},
+ { NET_IPSEC_DEBUG_NETLINK, "debug_netlink", &debug_netlink,
+ sizeof(int), 0644, NULL, &proc_dointvec},
+ { NET_IPSEC_DEBUG_XFORM, "debug_xform", &debug_xform,
+ sizeof(int), 0644, NULL, &proc_dointvec},
+ { NET_IPSEC_DEBUG_RCV, "debug_rcv", &debug_rcv,
+ sizeof(int), 0644, NULL, &proc_dointvec},
+ { NET_IPSEC_DEBUG_PFKEY, "debug_pfkey", &debug_pfkey,
+ sizeof(int), 0644, NULL, &proc_dointvec},
+ { NET_IPSEC_DEBUG_VERBOSE, "debug_verbose",&sysctl_ipsec_debug_verbose,
+ sizeof(int), 0644, NULL, &proc_dointvec},
+#ifdef CONFIG_IPSEC_IPCOMP
+ { NET_IPSEC_DEBUG_IPCOMP, "debug_ipcomp", &sysctl_ipsec_debug_ipcomp,
+ sizeof(int), 0644, NULL, &proc_dointvec},
+#endif /* CONFIG_IPSEC_IPCOMP */
+
+#ifdef CONFIG_IPSEC_REGRESS
+ { NET_IPSEC_REGRESS_PFKEY_LOSSAGE, "pfkey_lossage",
+ &sysctl_ipsec_regress_pfkey_lossage,
+ sizeof(int), 0644, NULL, &proc_dointvec},
+#endif /* CONFIG_IPSEC_REGRESS */
+
+#endif /* CONFIG_IPSEC_DEBUG */
+ { NET_IPSEC_ICMP, "icmp", &sysctl_ipsec_icmp,
+ sizeof(int), 0644, NULL, &proc_dointvec},
+ { NET_IPSEC_INBOUND_POLICY_CHECK, "inbound_policy_check", &sysctl_ipsec_inbound_policy_check,
+ sizeof(int), 0644, NULL, &proc_dointvec},
+ { NET_IPSEC_TOS, "tos", &sysctl_ipsec_tos,
+ sizeof(int), 0644, NULL, &proc_dointvec},
+ {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_table_header;
+
+int ipsec_sysctl_register(void)
+{
+ ipsec_table_header = register_sysctl_table(ipsec_root_table, 0);
+ if (!ipsec_table_header) {
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+void ipsec_sysctl_unregister(void)
+{
+ unregister_sysctl_table(ipsec_table_header);
+}
+
+#endif /* CONFIG_SYSCTL */
+
+/*
+ * $Log: sysctl_net_ipsec.c,v $
+ * Revision 1.1 2004/03/15 20:35:27 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.15 2002/04/24 07:55:32 mcr
+ * #include patches and Makefiles for post-reorg compilation.
+ *
+ * Revision 1.14 2002/04/24 07:36:35 mcr
+ * Moved from ./klips/net/ipsec/sysctl_net_ipsec.c,v
+ *
+ * Revision 1.13 2002/01/12 02:58:32 mcr
+ * first regression test causes acquire messages to be lost
+ * 100% of the time. This is to help testing of pluto.
+ *
+ * Revision 1.12 2001/06/14 19:35:13 rgb
+ * Update copyright date.
+ *
+ * Revision 1.11 2001/02/26 19:58:13 rgb
+ * Drop sysctl_ipsec_{no_eroute_pass,opportunistic}, replaced by magic SAs.
+ *
+ * Revision 1.10 2000/09/16 01:50:15 rgb
+ * Protect sysctl_ipsec_debug_ipcomp with compiler defines too so that the
+ * linker won't blame rj_delete() for missing symbols. ;-> Damn statics...
+ *
+ * Revision 1.9 2000/09/15 23:17:51 rgb
+ * Moved stuff around to compile with debug off.
+ *
+ * Revision 1.8 2000/09/15 11:37:02 rgb
+ * Merge in heavily modified Svenning Soerensen's <svenning@post5.tele.dk>
+ * IPCOMP zlib deflate code.
+ *
+ * Revision 1.7 2000/09/15 07:37:15 rgb
+ * Munged silly log comment that was causing a warning.
+ *
+ * Revision 1.6 2000/09/15 04:58:23 rgb
+ * Added tos runtime switch.
+ * Removed 'sysctl_ipsec_' prefix from /proc/sys/net/ipsec/ filenames.
+ *
+ * Revision 1.5 2000/09/12 03:25:28 rgb
+ * Filled in and implemented sysctl.
+ *
+ * Revision 1.4 1999/04/11 00:29:03 henry
+ * GPL boilerplate
+ *
+ * Revision 1.3 1999/04/06 04:54:29 rgb
+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+ * patch shell fixes.
+ *
+ */
diff --git a/linux/net/ipsec/tagsfile.mak b/linux/net/ipsec/tagsfile.mak
new file mode 100644
index 000000000..b2a5126a2
--- /dev/null
+++ b/linux/net/ipsec/tagsfile.mak
@@ -0,0 +1,6 @@
+TAGS:
+ etags *.c ../../include/*.h ../../include/freeswan/*.h
+ ctags *.c ../../include/*.h ../../include/freeswan/*.h
+
+
+