0
0
Fork 0
easterhegg-2005-website/noc/patches/linux-2.6.11.5-sinabox.diff

26282 lines
772 KiB
Diff
Raw Permalink Normal View History

2024-01-27 15:10:12 +01:00
diff -urN linux-2.6.11/arch/ppc/oprofile/op_model_fsl_booke.c linux.sinabox/arch/ppc/oprofile/op_model_fsl_booke.c
--- linux-2.6.11/arch/ppc/oprofile/op_model_fsl_booke.c 2005-03-02 08:38:33.000000000 +0100
+++ linux.sinabox/arch/ppc/oprofile/op_model_fsl_booke.c 2005-03-19 07:35:05.000000000 +0100
@@ -150,7 +150,6 @@
int is_kernel;
int val;
int i;
- unsigned int cpu = smp_processor_id();
/* set the PMM bit (see comment below) */
mtmsr(mfmsr() | MSR_PMM);
@@ -162,7 +161,7 @@
val = ctr_read(i);
if (val < 0) {
if (oprofile_running && ctr[i].enabled) {
- oprofile_add_sample(pc, is_kernel, i, cpu);
+ oprofile_add_pc(pc, is_kernel, i);
ctr_write(i, reset_value[i]);
} else {
ctr_write(i, 0);
diff -urN linux-2.6.11/arch/ppc/platforms/4xx/ebony.h linux.sinabox/arch/ppc/platforms/4xx/ebony.h
--- linux-2.6.11/arch/ppc/platforms/4xx/ebony.h 2005-03-02 08:38:18.000000000 +0100
+++ linux.sinabox/arch/ppc/platforms/4xx/ebony.h 2005-03-19 07:35:01.000000000 +0100
@@ -61,8 +61,8 @@
*/
/* OpenBIOS defined UART mappings, used before early_serial_setup */
-#define UART0_IO_BASE (u8 *) 0xE0000200
-#define UART1_IO_BASE (u8 *) 0xE0000300
+#define UART0_IO_BASE 0xE0000200
+#define UART1_IO_BASE 0xE0000300
/* external Epson SG-615P */
#define BASE_BAUD 691200
diff -urN linux-2.6.11/arch/ppc/platforms/4xx/luan.h linux.sinabox/arch/ppc/platforms/4xx/luan.h
--- linux-2.6.11/arch/ppc/platforms/4xx/luan.h 2005-03-02 08:38:13.000000000 +0100
+++ linux.sinabox/arch/ppc/platforms/4xx/luan.h 2005-03-19 07:35:00.000000000 +0100
@@ -47,9 +47,9 @@
#define RS_TABLE_SIZE 3
/* PIBS defined UART mappings, used before early_serial_setup */
-#define UART0_IO_BASE (u8 *) 0xa0000200
-#define UART1_IO_BASE (u8 *) 0xa0000300
-#define UART2_IO_BASE (u8 *) 0xa0000600
+#define UART0_IO_BASE 0xa0000200
+#define UART1_IO_BASE 0xa0000300
+#define UART2_IO_BASE 0xa0000600
#define BASE_BAUD 11059200
#define STD_UART_OP(num) \
diff -urN linux-2.6.11/arch/ppc/platforms/4xx/ocotea.h linux.sinabox/arch/ppc/platforms/4xx/ocotea.h
--- linux-2.6.11/arch/ppc/platforms/4xx/ocotea.h 2005-03-02 08:38:08.000000000 +0100
+++ linux.sinabox/arch/ppc/platforms/4xx/ocotea.h 2005-03-19 07:34:56.000000000 +0100
@@ -56,8 +56,8 @@
#define RS_TABLE_SIZE 2
/* OpenBIOS defined UART mappings, used before early_serial_setup */
-#define UART0_IO_BASE (u8 *) 0xE0000200
-#define UART1_IO_BASE (u8 *) 0xE0000300
+#define UART0_IO_BASE 0xE0000200
+#define UART1_IO_BASE 0xE0000300
#define BASE_BAUD 11059200/16
#define STD_UART_OP(num) \
diff -urN linux-2.6.11/conf.vars linux.sinabox/conf.vars
--- linux-2.6.11/conf.vars 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/conf.vars 2005-03-27 04:28:13.000000000 +0200
@@ -0,0 +1,9 @@
+VERSION = 2
+PATCHLEVEL = 6
+SUBLEVEL = 11
+EXTRAVERSION = .5
+KPKG_SELECTED_MODULES =
+Debian Revision = 10.00.Custom
+KPKG_ARCH =
+do_parallel =
+fast_dep =
diff -urN linux-2.6.11/debian/buildinfo linux.sinabox/debian/buildinfo
--- linux-2.6.11/debian/buildinfo 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/debian/buildinfo 2005-03-24 19:40:43.000000000 +0100
@@ -0,0 +1,21 @@
+gcc-3.3.5-1
+gcc-2.95-2.95.4-22
+gcc-3.0-base-3.0.4-16
+gcc-3.2-3.2.3-9
+gcc-3.2-base-3.2.3-9
+gcc-3.3-3.3.5-12
+gcc-3.3-base-3.3.5-12
+gcc-3.4-base-3.4.3-12
+perl-5.8.4-8
+dpkg-1.10.27
+libc6-2.3.2.ds1-20
+libc6-dev-2.3.2.ds1-20
+binutils-2.15-5
+ldso-1.9.11-15
+make-3.80-9
+dpkg-dev-1.10.27
+this was built on a machine with the kernel:
+Linux marwin 2.6.11-rc4n #1 SMP Tue Feb 15 13:50:10 CET 2005 i686 GNU/Linux
+using the compiler:
+gcc version 3.3.5 (Debian 1:3.3.5-12)
+applied kernel patches:
diff -urN linux-2.6.11/debian/changelog linux.sinabox/debian/changelog
--- linux-2.6.11/debian/changelog 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/debian/changelog 2005-03-24 19:30:47.000000000 +0100
@@ -0,0 +1,451 @@
+kernel-source-2.6.11.5 (10.00.Custom) unstable; urgency=low
+
+ * Added support for netwinders
+ * Modified modules support to not assume everything in /usr/src/modules
+ is a directory.
+
+ -- Manoj Srivastava <srivasta@debian.org> Wed, 25 Nov 1998 01:39:43 -0600
+
+kernel-source-0.34 (1.01) unstable; urgency=low
+
+ * This is a major change in the source/header packages. In architectures
+ different from i386, `kernel-headers-*' and `kernel-source-*' are
+ incompatible. This also has an effect on libc6-dev, which depends on
+ kernel-headers-2.0.3x | kernel-source-2.0.3x, which is only true on
+ i386 architectures. One possible solution would be to make libc6-dev
+ depend on kernel-headers-2.0.32, but that won't work because
+ kernel-source provides kernel-headers. In fact, since kernel-headers
+ are arch dependent, but kernel-source is arch: all, kernel-source-*
+ should not provide kernel-header* at all.
+
+ Once kernel source stops providing kernel-header*, and libc6-dev
+ depends on kernel-headers-2.0.32 and links /usr/include/{linux,asm} to
+ /usr/src/kernel-headers-2.0.32 (nor /usr/src/linux-2.0.32) things
+ would work again in a Multi arch compatible fashion.
+
+ Hence, now kernel-source-* packages compiled with this kernel-package
+ shall not provide any sort of kernel-headers. For the sake of
+ backwards compatibility, /usr/src/linux-$version symlinks are still
+ being provided (as people may upload newer kernels while keeping an
+ older libc6-dev around, which depends on /usr/src/linux-2.0.32.
+
+ However, I have been badgered enough about this that I shall remove
+ the /usr/src/linux-$version symlinks at some point. This version no
+ longer registers stuff in /usr/src/.linux-versions, and is no longer
+ as paranoid about /usr/src/linux; but it does not outright remove
+ those files either, so as not to cause people with older kernels
+ having a problem during removal.As soon as it is deemed permissible,
+ we shall get less paranoid about /usr/src/linux-$version as well.
+ * closes: Bug#18277
+
+ -- Manoj Srivastava <srivasta@debian.org> Wed, 18 Feb 1998 16:44:31 -0600
+
+kernel-source-0.33 (1.01) unstable; urgency=low
+
+ * Added SUBARCH, which is used to distinguish Amiga, Atari, Macintosh,
+ etc. kernels for Debian/m68k, and may well be required for the alpha,
+ from what I hear. Unlike the FLAVOURS variable, which affects
+ everything it can lay its grubby hands on (kernel image, headers,
+ source, doc package versions, and where the modules are looked for
+ under /lib/modules), this only affects the naming of the kernel-image
+ as the source and doc packages are architecture independent and the
+ kernel-headers do not vary from one sub-architecture to the
+ next. These changes are courtesy of James Troup <J.J.Troup@scm.brad.ac.uk>
+
+ -- Manoj Srivastava <srivasta@debian.org> Mon, 16 Feb 1998 16:47:08 -0600
+
+kernel-source-0.32 (1.01) unstable; urgency=low
+
+ * Ensure that the /usr/src/linux and /usr/src/linux-<version> links
+ always exist, no matter what. Apparently, upgrading from
+ kernel-source-2.0.32_2.0.32-1 to kernel-source-2.0.32_2.0.32-3 does
+ not create /usr/src/linux-<version>, which breaks libc6-dev.
+ * Toned down the language about LILO, so as not to startle new sparc users
+
+ -- Manoj Srivastava <srivasta@debian.org> Thu, 12 Feb 1998 21:56:50 -0600
+
+kernel-source-0.31 (1.01) unstable; urgency=low
+
+ * Added ARCH to make called, this allows for cross compiling kernels
+ (added on a request by James Troup <J.J.Troup@scm.brad.ac.uk>)
+ * Make kernel-headers arch: any, so we can indeed have different headers
+ for different architectures.
+ * m68k can now handle vmlinuz, so reverse that behaviour in the rules
+ file. AFAIK m68k still uses zImage.
+ * Improvements to /usr/doc/kernel-patch/MultiArch.gz, based on
+ suggestions by James Troup <J.J.Troup@scm.brad.ac.uk>/
+
+ -- Manoj Srivastava <srivasta@debian.org> Mon, 9 Feb 1998 17:11:05 -0600
+
+kernel-source-0.30 (1.01) unstable; urgency=low
+
+ * Redid the Headers README file
+ * Added a rationale to the LinkPolicy document. So far, it detailed
+ *what* Debian did. Now, it also says *why* we do it.
+
+ -- Manoj Srivastava <srivasta@debian.org> Thu, 29 Jan 1998 19:13:58 -0600
+
+kernel-source-0.29 (1.01) unstable; urgency=low
+
+ * Important changes for kernel-source-* and kernel-header-* packages: now
+ kernel-source-* packages also provide the exact kernel-header-* (libc6
+ need only depend on kernel-header-* now.
+ * The kernel-header-* and kernel-source-* packages now also maitain the
+ /usr/src/linux-X.YY.ZZ links (in addition to the /usr/src/linux links)
+ This is used in the libc6 package.
+
+ -- Manoj Srivastava <srivasta@debian.org> Sat, 13 Dec 1997 12:46:47 -0600
+
+
+kernel-source-0.28 (1.01) unstable; urgency=low
+
+ * Fixed a typo where we tried to dd /vmlinuz-2.0.32 rather than the
+ correct /boot/vmlinuz-2.0.32 in image.postinst. How come this glaring
+ an error has gone unreported until now?
+
+ -- Manoj Srivastava <srivasta@debian.org> Fri, 23 Jan 1998 14:36:34 -0600
+
+kernel-source-0.27 (1.01) unstable; urgency=low
+
+ * Fixed Typo in kernel rules that put all modules into block (this
+ is more of a thinko/cut and paste error. fixes: Bug#16697,Bug#16702
+ * No longer a fatal error if there is no /vmlinuz (or
+ equivalent). fixes: Bug#16899
+ * Added language to the abort on /usr/src/linux not being a
+ link.
+ * Documented the fact that if you re-run make-kpkg with a different
+ revision number, you have to reconfigure the kernel.
+ fixes: Bug#16968
+ * ignore obsolete fdformat in favour of superformat.
+ * Changed the kernel rules file not break on the sound modules of
+ 2.1.70+ kernels (I think it is a bug in the kernel Makefile, but this
+ fix make make-kpkg handle the problem and be more robust).
+ * Modified image.postinst to also cater to people on whose architecture
+ the image is not called vmlinuz but something else (like vmlinux, for
+ example). closes:Bug#16258
+ * Made the postrm's also know about the kernel versrion, not just the
+ postinst. (Sorry). closes:Bug#15920
+ * Changed include.postrm to be more careful about removing the symbolic
+ link /usr/src/linux-X.Y.Z. Keep track if there is another package
+ installed that could provide the link.
+
+ -- Manoj Srivastava <srivasta@debian.org> Wed, 21 Jan 1998 03:27:35 -0600
+
+kernel-source-0.26 (1.01) unstable; urgency=low
+
+ * Added HAM modules to the module we know about, these were introduced
+ in 2.1.70.
+
+ -- Manoj Srivastava <srivasta@debian.org> Tue, 9 Dec 1997 23:27:04 -0600
+
+kernel-source-0.25 (1.01) unstable; urgency=low
+
+ * Ignore unmounted devices while looking for a root file system. Much
+ thanks to Thomas Kocourek <tko@westgac3.dragon.com> for noticing
+ this.
+ * Make sure that the copyright file for the kernel-doc package is not
+ compressed. closes:Bug#14403,Bug#14405
+ * Added internal utility kpkg-vercheck to test the validity of the
+ package version.
+
+ -- Manoj Srivastava <srivasta@debian.org> Mon, 10 Nov 1997 10:37:08 -0600
+
+kernel-source-0.24 (1.01) unstable; urgency=low
+
+ * Install the README.headers in the right place for the source
+ package. closes:Bug#14552.
+ * Handle the new NLS_MODULES that have appeared in the newest 2.1.6x
+ kernels. closes:Bug#14527.
+
+ -- Manoj Srivastava <srivasta@debian.org> Wed, 5 Nov 1997 23:30:48 -0600
+
+kernel-source-0.23 (1.-0) unstable; urgency=low
+
+ * Added README.headers to the kernel-source package as well, since the
+ information _is_ relevant to compiling kernels. Since kernel source
+ packages have higher visibility than kernel header packages, this may
+ help avoid some FAQs from being asked.
+ * Changed image postinst not to use the obsolete -d option to
+ superformat. Removed extra spaces from the exec option, so that it is
+ more likely to work. Noticed by Joost Kooij <kooij@mpn.cp.philips.com>
+ * Note that the proposed two level versioning scheme fails if standard
+ kernels use epochs. Further note that one may introduce epochs even in
+ custom kernels.
+
+ -- Manoj Srivastava <srivasta@debian.org> Thu, 23 Oct 1997 12:19:51 -0500
+
+kernel-source-0.22 (1.01) unstable; urgency=low
+
+ * Handle obsolete /System.map and /System.old links left around by older
+ kernel-package packages. All the programs that look at the information
+ in the map files (including top, ps, and klogd) also will look at
+ /boot/System.map-<version>, we just need to ensure that that file is
+ present, and no longer require the symbolic link.
+ Actually, having the symbolic link in / is technically detrimental
+ (apart from cluttering up /); many programs, though looking in /boot,
+ still allow /System.map to override. If you use LILO to choose between
+ multiple kernels, then the /System.map symbolic link only applies to
+ one such kernel, for all other choices the symbols loaded will be
+ wrong. Not having the symbolic links at all prevents this.
+ Therefore, the new image.postinst file shall offer to remove the
+ symbolic links in /. This should fix BUG#13359
+
+ -- Manoj Srivastava <srivasta@debian.org> Fri, 26 Sep 1997 10:44:39 -0500
+
+kernel-source-0.21 (1.01) unstable; urgency=low
+
+ * Fixed handling of modules.dep in the image.postinst. We do not attempt
+ to recreate a modules.dep, since the man page admits the file so
+ created may be incorrect. We warn the installer that there maybe
+ problems loading modules into the kernel until reboot iff the version
+ being installed is the same as the version currently running.
+
+ -- Manoj Srivastava <srivasta@debian.org> Tue, 16 Sep 1997 15:07:02 -0500
+
+kernel-source-0.20 (1.01) unstable; urgency=low
+
+ * No longer create a System.map symlink in /, since that may confuse
+ klogd when choosing kernel images using LILO. Since top, ps, and klogd
+ look at /boot/System.map-<version>, we just need to make sure that
+ file is present. This makes us friendlier to multiple images of the
+ same kernel version.
+ * No longer redirect output to a file in /tmp for security reasons (we
+ use a log file in /var/log instead). This fixes BUG#11765,
+ BUG#11766 and BUG#11847
+ * Added support for different flavours of the same kernel version for
+ people who need them. This is based on the ideas and work of Bill
+ Mitchell <mitchell@mozcom.com> and Noel Maddy <ncm@biostat.hfh.edu>.
+ This should make us fully compliant to having multiple flavours of the
+ same kernel version.
+ * Added dependencies to targets in rules. Now things should work as
+ expected if one edits a .config file.
+ * Fixed destination for the Buildinfo file. This fixes BUG#11884.
+
+ -- Manoj Srivastava <srivasta@debian.org> Mon, 4 Aug 1997 13:03:51 -0500
+
+kernel-source-0.19 (1.01) unstable; urgency=low
+
+ * All kernel packages produced now list the version of kernel-package
+ used in the file /usr/doc/Buildinfo.
+ * The image prerm will allow you to remove an running kernel image and
+ hose your system. You will be warned. (under protest).
+ * Fixed typo in control file for kernel-doc description. This fixes
+ Bug#11568.
+
+ -- Manoj Srivastava <srivasta@debian.org> Tue, 29 Jul 1997 17:47:41 -0500
+
+kernel-source-0.18 (1.01) unstable; urgency=low
+
+ * No longer carries around an extra uncompressed kernel image, and does
+ not anymore create /boot/psdatabase-X.X.XX. The psdatabase file does
+ not seem to be required anymore.
+
+ -- Manoj Srivastava <srivasta@debian.org> Wed, 18 Jun 1997 13:05:33 -0500
+
+kernel-source-0.17 (1.01) unstable; urgency=low
+
+ * Added patches to support m68k from "Frank Neumann"
+ <Frank.Neumann@Informatik.Uni-Oldenburg.DE>.
+ * Added patched to support sparcs from Eric Delaunay
+ <delaunay@lix.polytechnique.fr>
+
+ -- Manoj Srivastava <srivasta@debian.org> Mon, 2 Jun 1997 15:17:59 -0500
+
+kernel-source-0.16 (1.01) unstable; urgency=low
+
+ * Moved config to /boot, where it arguably should have gone to in the
+ first place. The /boot directory contains other information pertinent
+ to the kernel, such as the System.map file, and the psdatabase. The
+ information about exactly what was configured into the kernel was
+ missing, and it can get quite critical on some machines. Also, the
+ config file may serve as a base for compiling the next kernel. This
+ file is not really a configuration file (not when packaged as part of
+ the kernel-image package), hence it does not belong in /etc (no amout
+ of changing this file will have any affet on system behaviour).
+
+ -- Manoj Srivastava <srivasta@debian.org> Wed, 21 May 1997 01:44:17 -0500
+
+kernel-source-0.15 (1.01) unstable; urgency=low
+
+ * Kernel-image and kernel-doc now suggest each other.
+ * Also recognize powerpc as a synonym for ppc in determining whether
+ we use zImage or bzImage by default.
+ * Fixed up some typos in documentation
+ * Added rules target kernel_doc. This fixes BUG#9138
+ * Also install .config file under /usr/doc. This fixes BUG#9298
+
+ -- Manoj Srivastava <srivasta@debian.org> Fri, 2 May 1997 14:34:51 -0500
+
+kernel-source-0.14 (1.01) unstable; urgency=low
+
+ * No longer install text files in the modules directory, since depmod
+ in modutils-2.1.34 fails when it finds a non-ELF file in modules
+ directory. This fixes Bug#9243.
+
+ -- Manoj Srivastava <srivasta@debian.org> Wed, 30 Apr 1997 15:24:51 -0500
+
+kernel-source-0.13 (1.01) unstable; urgency=low
+
+ * Really add in all the changes sent in by Herbert Xu. The changes are:
+ * Changed to source package name back to kernel-source-2.6.11.5 again.
+ * Changed the installs to be without -o root -g root since it is no
+ longer useful as the chowns are done before the packages are built. It
+ also means that if it is used in targets like stamp-configure which may
+ be run by anyone it won't not generate an error.
+ * Made rules file generate the control file.
+ * Fixed some typos in chown commands while generating the header
+ packages.
+
+ -- Manoj Srivastava <srivasta@debian.org> Mon, 21 Apr 1997 15:12:19 -0500
+
+ kernel-source-0.12 (1.01) unstable; urgency=low
+
+ * Forgot to mention that the source package for the kernel packages
+ (produced by make-kpkg buildpackage, for example) has been changed to
+ not contain the kernel version as part of the name (all the deb files
+ produced have not changed), so we now get kernel-image-xxx_yy_zz.deb,
+ kernel-source-xxx_yy_zz.deb, and kernel-headers-xxx_yy_zz.deb, along
+ with kernel-source.tar.gz and kernel-source_yy.diff.gz
+ * Added changes from the kernel packages maintainer (this is the
+ kernel-packages maintainer speaking, Herbert Xu handles the kernel
+ image, headers, and source packages at the moment).
+
+ -- Manoj Srivastava <srivasta@debian.org> Sun, 13 Apr 1997 00:03:36 -0500
+
+ kernel-source-0.11 (1.01) unstable; urgency=low
+
+ * set umask to copy the kernel source files untainted by package creators
+ umask.
+ * set umask to copy the kernel header files untainted by package creators
+ umask.
+
+ -- Manoj Srivastava <srivasta@debian.org> Tuesday, 1 Apr 1997 11:04:42 -0600
+
+ kernel-source-0.10 (1.01) unstable; urgency=low
+
+ * image postinst no longer aborts when the user gives up on formatting a
+ floppy, but is offered a choice to proceed with a preformatted floppy.
+ * Fixed spelling errors in kernel image postinst
+ * Offer to user superformat if it exists.
+ * Tested boot floppy creation.
+ * Tested on 2.0.29, 2.1.29, and 2.1.30
+ * Mention setfdprm in postinst if fail to format floppy.
+ * Fix a typo in code determining which floppy drive to use
+ * Allow leading whitespace in responses
+
+ -- Manoj Srivastava <srivasta@debian.org> Sun, 23 Mar 1997 22:53:13 -0600
+
+kernel-source-0.9 (1.01) unstable; urgency=low
+
+ n Stupid @#$%$%@! vi changed Feb to February in the changelog messing up
+ gencontrol.
+
+ -- Manoj Srivastava <srivasta@debian.org> Mon, 17 Feb 1997 19:29:02 -0600
+
+kernel-source-0.8 (1.01) unstable; urgency=low
+
+ * Removed extra root checks
+ * Added error messages to failed root check
+
+ -- Manoj Srivastava <srivasta@debian.org> Thursday, 13 February 1997 14:47:06 -0600
+
+kernel-source-0.7 (1.01) unstable; urgency=low
+
+ * Fixed kernel rules file so that one does not depend on the existence of modules
+
+ -- Manoj Srivastava <srivasta@debian.org> Tuesday, 28 January 1997 22:15:27 -0600
+
+kernel-source-0.6 (1.01) unstable; urgency=low
+
+ * changed priority of kernel-source package to optional
+ * changed priority of kernel-image package to optional
+
+ -- Manoj Srivastava <srivasta@debian.org> Fri, 22 Nov 1996 11:02:31 -0600
+
+
+kernel-source-0.5 (1.01) unstable; urgency=low
+
+ * kernel-source-X.XX now no longer recommends bin86, since bin86 is only
+ available intel platforms. It now merely mentions it in the
+ description.
+
+ -- Manoj Srivastava <srivasta@debian.org> Thu, 7 Nov 1996 22:17:47 -0600
+
+kernel-source-0.4 (1.01) unstable; urgency=low
+
+ * kernel-source-X.XX now recommends bin86, which fixes Bug#4443
+ * Added short, succinct (and potentially dangerous) instructions on
+ compiling kernels at the top of the README file. This fixes Bug#4445.
+
+ -- Manoj Srivastava <srivasta@debian.org> Wed, 6 Nov 1996 23:59:47 -0600
+
+kernel-source-0.3 (1.01) unstable; urgency=low
+
+ * Changed everything to new packaging standards.
+ * Major re-organization.
+ * Added explanation for kernel-headers-X.XX (and why we need this
+ package inspite of having headers in libc5-dev)
+ * Added README files for all packages (the old README files became
+ copyright files).
+ * Added target for buildpackage (wich needed a hack in the target clean
+ so as not to remove the ./debian directory prematurely)
+
+ -- Manoj Srivastava <srivasta@debian.org> Tue, 5 Nov 1996 22:42:12 -0600
+
+kernel-source-0.2 (1.01) unstable; urgency=low
+
+ * Made image.postinst more polite.
+ * Also enabled kernel-{source,image,headers} targets in kernel.rules
+ * Changed make-kpkg to also accept the new targets.
+ * Fixed typo in man page.
+ * The man page says it is an administrators man page rather than a
+ programmers man page.
+ * Recommended libc-dev for kernel-source and kernel-package
+ * source suggests ncurses3.0-dev, tk40-dev and the description explains
+ you could use make menuconfig rather than plain old make config if you
+ had these packages.
+ * Fixed typo in the rules for modules in /usr/src/modules/ directory
+ * Made the rules for such modules ignore errors (since they are not
+ really a part of this package, error there should not halt this build
+ (or so people seem to want it)
+ * Look for modules in the kernel config file (or the default config file
+ if the user has not supplied a config file), and only make modules and
+ install them if modules have been configured in the config file. This
+ could be tested better.
+ * Fixed the make-kpkg.8 man page so that it now does not seem to mandate
+ a source and diff file for additional modules installed under the
+ directory /usr/src/modules/ (whether these files are produced is at
+ the discretion of the maintainer of that modules package.
+ * Make configure depend on stamp-configure which in turn depends on
+ .config Hopefully, this will remake the image target if one changes
+ the config file Hopefully, this will not cause the image target to
+ build needlessly.
+
+ -- Manoj Srivastava <srivasta@debian.org>
+
+kernel-source-0.1 (1.01) unstable; urgency=low
+
+ * Changed the scripts to refer to /usr/bin/perl rather than /bin/perl.
+ * Added an extended description to the image control file.
+ * Added a note that the dist target requires a PGP key.
+ * Fixed a typo (missing DEBDIR) in debian.rules.
+ * Fixed the targets expected by make-kpkg (kernel_image rather than
+ kernel-image, etc).
+ * In image.postinst, made arguments to system be a single argument if
+ the arguments contain shell meta-characters, (this way perl passes
+ them to sh -c).
+ * Made make-kpkg accept non floats as revision numbers, to facilitate
+ local names.
+ * Fixed silly bug in makefloppy in image.postinst.
+ * Fixed the extended description of the kernel-package package.
+ * Updated the image postinst to install the mbr, if it exists, and to
+ activate the root partition, and to not overwrite the mbr (oops).
+ * Changed maintainer email address to debian.org (I'll be in a state of
+ flux soon)
+
+
+ -- Manoj Srivastava <srivasta@pilgrim.umass.edu>
+
+Local variables:
+mode: debian-changelog
+End:
diff -urN linux-2.6.11/debian/control linux.sinabox/debian/control
--- linux-2.6.11/debian/control 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/debian/control 2005-03-24 19:30:47.000000000 +0100
@@ -0,0 +1,115 @@
+Source: kernel-source-2.6.11.5
+Section: devel
+Priority: optional
+Maintainer: Unknown Kernel Package Maintainer <unknown@unconfigured.in.etc.kernel-pkg.conf>
+Standards-Version: 3.5.9.0
+
+Package: kernel-headers-2.6.11.5
+Architecture: any
+Section: devel
+Priority: optional
+Provides: kernel-headers, kernel-headers-2.6
+Description: Header files related to Linux kernel version 2.6.11.5
+ This package provides kernel header files for version 2.6.11.5, for sites
+ that want the latest kernel headers. Please read
+ /usr/share/doc/kernel-headers-2.6.11.5/debian.README.gz for details
+
+Package: kernel-source-2.6.11.5
+Architecture: all
+Section: devel
+Priority: optional
+Provides: kernel-source, kernel-source-2.6
+Depends: binutils, bzip2
+Recommends: libc-dev, gcc, make
+Suggests: libncurses-dev | ncurses-dev, kernel-package
+Description: Linux kernel source for version 2.6.11.5
+ This package provides the source code for the Linux kernel version 2.6.11.5.
+ .
+ You may configure the kernel to your setup by typing "make config"
+ and following instructions, but you could get ncursesX.X-dev and try
+ "make menuconfig" for a jazzier, and easier to use interface. There
+ are options to use QT or GNOME based configuration interfaces, but they
+ need additional packages to be installed. Also, please read the detailed
+ documentation in the file
+ /usr/share/doc/kernel-source-2.6.11.5/README.headers.gz.
+ .
+ If you wish to use this package to create a custom Linux kernel, then
+ it is suggested that you investigate the package kernel-package,
+ which has been designed to ease the task of creating kernel image
+ packages.
+
+Package: kernel-image-2.6.11.5
+Architecture: i386
+Section: base
+Priority: optional
+Provides: kernel-image, kernel-image-2.6
+Depends: coreutils | fileutils (>= 4.0)
+Suggests: lilo (>= 19.1) | grub, fdutils, kernel-doc-2.6.11.5 | kernel-source-2.6.11.5
+Description: Linux kernel binary image for version 2.6.11.5.
+ This package contains the Linux kernel image for version 2.6.11.5,
+ the corresponding System.map file, and the modules built by the
+ packager. It also contains scripts that try to ensure that the
+ system is not left in a unbootable state after an update.
+ .
+ If you wish to update a bootdisk, or to use a bootloader to make
+ installing and using the image easier, we suggest you install the latest
+ fdutils (for formatting a floppy to be used as boot disk), and LILO, for a
+ powerful bootloader. Of course, both these are optional.
+ .
+ Kernel image packages are generally produced using kernel-package,
+ and it is suggested that you install that package if you wish to
+ create a custom kernel from the sources. Please look at kernel-img.conf(5),
+ and /usr/share/doc/kernel-package/README.gz from the package kernel-package
+ for details on how to tailor the installation of this or any other kernel
+ image package
+
+Package: kernel-doc-2.6.11.5
+Architecture: all
+Section: doc
+Priority: optional
+Provides: kernel-doc-2.6
+Suggests: kernel-image-2.6.11.5
+Description: Linux kernel specific documentation for version 2.6.11.5.
+ This package provides various Readme's in the 2.6.11.5 kernel
+ Documentation/ subdirectory: these typically contain kernel-specific
+ installation notes for some drivers. for example. Please see
+ /usr/share/doc/kernel-doc-X.X.XX/Documentation/00-INDEX for a list of
+ contents. Please also read the Changes file, as it contains
+ information about the problems which may result by upgrading your
+ kernel.
+
+Package: kernel-uml-2.6.11.5
+Architecture: i386
+Section: base
+Priority: optional
+Provides: kernel-uml, kernel-uml-2.6, user-mode-linux
+Depends: coreutils | fileutils (>= 4.0)
+Suggests: lilo (>= 19.1) | grub, fdutils, kernel-doc-2.6.11.5 | kernel-source-2.6.11.5, uml-utilities
+Conflicts: user-mode-linux (>= 2.0)
+Replaces: user-mode-linux
+Description: Linux uml kernel binary image for version 2.6.11.5.
+ This package contains the Linux uml kernel image for version 2.6.11.5
+ and the modules built by the packager.
+
+Package: kernel-xen0-2.6.11.5
+Architecture: i386
+Section: base
+Priority: optional
+Provides: kernel-xen0, kernel-xen0-2.6
+Depends: coreutils | fileutils (>= 4.0)
+Suggests: lilo (>= 19.1) | grub, fdutils, kernel-doc-2.6.11.5 | kernel-source-2.6.11.5
+Description: Linux xen kernel binary image for version 2.6.11.5.
+ This package contains the Linux xen kernel image for version 2.6.11.5
+ and the modules built by the packager.
+
+Package: kernel-xenu-2.6.11.5
+Architecture: i386
+Section: base
+Priority: optional
+Provides: kernel-xenu, kernel-xenu-2.6
+Depends: coreutils | fileutils (>= 4.0)
+Suggests: lilo (>= 19.1) | grub, fdutils, kernel-doc-2.6.11.5 | kernel-source-2.6.11.5
+Description: Linux xen kernel binary image for version 2.6.11.5.
+ This package contains the Linux xen kernel image for version 2.6.11.5
+ and the modules built by the packager.
+
diff -urN linux-2.6.11/debian/files linux.sinabox/debian/files
--- linux-2.6.11/debian/files 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/debian/files 2005-03-27 04:28:23.000000000 +0200
@@ -0,0 +1 @@
+kernel-image-2.6.11.5_10.00.Custom_i386.deb base optional
diff -urN linux-2.6.11/debian/rules linux.sinabox/debian/rules
--- linux-2.6.11/debian/rules 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/debian/rules 2005-03-20 07:41:15.000000000 +0100
@@ -0,0 +1,2596 @@
+#! /usr/bin/make -f
+############################ -*- Mode: Makefile -*- ###########################
+## debian.rules ---
+## Author : Manoj Srivastava ( srivasta@pilgrim.umass.edu )
+## Created On : Sat Apr 27 06:36:31 1996
+## Created On Node : melkor.pilgrim.umass.edu
+## Last Modified By : Manoj Srivastava
+## Last Modified On : Sat Mar 19 23:09:13 2005
+## Last Machine Used: glaurung.internal.golden-gryphon.com
+## Update Count : 776
+## Status : Unknown, Use with caution!
+## HISTORY :
+## Description :
+## arch-tag: aa70d4e5-79bf-405c-95ec-5fa9f7ae7b69
+###############################################################################
+
+DPKG_ARCH := dpkg-architecture
+
+ifeq ($(strip $(KPKG_ARCH)),um)
+ MAKING_VIRTUAL_IMAGE:=YES
+endif
+ifeq ($(strip $(KPKG_ARCH)),xen)
+ MAKING_VIRTUAL_IMAGE:=YES
+endif
+
+ifdef KPKG_ARCH
+ ifeq ($(strip $(MAKING_VIRTUAL_IMAGE)),)
+ ha:=-a$(KPKG_ARCH)
+ endif
+endif
+
+# set the dpkg-architecture vars
+export DEB_BUILD_ARCH := $(shell $(DPKG_ARCH) $(ha) -qDEB_BUILD_ARCH)
+export DEB_BUILD_GNU_CPU := $(shell $(DPKG_ARCH) $(ha) -qDEB_BUILD_GNU_CPU)
+export DEB_BUILD_GNU_TYPE := $(shell $(DPKG_ARCH) $(ha) -qDEB_BUILD_GNU_TYPE)
+export DEB_HOST_ARCH := $(shell $(DPKG_ARCH) $(ha) -qDEB_HOST_ARCH)
+export DEB_HOST_GNU_CPU := $(shell $(DPKG_ARCH) $(ha) -qDEB_HOST_GNU_CPU)
+export DEB_HOST_GNU_SYSTEM := $(shell $(DPKG_ARCH) $(ha) -qDEB_HOST_GNU_SYSTEM)
+export DEB_HOST_GNU_TYPE := $(shell $(DPKG_ARCH) $(ha) -qDEB_HOST_GNU_TYPE)
+export DEB_BUILD_GNU_SYSTEM:= $(shell $(DPKG_ARCH) $(ha) -qDEB_BUILD_GNU_SYSTEM)
+
+#
+# VERSION=$(shell LC_ALL=C dpkg-parsechangelog | grep ^Version: | \
+# sed 's/^Version: *//')
+#
+
+# The version of kernel-package this belongs to
+kpkg_version := 8.129
+
+# The maintainer information.
+maintainer = Debian Kernel Team
+email= debian-kernel@lists.debian.org
+
+pgp=$(maintainer)
+
+# Where we read our config information from
+CONFLOC :=$(shell if test -f ~/.kernel-pkg.conf; then\
+ echo ~/.kernel-pkg.conf; \
+ else \
+ echo /etc/kernel-pkg.conf; \
+ fi)
+# Where the package libs are stored
+LIBLOC :=/usr/share/kernel-package
+# Default location of the modules
+ifeq ($(strip $(MODULE_LOC)),)
+MODULE_LOC =/usr/src/modules
+endif
+#
+DEBDIR = $(LIBLOC)
+DEBDIR_NAME = $(shell basename $(DEBDIR))
+
+DEBIAN_FILES = kernel_version.mk config kpkg-vercheck Control Control.bin86 rules \
+ README README.grub README.headers README.tecra README.modules \
+ sample.module.control Flavours Rationale copyright.source \
+ README.Debian src.postinst README.source include.postinst \
+ copyright.headers README.headers README.doc copyright.doc \
+ src.postinst image.postinst image.postrm image.preinst image.prerm \
+ xen.postinst xen.prerm um.postinst um.prerm linux.1 $(loaderdoc) \
+ README.image copyright.image
+DEBIAN_DIRS = Config
+
+# Package specific stuff
+# decide if image is meant to be in /boot rather than /
+link_in_boot :=
+# Can we use symlinks?
+no_symlink :=
+# If so, where is the real file (usually, vmlinuz-X.X.X is real, and
+# vmlinuz is the link, this variable reverses it.
+reverse_symlink :=
+
+# The version numbers for kernel-image, kernel-headers and
+# kernel-source are deduced from the Makefile (see below,
+# and footnote 1 for details)
+
+# Whether to look for and install kernel patches by default.
+# Be very careful if you do this.
+patch_the_kernel := AUTO
+
+# do not create libc headers by default
+make_libc_headers := NO
+
+# run make clean after build
+do_clean := NO
+
+# install uncompressed kernel ELF-image (for oprofile)
+int_install_vmlinux := NO
+
+# what kernel config target to run in our configure target.
+config_target := oldconfig
+
+
+# The default architecture (all if architecture independent)
+CROSS_ARG:=
+
+ifdef KPKG_ARCH
+ architecture:=$(KPKG_ARCH)
+else
+ #architecture:=$(shell CC=$(HOSTCC) dpkg --print-gnu-build-architecture)
+ architecture:=$(DEB_HOST_ARCH)
+endif
+
+ifndef CROSS_COMPILE
+ ifeq ($(strip $(MAKING_VIRTUAL_IMAGE)),)
+ ifneq ($(strip $(architecture)),$(strip $(DEB_BUILD_ARCH)))
+ KERNEL_CROSS:=$(architecture)-$(strip $(DEB_HOST_GNU_SYSTEM))-
+ endif
+ endif
+else
+ KERNEL_CROSS:=$(CROSS_COMPILE)-
+endif
+
+KERNEL_CROSS:=$(shell echo $(KERNEL_CROSS) | sed -e 's,--$$,-,')
+
+ifneq ($(strip $(KERNEL_CROSS)),)
+ CROSS_ARG:=CROSS_COMPILE=$(KERNEL_CROSS)
+endif
+
+KERNEL_ARCH:=$(architecture)
+DEBCONFIG = $(CONFDIR)/config
+IMAGEDIR=/boot
+INT_IMAGE_DESTDIR=debian/tmp-image$(IMAGEDIR)
+
+
+
+comma:= ,
+empty:=
+space:= $(empty) $(empty)
+
+# Install rules
+install_file= install -p -o root -g root -m 644
+install_program= install -p -o root -g root -m 755
+make_directory= install -p -d -o root -g root -m 755
+deb_rule = $(MAKE) -f $(DEBDIR)/rules
+
+
+# localversion_files := $(wildcard localversion*)
+# VERSION =$(shell grep -E '^VERSION +=' Makefile 2>/dev/null | \
+# sed -e 's/[^0-9]*\([0-9]*\)/\1/')
+# PATCHLEVEL =$(shell grep -E '^PATCHLEVEL +=' Makefile 2>/dev/null | \
+# sed -e 's/[^0-9]*\([0-9]*\)/\1/')
+# SUBLEVEL =$(shell grep -E '^SUBLEVEL +=' Makefile 2>/dev/null | \
+# sed -e 's/[^0-9]*\([0-9]*\)/\1/')
+# EXTRA_VERSION =$(shell grep -E '^EXTRAVERSION +=' Makefile 2>/dev/null | \
+# sed -e 's/EXTRAVERSION *= *\([^ \t]*\)/\1/')
+# LOCALVERSION = $(subst $(space),, $(shell cat /dev/null $(localversion_files)) \
+# $(CONFIG_LOCALVERSION))
+
+# Could have used :=, but some patches do seem to patch the
+# Makefile. perhaps deferring the rule makes that better
+VERSION :=$(shell $(MAKE) $(CROSS_ARG) --no-print-directory -sf $(DEBDIR)/kernel_version.mk debian_VERSION)
+PATCHLEVEL :=$(shell $(MAKE) $(CROSS_ARG) --no-print-directory -sf $(DEBDIR)/kernel_version.mk debian_PATCHLEVEL)
+SUBLEVEL :=$(shell $(MAKE) $(CROSS_ARG) --no-print-directory -sf $(DEBDIR)/kernel_version.mk debian_SUBLEVEL)
+EXTRA_VERSION:=$(shell $(MAKE) $(CROSS_ARG) --no-print-directory -sf $(DEBDIR)/kernel_version.mk debian_EXTRAVERSION)
+LOCALVERSION :=$(shell $(MAKE) $(CROSS_ARG) --no-print-directory -sf $(DEBDIR)/kernel_version.mk debian_LOCALVERSION)
+
+
+
+HAVE_NEW_MODLIB =$(shell grep -E '\(INSTALL_MOD_PATH\)' Makefile 2>/dev/null )
+
+ifneq ($(strip $(EXTRA_VERSION)),)
+HAS_ILLEGAL_EXTRA_VERSION =$(shell \
+ perl -e '$$i="$(EXTRA_VERSION)"; $$i !~ m/^[a-z\.\-\+][a-z\d\.\-\+]*$$/o && print YES;')
+ ifneq ($(strip $(HAS_ILLEGAL_EXTRA_VERSION)),)
+ $(error Error: The EXTRAVERSION may only contain lowercase alphanumerics \
+ and the characters - + . The current value is: $(EXTRA_VERSION). Aborting.)
+ endif
+endif
+
+AM_OFFICIAL := $(shell if [ -f debian/official ]; then echo YES; fi )
+
+######################################################################
+### Architecture specific stuff ###
+######################################################################
+# Each architecture has the following specified for it
+# (a) The kernel image type (i.e. zImage or bzImage)
+# (b) The dependency on a loader, if any
+# (c) The name of the loader
+# (d) The name of the documentation file for the loader
+# (e) The build target
+# (f) The location of the kernelimage source
+# (g) The location of the kernelimage destination
+# (h) The name of the arch specific configuration file
+# Some architectures has sub architectures
+
+### m68k
+ifeq ($(strip $(architecture)),m68k)
+ ifeq (,$(findstring /$(KPKG_SUBARCH)/,/amiga/atari/mac/mvme147/mvme16x/bvme6000/))
+ GUESS_SUBARCH:=$(shell awk '/Model/ { print $$2}' /proc/hardware)
+ ifneq (,$(findstring Motorola,$(GUESS_SUBARCH)))
+ GUESS_SUBARCH:=$(shell awk '/Model/ { print $$3}' /proc/hardware)
+ ifneq (,$(findstring MVME147,$(GUESS_SUBARCH)))
+ KPKG_SUBARCH:=mvme147
+ else
+ KPKG_SUBARCH:=mvme16x
+ endif
+ else
+ ifneq (,$(findstring BVME,$(GUESS_SUBARCH)))
+ KPKG_SUBARCH:=bvme6000
+ else
+ ifneq (,$(findstring Amiga,$(GUESS_SUBARCH)))
+ KPKG_SUBARCH:=amiga
+ else
+ ifneq (,$(findstring Atari,$(GUESS_SUBARCH)))
+ KPKG_SUBARCH:=atari
+ else
+ ifneq (,$(findstring Mac,$(GUESS_SUBARCH)))
+ KPKG_SUBARCH:=mac
+ endif
+ endif
+ endif
+ endif
+ endif
+ endif
+ NEED_DIRECT_GZIP_IMAGE=NO
+ kimage := zImage
+ target = $(kimage)
+ kimagesrc = vmlinux.gz
+ kimagedest = $(INT_IMAGE_DESTDIR)/vmlinuz-$(version)
+ kelfimagesrc = vmlinux
+ kelfimagedest = $(INT_IMAGE_DESTDIR)/vmlinux-$(version)
+ DEBCONFIG = $(CONFDIR)/config.$(KPKG_SUBARCH)
+ ifneq (,$(findstring $(KPKG_SUBARCH),mvme147 mvme16x bvme6000))
+ loaderdep=vmelilo
+ loader=vmelilo
+ loaderdoc=VmeliloDefault
+ else
+ loaderdep=
+ loader=lilo
+ loaderdoc=
+ endif
+endif
+
+### ARM
+ifeq ($(strip $(architecture)),arm)
+ GUESS_SUBARCH:='netwinder'
+
+ ifneq (,$(findstring $(KPKG_SUBARCH),netwinder))
+ KPKG_SUBARCH:=$(GUESS_SUBARCH)
+ kimage := zImage
+ target = Image
+ kimagesrc = arch/$(KERNEL_ARCH)/boot/Image
+ kimagedest = $(INT_IMAGE_DESTDIR)/vmlinuz-$(version)
+ loaderdep=
+ loader=nettrom
+ loaderdoc=
+ NEED_DIRECT_GZIP_IMAGE=NO
+ DEBCONFIG= $(CONFDIR)/config.netwinder
+ else
+ kimage := zImage
+ target = zImage
+ NEED_DIRECT_GZIP_IMAGE=NO
+ kimagesrc = arch/$(KERNEL_ARCH)/boot/zImage
+ kimagedest = $(INT_IMAGE_DESTDIR)/vmlinuz-$(version)
+ DEBCONFIG = $(CONFDIR)/config.arm
+ endif
+ kelfimagesrc = vmlinux
+ kelfimagedest = $(INT_IMAGE_DESTDIR)/vmlinux-$(version)
+endif
+
+##### PowerPC64
+ifeq ($(strip $(architecture)), powerpc64)
+ KERNEL_ARCH=ppc64
+ kimage := vmlinux
+ loader=NoLoader
+ target = $(kimage)
+ kimagesrc = vmlinux
+ kimagedest = $(INT_IMAGE_DESTDIR)/vmlinux-$(version)
+ DEBCONFIG= $(CONFDIR)/config.$(KPKG_SUBARCH)
+ kelfimagesrc = vmlinux
+ kelfimagedest = $(INT_IMAGE_DESTDIR)/vmlinux-$(version)
+endif
+
+### PowerPC
+ifneq ($(strip $(filter ppc powerpc,$(architecture))),)
+ ifeq ($(DEB_BUILD_ARCH),powerpc)
+ # This is only meaningful when building on a PowerPC
+ ifeq ($(GUESS_SUBARCH),)
+ GUESS_SUBARCH:=$(shell awk '/machine/ { print $$3}' /proc/cpuinfo)
+ ifneq (,$(findstring Power,$(GUESS_SUBARCH)))
+ GUESS_SUBARCH:=pmac
+ else
+ # At the request of Colin Watson, changed from find string iMac.
+ # Any powerpc system that would contain Mac in /proc/cpuinfo is a
+ # PowerMac system, according to arch/ppc/platforms/* in the kernel source
+ ifneq (,$(findstring Mac,$(GUESS_SUBARCH)))
+ GUESS_SUBARCH:=pmac
+ endif
+ endif
+ else
+ GUESS_SUBARCH:=pmac
+ endif
+ # Well NuBus powermacs are not pmac subarchs, but nubus ones.
+ #ifeq (,$(shell grep NuBus /proc/cpuinfo))
+ # GUESS_SUBARCH:=nubus
+ #endif
+ endif
+
+ ifeq (,$(findstring $(KPKG_SUBARCH),apus prpmc chrp mbx pmac prep Amiga APUs CHRP MBX PReP chrp-rs6k nubus ))
+ KPKG_SUBARCH:=$(GUESS_SUBARCH)
+ endif
+
+ KERNEL_ARCH:=ppc
+
+ ifneq (,$(findstring $(KPKG_SUBARCH),APUs apus Amiga))
+ KPKG_SUBARCH:=apus
+ loader := NoLoader
+ kimage := vmapus.gz
+ target = zImage
+ kimagesrc = $(shell if [ -d arch/$(KERNEL_ARCH)/boot/images ]; then \
+ echo arch/$(KERNEL_ARCH)/boot/images/vmapus.gz ; else \
+ echo arch/$(KERNEL_ARCH)/boot/$(kimage) ; fi)
+ kimagedest = $(INT_IMAGE_DESTDIR)/vmlinuz-$(version)
+ kelfimagesrc = vmlinux
+ kelfimagedest = $(INT_IMAGE_DESTDIR)/vmlinux-$(version)
+ DEBCONFIG = $(CONFDIR)/config.apus
+ endif
+
+ ifneq (,$(findstring $(KPKG_SUBARCH),chrp-rs6k))
+ KPKG_SUBARCH:=chrp-rs6k
+ loaderdep=quik
+ loader=quik
+ loaderdoc=QuikDefault
+ kimage := zImage
+ target = $(kimage)
+ kimagesrc = $(shell if [ -d arch/$(KERNEL_ARCH)/chrpboot ]; then \
+ echo arch/$(KERNEL_ARCH)/chrpboot/$(kimage) ; else \
+ echo arch/$(KERNEL_ARCH)/boot/images/$(kimage).chrp-rs6k ; fi)
+ kimagedest = $(INT_IMAGE_DESTDIR)/vmlinuz-$(version)
+ kelfimagesrc = vmlinux
+ kelfimagedest = $(INT_IMAGE_DESTDIR)/vmlinux-$(version)
+ DEBCONFIG = $(CONFDIR)/config.chrp
+ endif
+
+ ifneq (,$(findstring $(KPKG_SUBARCH),CHRP chrp))
+ KPKG_SUBARCH:=chrp
+ loaderdep=quik
+ loader=quik
+ loaderdoc=QuikDefault
+ kimage := zImage
+ target = $(kimage)
+ kimagesrc = $(shell if [ -d arch/$(KERNEL_ARCH)/chrpboot ]; then \
+ echo arch/$(KERNEL_ARCH)/chrpboot/$(kimage) ; else \
+ echo arch/$(KERNEL_ARCH)/boot/images/$(kimage).chrp ; fi)
+ kimagedest = $(INT_IMAGE_DESTDIR)/vmlinuz-$(version)
+ kelfimagesrc = vmlinux
+ kelfimagedest = $(INT_IMAGE_DESTDIR)/vmlinux-$(version)
+ DEBCONFIG = $(CONFDIR)/config.chrp
+ endif
+
+ ifneq (,$(findstring $(KPKG_SUBARCH),PRPMC prpmc))
+ KPKG_SUBARCH:=prpmc
+ loader := NoLoader
+ kimage := zImage
+ target = $(kimage)
+ kimagesrc = arch/$(KERNEL_ARCH)/boot/images/zImage.pplus
+ kimagedest = $(INT_IMAGE_DESTDIR)/vmlinuz-$(version)
+ kelfimagesrc = vmlinux
+ kelfimagedest = $(INT_IMAGE_DESTDIR)/vmlinux-$(version)
+ endif
+
+ ifneq (,$(findstring $(KPKG_SUBARCH),MBX mbx))
+ KPKG_SUBARCH:=mbx
+ loader := NoLoader
+ kimage := zImage
+ target = $(kimage)
+ kimagesrc = $(shell if [ -d arch/$(KERNEL_ARCH)/mbxboot ]; then \
+ echo arch/$(KERNEL_ARCH)/mbxboot/$(kimage) ; else \
+ echo arch/$(KERNEL_ARCH)/boot/images/zvmlinux.embedded; fi)
+ kimagedest = $(INT_IMAGE_DESTDIR)/vmlinuz-$(version)
+ kelfimagesrc = vmlinux
+ kelfimagedest = $(INT_IMAGE_DESTDIR)/vmlinux-$(version)
+ DEBCONFIG = $(CONFDIR)/config.mbx
+ endif
+
+ ifneq (,$(findstring $(KPKG_SUBARCH),pmac))
+ KPKG_SUBARCH:=pmac
+ target := zImage
+ ifeq ($(DEB_BUILD_ARCH),powerpc)
+ # This is only meaningful when building on a PowerPC
+ ifneq (,$(shell grep NewWorld /proc/cpuinfo))
+ loaderdep=yaboot
+ loader=yaboot
+ #loaderdoc=
+ else
+ loaderdep=quik
+ loader=quik
+ loaderdoc=QuikDefault
+ endif
+ else
+ loaderdep=yaboot
+ loader=yaboot
+ endif
+ kimagesrc = vmlinux
+ kimage := vmlinux
+ kimagedest = $(INT_IMAGE_DESTDIR)/vmlinux-$(version)
+ HAVE_COFF_IMAGE = YES
+ coffsrc = $(shell if [ -d arch/$(KERNEL_ARCH)/coffboot ]; then \
+ echo arch/$(KERNEL_ARCH)/coffboot/$(kimage).coff ; else \
+ echo arch/$(KERNEL_ARCH)/boot/images/$(kimage).coff ; fi)
+ coffdest=$(INT_IMAGE_DESTDIR)/vmlinux.coff-$(version)
+ DEBCONFIG = $(CONFDIR)/config.pmac
+ endif
+
+ ifneq (,$(findstring $(KPKG_SUBARCH),PReP prep))
+ KPKG_SUBARCH:=prep
+ loader := NoLoader
+ kimage := zImage
+ target = $(kimage)
+ kimagesrc = $(shell if [ -d arch/$(KERNEL_ARCH)/boot/images ]; then \
+ echo arch/$(KERNEL_ARCH)/boot/images/$(kimage).prep ; else \
+ echo arch/$(KERNEL_ARCH)/boot/$(kimage) ; fi)
+ kimagedest = $(INT_IMAGE_DESTDIR)/vmlinuz-$(version)
+ kelfimagesrc = vmlinux
+ kelfimagedest = $(INT_IMAGE_DESTDIR)/vmlinux-$(version)
+ DEBCONFIG = $(CONFDIR)/config.prep
+ endif
+
+ ifneq (,$(findstring $(KPKG_SUBARCH), NuBuS nubus))
+ KPKG_SUBARCH := nubus
+ target := zImage
+ loader= NoLoader
+ kimagesrc = arch/$(KERNEL_ARCH)/appleboot/Mach\ Kernel
+ kimage := vmlinux
+ kimagedest = $(INT_IMAGE_DESTDIR)/vmlinuz-$(version)
+ endif
+
+endif
+
+
+##### Alpha
+ifeq ($(strip $(architecture)),alpha)
+ kimage := vmlinuz
+ loaderdep=
+ loader=milo
+ loaderdoc=
+ target = boot
+ kimagesrc = arch/$(KERNEL_ARCH)/boot/vmlinux.gz
+ kimagedest = $(INT_IMAGE_DESTDIR)/vmlinuz-$(version)
+ kelfimagesrc = vmlinux
+ kelfimagedest = $(INT_IMAGE_DESTDIR)/vmlinux-$(version)
+ DEBCONFIG = $(CONFDIR)/config.alpha
+endif
+
+
+##### Sparc
+ifeq ($(strip $(architecture)),sparc)
+ kimage := vmlinuz
+ loaderdep = silo
+ loader = silo
+ loaderdoc=SiloDefault
+ NEED_DIRECT_GZIP_IMAGE = YES
+ kimagedest = $(INT_IMAGE_DESTDIR)/vmlinuz-$(version)
+ DEBCONFIG = $(CONFDIR)/config.sparc
+ ifeq (,$(APPEND_TO_VERSION))
+ ARCH_IN_NAME = YES
+ endif
+
+ ifeq (,$(KPKG_SUBARCH))
+ ifeq (sparc64,$(strip $(shell uname -m)))
+ KPKG_SUBARCH = sparc64
+ else
+ KPKG_SUBARCH = sparc32
+ endif
+ endif
+
+ ifneq (,$(filter sparc64%,$(KPKG_SUBARCH)))
+ KERNEL_ARCH = sparc64
+ else
+ ifneq (,$(filter sparc%,$(KPKG_SUBARCH)))
+ KERNEL_ARCH = sparc
+ else
+ KERNEL_ARCH = $(strip $(shell uname -m))
+ endif
+ endif
+
+ ifneq ($(shell if [ $(VERSION) -ge 2 ] && [ $(PATCHLEVEL) -ge 5 ] && \
+ [ $(SUBLEVEL) -ge 41 ]; then echo new; \
+ elif [ $(VERSION) -ge 2 ] && [ $(PATCHLEVEL) -ge 6 ]; then \
+ echo new; \
+ elif [ $(VERSION) -ge 3 ]; then echo new; fi),)
+ target = image
+ kimagesrc = arch/$(KERNEL_ARCH)/boot/image
+ kelfimagesrc = vmlinux
+ kelfimagedest = $(INT_IMAGE_DESTDIR)/vmlinux-$(version)
+ else
+ target = vmlinux
+ kimagesrc = vmlinux
+ endif
+endif
+
+##### amd64
+ifeq ($(strip $(architecture)),amd64)
+ KERNEL_ARCH=x86_64
+ kimage := bzImage
+ loaderdep=lilo (>= 19.1) | grub
+ loader=lilo
+ loaderdoc=LiloDefault
+ target = $(kimage)
+ kimagesrc = $(strip arch/$(KERNEL_ARCH)/boot/$(kimage))
+ kimagedest = $(INT_IMAGE_DESTDIR)/vmlinuz-$(version)
+ DEBCONFIG= $(CONFDIR)/config.$(KPKG_SUBARCH)
+ kelfimagesrc = vmlinux
+ kelfimagedest = $(INT_IMAGE_DESTDIR)/vmlinux-$(version)
+endif
+
+
+##### i386 and such
+ifeq ($(strip $(architecture)),i386)
+ # sub archs can be i386 i486 i586 i686
+ GUESS_SUBARCH:=$(shell if test -f .config; then \
+ perl -nle '/^CONFIG_M(.86)=y/ && print "$$1"' .config;\
+ else \
+ uname -m;\
+ fi)
+ ifeq (,$(findstring $(KPKG_SUBARCH),i386 i486 i586 i686))
+ KPKG_SUBARCH:=$(GUESS_SUBARCH)
+ endif
+ kimage := bzImage
+ loaderdep=lilo (>= 19.1) | grub
+ loader=lilo
+ loaderdoc=LiloDefault
+ target = $(kimage)
+ kimagesrc = $(strip arch/$(KERNEL_ARCH)/boot/$(kimage))
+ kimagedest = $(INT_IMAGE_DESTDIR)/vmlinuz-$(version)
+ DEBCONFIG= $(CONFDIR)/config.$(KPKG_SUBARCH)
+ kelfimagesrc = vmlinux
+ kelfimagedest = $(INT_IMAGE_DESTDIR)/vmlinux-$(version)
+endif
+
+##### S/390
+ifeq ($(strip $(architecture)),s390)
+ # make it possible to build s390x kernels on s390 for 2.4 kernels only
+ # because 2.6 always use s390 as architecture.
+ ifeq (4,$(PATCHLEVEL))
+ ifeq (,$(findstring $(KPKG_SUBARCH),s390 s390x))
+ KPKG_SUBARCH = s390
+ endif
+ KERNEL_ARCH = $(KPKG_SUBARCH)
+ ifneq ($(shell uname -m),$(KPKG_SUBARCH))
+ UNAME_MACHINE = $(KPKG_SUBARCH)
+ export UNAME_MACHINE
+ endif
+ endif
+ kimage := zimage
+ loaderdep=zipl
+ loader=zipl
+ loaderdoc=
+ target = image
+ NEED_DIRECT_GZIP_IMAGE=NO
+ kimagesrc = $(strip arch/$(KERNEL_ARCH)/boot/$(target))
+ kimagedest = $(INT_IMAGE_DESTDIR)/vmlinuz-$(version)
+ DEBCONFIG= $(CONFDIR)/config.$(KPKG_SUBARCH)
+ kelfimagesrc = vmlinux
+ kelfimagedest = $(INT_IMAGE_DESTDIR)/vmlinux-$(version)
+endif
+
+##### hppa
+ifeq ($(strip $(architecture)),hppa)
+ kimage := vmlinux
+ loaderdep=palo
+ loader=palo
+ loaderdoc=
+ target=$(kimage)
+ NEED_DIRECT_GZIP_IMAGE=NO
+ # Override arch name because hppa uses arch/parisc not arch/hppa
+ KERNEL_ARCH := parisc
+ kimagesrc=$(kimage)
+ kimagedest=$(INT_IMAGE_DESTDIR)/vmlinux-$(version)
+ # This doesn't seem to work, but the other archs do it...
+ DEBCONFIG=$(CONFDIR)/config.$(KPKG_SUBARCH)
+endif
+
+##### ia64
+ifeq ($(strip $(architecture)),ia64)
+ kimage := vmlinuz
+ loaderdep=elilo
+ loader=elilo
+ loaderdoc=
+ target=compressed
+ NEED_DIRECT_GZIP_IMAGE=NO
+ kimagesrc=vmlinux.gz
+ kimagedest=$(INT_IMAGE_DESTDIR)/vmlinuz-$(version)
+ kelfimagesrc = vmlinux
+ kelfimagedest = $(INT_IMAGE_DESTDIR)/vmlinux-$(version)
+ DEBCONFIG=$(CONFDIR)/config.$(KPKG_SUBARCH)
+endif
+
+##### mips
+ifeq ($(strip $(architecture)),mips)
+ # SGI ELF32
+ ifneq (,$(filter r4k-ip22 r5k-ip22 r5k-ip32 r10k-ip32,$(strip $(KPKG_SUBARCH))))
+ kimage := vmlinux
+ loaderdep = arcboot
+ loader = arcboot
+ loaderdoc =
+ endif
+ # SGI ELF64
+ ifneq (,$(filter r10k-ip27 r10k-ip28 r10k-ip30,$(strip $(KPKG_SUBARCH))))
+ kimage := vmlinux.64
+ loaderdep = arcboot
+ loader = arcboot
+ loaderdoc =
+ endif
+ # Broadcom SWARM
+ ifneq (,$(filter sb1-swarm-bn,$(strip $(KPKG_SUBARCH))))
+ kimage := vmlinux
+ loaderdep = sibyl
+ loader = sibyl
+ loaderdoc =
+ endif
+
+ # Default value for e.g. a generic header package
+ ifeq (,$(kimage))
+ kimage := vmlinux
+ endif
+ ifeq (,$(kimagesrc))
+ kimagesrc := $(kimage)
+ endif
+
+ NEED_DIRECT_GZIP_IMAGE = NO
+ kimagesrc = $(kimage)
+ kimagedest = $(INT_IMAGE_DESTDIR)/vmlinux-$(version)
+
+ ifneq ($(shell if [ $(VERSION) -ge 2 ] && [ $(PATCHLEVEL) -ge 5 ] && \
+ [ $(SUBLEVEL) -ge 41 ]; then echo new; \
+ elif [ $(VERSION) -ge 2 ] && [ $(PATCHLEVEL) -ge 6 ]; then \
+ echo new; \
+ elif [ $(VERSION) -ge 3 ]; then echo new; fi),)
+ target =
+ else
+ target = boot
+ endif
+
+ ifneq (,$(filter mips64%,$(KPKG_SUBARCH)))
+ KERNEL_ARCH = mips64
+ endif
+ ifneq (,$(filter %-64,$(KPKG_SUBARCH)))
+ KERNEL_ARCH = mips64
+ endif
+endif
+
+##### mipsel
+ifeq ($(strip $(architecture)),mipsel)
+ # DECstations
+ ifneq (,$(filter r3k-kn02 r4k-kn04,$(strip $(KPKG_SUBARCH))))
+ kimage := vmlinux
+ kimagesrc = $(kimage)
+ loaderdep = delo
+ loader = delo
+ loaderdoc =
+ endif
+ # Cobalt
+ ifneq (,$(filter r5k-cobalt,$(strip $(KPKG_SUBARCH))))
+ kimage := vmlinux
+ kimagesrc = $(kimage)
+ loaderdep = colo
+ loader = colo
+ loaderdoc =
+ endif
+ # LASAT
+ ifneq (,$(filter r5k-lasat,$(strip $(KPKG_SUBARCH))))
+ kimage := vmlinux
+ kimagesrc = $(kimage)
+ loaderdep =
+ loader =
+ loaderdoc =
+ endif
+ # Broadcom SWARM
+ ifneq (,$(filter sb1-swarm-bn,$(strip $(KPKG_SUBARCH))))
+ kimage := vmlinux
+ kimagesrc = $(kimage)
+ loaderdep = sibyl
+ loader = sibyl
+ loaderdoc =
+ endif
+ # xxs1500
+ ifneq (,$(filter xxs1500,$(strip $(KPKG_SUBARCH))))
+ kimage := vmlinux.srec
+ kimagesrc = $(strip arch/$(KERNEL_ARCH)/boot/$(kimage))
+ loaderdep =
+ loader =
+ loaderdoc =
+ endif
+
+ # Default value for e.g. a generic header package
+ ifeq (,$(kimage))
+ kimage := vmlinux
+ endif
+
+ NEED_DIRECT_GZIP_IMAGE = NO
+ kimagedest = $(INT_IMAGE_DESTDIR)/vmlinux-$(version)
+
+ ifneq ($(shell if [ $(VERSION) -ge 2 ] && [ $(PATCHLEVEL) -ge 5 ] && \
+ [ $(SUBLEVEL) -ge 41 ]; then echo new; \
+ elif [ $(VERSION) -ge 2 ] && [ $(PATCHLEVEL) -ge 6 ]; then \
+ echo new; \
+ elif [ $(VERSION) -ge 3 ]; then echo new; fi),)
+ target =
+ else
+ target = boot
+ endif
+
+ KERNEL_ARCH = mips
+ ifneq (,$(filter mips64el%,$(KPKG_SUBARCH)))
+ KERNEL_ARCH = mips64
+ endif
+ ifneq (,$(filter %-64,$(KPKG_SUBARCH)))
+ KERNEL_ARCH = mips64
+ endif
+endif
+
+##### m32r
+ifeq ($(strip $(architecture)),m32r)
+ KERNEL_ARCH := m32r
+ kimage := zImage
+ loaderdep=
+ loader=
+ loaderdoc=
+ target = $(kimage)
+ kimagesrc = $(strip arch/$(KERNEL_ARCH)/boot/$(kimage))
+ kimagedest = $(INT_IMAGE_DESTDIR)/vmlinuz-$(version)
+ DEBCONFIG= $(CONFDIR)/config.$(KPKG_SUBARCH)
+endif
+
+
+# usermode linux
+ifeq ($(strip $(architecture)),um)
+ DEBCONFIG = $(CONFDIR)/config.um
+
+
+ ifneq ($(shell if [ $(VERSION) -ge 2 ] && [ $(PATCHLEVEL) -ge 6 ] && \
+ [ $(SUBLEVEL) -ge 9 ]; then echo new; \
+ elif [ $(VERSION) -ge 2 ] && [ $(PATCHLEVEL) -ge r ]; then \
+ echo new; \
+ elif [ $(VERSION) -ge 3 ]; then echo new; fi),)
+ target = vmlinux
+ kimage := vmlinux
+ else
+ target = linux
+ kimage := linux
+ endif
+
+
+ kimagesrc = $(strip $(kimage))
+ INT_IMAGE_DESTDIR=$(IMAGE_DOC)
+ kimagedest = debian/tmp-image$(IMAGEDIR)/linux-$(version)
+ loaderdep=
+ loaderdoc=
+ KERNEL_ARCH = um
+ architecture = i386
+ IMAGEDIR = /usr/bin
+endif
+
+# xen-linux
+ifeq ($(strip $(architecture)),xen)
+ KERNEL_ARCH = xen
+ architecture = i386
+
+ ifeq (,$(findstring $(KPKG_SUBARCH),xen0 xenu))
+ KPKG_SUBARCH:=xen0
+ endif
+ DEBCONFIG = $(CONFDIR)/config.$(KPKG_SUBARCH)
+
+ ifneq ($(shell if [ $(VERSION) -ge 2 ] && [ $(PATCHLEVEL) -ge 5 ] && \
+ [ $(SUBLEVEL) -ge 41 ]; then echo new; \
+ elif [ $(VERSION) -ge 2 ] && [ $(PATCHLEVEL) -ge 6 ]; then \
+ echo new; \
+ elif [ $(VERSION) -ge 3 ]; then echo new; fi),)
+ target = vmlinuz
+ else
+ target = bzImage
+ endif
+ kimage := $(target)
+
+ ifeq (,$(filter xen0,$(KPKG_SUBARCH)))
+ # only domain-0 are bootable via xen so only domain0 subarch needs grub and xen-vm
+ loaderdep=grub,xen-vm
+ loader=grub
+ loaderdoc=
+ else
+ loaderdep=
+ loader=
+ loaderdoc=
+ endif
+
+ kimagesrc = $(kimage)
+ kimagedest = $(INT_IMAGE_DESTDIR)/xen-linux-$(version)
+endif
+
+
+######################################################################
+######################################################################
+
+ifneq ($(strip $(KPKG_STEM)),)
+INT_STEM := $(KPKG_STEM)
+else
+INT_STEM := kernel
+endif
+
+ifneq ($(strip $(loaderdep)),)
+ int_loaderdep := $(loaderdep),
+else
+ int_loaderdep :=
+endif
+
+
+
+# The following variable is used to simplify the process of making
+# diffs and orig targets, Please set it if AND ONLY IF no patches
+# have been applied to the upstream source, in other words, we have
+# just added debian* files. If any patches were applied, please
+# leave it empty
+
+# NO_SRC_CHANGES =
+NO_SRC_CHANGES = YES
+
+
+# NOTE: FLAVOUR is now obsolete
+# If you want to have more than one kernel configuration per kernel
+# version, set FLAVOUR in the top level kernel Makefile *before*
+# invoking make-kpkg -- it will be appended to UTS_RELEASE in
+# version.h (separated by a hyphen). This affects everything -- the
+# names and versions of the image, source, headers, and doc packages,
+# and where the modules are searched for in /lib/modules.
+
+ifdef FLAVOUR
+# uhm - should check if we really have a Makefile capable of Flavours?
+endif
+
+FLAVOUR:=$(shell grep ^FLAVOUR Makefile 2>/dev/null | \
+ perl -ple 's/FLAVOUR[\s:=]+//g')
+
+ifeq ($(strip $(FLAVOUR_SEP)),)
+FLAVOUR_SEP:= +
+endif
+
+ifneq ($(strip $(FLAVOUR)),)
+INT_FLAV := $(FLAVOUR_SEP)$(FLAVOUR)
+FLAV_ARG := FLAVOUR=$(FLAVOUR)
+else
+INT_FLAV :=
+FLAV_ARG :=
+endif
+
+## This is the replacement for FLAVOUR
+EXTRAVERSION =$(strip $(EXTRA_VERSION))
+ifneq ($(strip $(APPEND_TO_VERSION)),)
+iatv := $(strip $(APPEND_TO_VERSION))
+EXTRAV_ARG := EXTRAVERSION=${EXTRA_VERSION}${iatv}
+else
+iatv :=
+EXTRAV_ARG :=
+endif
+
+UTS_RELEASE_VERSION=$(shell if [ -f include/linux/version.h ]; then \
+ grep 'define UTS_RELEASE' include/linux/version.h | \
+ perl -nle 'm/^\s*\#define\s+UTS_RELEASE\s+("?)(\S+)\1/g && print $$2;';\
+ else echo "" ; \
+ fi)
+
+version = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)$(iatv)$(INT_FLAV)$(LOCALVERSION)
+
+# See if we are being run in the kernel directory
+IN_KERNEL_DIR := $(shell if test -d drivers && test -d kernel && test -d fs && test \
+ -d include/linux ; then \
+ echo YES; \
+ fi )
+
+IN_KERNEL_HEADERS=$(shell if [ -f $(INT_STEM)-headers.revision ]; then \
+ cat $(INT_STEM)-headers.revision; \
+ else echo "" ; \
+ fi)
+
+ifeq ($(strip $(IN_KERNEL_DIR)),)
+ifneq ($(strip $(IN_KERNEL_HEADERS)),)
+version=$(UTS_RELEASE_VERSION)
+debian :=$(IN_KERNEL_HEADERS)
+endif
+endif
+
+# Bug out if the version number id not all lowercase
+lc_version = $(shell echo $(version) | tr A-Z a-z)
+ifneq ($(strip $(version)),$(strip $(lc_version)))
+ ifeq ($(strip $(IGNORE_UPPERCASE_VERSION)),)
+ $(error Error. The version number $(strip $(version)) is not all \
+ lowercase. Since the version ends up in the package name of the \
+ kernel image package, this is a Debian policy violation, and \
+ the packaging system shall refuse to package the image. )
+ else
+ $(warn Error. The version number $(strip $(version)) is not all \
+ lowercase. Since the version ends up in the package name of the \
+ kernel image package, this is a Debian policy violation, and \
+ the packaging system shall refuse to package the image. Lower -casing version.)
+
+ version := $(strip $(lc_version))
+ endif
+endif
+
+
+
+# KPKG_SUBARCH is used to distinguish Amiga, Atari, Macintosh, etc. kernels
+# for Debian/m68k. INT_SUBARCH is used in the names of the image file
+# produced. It only affects the naming of the kernel-image as the
+# source and doc packages are architecture independent and the
+# kernel-headers do not vary from one sub-architecture to the next.
+
+# This is the default
+INT_SUBARCH :=
+
+ifneq ($(strip $(ARCH_IN_NAME)),)
+ifneq ($(strip $(KPKG_SUBARCH)),)
+INT_SUBARCH := -$(KPKG_SUBARCH)
+endif
+endif
+
+# The name of the package (for example, 'emacs').
+package := $(INT_STEM)-source-$(version)
+h_package := $(INT_STEM)-headers-$(version)
+ifeq ($(strip $(KERNEL_ARCH)),um)
+ i_package := $(INT_STEM)-uml-$(version)$(INT_SUBARCH)
+else
+ ifeq ($(strip $(KERNEL_ARCH)),xen)
+ i_package := $(INT_STEM)-$(KPKG_SUBARCH)-$(version)
+ else
+ i_package := $(INT_STEM)-image-$(version)$(INT_SUBARCH)
+ endif
+endif
+d_package := $(INT_STEM)-doc-$(version)
+l_package := libc-kheaders
+
+SOURCE_TOP:= debian/tmp-source
+HEADER_TOP:= debian/tmp-headers
+IMAGE_TOP := debian/tmp-image
+DOC_TOP := debian/tmp-doc
+MAN1DIR = $(IMAGE_TOP)/usr/share/man/man1
+
+SOURCE_DOC:= $(SOURCE_TOP)/usr/share/doc/$(package)
+HEADER_DOC:= $(HEADER_TOP)/usr/share/doc/$(h_package)
+IMAGE_DOC := $(IMAGE_TOP)/usr/share/doc/$(i_package)
+DOC_DOC := $(DOC_TOP)/usr/share/doc/$(d_package)
+
+SOURCE_SRC:= $(SOURCE_TOP)/usr/src/$(package)
+HEADER_SRC:= $(HEADER_TOP)/usr/src/$(h_package)
+UML_DIR := $(IMAGE_TOP)/usr/lib/uml/modules
+
+
+FILES_TO_CLEAN = modules/modversions.h modules/ksyms.ver debian/files \
+ conf.vars scripts/cramfs/cramfsck scripts/cramfs/mkcramfs \
+ applied_patches debian/buildinfo
+STAMPS_TO_CLEAN = stamp-build stamp-configure stamp-source stamp-image \
+ stamp-headers stamp-src stamp-diff stamp-doc \
+ stamp-buildpackage stamp-libc-kheaders stamp-debian \
+ stamp-patch stamp-kernel-configure
+DIRS_TO_CLEAN = $(SOURCE_TOP) $(HEADER_TOP) $(IMAGE_TOP) $(DOC_TOP)
+
+ifeq ($(strip $(VERSIONED_PATCH_DIR)),)
+VERSIONED_PATCH_DIR = $(shell if [ -d \
+/usr/src/kernel-patches/$(architecture)/$(VERSION).$(PATCHLEVEL).$(SUBLEVEL) \
+ ]; then echo \
+/usr/src/kernel-patches/$(architecture)/$(VERSION).$(PATCHLEVEL).$(SUBLEVEL); \
+ fi)
+endif
+
+ifeq ($(strip $(VERSIONED_ALL_PATCH_DIR)),)
+VERSIONED_ALL_PATCH_DIR = $(shell if [ -d \
+/usr/src/kernel-patches/all/$(VERSION).$(PATCHLEVEL).$(SUBLEVEL) \
+ ]; then echo \
+/usr/src/kernel-patches/all/$(VERSION).$(PATCHLEVEL).$(SUBLEVEL); \
+ fi)
+endif
+
+ifeq ($(strip $(PATCH_DIR)),)
+PATCH_DIR = $(shell if [ -d /usr/src/kernel-patches/$(architecture)/ ];\
+ then echo /usr/src/kernel-patches/$(architecture); \
+ fi)
+endif
+
+ifeq ($(strip $(ALL_PATCH_DIR)),)
+ALL_PATCH_DIR = $(shell if [ -d /usr/src/kernel-patches/all/ ]; \
+ then echo /usr/src/kernel-patches/all ;\
+ fi)
+endif
+
+VERSIONED_ALL_PATCH_APPLY = $(VERSIONED_ALL_PATCH_DIR)/apply
+VERSIONED_ALL_PATCH_UNPATCH = $(VERSIONED_ALL_PATCH_DIR)/unpatch
+
+VERSIONED_DIR_PATCH_APPLY = $(VERSIONED_PATCH_DIR)/apply
+VERSIONED_DIR_PATCH_UNPATCH = $(VERSIONED_PATCH_DIR)/unpatch
+
+ALL_PATCH_APPLY = $(ALL_PATCH_DIR)/apply
+ALL_PATCH_UNPATCH = $(ALL_PATCH_DIR)/unpatch
+
+DIR_PATCH_APPLY = $(PATCH_DIR)/apply
+DIR_PATCH_UNPATCH = $(PATCH_DIR)/unpatch
+
+# The destination of all .deb files
+# (suggested by Rob Browning <osiris@cs.utexas.edu>)
+DEB_DEST := ..
+SRCTOP := $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi)
+INSTALL_MOD_PATH=$(SRCTOP)/$(IMAGE_TOP)
+KPKG_DEST_DIR ?= $(SRCTOP)/..
+
+# Include any site specific overrides here.
+-include $(CONFLOC)
+
+# Over ride the config file from the environment/command line
+ifneq ($(strip $(KPKG_MAINTAINER)),)
+maintainer=$(KPKG_MAINTAINER)
+endif
+
+ifneq ($(strip $(KPKG_EMAIL)),)
+email=$(KPKG_EMAIL)
+endif
+
+# This should be a name to feed the modules build for pgp signature,
+# since we the maintainer would be different there.
+ifneq ($(strip $(PGP_SIGNATURE)),)
+pgp=$(PGP_SIGNATURE)
+endif
+
+ifneq ($(strip $(EXTRA_DOCS)),)
+extra_docs = $(EXTRA_DOCS)
+endif
+
+ifneq ($(strip $(extra_docs)),)
+HAVE_EXTRA_DOCS:=$(shell if [ -e $(extra_docs) ]; then echo YES; fi)
+endif
+
+ifneq ($(strip $(DEBIAN_REVISION_MANDATORY)),)
+debian_revision_mandatory:=$(DEBIAN_REVISION_MANDATORY)
+endif
+
+
+ifneq ($(strip $(install_vmlinux)),)
+int_install_vmlinux:=$(install_vmlinux)
+endif
+
+ifneq ($(strip $(KPKG_FOLLOW_SYMLINKS_IN_SRC)),)
+int_follow_symlinks_in_src=YES
+else
+ifneq ($(strip $(kpkg_follow_symlinks_in_src)),)
+int_follow_symlinks_in_src=YES
+endif
+endif
+
+
+
+
+
+# The Debian revision
+ifneq ($(strip $(DEBIAN_REVISION)),)
+HAS_CHANGELOG := $(shell \
+ if test -f debian/changelog && ( test -f stamp-debian || test -f debian/official );\
+ then echo YES;\
+ else echo NO; fi; )
+else
+HAS_CHANGELOG := $(shell if test -f debian/changelog; then echo YES;\
+ else echo NO; fi; )
+endif
+# If there is a changelog file, it overrides. The only exception is
+# when there is no stamp-config, and there is no debian/official,
+# *AND* there is a DEBIAN_REVISION, in which case the DEBIAN_REVISION
+# over rides (since we are going to replace the changelog file soon
+# anyway. Else, use the commandline or env var setting. Or else
+# default to 10.00.Custom, unless the human has requested that the
+# revision is mandatory, in which case we raise an error
+
+ifeq ($(strip $(HAS_CHANGELOG)),YES)
+debian := $(shell if test -f debian/changelog; then \
+ perl -nle 'print /\((\S+)\)/; exit 0' debian/changelog;\
+ fi; )
+else
+ifneq ($(strip $(DEBIAN_REVISION)),)
+debian := $(DEBIAN_REVISION)
+else
+ifeq ($(strip $(debian)),)
+ifneq ($(strip $(debian_revision_mandatory)),)
+$(error A Debian revision is mandatory, but none was provided)
+else
+debian := 10.00.Custom
+endif
+endif
+endif
+endif
+
+# Hmm. The version that we have computed *MUST* match the one that is in the
+# changelog.
+ifeq ($(strip $(HAS_CHANGELOG)),YES)
+saved_version := $(shell if test -f debian/changelog; then \
+ perl -nle 'print /^$(INT_STEM)-source-(\S+)/; exit 0' \
+ debian/changelog;\
+ fi; )
+ifneq ($(strip $(saved_version)),)
+ifneq ($(strip $(saved_version)),$(strip $(version)))
+HAVE_VERSION_MISMATCH=YES
+endif
+endif
+endif
+
+
+ifneq ($(strip $(DELETE_BUILD_LINK)),)
+delete_build_link := YES
+else
+ifeq ($(strip $(delete_build_link)),)
+delete_build_link := $(shell if test -f debian/official; then echo YES;\
+ else echo NO; fi; )
+endif
+endif
+
+ifneq ($(strip $(IMAGE_IN_BOOT)),)
+link_in_boot := $(IMAGE_IN_BOOT)
+endif
+
+ifneq ($(strip $(LINK_IN_BOOT)),)
+link_in_boot := $(LINK_IN_BOOT)
+endif
+
+ifneq ($(strip $(NO_SYMLINK)),)
+no_symlink := $(NO_SYMLINK)
+endif
+
+ifneq ($(strip $(REVERSE_SYMLINK)),)
+reverse_symlink := $(REVERSE_SYMLINK)
+endif
+
+ifneq ($(strip $(IMAGE_TYPE)),)
+kimage = $(IMAGE_TYPE)
+endif
+
+ifneq ($(strip $(PATCH_THE_KERNEL)),)
+patch_the_kernel = $(PATCH_THE_KERNEL)
+endif
+
+ifneq ($(strip $(KPKG_SELECTED_PATCHES)),)
+ifeq ($(strip $(patch_the_kernel)),NO)
+patch_the_kernel = NO
+else
+ifeq ($(strip $(patch_the_kernel)),no)
+patch_the_kernel = NO
+else
+patch_the_kernel = YES
+endif
+endif
+endif
+
+
+ifeq ($(strip $(patch_the_kernel)),yes)
+patch_the_kernel = YES
+endif
+ifeq ($(strip $(patch_the_kernel)),Yes)
+patch_the_kernel = YES
+endif
+ifeq ($(strip $(patch_the_kernel)),YEs)
+patch_the_kernel = YES
+endif
+ifeq ($(strip $(patch_the_kernel)),yEs)
+patch_the_kernel = YES
+endif
+ifeq ($(strip $(patch_the_kernel)),yES)
+patch_the_kernel = YES
+endif
+ifeq ($(strip $(patch_the_kernel)),yeS)
+patch_the_kernel = YES
+endif
+
+
+
+ifneq ($(strip $(CONFIG_TARGET)),)
+config_target := $(CONFIG_TARGET)
+have_new_config_target := YES
+endif
+
+# If config_target doesn't end in 'config' then reset it to 'oldconfig'.
+ifneq ($(patsubst %config,config,$(strip $(config_target))),config)
+config_target := oldconfig
+have_new_config_target :=
+endif
+
+ifneq ($(strip $(USE_SAVED_CONFIG)),)
+use_saved_config = $(USE_SAVED_CONFIG)
+endif
+
+#ifeq ($(origin var),command line)
+#$(warn You are setting an internal var from the cmdline. Use at your own risk)
+#endif
+#you can automated it a bit more with $(foreach) and $(if)
+
+
+###
+### In the following, we define these variables
+### ROOT_CMD -- set in the environment, plaing old sudo or fakeroot
+### root_cmd -- The same
+### int_root_cmd -- the argument passed to dpkg-buildpackage
+### -r$(ROOT_CMD)
+ifneq ($(strip $(ROOT_CMD)),)
+ # ROOT_CMD is not supposed to have -r or -us and -uc
+ int_dummy_root := $(ROOT_CMD)
+ # remove -us and -uc
+ ifneq ($(strip $(findstring -us, $(int_dummy_root))),)
+ int_dummy_root := $(subst -us,, $(strip $(int_dummy_root)))
+ int_us := -us
+ endif
+ ifneq ($(strip $(findstring -uc, $(int_dummy_root))),)
+ int_dummy_root := $(subst -uc,, $(strip $(int_dummy_root)))
+ int_uc := -uc
+ endif
+ ifneq ($(strip $(findstring -r, $(int_dummy_root))),)
+ int_dummy_root := $(subst -r,, $(strip $(int_dummy_root)))
+ endif
+ # sanitize
+ ROOT_CMD := $(strip $(int_dummy_root))
+ int_root_cmd := -r$(strip $(int_dummy_root))
+else
+ # well, ROOT_CMD is not set yet
+ ifneq ($(strip $(root_cmd)),)
+ # Try and set ROOT_CMD from root_cmd
+ int_dummy_root := $(root_cmd)
+ # remove -us and -uc
+ ifneq ($(strip $(findstring -us, $(int_dummy_root))),)
+ int_dummy_root := $(subst -us,, $(strip $(int_dummy_root)))
+ int_us := -us
+ endif
+ ifneq ($(strip $(findstring -uc, $(int_dummy_root))),)
+ int_dummy_root := $(subst -uc,, $(strip $(int_dummy_root)))
+ int_uc := -uc
+ endif
+ # now that -us and -uc are gone, remove -r
+ ifneq ($(strip $(findstring -r, $(int_dummy_root))),)
+ int_dummy_root := $(subst -r,, $(strip $(int_dummy_root)))
+ endif
+ # Finally, sanitized
+ ROOT_CMD := $(strip $(int_dummy_root))
+ int_root_cmd := -r$(strip $(int_dummy_root))
+ endif
+endif
+
+# make sure that root_cmd and ROOT_CMD are the same
+ifneq ($(strip $(ROOT_CMD)),)
+ root_cmd := $(ROOT_CMD)
+endif
+
+ifneq ($(strip $(UNSIGN_SOURCE)),)
+ int_us := -us
+endif
+
+ifneq ($(strip $(UNSIGN_CHANGELOG)),)
+ int_uc := -uc
+endif
+
+int_am_root := $(shell [ $$(id -u) -eq 0 ] && echo "YES" )
+
+
+ifneq ($(strip $(CLEAN_SOURCE)),)
+do_clean = $(CLEAN_SOURCE)
+endif
+
+ifneq ($(strip $(CONCURRENCY_LEVEL)),)
+do_parallel = -j$(CONCURRENCY_LEVEL)
+
+# Well, I wish there was something better than guessing by version number
+CAN_DO_DEP_FAST=$(shell if [ $(VERSION) -lt 2 ]; then echo ''; \
+ elif [ $(VERSION) -gt 2 ]; then echo YES; \
+ elif [ $(PATCHLEVEL) -lt 4 ]; then echo ''; \
+ else echo YES; \
+ fi)
+ifneq ($(strip $(CAN_DO_DEP_FAST)),)
+fast_dep= -j$(CONCURRENCY_LEVEL)
+endif
+
+endif
+
+ifneq ($(strip $(SOURCE_CLEAN_HOOK)),)
+source_clean_hook=$(SOURCE_CLEAN_HOOK)
+endif
+ifneq ($(strip $(HEADER_CLEAN_HOOK)),)
+header_clean_hook=$(HEADER_CLEAN_HOOK)
+endif
+ifneq ($(strip $(DOC_CLEAN_HOOK)),)
+doc_clean_hook=$(DOC_CLEAN_HOOK)
+endif
+ifneq ($(strip $(IMAGE_CLEAN_HOOK)),)
+image_clean_hook=$(IMAGE_CLEAN_HOOK)
+endif
+
+ifneq ($(strip $(INITRD)),)
+initrddep := initrd-tools (>= 0.1.48), # there is a space here
+else
+initrddep :=
+endif
+
+ifeq ($(strip $(CONFDIR)),)
+ifeq ($(strip $(patch_the_kernel)),YES)
+CONFDIR = $(PATCH_DIR)
+else
+ifeq ($(strip $(patch_the_kernel)),yes)
+CONFDIR = $(PATCH_DIR)
+else
+CONFDIR = $(DEBDIR)/Config
+endif
+endif
+endif
+
+# The file which has local configuration
+CONFIG_FILE := $(shell if test -e .config ; then \
+ echo .config; \
+ elif test -e $(DEBCONFIG) ; then \
+ echo $(DEBCONFIG); \
+ elif test -e $(CONFDIR)/config ; then \
+ echo $(CONFDIR)/config ; \
+ elif test -e $(DEBDIR)/config ; then \
+ echo $(DEBDIR)/config ; \
+ elif test -e /boot/config-$(version) ; then \
+ echo /boot/config-$(version) ; \
+ elif test -e /boot/config-$$(uname -r) ; then \
+ echo /boot/config-$$(uname -r) ; \
+ else echo /dev/null ; \
+ fi)
+
+
+# Deal with modules issues
+
+# define MODULES_ENABLED if appropriate
+ifneq ($(strip $(shell grep -E ^[^\#]*CONFIG_MODULES $(CONFIG_FILE))),)
+MODULES_ENABLED := YES
+endif
+
+# accept both space separated list of modules, as well as comma
+# separated ones
+valid_modules:=
+
+# See what modules we are talking about
+ifeq ($(strip $(MODULES_ENABLED)),YES)
+ifneq ($(strip $(KPKG_SELECTED_MODULES)),)
+canonical_modules=$(subst $(comma),$(space),$(KPKG_SELECTED_MODULES))
+else
+canonical_modules=$(shell test -e $(MODULE_LOC) && \
+ find $(MODULE_LOC) -follow -maxdepth 1 -type d -print |\
+ grep -E -v '^$(MODULE_LOC)/$$')
+endif
+
+
+# Now, if we have any modules at all, they are in canonical_modules
+ifneq ($(strip $(canonical_modules)),)
+
+# modules can have the full path, or just the name of the module. We
+# make all the modules ahve absolute paths by fleshing them out.
+path_modules :=$(filter /%, $(canonical_modules))
+no_path_modules:=$(filter-out /%, $(canonical_modules))
+fleshed_out :=$(foreach mod,$(no_path_modules),$(MODULE_LOC)/$(mod))
+
+# Hmmph. recreate the canonical modules; now everything has a full
+# path name.
+
+canonical_modules:=$(path_modules) $(fleshed_out)
+# test to see if the dir names are real
+valid_modules = $(shell for dir in $(canonical_modules); do \
+ if [ -d $$dir ] && [ -x $$dir/debian/rules ]; then \
+ echo $$dir; \
+ fi; \
+ done)
+
+
+endif
+endif
+
+ifeq ($(strip $(patch_the_kernel)),YES)
+
+# Well then. Let us see if we want to select the patches we apply.
+ifneq ($(strip $(KPKG_SELECTED_PATCHES)),)
+canonical_patches=$(subst $(comma),$(space),$(KPKG_SELECTED_PATCHES))
+
+ifneq ($(strip $(canonical_patches)),)
+# test to see if the patches exist
+temp_valid_patches = $(shell for name in $(canonical_patches); do \
+ if [ -x $(VERSIONED_DIR_PATCH_APPLY)/$$name ] && \
+ [ -x $(VERSIONED_DIR_PATCH_UNPATCH)/$$name ]; \
+ then echo $(VERSIONED_DIR_PATCH_APPLY)/$$name; \
+ elif [ -x $(VERSIONED_ALL_PATCH_APPLY)/$$name ] && \
+ [ -x $(VERSIONED_ALL_PATCH_UNPATCH)/$$name ]; \
+ then echo $(VERSIONED_ALL_PATCH_APPLY)/$$name; \
+ elif [ -x $(DIR_PATCH_APPLY)/$$name ] && \
+ [ -x $(DIR_PATCH_UNPATCH)/$$name ]; then \
+ echo $(DIR_PATCH_APPLY)/$$name; \
+ elif [ -x $(ALL_PATCH_APPLY)/$$name ] && \
+ [ -x $(ALL_PATCH_UNPATCH)/$$name ]; then \
+ echo $(ALL_PATCH_APPLY)/$$name; \
+ else \
+ echo $$name.error; \
+ fi; \
+ done)
+
+temp_patch_not_found = $(filter %.error, $(temp_valid_patches))
+patch_not_found = $(subst .error,,$(temp_patch_not_found))
+ifneq ($(strip $(patch_not_found)),)
+$(error Could not find patch for $(patch_not_found))
+endif
+
+valid_patches = $(filter-out %.error, $(temp_valid_patches))
+
+ifeq ($(strip $(valid_patches)),)
+$(error Could not find patch scripts for $(canonical_patches))
+endif
+
+
+
+canonical_unpatches = $(shell new=""; \
+ for name in $(canonical_patches); do \
+ new="$$name $$new"; \
+ done; \
+ echo $$new;)
+
+temp_valid_unpatches = $(shell for name in $(canonical_unpatches); do \
+ if [ -x $(VERSIONED_DIR_PATCH_APPLY)/$$name ] && \
+ [ -x $(VERSIONED_DIR_PATCH_UNPATCH)/$$name ]; \
+ then echo $(VERSIONED_DIR_PATCH_UNPATCH)/$$name; \
+ elif [ -x $(VERSIONED_ALL_PATCH_APPLY)/$$name ] && \
+ [ -x $(VERSIONED_ALL_PATCH_UNPATCH)/$$name ]; \
+ then echo $(VERSIONED_ALL_PATCH_UNPATCH)/$$name; \
+ elif [ -x $(DIR_PATCH_APPLY)/$$name ] && \
+ [ -x $(DIR_PATCH_UNPATCH)/$$name ]; then \
+ echo $(DIR_PATCH_UNPATCH)/$$name; \
+ elif [ -x $(ALL_PATCH_APPLY)/$$name ] && \
+ [ -x $(ALL_PATCH_UNPATCH)/$$name ]; then \
+ echo $(ALL_PATCH_UNPATCH)/$$name; \
+ else \
+ echo $$name.error; \
+ fi; \
+ done)
+temp_unpatch_not_found = $(filter %.error, $(temp_valid_unpatches))
+unpatch_not_found = $(subst .error,,$(temp_unpatch_not_found))
+ifneq ($(strip $(unpatch_not_found)),)
+$(error Could not find unpatch for $(unpatch_not_found))
+endif
+
+valid_unpatches = $(filter-out %.error, $(temp_valid_unpatches))
+
+ifeq ($(strip $(valid_unpatches)),)
+$(error Could not find un-patch scripts for $(canonical_unpatches))
+endif
+
+
+endif
+else
+# OK. We want to patch the kernel, but there are no patches specified.
+valid_patches = $(shell if [ -n "$(VERSIONED_PATCH_DIR)" ] && \
+ [ -d $(VERSIONED_DIR_PATCH_APPLY) ]; then \
+ run-parts --test $(VERSIONED_DIR_PATCH_APPLY); \
+ fi; \
+ if [ -n "$(VERSIONED_ALL_PATCH_DIR)" ] && \
+ [ -d $(VERSIONED_ALL_PATCH_APPLY) ]; then \
+ run-parts --test $(VERSIONED_ALL_PATCH_APPLY); \
+ fi; \
+ if [ -n "$(PATCH_DIR)" ] && \
+ [ -d $(DIR_PATCH_APPLY) ]; then \
+ run-parts --test $(DIR_PATCH_APPLY); \
+ fi; \
+ if [ -n "$(ALL_PATCH_DIR)" ] && \
+ [ -d $(ALL_PATCH_APPLY) ]; then \
+ run-parts --test $(ALL_PATCH_APPLY); \
+ fi)
+valid_unpatches = $(shell ( if [ -n "$(VERSIONED_PATCH_DIR)" ] && \
+ [ -d $(VERSIONED_DIR_PATCH_UNPATCH) ]; then \
+ run-parts --test $(VERSIONED_DIR_PATCH_UNPATCH); \
+ fi; \
+ if [ -n "$(VERSIONED_ALL_PATCH_DIR)" ] && \
+ [ -d $(VERSIONED_ALL_PATCH_UNPATCH) ]; then \
+ run-parts --test $(VERSIONED_ALL_PATCH_UNPATCH); \
+ fi; \
+ if [ -n "$(PATCH_DIR)" ] && \
+ [ -d $(DIR_PATCH_UNPATCH) ]; then \
+ run-parts --test $(DIR_PATCH_UNPATCH); \
+ fi; \
+ if [ -n "$(ALL_PATCH_DIR)" ] && \
+ [ -d $(ALL_PATCH_UNPATCH) ]; then \
+ run-parts --test $(ALL_PATCH_UNPATCH); \
+ fi) | tac)
+endif
+endif
+
+old_applied_patches=$(shell if [ -f applied_patches ]; then \
+ cat applied_patches; \
+ else \
+ echo ''; \
+ fi )
+
+ifeq ($(strip $(valid_unpatches)),)
+ifneq ($(strip $(old_applied_patches)),)
+old_unpatches=$(shell new=""; \
+ for name in $(notdir $(old_applied_patches)); do \
+ new="$$name $$new"; \
+ done; \
+ echo $$new;)
+temp_old_unpatches = $(shell for name in $(old_unpatches); do \
+ if [ -x $(VERSIONED_DIR_PATCH_UNPATCH)/$$name ]; \
+ then echo $(VERSIONED_DIR_PATCH_UNPATCH)/$$name;\
+ elif [ -x $(VERSIONED_ALL_PATCH_UNPATCH)/$$name ];\
+ then echo $(VERSIONED_ALL_PATCH_UNPATCH)/$$name;\
+ elif [ -x $(DIR_PATCH_UNPATCH)/$$name ]; then \
+ echo $(DIR_PATCH_UNPATCH)/$$name; \
+ elif [ -x $(ALL_PATCH_UNPATCH)/$$name ]; then \
+ echo $(ALL_PATCH_UNPATCH)/$$name; \
+ else \
+ echo $$name.error; \
+ fi; \
+ done)
+temp_old_unpatch_not_found = $(filter %.error, $(temp_old_unpatches))
+old_unpatch_not_found = $(subst .error,,$(temp_unpatch_not_found))
+valid_unpatches = $(filter-out %.error, $(temp_old_unpatches))
+endif
+endif
+
+# See if the version numbers are valid
+HAVE_VALID_PACKAGE_VERSION := $(shell \
+ if test -x $(DEBDIR)/kpkg-vercheck; then \
+ $(DEBDIR)/kpkg-vercheck $(debian) ; \
+ else \
+ echo "Could not find $(DEBDIR)/kpkg-vercheck" ; \
+ fi )
+
+TAR_COMPRESSION := $(shell \
+ if tar --help | grep -- \-\-bzip2 >/dev/null; then \
+ echo --bzip2; \
+ else \
+ echo --gzip; \
+ fi )
+TAR_SUFFIX := $(shell \
+ if tar --help | grep -- \-\-bzip2 >/dev/null; then \
+ echo bz2; \
+ else \
+ echo gz; \
+ fi )
+
+STOP_FOR_BIN86 = NO
+CONTROL=$(DEBDIR)/Control
+ifeq ($(strip $(architecture)),i386)
+NEED_BIN86 := $(shell if dpkg --compare-versions \
+ $(VERSION).$(PATCHLEVEL) lt 2.4 >/dev/null 2>&1; \
+ then echo YES; fi)
+ifeq ($(strip $(NEED_BIN86)),YES)
+CONTROL=$(DEBDIR)/Control.bin86
+HAVE_BIN86 := $(shell if test -x /usr/bin/as86; then echo YES; \
+ else echo NO; fi )
+ifeq ($(strip $(HAVE_BIN86)),NO)
+STOP_FOR_BIN86 = YES
+endif
+endif
+endif
+
+
+
+ifeq (,$(strip $(kimagedest)))
+$(error Error. I do not know where the kernel image goes to [kimagedest undefined]\
+ The usual case for this is that I could not determine which arch or subarch \
+ tihs machine belongs to. Please specify a subarch, and try again.)
+endif
+ifeq (,$(strip $(kimagesrc)))
+$(error Error. I do not know where the kernel image goes to [kimagesrc undefined]\
+ The usual case for this is that I could not determine which arch or subarch \
+ tihs machine belongs to. Please specify a subarch, and try again.)
+endif
+
+# export variables
+export root_cmd FLAVOUR INT_SUBARCH APPEND_TO_VERSION UNSIGN_CHANGELOG \
+ UNSIGN_SOURCE ROOT_CMD MODULE_LOC EXTRAVERSION ALL_PATCH_DIR \
+ ALL_PATCH_APPLY ALL_PATCH_UNPATCH DIR_PATCH_UNPATCH \
+ DIR_PATCH_APPLY VERSIONED_PATCH_DIR VERSIONED_ALL_PATCH_UNPATCH \
+ VERSIONED_ALL_PATCH_APPLY VERSIONED_DIR_PATCH_UNPATCH \
+ VERSIONED_DIR_PATCH_APPLY KPKG_SELECTED_PATCHES \
+ KPKG_SELECTED_MODULES CONCURRENCY_LEVEL
+
+
+ifeq ($(strip $(IN_KERNEL_DIR)),)
+# Hah! Not in kernel directory!!
+build configure clean binary kernel_source kernel-source kernel-headers\
+stamp-source kernel_headers stamp-headers kernel_image stamp-image \
+kernel-image kernel-doc kernel_doc stamp-doc buildpackage \
+libc_kheaders libc-kheaders stamp-libc-kheaders kernel-image-deb debian:
+ @echo "You should invoke this command from the top level directory of"
+ @echo "a linux kernel source directory tree, and as far as I can tell,"
+ @echo "the current directory:"
+ @echo " $(SRCTOP)"
+ @echo "is not a top level linux kernel source directory. "
+ @echo ""
+ @echo " (If I am wrong then kernel-packages and the linux kernel"
+ @echo " are so out sync that you'd better get the latest versions"
+ @echo " of the kernel-package package and the Linux sources)"
+ @echo ""
+ @echo "Please change directory to wherever linux kernel sources"
+ @echo "reside and try again."
+else
+ifneq ($(strip $(HAVE_VALID_PACKAGE_VERSION)),YES)
+# Hah! Bogus version number
+build configure clean binary kernel_source kernel-source kernel-headers\
+stamp-source kernel_headers stamp-headers kernel_image stamp-image \
+kernel-image kernel-doc kernel_doc stamp-doc buildpackage kernel-image-deb \
+debian:
+ @echo "Problems ecountered with the version number $(debian)."
+ @echo "$(HAVE_VALID_PACKAGE_VERSION)"
+ @echo ""
+ @echo "Please re-read the README file and try again."
+else
+ifeq ($(strip $(STOP_FOR__BIN86)),YES)
+# Hah! we need bin 86, but it aint here
+build configure clean binary kernel_source kernel-source kernel-headers\
+stamp-source kernel_headers stamp-headers kernel_image stamp-image \
+kernel-image kernel-doc kernel_doc stamp-doc buildpackage kernel-image-deb \
+debian:
+ @echo "You Need to install the package bin86 before you can "
+ @echo "compile the kernel on this machine"
+ @echo ""
+ @echo "Please install bin86 and try again."
+else
+all build: debian configure stamp-build
+stamp-build:
+# Builds the binary package.
+# debian.config contains the current idea of what the image should
+# have.
+ifneq ($(strip $(HAVE_VERSION_MISMATCH)),)
+ @(echo "The changelog says we are creating $(saved_version), but I thought the version is $(version)"; exit 1)
+endif
+ifneq ($(strip $(UTS_RELEASE_VERSION)), $(strip $(version)))
+ if [ -f include/linux/version.h ]; then \
+ uts_ver=$$(grep 'define UTS_RELEASE' include/linux/version.h | \
+ perl -nle 'm/^\s*\#define\s+UTS_RELEASE\s+("?)(\S+)\1/g && print $$2;'); \
+ if [ "X$$uts_ver" != "X$(strip $(UTS_RELEASE_VERSION))" ]; then \
+ echo "The UTS Release version in include/linux/version.h"; \
+ echo " \"$$uts_ver\" "; \
+ echo "does not match current version " ; \
+ echo " \"$(strip $(version))\" " ; \
+ echo "Reconfiguring." ; \
+ touch Makefile; \
+ fi; \
+ fi
+endif
+ -test -f stamp-configure || $(deb_rule) configure
+ $(MAKE) $(do_parallel) $(EXTRAV_ARG) $(FLAV_ARG) ARCH=$(KERNEL_ARCH) \
+ $(CROSS_ARG) $(target)
+ifneq ($(strip $(shell grep -E ^[^\#]*CONFIG_MODULES $(CONFIG_FILE))),)
+ $(MAKE) $(do_parallel) $(EXTRAV_ARG) $(FLAV_ARG) ARCH=$(KERNEL_ARCH) \
+ $(CROSS_ARG) modules
+endif
+ COLUMNS=150 dpkg -l 'gcc*' perl dpkg 'libc6*' binutils ldso make dpkg-dev |\
+ awk '$$1 ~ /[hi]i/ { printf("%s-%s\n", $$2, $$3) }' > debian/buildinfo
+ @echo this was built on a machine with the kernel: >> debian/buildinfo
+ uname -a >> debian/buildinfo
+ echo using the compiler: >> debian/buildinfo
+ grep LINUX_COMPILER include/linux/compile.h | \
+ sed -e 's/.*LINUX_COMPILER "//' -e 's/"$$//' >> debian/buildinfo
+ifneq ($(strip $(shell test -f version.Debian && cat version.Debian)),)
+ echo kernel source package used: >> debian/buildinfo
+ COLUMNS=150 dpkg -l kernel-source-$(shell test -f version.Debian && \
+ cat version.Debian | sed -e 's/-.*$$//') | \
+ awk '$$1 ~ /[hi]i/ { printf("%s-%s\n", $$2, $$3) }' >> debian/buildinfo
+endif
+ echo applied kernel patches: >> debian/buildinfo
+ifneq ($(strip $(valid_patches)),)
+ COLUMNS=150 dpkg -l $(shell echo $(valid_patches) | tr ' ' '\n' | \
+ sed -ne 's/^.*\/\(.*\)/kernel-patch-\1/p') | \
+ awk '$$1 ~ /[hi]i/ { printf("%s-%s\n", $$2, $$3) }' >> debian/buildinfo
+endif
+ echo done > $@
+
+buildpackage: clean stamp-buildpackage
+stamp-buildpackage: configure
+ifneq ($(strip $(HAVE_VERSION_MISMATCH)),)
+ @(echo "The changelog says we are creating $(saved_version), but I thought the version is $(version)"; exit 1)
+endif
+ test -f stamp-configure || $(deb_rule) configure
+ echo 'Building Package' > stamp-building
+ dpkg-buildpackage -nc $(strip $(int_root_cmd)) $(strip $(int_us)) $(strip $(int_uc)) \
+ -m"$(maintainer) <$(email)>" -k"$(pgp)"
+ rm -f stamp-building
+ echo done > $@
+
+# stamp-debian and stamp-configure used to be a single target. Now
+# they are split - the reason is that arch-indep packages need to be
+# built before arch-dep packages, and make-kpkg tries to do 'make
+# config' for both cases. This used to work because the .config file
+# resided with kernel-source, but now that it is in kernel-patch, it
+# breaks down. I think the cleanest way out of this is to only deal
+# with config files when necessary, and thus the split. Herbert Xu
+debian: stamp-debian
+stamp-debian:
+ifneq ($(strip $(HAVE_VERSION_MISMATCH)),)
+ @(echo "The changelog says we are creating $(saved_version), but I thought the version is $(version)"; exit 1)
+endif
+ # work around idiocy in recent kernel versions
+ test ! -e scripts/package/builddeb || \
+ mv -f scripts/package/builddeb scripts/package/builddeb.dist
+ test ! -e scripts/package/Makefile || \
+ (mv -f scripts/package/Makefile scripts/package/Makefile.dist && \
+ (echo "# Dummy file "; echo "help:") > scripts/package/Makefile)
+ @test -f $(DEBDIR)/rules || \
+ echo Error: Could not find $(DEBDIR)/rules
+ -test ! -f stamp-debian && test ! -f debian/official && \
+ rm -rf ./debian && mkdir ./debian
+ifeq ($(strip $(patch_the_kernel)),YES)
+ -test -f applied_patches && rm -f applied_patches
+ifneq ($(strip $(valid_patches)),)
+ -for patch in $(valid_patches) ; do \
+ if test -x $$patch; then \
+ if $$patch; then \
+ echo "Patch $$patch processed fine"; \
+ echo "$(notdir $$patch)" >> applied_patches; \
+ else \
+ echo "Patch $(notdir $$patch) failed."; \
+ echo "Hit return to Continue"; \
+ read ans; \
+ fi; \
+ fi; \
+ done
+ echo done > stamp-patch
+endif
+endif
+ -test ! -f stamp-debian && \
+ ( test ! -f debian/official || test ! -f debian/control) && \
+ sed -e 's/=V/$(version)/g' -e 's/=D/$(debian)/g' \
+ -e 's/=A/$(architecture)/g' -e 's/=SA/$(INT_SUBARCH)/g' \
+ -e 's/=L/$(int_loaderdep) /g' -e 's/=I/$(initrddep)/g' \
+ -e 's/=CV/$(VERSION).$(PATCHLEVEL)/g' \
+ -e 's/=M/$(maintainer) <$(email)>/g' \
+ -e 's/=ST/$(INT_STEM)/g' \
+ $(CONTROL)> debian/control
+ -test ! -f stamp-debian && test ! -f debian/official && \
+ sed -e 's/=V/$(version)/g' -e 's/=D/$(debian)/g' \
+ -e 's/=A/$(architecture)/g' -e 's/=M/$(maintainer) <$(email)>/g' \
+ -e 's/=ST/$(INT_STEM)/g' \
+ $(DEBDIR)/changelog > debian/changelog
+ -test ! -f debian/rules && \
+ install -p -m 755 $(DEBDIR)/rules debian/rules
+# -test ! -f stamp-debian && test ! -f debian/official && \
+# for file in $(DEBIAN_FILES); do cp -f $(LIBLOC)/$$file ./debian/; done
+# for dir in $(DEBIAN_DIRS); do cp -af $(LIBLOC)/$$dir ./debian/; done
+ echo done > $@
+
+conf.vars: Makefile .config
+ @rm -f .mak
+ @touch .mak
+ @echo Please ignore the warning about overriding and ignoring targets above.
+ @echo These are harmless. They are only invoked in a part of the process
+ @echo that tries to snarf variable values for the conf.vars file.
+ @echo "VERSION = $(VERSION)" >> .mak
+ @echo "PATCHLEVEL = $(PATCHLEVEL)" >> .mak
+ @echo "SUBLEVEL = $(SUBLEVEL)" >> .mak
+ @echo "EXTRAVERSION = $(EXTRAVERSION)" >> .mak
+ifneq ($(strip $(iatv)),)
+ @echo "APPEND_TO_VERSION = $(iatv)" >> .mak
+endif
+ifeq ($(strip $(patch_the_kernel)),YES)
+ @echo "KPKG_SELECTED_PATCHES = $(KPKG_SELECTED_PATCHES)" >> .mak
+endif
+ifeq ($(strip $(MODULES_ENABLED)),YES)
+ @echo "KPKG_SELECTED_MODULES = $(KPKG_SELECTED_MODULES)" >> .mak
+endif
+ @echo "Debian Revision = $(debian)" >> .mak
+ @echo "KPKG_ARCH = $(KPKG_ARCH)" >> .mak
+# Fetch the rest of the information from the kernel's Makefile
+ @$(MAKE) --no-print-directory -sf $(DEBDIR)/kernel_version.mk ARCH=$(KERNEL_ARCH) \
+ $(CROSS_ARG) debian_conf_var >> .mak
+ @echo "do_parallel = $(do_parallel)" >> .mak
+ @echo "fast_dep = $(fast_dep)" >> .mak
+# @sed -e 's%$(TOPDIR)%$$(TOPDIR)%g' .mak > conf.vars
+# Use the kernel's Makefile to calculate the TOPDIR.
+# TOPDIR is obsolete in 2.6 kernels, so the kernel_version.mk
+# will get us the right answer
+ @sed -e 's%$(shell $(MAKE) --no-print-directory -sf $(DEBDIR)/kernel_version.mk debian_TOPDIR)%$$(TOPDIR)%g' .mak > conf.vars
+ @rm -f .mak
+
+dummy_do_dep:
+ +$(MAKE) $(EXTRAV_ARG) $(FLAV_ARG) $(CROSS_ARG) \
+ ARCH=$(KERNEL_ARCH) $(fast_dep) dep
+
+stamp-kernel-configure: stamp-debian .config
+ $(MAKE) $(EXTRAV_ARG) $(FLAV_ARG) $(CROSS_ARG) \
+ ARCH=$(KERNEL_ARCH) $(config_target)
+ifeq ($(shell if [ $(VERSION) -ge 2 ] && [ $(PATCHLEVEL) -ge 5 ]; then \
+ echo new;fi),)
+ +$(MAKE) -f ./debian/rules dummy_do_dep
+ $(MAKE) $(EXTRAV_ARG) $(FLAV_ARG) $(CROSS_ARG) \
+ ARCH=$(KERNEL_ARCH) clean
+else
+ifeq ($(strip $(MAKING_VIRTUAL_IMAGE)),)
+ $(MAKE) $(EXTRAV_ARG) $(FLAV_ARG) $(CROSS_ARG) \
+ ARCH=$(KERNEL_ARCH) prepare
+endif
+endif
+ echo done > $@
+
+configure: debian .config stamp-configure
+stamp-configure: stamp-debian .config conf.vars stamp-kernel-configure
+ echo done > $@
+
+
+
+.config:
+ifneq ($(strip $(use_saved_config)),NO)
+ test -f .config || test ! -f .config.save || \
+ cp -pf .config.save .config
+endif
+ test -f .config || test ! -f $(CONFIG_FILE) || \
+ cp -pf $(CONFIG_FILE) .config
+ test -f .config || test ! -f $(DEBDIR)/config || \
+ cp -pf $(DEBDIR)/config .config
+ifeq ($(strip $(have_new_config_target)),)
+ test -f .config || (echo "*** Need a config file .config" && false)
+endif
+# if $(have_new_config_target) is set, then we need not have a .config
+# file at this point
+
+clean:
+ifeq ($(strip $(int_am_root)),)
+ifeq ($(strip $(ROOT_CMD)),)
+ @echo "You may need root privileges - some parts may fail"
+endif
+ $(ROOT_CMD) $(deb_rule) real_stamp_clean
+else
+ $(deb_rule) real_stamp_clean
+endif
+
+# Perhaps a list of patches should be dumped to a file on patching? so we
+# only unpatch what we have applied? That would be changed, though saner,
+# behaviour
+real_stamp_clean:
+ test ! -f .config || cp -pf .config config.precious
+ -test -f Makefile && \
+ $(MAKE) $(FLAV_ARG) $(EXTRAV_ARG) $(CROSS_ARG) ARCH=$(KERNEL_ARCH) distclean
+ test ! -f config.precious || mv -f config.precious .config
+ifeq ($(strip $(patch_the_kernel)),YES)
+ $(deb_rule) unpatch_now
+endif
+ifeq ($(strip $(NO_UNPATCH_BY_DEFAULT)),)
+ test ! -f stamp-patch || $(deb_rule) unpatch_now
+endif
+ -test -f stamp-building || test -f debian/official || rm -rf debian
+ # work around idiocy in recent kernel versions
+ test ! -e scripts/package/builddeb.dist || \
+ mv -f scripts/package/builddeb.dist scripts/package/builddeb
+ test ! -e scripts/package/Makefile.dist || \
+ mv -f scripts/package/Makefile.dist scripts/package/Makefile
+ rm -f $(FILES_TO_CLEAN) $(STAMPS_TO_CLEAN)
+ rm -rf $(DIRS_TO_CLEAN)
+
+
+unpatch_now:
+ifneq ($(strip $(valid_unpatches)),)
+ -for patch in $(valid_unpatches) ; do \
+ if test -x $$patch; then \
+ if $$patch; then \
+ echo "Removed Patch $$patch "; \
+ else \
+ echo "Patch $$patch failed."; \
+ echo "Hit return to Continue"; \
+ read ans; \
+ fi; \
+ fi; \
+ done
+ rm -f stamp-patch
+endif
+
+
+binary: binary-indep binary-arch
+binary-indep: kernel_source kernel_doc
+binary-arch: kernel_image kernel_headers
+
+
+kernel-source kernel_source: stamp-source
+stamp-source: stamp-debian
+ifeq ($(strip $(int_am_root)),)
+ifeq ($(strip $(ROOT_CMD)),)
+ @echo need root privileges; exit 1
+else
+ $(ROOT_CMD) $(deb_rule) real_stamp_source
+endif
+else
+ $(deb_rule) real_stamp_source
+endif
+
+real_stamp_source:
+ifneq ($(strip $(MAKING_VIRTUAL_IMAGE)),)
+ echo done > stamp-source
+else
+ifneq ($(strip $(HAVE_VERSION_MISMATCH)),)
+ @(echo "The changelog says we are creating $(saved_version), but I thought the version is $(version)"; exit 1)
+endif
+ test -f stamp-debian || $(deb_rule) debian
+ rm -rf $(SOURCE_TOP)
+ $(make_directory) $(SOURCE_TOP)/DEBIAN
+ $(make_directory) $(SOURCE_SRC)
+ $(make_directory) $(SOURCE_DOC)
+ sed -e 's/=P/$(package)/g' -e 's/=V/$(version)/g' \
+ $(DEBDIR)/src.postinst > $(SOURCE_TOP)/DEBIAN/postinst
+ chmod 755 $(SOURCE_TOP)/DEBIAN/postinst
+ $(install_file) debian/changelog $(SOURCE_DOC)/changelog.Debian
+ gzip -9qf $(SOURCE_DOC)/changelog.Debian
+ $(install_file) $(DEBDIR)/README $(SOURCE_DOC)/debian.README
+ gzip -9qf $(SOURCE_DOC)/debian.README
+ $(install_file) $(DEBDIR)/README.grub $(SOURCE_DOC)/README.grub
+ gzip -9qf $(SOURCE_DOC)/README.grub
+ $(install_file) $(DEBDIR)/README.headers $(SOURCE_DOC)/README.headers
+ gzip -9qf $(SOURCE_DOC)/README.headers
+ $(install_file) $(DEBDIR)/README.tecra $(SOURCE_DOC)/README.tecra
+ gzip -9qf $(SOURCE_DOC)/README.tecra
+ $(install_file) $(DEBDIR)/README.modules $(SOURCE_DOC)/README.modules
+ gzip -9qf $(SOURCE_DOC)/README.modules
+ $(install_file) $(DEBDIR)/sample.module.control \
+ $(SOURCE_DOC)/sample.module.control
+ gzip -9qf $(SOURCE_DOC)/sample.module.control
+ $(install_file) README $(SOURCE_DOC)/README
+ gzip -9qf $(SOURCE_DOC)/README
+ $(install_file) $(DEBDIR)/Flavours $(SOURCE_DOC)/Flavours
+ gzip -9qf $(SOURCE_DOC)/Flavours
+ $(install_file) $(DEBDIR)/Rationale $(SOURCE_DOC)/Rationale
+ gzip -9qf $(SOURCE_DOC)/Rationale
+ $(install_file) $(DEBDIR)/copyright.source $(SOURCE_DOC)/copyright
+ echo "This was produced by kernel-package version $(kpkg_version)." > \
+ $(SOURCE_DOC)/Buildinfo
+ifneq ($(strip $(int_follow_symlinks_in_src)),)
+ -tar cfh - $$(echo * | sed -e 's/ debian//g' -e 's/\.deb//g' ) \
+ | (cd $(SOURCE_SRC); umask 000; tar xpsf -)
+ (cd $(SOURCE_SRC)/include; rm -rf asm ; )
+else
+ -tar cf - $$(echo * | sed -e 's/ debian//g' -e 's/\.deb//g' ) \
+ | (cd $(SOURCE_SRC); umask 000; tar xspf -)
+ (cd $(SOURCE_SRC)/include; rm -f asm ; )
+endif
+ $(install_file) debian/changelog $(SOURCE_SRC)/Debian.src.changelog
+ (cd $(SOURCE_SRC); \
+ $(MAKE) $(EXTRAV_ARG) $(FLAV_ARG) $(CROSS_ARG) ARCH=$(KERNEL_ARCH) distclean)
+ (cd $(SOURCE_SRC); rm -f stamp-building $(STAMPS_TO_CLEAN))
+ (cd $(SOURCE_SRC); \
+ [ ! -d scripts/cramfs ] || make -C scripts/cramfs distclean ; )
+ if test -f debian/official && test -f debian/README.Debian ; then \
+ $(install_file) debian/README.Debian $(SOURCE_SRC)/README.Debian ; \
+ $(install_file) debian/README.Debian $(SOURCE_DOC)/README.Debian ; \
+ gzip -9qf $(SOURCE_DOC)/README.Debian;\
+ else \
+ sed -e 's/=V/$(version)/g' -e 's/=A/$(architecture)/g' \
+ -e 's/=ST/$(INT_STEM)/g' \
+ $(DEBDIR)/README.source > $(SOURCE_SRC)/README.Debian ; \
+ fi
+ if test -f README.Debian ; then \
+ $(install_file) README.Debian $(SOURCE_DOC)/README.Debian.1st; \
+ gzip -9qf $(SOURCE_DOC)/README.Debian.1st;\
+ fi
+ifneq ($(strip $(source_clean_hook)),)
+ (cd $(SOURCE_SRC); \
+ test -x $(source_clean_hook) && $(source_clean_hook))
+endif
+ chmod -R og=rX $(SOURCE_TOP)
+ chown -R root:root $(SOURCE_TOP)
+ (cd $(SOURCE_TOP)/usr/src/ && \
+ tar $(TAR_COMPRESSION) -cf $(package).tar.$(TAR_SUFFIX) $(package) &&\
+ rm -rf $(package);)
+ dpkg-gencontrol -isp -p$(package) -P$(SOURCE_TOP)/
+ chmod -R og=rX $(SOURCE_TOP)
+ chown -R root:root $(SOURCE_TOP)
+ dpkg --build $(SOURCE_TOP) $(DEB_DEST)
+ rm -f -r $(SOURCE_TOP)
+ echo done > stamp-source
+endif
+
+libc-kheaders libc_kheaders: stamp-libc-kheaders
+stamp-libc-kheaders: configure
+ @echo This target is now obsolete.
+
+
+kernel-headers kernel_headers: stamp-headers
+stamp-headers: configure
+ifeq ($(strip $(int_am_root)),)
+ifeq ($(strip $(ROOT_CMD)),)
+ @echo need root privileges; exit 1
+else
+ $(ROOT_CMD) $(deb_rule) real_stamp_headers
+endif
+else
+ $(deb_rule) real_stamp_headers
+endif
+
+real_stamp_headers:
+ifneq ($(strip $(MAKING_VIRTUAL_IMAGE)),)
+ echo done > stamp-headers
+else
+ifneq ($(strip $(HAVE_VERSION_MISMATCH)),)
+ @(echo "The changelog says we are creating $(saved_version), but I thought the version is $(version)"; exit 1)
+endif
+ifneq ($(strip $(UTS_RELEASE_VERSION)),$(strip $(version)))
+ @echo "The UTS Release version in include/linux/version.h $(UTS_RELEASE_VERSION) does not match current version $(version), reconfiguring"
+ touch Makefile
+endif
+ test -f stamp-configure || $(deb_rule) configure
+ rm -rf $(HEADER_TOP)
+ $(make_directory) $(HEADER_TOP)/DEBIAN
+ $(make_directory) $(HEADER_SRC)
+ $(make_directory) $(HEADER_DOC)
+ $(make_directory) $(HEADER_SRC)/arch/$(KERNEL_ARCH)
+ sed -e 's/=P/$(h_package)/g' -e 's/=V/$(version)/g' \
+ $(DEBDIR)/include.postinst > $(HEADER_TOP)/DEBIAN/postinst
+ chmod 755 $(HEADER_TOP)/DEBIAN/postinst
+ $(install_file) $(DEBDIR)/copyright.headers $(HEADER_DOC)/copyright
+ $(install_file) debian/changelog $(HEADER_DOC)/changelog.Debian
+ gzip -9qf $(HEADER_DOC)/changelog.Debian
+ $(install_file) $(DEBDIR)/README.headers $(HEADER_DOC)/debian.README
+ gzip -9qf $(HEADER_DOC)/debian.README
+ $(install_file) .config $(HEADER_DOC)/config-$(version)
+ $(install_file) conf.vars $(HEADER_DOC)/conf.vars
+ gzip -9qf $(HEADER_DOC)/config-$(version)
+ gzip -9qf $(HEADER_DOC)/conf.vars
+ $(install_file) CREDITS $(HEADER_DOC)/
+ gzip -9qf $(HEADER_DOC)/CREDITS
+ $(install_file) MAINTAINERS $(HEADER_DOC)/
+ gzip -9qf $(HEADER_DOC)/MAINTAINERS
+ $(install_file) REPORTING-BUGS $(HEADER_DOC)/
+ gzip -9qf $(HEADER_DOC)/REPORTING-BUGS
+ $(install_file) README $(HEADER_DOC)/
+ gzip -9qf $(HEADER_DOC)/README
+ if test -f debian/official && test -f debian/README.Debian ; then \
+ $(install_file) debian/README.Debian $(HEADER_DOC)/README.Debian ; \
+ gzip -9qf $(HEADER_DOC)/README.Debian ; \
+ $(install_file) README.Debian $(HEADER_DOC)/README.Debian;\
+ gzip -9qf $(HEADER_DOC)/README.Debian;\
+ fi
+ if test -f README.Debian ; then \
+ $(install_file) README.Debian $(HEADER_DOC)/README.Debian.1st;\
+ gzip -9qf $(HEADER_DOC)/README.Debian.1st;\
+ fi
+ echo "This was produced by kernel-package version $(kpkg_version)." > \
+ $(HEADER_DOC)/Buildinfo
+ chmod 0644 $(HEADER_DOC)/Buildinfo
+ $(install_file) Makefile $(HEADER_SRC)
+ test ! -e Rules.make || $(install_file) Rules.make $(HEADER_SRC)
+ test ! -e arch/$(KERNEL_ARCH)/Makefile || \
+ $(install_file) arch/$(KERNEL_ARCH)/Makefile $(HEADER_SRC)/arch/$(KERNEL_ARCH)
+ test ! -e Rules.make || $(install_file) Rules.make $(HEADER_SRC)
+ifneq ($(strip $(int_follow_symlinks_in_src)),)
+ -tar cfh - include | (cd $(HEADER_SRC); umask 000; tar xsf -)
+ (cd $(HEADER_SRC)/include; rm -rf asm; ln -s asm-$(KERNEL_ARCH) asm)
+else
+ -tar cf - include | (cd $(HEADER_SRC); umask 000; tar xsf -)
+ (cd $(HEADER_SRC)/include; rm -f asm; ln -s asm-$(KERNEL_ARCH) asm)
+endif
+ $(install_file) .config $(HEADER_SRC)/.config
+ echo $(debian) > $(HEADER_SRC)/$(INT_STEM)-headers.revision
+ifneq ($(strip $(header_clean_hook)),)
+ (cd $(HEADER_SRC); \
+ test -x $(header_clean_hook) && $(header_clean_hook))
+endif
+ dpkg-gencontrol -DArchitecture=$(architecture) -isp \
+ -p$(h_package) -P$(HEADER_TOP)/
+ chown -R root:root $(HEADER_TOP)
+ chmod -R og=rX $(HEADER_TOP)
+ dpkg --build $(HEADER_TOP) $(DEB_DEST)
+ rm -rf $(HEADER_TOP)
+ echo done > stamp-headers
+endif
+
+kernel-doc kernel_doc: stamp-doc
+stamp-doc: stamp-debian
+ifeq ($(strip $(int_am_root)),)
+ifeq ($(strip $(ROOT_CMD)),)
+ @echo need root privileges; exit 1
+else
+ $(ROOT_CMD) $(deb_rule) real_stamp_doc
+endif
+else
+ $(deb_rule) real_stamp_doc
+endif
+
+real_stamp_doc:
+ifneq ($(strip $(MAKING_VIRTUAL_IMAGE)),)
+ echo done > stamp-doc
+else
+ifneq ($(strip $(HAVE_VERSION_MISMATCH)),)
+ @(echo "The changelog says we are creating $(saved_version), but I thought the version is $(version)"; exit 1)
+endif
+ test -f stamp-debian || $(deb_rule) debian
+ rm -rf $(DOC_TOP)
+ $(make_directory) $(DOC_TOP)/DEBIAN
+ $(make_directory) $(DOC_DOC)
+ $(install_file) debian/changelog $(DOC_DOC)/changelog.Debian
+ $(install_file) $(DEBDIR)/README.doc $(DOC_DOC)/README.Debian
+ echo "This was produced by kernel-package version $(kpkg_version)." > \
+ $(DOC_DOC)/Buildinfo
+ chmod 0644 $(DOC_DOC)/Buildinfo
+ if test -f debian/official && test -f debian/README.Debian ; then \
+ $(install_file) debian/README.Debian $(DOC_DOC)/README.Debian;\
+ fi
+ if test -f README.Debian ; then \
+ $(install_file) README.Debian $(DOC_DOC)/README.Debian.1st;\
+ fi
+ifneq ($(strip $(shell if [ -x /usr/bin/db2html ]; then echo YSE; fi)),)
+ $(MAKE) mandocs htmldocs
+endif
+ -tar cf - Documentation | (cd $(DOC_DOC); umask 000; tar xsf -)
+ifneq ($(shell if [ $(VERSION) -ge 2 ] && [ $(PATCHLEVEL) -ge 5 ]; then \
+ echo new;fi),)
+ find -name Kconfig -print0 | xargs -0r cat | \
+ (umask 000 ; cat > $(DOC_DOC)/Kconfig.collected)
+# removing if empty should be faster than running find twice
+ if ! test -s $(DOC_DOC)/Kconfig.collected ; then \
+ rm -f $(DOC_DOC)/Kconfig.collected ; \
+ fi
+endif
+ifneq ($(strip $(doc_clean_hook)),)
+ (cd $(DOC_DOC); \
+ test -x $(doc_clean_hook) && $(doc_clean_hook))
+endif
+ -gzip -9qfr $(DOC_DOC)
+ -find $(DOC_DOC) -type f -name \*.gz -perm +111 -exec gunzip {} \;
+ $(install_file) $(DEBDIR)/copyright.doc $(DOC_DOC)/copyright
+ sed -e 's/=P/$(d_package)/g' -e 's/=V/$(version)/g' \
+ $(DEBDIR)/src.postinst > $(DOC_TOP)/DEBIAN/postinst
+ chmod 755 $(DOC_TOP)/DEBIAN/postinst
+ dpkg-gencontrol -isp -p$(d_package) -P$(DOC_TOP)/
+ chmod -R og=rX $(DOC_TOP)
+ chown -R root:root $(DOC_TOP)
+ dpkg --build $(DOC_TOP) $(DEB_DEST)
+ rm -rf $(DOC_TOP)
+ echo done > stamp-doc
+endif
+
+kernel-image kernel_image: stamp-image
+stamp-image: configure build kernel-image-deb
+# % make config
+# % make-kpkg build
+# % sudo make -f debian/rules kernel-image-deb
+# seems to create a working .deb with a kernel that gives the correct
+# user name (as opposed to root@...)
+kernel-image-deb:
+ifeq ($(strip $(int_am_root)),)
+ifeq ($(strip $(ROOT_CMD)),)
+ @echo need root privileges; exit 1
+else
+ $(ROOT_CMD) $(deb_rule) real_stamp_image
+endif
+else
+ $(deb_rule) real_stamp_image
+endif
+
+real_stamp_image:
+ifneq ($(strip $(HAVE_VERSION_MISMATCH)),)
+ @(echo "The changelog says we are creating $(saved_version), but I thought the version is $(version)"; exit 1)
+endif
+ifneq ($(strip $(UTS_RELEASE_VERSION)),$(strip $(version)))
+ @echo "The UTS Release version in include/linux/version.h $(UTS_RELEASE_VERSION) does not match current version $(version), reconfiguring."
+ touch Makefile
+endif
+ rm -f -r ./$(IMAGE_TOP) ./$(IMAGE_TOP).deb
+ test -f stamp-configure || $(deb_rule) configure
+ test -f stamp-build || $(deb_rule) build
+ $(make_directory) $(IMAGE_TOP)/DEBIAN
+ $(make_directory) $(IMAGE_TOP)/$(IMAGEDIR)
+ $(make_directory) $(IMAGE_DOC)
+ifneq ($(strip $(KERNEL_ARCH)),um)
+ ifneq ($(strip $(KERNEL_ARCH)),xen)
+ sed -e 's/=V/$(version)/g' -e 's/=B/$(link_in_boot)/g' \
+ -e 's/=ST/$(INT_STEM)/g' -e 's/=R/$(reverse_symlink)/g' \
+ -e 's/=K/$(kimage)/g' -e 's/=L/$(loader)/g' \
+ -e 's/=I/$(INITRD)/g' -e 's,=D,$(IMAGEDIR),g' \
+ -e 's@=M@$(MKIMAGE)@g' -e 's/=OF/$(AM_OFFICIAL)/g' \
+ -e 's@=A@$(DEB_HOST_ARCH)@g' \
+ -e 's/=S/$(no_symlink)/g' \
+ $(DEBDIR)/image.postinst > $(IMAGE_TOP)/DEBIAN/postinst
+ chmod 755 $(IMAGE_TOP)/DEBIAN/postinst
+ sed -e 's/=V/$(version)/g' -e 's/=B/$(link_in_boot)/g' \
+ -e 's/=ST/$(INT_STEM)/g' -e 's/=R/$(reverse_symlink)/g' \
+ -e 's/=K/$(kimage)/g' -e 's/=L/$(loader)/g' \
+ -e 's/=I/$(INITRD)/g' -e 's,=D,$(IMAGEDIR),g' \
+ -e 's@=M@$(MKIMAGE)@g' -e 's/=OF/$(AM_OFFICIAL)/g' \
+ -e 's@=A@$(DEB_HOST_ARCH)@g' \
+ -e 's/=S/$(no_symlink)/g' \
+ $(DEBDIR)/image.postrm > $(IMAGE_TOP)/DEBIAN/postrm
+ chmod 755 $(IMAGE_TOP)/DEBIAN/postrm
+ sed -e 's/=V/$(version)/g' -e 's/=B/$(link_in_boot)/g' \
+ -e 's/=ST/$(INT_STEM)/g' -e 's/=R/$(reverse_symlink)/g' \
+ -e 's/=K/$(kimage)/g' -e 's/=L/$(loader)/g' \
+ -e 's/=I/$(INITRD)/g' -e 's,=D,$(IMAGEDIR),g' \
+ -e 's@=M@$(MKIMAGE)@g' -e 's/=OF/$(AM_OFFICIAL)/g' \
+ -e 's@=A@$(DEB_HOST_ARCH)@g' \
+ -e 's/=S/$(no_symlink)/g' \
+ $(DEBDIR)/image.preinst > $(IMAGE_TOP)/DEBIAN/preinst
+ chmod 755 $(IMAGE_TOP)/DEBIAN/preinst
+ sed -e 's/=V/$(version)/g' -e 's/=B/$(link_in_boot)/g' \
+ -e 's/=ST/$(INT_STEM)/g' -e 's/=R/$(reverse_symlink)/g' \
+ -e 's/=K/$(kimage)/g' -e 's/=L/$(loader)/g' \
+ -e 's/=I/$(INITRD)/g' -e 's,=D,$(IMAGEDIR),g' \
+ -e 's@=M@$(MKIMAGE)@g' -e 's/=OF/$(AM_OFFICIAL)/g' \
+ -e 's@=A@$(DEB_HOST_ARCH)@g' \
+ -e 's/=S/$(no_symlink)/g' \
+ $(DEBDIR)/image.prerm > $(IMAGE_TOP)/DEBIAN/prerm
+ chmod 755 $(IMAGE_TOP)/DEBIAN/prerm
+ else
+ sed -e 's/=V/$(version)/g' -e 's/=B/$(link_in_boot)/g' \
+ -e 's/=ST/$(INT_STEM)/g' -e 's/=R/$(reverse_symlink)/g' \
+ -e 's/=K/$(kimage)/g' -e 's/=L/$(loader)/g' \
+ -e 's/=I/$(INITRD)/g' -e 's,=D,$(IMAGEDIR),g' \
+ -e 's@=M@$(MKIMAGE)@g' -e 's/=OF/$(AM_OFFICIAL)/g' \
+ -e 's@=A@$(DEB_HOST_ARCH)@g' \
+ -e 's/=S/$(no_symlink)/g' \
+ $(DEBDIR)/xen.postinst > $(IMAGE_TOP)/DEBIAN/postinst
+ chmod 755 $(IMAGE_TOP)/DEBIAN/postinst
+ sed -e 's/=V/$(version)/g' -e 's/=B/$(link_in_boot)/g' \
+ -e 's/=ST/$(INT_STEM)/g' -e 's/=R/$(reverse_symlink)/g' \
+ -e 's/=K/$(kimage)/g' -e 's/=L/$(loader)/g' \
+ -e 's/=I/$(INITRD)/g' -e 's,=D,$(IMAGEDIR),g' \
+ -e 's@=M@$(MKIMAGE)@g' -e 's/=OF/$(AM_OFFICIAL)/g' \
+ -e 's@=A@$(DEB_HOST_ARCH)@g' \
+ -e 's/=S/$(no_symlink)/g' \
+ $(DEBDIR)/xen.prerm > $(IMAGE_TOP)/DEBIAN/prerm
+ chmod 755 $(IMAGE_TOP)/DEBIAN/prerm
+ endif
+else
+ $(make_directory) $(UML_DIR)
+ $(make_directory) $(MAN1DIR)
+ sed -e 's/=V/$(version)/g' -e 's/=B/$(link_in_boot)/g' \
+ -e 's/=ST/$(INT_STEM)/g' -e 's/=R/$(reverse_symlink)/g' \
+ -e 's/=K/$(kimage)/g' -e 's/=L/$(loader)/g' \
+ -e 's/=I/$(INITRD)/g' -e 's,=D,$(IMAGEDIR),g' \
+ -e 's@=M@$(MKIMAGE)@g' -e 's/=OF/$(AM_OFFICIAL)/g' \
+ -e 's@=A@$(DEB_HOST_ARCH)@g' \
+ -e 's/=S/$(no_symlink)/g' \
+ $(DEBDIR)/um.postinst > $(IMAGE_TOP)/DEBIAN/postinst
+ chmod 755 $(IMAGE_TOP)/DEBIAN/postinst
+ sed -e 's/=V/$(version)/g' -e 's/=B/$(link_in_boot)/g' \
+ -e 's/=ST/$(INT_STEM)/g' -e 's/=R/$(reverse_symlink)/g' \
+ -e 's/=K/$(kimage)/g' -e 's/=L/$(loader)/g' \
+ -e 's/=I/$(INITRD)/g' -e 's,=D,$(IMAGEDIR),g' \
+ -e 's@=M@$(MKIMAGE)@g' -e 's/=OF/$(AM_OFFICIAL)/g' \
+ -e 's@=A@$(DEB_HOST_ARCH)@g' \
+ -e 's/=S/$(no_symlink)/g' \
+ $(DEBDIR)/um.prerm > $(IMAGE_TOP)/DEBIAN/prerm
+ chmod 755 $(IMAGE_TOP)/DEBIAN/prerm
+ $(install_file) $(DEBDIR)/linux.1 $(MAN1DIR)/linux-$(version).1
+ gzip -9fq $(MAN1DIR)/linux-$(version).1
+endif
+ $(install_file) Documentation/Changes $(IMAGE_DOC)/
+ gzip -9qf $(IMAGE_DOC)/Changes
+ $(install_file) debian/changelog $(IMAGE_DOC)/changelog.Debian
+ gzip -9qf $(IMAGE_DOC)/changelog.Debian
+ifdef loaderdoc
+ $(install_file) $(DEBDIR)/$(loaderdoc) $(IMAGE_DOC)/$(loaderdoc)
+ gzip -9qf $(IMAGE_DOC)/$(loaderdoc)
+endif
+ $(install_file) $(DEBDIR)/README.image $(IMAGE_DOC)/debian.README
+ gzip -9qf $(IMAGE_DOC)/debian.README
+ $(install_file) $(DEBDIR)/copyright.image $(IMAGE_DOC)/copyright
+ echo "This was produced by kernel-package version $(kpkg_version)." > \
+ $(IMAGE_DOC)/Buildinfo
+ chmod 0644 $(IMAGE_DOC)/Buildinfo
+ $(install_file) .config $(INT_IMAGE_DESTDIR)/config-$(version)
+ $(install_file) conf.vars $(IMAGE_DOC)/conf.vars
+ gzip -9qf $(IMAGE_DOC)/conf.vars
+ $(install_file) debian/buildinfo $(IMAGE_DOC)/buildinfo
+ gzip -9qf $(IMAGE_DOC)/buildinfo
+ if test -f debian/official && test -f debian/README.Debian ; then \
+ $(install_file) debian/README.Debian $(IMAGE_DOC)/README.Debian ; \
+ gzip -9qf $(IMAGE_DOC)/README.Debian;\
+ fi
+ if test -f README.Debian ; then \
+ $(install_file) README.Debian $(IMAGE_DOC)/README.Debian.1st;\
+ gzip -9qf $(IMAGE_DOC)/README.Debian.1st;\
+ fi
+ if test -f Debian.src.changelog; then \
+ $(install_file) Debian.src.changelog $(IMAGE_DOC)/; \
+ gzip -9qf $(IMAGE_DOC)/Debian.src.changelog;\
+ fi
+ifeq ($(strip $(HAVE_EXTRA_DOCS)),YES)
+ $(install_file) $(extra_docs) $(IMAGE_DOC)/
+endif
+ifneq ($(strip $(shell grep -E ^[^\#]*CONFIG_MODULES $(CONFIG_FILE))),)
+ifeq ($(strip $(HAVE_NEW_MODLIB)),)
+ $(mod_inst_cmds)
+else
+# could have also said DEPMOD=/bin/true instead of moving files
+ifneq ($(strip $(KERNEL_CROSS)),)
+ mv System.map System.precious
+endif
+ $(MAKE) $(EXTRAV_ARG) INSTALL_MOD_PATH=$(INSTALL_MOD_PATH) \
+ $(CROSS_ARG) ARCH=$(KERNEL_ARCH) modules_install
+ifneq ($(strip $(KERNEL_CROSS)),)
+ mv System.precious System.map
+endif
+endif
+ test ! -e $(IMAGE_TOP)/lib/modules/$(version)/source || \
+ mv $(IMAGE_TOP)/lib/modules/$(version)/source ./debian/source-link
+ test ! -e $(IMAGE_TOP)/lib/modules/$(version)/build || \
+ mv $(IMAGE_TOP)/lib/modules/$(version)/build ./debian/build-link
+ifeq ($(strip $(KERNEL_ARCH)),um)
+ -depmod -q -FSystem.map -b $(IMAGE_TOP) \
+ $(version)-$$(sed q include/linux/version.h | sed s/\"//g | awk -F\- '{print $$2}')
+else
+ifeq ($(DEB_BUILD_GNU_TYPE),$(DEB_HOST_GNU_TYPE))
+ -depmod -q -FSystem.map -b $(IMAGE_TOP) $(version);
+endif
+endif
+ test ! -e ./debian/source-link || \
+ mv ./debian/source-link $(IMAGE_TOP)/lib/modules/$(version)/source
+ test ! -e ./debian/build-link || \
+ mv ./debian/build-link $(IMAGE_TOP)/lib/modules/$(version)/build
+
+endif
+ifeq ($(strip $(NEED_DIRECT_GZIP_IMAGE)),YES)
+ gzip -9vc $(kimagesrc) > $(kimagedest)
+else
+ cp $(kimagesrc) $(kimagedest)
+endif
+ifeq ($(strip $(KERNEL_ARCH)),um)
+ chmod 755 $(kimagedest);
+ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
+ strip --strip-unneeded --remove-section=.note --remove-section=.comment $(kimagedest);
+endif
+else
+ chmod 644 $(kimagedest);
+endif
+ifeq ($(strip $(HAVE_COFF_IMAGE)),YES)
+ cp $(coffsrc) $(coffdest)
+ chmod 644 $(coffdest)
+endif
+ifeq ($(strip $(int_install_vmlinux)),YES)
+ifneq ($(strip $(kelfimagesrc)),)
+ cp $(kelfimagesrc) $(kelfimagedest)
+ chmod 644 $(kelfimagedest)
+endif
+endif
+ if test -d $(SRCTOP)/debian/image.d ; then \
+ IMAGE_TOP=$(IMAGE_TOP) version=$(version) \
+ run-parts --verbose $(SRCTOP)/debian/image.d ; \
+ fi
+ if [ -x debian/post-install ]; then \
+ IMAGE_TOP=$(IMAGE_TOP) STEM=$(INT_STEM) version=$(version) \
+ debian/post-install; \
+ fi
+ifneq ($(strip $(image_clean_hook)),)
+ (cd $(IMAGE_TOP); \
+ test -x $(image_clean_hook) && $(image_clean_hook))
+endif
+ test ! -s applied_patches || cp applied_patches \
+ $(INT_IMAGE_DESTDIR)/patches-$(version)
+ test ! -s applied_patches || chmod 644 \
+ $(INT_IMAGE_DESTDIR)/patches-$(version)
+ifneq ($(strip $(KERNEL_ARCH)),um)
+ test ! -f System.map || cp System.map \
+ $(INT_IMAGE_DESTDIR)/System.map-$(version);
+ test ! -f System.map || chmod 644 \
+ $(INT_IMAGE_DESTDIR)/System.map-$(version);
+else
+ mv $(INSTALL_MOD_PATH)/lib/modules/* $(UML_DIR)/ -v
+ rm -rf $(INSTALL_MOD_PATH)/lib
+endif
+ # For LKCD enabled kernels
+ test ! -f Kerntypes || cp Kerntypes \
+ $(INT_IMAGE_DESTDIR)/Kerntypes-$(version)
+ test ! -f Kerntypes || chmod 644 \
+ $(INT_IMAGE_DESTDIR)/Kerntypes-$(version)
+ifeq ($(strip $(delete_build_link)),YES)
+ rm -f $(IMAGE_TOP)/lib/modules/$(version)/build
+endif
+ dpkg-gencontrol -DArchitecture=$(architecture) -isp \
+ -p$(i_package) -P$(IMAGE_TOP)/
+ chmod -R og=rX $(IMAGE_TOP)
+ chown -R root:root $(IMAGE_TOP)
+ dpkg --build $(IMAGE_TOP) $(DEB_DEST)
+ rm -f -r $(IMAGE_TOP)
+ifeq ($(strip $(do_clean)),YES)
+ $(MAKE) $(EXTRAV_ARG) $(FLAV_ARG) $(CROSS_ARG) ARCH=$(KERNEL_ARCH) clean
+ rm -f stamp-build
+endif
+ echo done > stamp-image
+
+# This for STOP_FOR_BIN86
+endif
+
+# This endif is for HAVE_VALID_PACKAGE_VERSION
+endif
+
+#This endif is for IN_KERNEL_DIR
+endif
+
+
+# only generate module image packages
+modules-image modules_image: configure
+ifeq ($(strip $(shell grep -E ^[^\#]*CONFIG_MODULES $(CONFIG_FILE))),)
+ @echo Modules not configured, so not making $@
+else
+ifneq ($(strip $(HAVE_VERSION_MISMATCH)),)
+ @(echo "The changelog says we are creating $(saved_version), but I thought the version is $(version)"; exit 1)
+endif
+ -for module in $(valid_modules) ; do \
+ if test -d $$module; then \
+ (cd $$module; \
+ if ./debian/rules KVERS="$(version)" KSRC="$(SRCTOP)" \
+ KMAINT="$(pgp)" KEMAIL="$(email)" \
+ KPKG_DEST_DIR="$(KPKG_DEST_DIR)" \
+ KPKG_MAINTAINER="$(maintainer)" \
+ KPKG_EXTRAV_ARG="$(EXTRAV_ARG)" \
+ ARCH="$(KERNEL_ARCH)" \
+ KDREV="$(debian)" kdist_image; then \
+ echo "Module $$module processed fine"; \
+ else \
+ echo "Module $$module failed."; \
+ if [ "X$(strip $(ROOT_CMD))" != "X" ]; then \
+ echo "Perhaps $$module does not understand --rootcmd?"; \
+ echo "If you see messages that indicate that it is not"; \
+ echo "in fact being built as root, please file a bug "; \
+ echo "against $$module."; \
+ fi; \
+ echo "Hit return to Continue"; \
+ read ans; \
+ fi; \
+ ); \
+ fi; \
+ done
+endif
+
+# generate the modules packages and sign them
+modules: configure
+ifeq ($(strip $(shell grep -E ^[^\#]*CONFIG_MODULES $(CONFIG_FILE))),)
+ @echo Modules not configured, so not making $@
+else
+ifneq ($(strip $(HAVE_VERSION_MISMATCH)),)
+ @(echo "The changelog says we are creating $(saved_version), but I thought the version is $(version)"; exit 1)
+endif
+ -for module in $(valid_modules) ; do \
+ if test -d $$module; then \
+ (cd $$module; \
+ if ./debian/rules KVERS="$(version)" KSRC="$(SRCTOP)" \
+ KMAINT="$(pgp)" KEMAIL="$(email)" \
+ KPKG_DEST_DIR="$(KPKG_DEST_DIR)" \
+ KPKG_MAINTAINER="$(maintainer)" \
+ ARCH=$(KERNEL_ARCH) \
+ KPKG_EXTRAV_ARG="$(EXTRAV_ARG)" \
+ KDREV="$(debian)" kdist; then \
+ echo "Module $$module processed fine"; \
+ else \
+ echo "Module $$module failed."; \
+ if [ "X$(strip $(ROOT_CMD))" != "X" ]; then \
+ echo "Perhaps $$module does not understand --rootcmd?"; \
+ echo "If you see messages that indicate that it is not"; \
+ echo "in fact being built as root, please file a bug "; \
+ echo "against $$module."; \
+ fi; \
+ echo "Hit return to Continue?"; \
+ read ans; \
+ fi; \
+ ); \
+ fi; \
+ done
+endif
+
+# configure the modules packages
+modules-config modules_config: configure
+ifeq ($(strip $(shell grep -E ^[^\#]*CONFIG_MODULES $(CONFIG_FILE))),)
+ @echo Modules not configured, so not making $@
+else
+ifneq ($(strip $(HAVE_VERSION_MISMATCH)),)
+ @(echo "The changelog says we are creating $(saved_version), but I thought the version is $(version)"; exit 1)
+endif
+ -for module in $(valid_modules) ; do \
+ if test -d $$module; then \
+ (cd $$module; \
+ if ./debian/rules KVERS="$(version)" KSRC="$(SRCTOP)" \
+ KMAINT="$(pgp)" KEMAIL="$(email)" \
+ KPKG_DEST_DIR="$(KPKG_DEST_DIR)" \
+ KPKG_MAINTAINER="$(maintainer)" \
+ ARCH=$(KERNEL_ARCH) \
+ KPKG_EXTRAV_ARG="$(EXTRAV_ARG)" \
+ KDREV="$(debian)" kdist_configure; then\
+ echo "Module $$module configured fine"; \
+ else \
+ echo "Module $$module failed to configure"; \
+ echo "Hit return to Continue?"; \
+ read ans; \
+ fi; \
+ ); \
+ fi; \
+ done
+endif
+
+modules-clean modules_clean: .config
+ifeq ($(strip $(shell grep -E ^[^\#]*CONFIG_MODULES $(CONFIG_FILE))),)
+ @echo Modules not configured, so not making $@
+else
+ -for module in $(valid_modules); do \
+ if test -d $$module; then \
+ (cd $$module; \
+ if ./debian/rules KVERS="$(version)" KSRC="$(SRCTOP)" \
+ KMAINT="$(pgp)" KEMAIL="$(email)" \
+ KPKG_DEST_DIR="$(KPKG_DEST_DIR)" \
+ KPKG_MAINTAINER="$(maintainer)" \
+ ARCH=$(KERNEL_ARCH) \
+ KPKG_EXTRAV_ARG="$(EXTRAV_ARG)" \
+ KDREV="$(debian)" kdist_clean; then \
+ echo "Module $$module cleaned"; \
+ else \
+ echo "Module $$module failed to clean up"; \
+ echo "Hit return to Continue?"; \
+ read ans; \
+ fi; \
+ ); \
+ fi; \
+ done
+endif
+
+
+source diff:
+ @echo >&2 'source and diff are obsolete - use dpkg-source -b'; false
+
+define mod_inst_cmds
+ @( \
+ MODLIB=$(INSTALL_MOD_PATH)/lib/modules/$(version); \
+ cd modules; \
+ MODULES=""; \
+ inst_mod() { These="$$(cat $$1)"; MODULES="$$MODULES $$These"; \
+ mkdir -p $$MODLIB/$$2; cp $$These $$MODLIB/$$2; \
+ echo Installing modules under $$MODLIB/$$2; \
+ }; \
+ \
+ if [ -f BLOCK_MODULES ]; then inst_mod BLOCK_MODULES block; fi; \
+ if [ -f NET_MODULES ]; then inst_mod NET_MODULES net; fi; \
+ if [ -f IPV4_MODULES ]; then inst_mod IPV4_MODULES ipv4; fi; \
+ if [ -f IPV6_MODULES ]; then inst_mod IPV6_MODULES ipv6; fi; \
+ if [ -f ATM_MODULES ]; then inst_mod ATM_MODULES atm; fi; \
+ if [ -f SCSI_MODULES ]; then inst_mod SCSI_MODULES scsi; fi; \
+ if [ -f FS_MODULES ]; then inst_mod FS_MODULES fs; fi; \
+ if [ -f NLS_MODULES ]; then inst_mod NLS_MODULES fs; fi; \
+ if [ -f CDROM_MODULES ]; then inst_mod CDROM_MODULES cdrom; fi; \
+ if [ -f HAM_MODULES ]; then inst_mod HAM_MODULES net; fi; \
+ if [ -f SOUND_MODULES ]; then inst_mod SOUND_MODULES sound; fi; \
+ if [ -f VIDEO_MODULES ]; then inst_mod VIDEO_MODULES video; fi; \
+ if [ -f FC4_MODULES ]; then inst_mod FC4_MODULES fc4; fi; \
+ if [ -f IRDA_MODULES ]; then inst_mod IRDA_MODULES net; fi; \
+ if [ -f USB_MODULES ]; then inst_mod USB_MODULES usb; fi; \
+ if [ -f SK98LIN_MODULES ]; then inst_mod SK98LIN_MODULES net; fi; \
+ if [ -f SKFP_MODULES ]; then inst_mod SKFP_MODULES net; fi; \
+ if [ -f IEEE1394_MODULES ]; then inst_mod IEEE1394_MODULES ieee1394; fi; \
+ if [ -f PCMCIA_MODULES ]; then inst_mod PCMCIA_MODULES pcmcia; fi; \
+ if [ -f PCMCIA_NET_MODULES ]; then inst_mod PCMCIA_NET_MODULES pcmcia; fi; \
+ if [ -f PCMCIA_CHAR_MODULES ]; then inst_mod PCMCIA_CHAR_MODULES pcmcia; fi; \
+ if [ -f PCMCIA_SCSI_MODULES ]; then inst_mod PCMCIA_SCSI_MODULES pcmcia; fi; \
+ \
+ for f in *.o; do [ -r $$f ] && echo $$f; done > .allmods; \
+ echo $$MODULES | tr ' ' '\n' | sort | comm -23 .allmods - > .misc; \
+ if [ -s .misc ]; then inst_mod .misc misc; fi; \
+ rm -f .misc .allmods; \
+ )
+endef
+
+# 2.0.38 2.2.12 2.3.1
+# BLOCK_MODULES X X X
+# NET_MODULES X X X
+# IPV4_MODULES X X X
+# IPV6_MODULES X X
+# ATM_MODULES X
+# SCSI_MODULES X X X
+# FS_MODULES X X X
+# NLS_MODULES X X
+# CDROM_MODULES X X X
+# HAM_MODULES X X
+# SOUND_MODULES X X
+# VIDEO_MODULES X X
+# FC4_MODULES X X
+# IRDA_MODULES X X
+# USB_MODULES X
+
+.PHONY: binary binary-arch binary-indep clean debian modules modules_image
+
+test:
+ echo version: $(version)
+ echo KPKG_ARCH: $(KPKG_ARCH)
+ echo $(DEB_BUILD_ARCH)
+ echo $(DEB_BUILD_GNU_CPU)
+ echo $(DEB_BUILD_GNU_TYPE)
+ echo $(DEB_HOST_ARCH)
+ echo $(DEB_HOST_GNU_CPU)
+ echo $(DEB_HOST_GNU_SYSTEM)
+ echo $(DEB_HOST_GNU_TYPE)
+ echo $(DEB_BUILD_GNU_SYSTEM)
diff -urN linux-2.6.11/Documentation/networking/ip-sysctl.txt linux.sinabox/Documentation/networking/ip-sysctl.txt
--- linux-2.6.11/Documentation/networking/ip-sysctl.txt 2005-03-02 08:38:07.000000000 +0100
+++ linux.sinabox/Documentation/networking/ip-sysctl.txt 2005-03-26 19:02:06.000000000 +0100
@@ -661,7 +661,7 @@
TRUE: disable IPv4-mapped address feature
FALSE: enable IPv4-mapped address feature
- Default: FALSE (as specified in RFC2553bis)
+ Default: FALSE (as specified in RFC3493)
IPv6 Fragmentation:
diff -urN linux-2.6.11/drivers/char/drm/drm_ioctl.c linux.sinabox/drivers/char/drm/drm_ioctl.c
--- linux-2.6.11/drivers/char/drm/drm_ioctl.c 2005-03-02 08:37:50.000000000 +0100
+++ linux.sinabox/drivers/char/drm/drm_ioctl.c 2005-03-19 07:34:53.000000000 +0100
@@ -326,6 +326,8 @@
DRM_COPY_FROM_USER_IOCTL(sv, argp, sizeof(sv));
+ memset(&version, 0, sizeof(version));
+
dev->driver->version(&version);
retv.drm_di_major = DRM_IF_MAJOR;
retv.drm_di_minor = DRM_IF_MINOR;
diff -urN linux-2.6.11/drivers/input/serio/i8042-x86ia64io.h linux.sinabox/drivers/input/serio/i8042-x86ia64io.h
--- linux-2.6.11/drivers/input/serio/i8042-x86ia64io.h 2005-03-02 08:38:17.000000000 +0100
+++ linux.sinabox/drivers/input/serio/i8042-x86ia64io.h 2005-03-19 07:35:01.000000000 +0100
@@ -88,7 +88,7 @@
};
#endif
-#ifdef CONFIG_ACPI
+#if defined(__ia64__) && defined(CONFIG_ACPI)
#include <linux/acpi.h>
#include <acpi/acpi_bus.h>
@@ -281,7 +281,7 @@
i8042_kbd_irq = I8042_MAP_IRQ(1);
i8042_aux_irq = I8042_MAP_IRQ(12);
-#ifdef CONFIG_ACPI
+#if defined(__ia64__) && defined(CONFIG_ACPI)
if (i8042_acpi_init())
return -1;
#endif
@@ -300,7 +300,7 @@
static inline void i8042_platform_exit(void)
{
-#ifdef CONFIG_ACPI
+#if defined(__ia64__) && defined(CONFIG_ACPI)
i8042_acpi_exit();
#endif
}
diff -urN linux-2.6.11/drivers/md/raid6altivec.uc linux.sinabox/drivers/md/raid6altivec.uc
--- linux-2.6.11/drivers/md/raid6altivec.uc 2005-03-02 08:38:25.000000000 +0100
+++ linux.sinabox/drivers/md/raid6altivec.uc 2005-03-19 07:35:02.000000000 +0100
@@ -108,7 +108,11 @@
int raid6_have_altivec(void)
{
/* This assumes either all CPUs have Altivec or none does */
+#ifdef CONFIG_PPC64
return cur_cpu_spec->cpu_features & CPU_FTR_ALTIVEC;
+#else
+ return cur_cpu_spec[0]->cpu_features & CPU_FTR_ALTIVEC;
+#endif
}
#endif
diff -urN linux-2.6.11/drivers/media/video/adv7170.c linux.sinabox/drivers/media/video/adv7170.c
--- linux-2.6.11/drivers/media/video/adv7170.c 2005-03-02 08:38:26.000000000 +0100
+++ linux.sinabox/drivers/media/video/adv7170.c 2005-03-19 07:35:03.000000000 +0100
@@ -130,7 +130,7 @@
u8 block_data[32];
msg.addr = client->addr;
- msg.flags = client->flags;
+ msg.flags = 0;
while (len >= 2) {
msg.buf = (char *) block_data;
msg.len = 0;
diff -urN linux-2.6.11/drivers/media/video/adv7175.c linux.sinabox/drivers/media/video/adv7175.c
--- linux-2.6.11/drivers/media/video/adv7175.c 2005-03-02 08:38:26.000000000 +0100
+++ linux.sinabox/drivers/media/video/adv7175.c 2005-03-19 07:35:03.000000000 +0100
@@ -126,7 +126,7 @@
u8 block_data[32];
msg.addr = client->addr;
- msg.flags = client->flags;
+ msg.flags = 0;
while (len >= 2) {
msg.buf = (char *) block_data;
msg.len = 0;
diff -urN linux-2.6.11/drivers/media/video/bt819.c linux.sinabox/drivers/media/video/bt819.c
--- linux-2.6.11/drivers/media/video/bt819.c 2005-03-02 08:37:48.000000000 +0100
+++ linux.sinabox/drivers/media/video/bt819.c 2005-03-19 07:34:51.000000000 +0100
@@ -146,7 +146,7 @@
u8 block_data[32];
msg.addr = client->addr;
- msg.flags = client->flags;
+ msg.flags = 0;
while (len >= 2) {
msg.buf = (char *) block_data;
msg.len = 0;
diff -urN linux-2.6.11/drivers/media/video/saa7110.c linux.sinabox/drivers/media/video/saa7110.c
--- linux-2.6.11/drivers/media/video/saa7110.c 2005-03-02 08:37:30.000000000 +0100
+++ linux.sinabox/drivers/media/video/saa7110.c 2005-03-19 07:34:49.000000000 +0100
@@ -60,8 +60,10 @@
#define I2C_SAA7110 0x9C /* or 0x9E */
+#define SAA7110_NR_REG 0x35
+
struct saa7110 {
- unsigned char reg[54];
+ u8 reg[SAA7110_NR_REG];
int norm;
int input;
@@ -95,31 +97,28 @@
unsigned int len)
{
int ret = -1;
- u8 reg = *data++;
+ u8 reg = *data; /* first register to write to */
- len--;
+ /* Sanity check */
+ if (reg + (len - 1) > SAA7110_NR_REG)
+ return ret;
/* the saa7110 has an autoincrement function, use it if
* the adapter understands raw I2C */
if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
struct saa7110 *decoder = i2c_get_clientdata(client);
struct i2c_msg msg;
- u8 block_data[54];
- msg.len = 0;
- msg.buf = (char *) block_data;
+ msg.len = len;
+ msg.buf = (char *) data;
msg.addr = client->addr;
- msg.flags = client->flags;
- while (len >= 1) {
- msg.len = 0;
- block_data[msg.len++] = reg;
- while (len-- >= 1 && msg.len < 54)
- block_data[msg.len++] =
- decoder->reg[reg++] = *data++;
- ret = i2c_transfer(client->adapter, &msg, 1);
- }
+ msg.flags = 0;
+ ret = i2c_transfer(client->adapter, &msg, 1);
+
+ /* Cache the written data */
+ memcpy(decoder->reg + reg, data + 1, len - 1);
} else {
- while (len-- >= 1) {
+ for (++data, --len; len; len--) {
if ((ret = saa7110_write(client, reg++,
*data++)) < 0)
break;
@@ -192,7 +191,7 @@
return 0;
}
-static const unsigned char initseq[] = {
+static const unsigned char initseq[1 + SAA7110_NR_REG] = {
0, 0x4C, 0x3C, 0x0D, 0xEF, 0xBD, 0xF2, 0x03, 0x00,
/* 0x08 */ 0xF8, 0xF8, 0x60, 0x60, 0x00, 0x86, 0x18, 0x90,
/* 0x10 */ 0x00, 0x59, 0x40, 0x46, 0x42, 0x1A, 0xFF, 0xDA,
diff -urN linux-2.6.11/drivers/media/video/saa7114.c linux.sinabox/drivers/media/video/saa7114.c
--- linux-2.6.11/drivers/media/video/saa7114.c 2005-03-02 08:38:25.000000000 +0100
+++ linux.sinabox/drivers/media/video/saa7114.c 2005-03-19 07:35:02.000000000 +0100
@@ -163,7 +163,7 @@
u8 block_data[32];
msg.addr = client->addr;
- msg.flags = client->flags;
+ msg.flags = 0;
while (len >= 2) {
msg.buf = (char *) block_data;
msg.len = 0;
diff -urN linux-2.6.11/drivers/media/video/saa7185.c linux.sinabox/drivers/media/video/saa7185.c
--- linux-2.6.11/drivers/media/video/saa7185.c 2005-03-02 08:38:34.000000000 +0100
+++ linux.sinabox/drivers/media/video/saa7185.c 2005-03-19 07:35:06.000000000 +0100
@@ -118,7 +118,7 @@
u8 block_data[32];
msg.addr = client->addr;
- msg.flags = client->flags;
+ msg.flags = 0;
while (len >= 2) {
msg.buf = (char *) block_data;
msg.len = 0;
diff -urN linux-2.6.11/drivers/net/amd8111e.c linux.sinabox/drivers/net/amd8111e.c
--- linux-2.6.11/drivers/net/amd8111e.c 2005-03-02 08:38:38.000000000 +0100
+++ linux.sinabox/drivers/net/amd8111e.c 2005-03-19 07:35:06.000000000 +0100
@@ -1381,6 +1381,8 @@
if(amd8111e_restart(dev)){
spin_unlock_irq(&lp->lock);
+ if (dev->irq)
+ free_irq(dev->irq, dev);
return -ENOMEM;
}
/* Start ipg timer */
diff -urN linux-2.6.11/drivers/net/imq.c linux.sinabox/drivers/net/imq.c
--- linux-2.6.11/drivers/net/imq.c 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/drivers/net/imq.c 2005-03-26 00:49:04.000000000 +0100
@@ -0,0 +1,387 @@
+/*
+ * Pseudo-driver for the intermediate queue device.
+ *
+ * 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.
+ *
+ * Authors: Patrick McHardy, <kaber@trash.net>
+ *
+ * The first version was written by Martin Devera, <devik@cdi.cz>
+ *
+ * Credits: Jan Rafaj <imq2t@cedric.vabo.cz>
+ * - Update patch to 2.4.21
+ * Sebastian Strollo <sstrollo@nortelnetworks.com>
+ * - Fix "Dead-loop on netdevice imq"-issue
+ * Marcel Sebek <sebek64@post.cz>
+ * - Update to 2.6.2-rc1
+ *
+ * After some time of inactivity there is a group taking care
+ * of IMQ again: http://www.linuximq.net
+ *
+ *
+ * 2004/06/30 - New version of IMQ patch to kernels <=2.6.7 including
+ * the following changes:
+ *
+ * - Correction of ipv6 support "+"s issue (Hasso Tepper)
+ * - Correction of imq_init_devs() issue that resulted in
+ * kernel OOPS unloading IMQ as module (Norbert Buchmuller)
+ * - Addition of functionality to choose number of IMQ devices
+ * during kernel config (Andre Correa)
+ * - Addition of functionality to choose how IMQ hooks on
+ * PRE and POSTROUTING (after or before NAT) (Andre Correa)
+ * - Cosmetic corrections (Norbert Buchmuller) (Andre Correa)
+ *
+ * More info at: http://www.linuximq.net/ (2004-04-22)
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/moduleparam.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/if_arp.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+ #include <linux/netfilter_ipv6.h>
+#endif
+#include <linux/imq.h>
+#include <net/pkt_sched.h>
+
+static nf_hookfn imq_nf_hook;
+
+static struct nf_hook_ops imq_ingress_ipv4 = {
+ .hook = imq_nf_hook,
+ .owner = THIS_MODULE,
+ .pf = PF_INET,
+ .hooknum = NF_IP_PRE_ROUTING,
+#if defined(CONFIG_IMQ_BEHAVIOR_BA) || defined(CONFIG_IMQ_BEHAVIOR_BB)
+ .priority = NF_IP_PRI_MANGLE + 1
+#else
+ .priority = NF_IP_PRI_NAT_DST + 1
+#endif
+};
+
+static struct nf_hook_ops imq_egress_ipv4 = {
+ .hook = imq_nf_hook,
+ .owner = THIS_MODULE,
+ .pf = PF_INET,
+ .hooknum = NF_IP_POST_ROUTING,
+#if defined(CONFIG_IMQ_BEHAVIOR_AA) || defined(CONFIG_IMQ_BEHAVIOR_BA)
+ .priority = NF_IP_PRI_LAST
+#else
+ .priority = NF_IP_PRI_NAT_SRC - 1
+#endif
+};
+
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+static struct nf_hook_ops imq_ingress_ipv6 = {
+ .hook = imq_nf_hook,
+ .owner = THIS_MODULE,
+ .pf = PF_INET6,
+ .hooknum = NF_IP6_PRE_ROUTING,
+#if defined(CONFIG_IMQ_BEHAVIOR_BA) || defined(CONFIG_IMQ_BEHAVIOR_BB)
+ .priority = NF_IP6_PRI_MANGLE + 1
+#else
+ .priority = NF_IP6_PRI_NAT_DST + 1
+#endif
+};
+
+static struct nf_hook_ops imq_egress_ipv6 = {
+ .hook = imq_nf_hook,
+ .owner = THIS_MODULE,
+ .pf = PF_INET6,
+ .hooknum = NF_IP6_POST_ROUTING,
+#if defined(CONFIG_IMQ_BEHAVIOR_AA) || defined(CONFIG_IMQ_BEHAVIOR_BA)
+ .priority = NF_IP6_PRI_LAST
+#else
+ .priority = NF_IP6_PRI_NAT_SRC - 1
+#endif
+};
+#endif
+
+#if defined(CONFIG_IMQ_NUM_DEVS)
+static unsigned int numdevs = CONFIG_IMQ_NUM_DEVS;
+#else
+static unsigned int numdevs = 2;
+#endif
+
+static struct net_device *imq_devs;
+
+static struct net_device_stats *imq_get_stats(struct net_device *dev)
+{
+ return (struct net_device_stats *)dev->priv;
+}
+
+/* called for packets kfree'd in qdiscs at places other than enqueue */
+static void imq_skb_destructor(struct sk_buff *skb)
+{
+ struct nf_info *info = skb->nf_info;
+
+ if (info) {
+ if (info->indev)
+ dev_put(info->indev);
+ if (info->outdev)
+ dev_put(info->outdev);
+ kfree(info);
+ }
+}
+
+static int imq_dev_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct net_device_stats *stats = (struct net_device_stats*) dev->priv;
+
+ stats->tx_bytes += skb->len;
+ stats->tx_packets++;
+
+ skb->imq_flags = 0;
+ skb->destructor = NULL;
+
+ dev->trans_start = jiffies;
+ nf_reinject(skb, skb->nf_info, NF_ACCEPT);
+ return 0;
+}
+
+static int imq_nf_queue(struct sk_buff *skb, struct nf_info *info, void *data)
+{
+ struct net_device *dev;
+ struct net_device_stats *stats;
+ struct sk_buff *skb2 = NULL;
+ struct Qdisc *q;
+ unsigned int index = skb->imq_flags&IMQ_F_IFMASK;
+ int ret = -1;
+
+ if (index > numdevs)
+ return -1;
+
+ dev = imq_devs + index;
+ if (!(dev->flags & IFF_UP)) {
+ skb->imq_flags = 0;
+ nf_reinject(skb, info, NF_ACCEPT);
+ return 0;
+ }
+ dev->last_rx = jiffies;
+
+ if (skb->destructor) {
+ skb2 = skb;
+ skb = skb_clone(skb, GFP_ATOMIC);
+ if (!skb)
+ return -1;
+ }
+ skb->nf_info = info;
+
+ stats = (struct net_device_stats *)dev->priv;
+ stats->rx_bytes+= skb->len;
+ stats->rx_packets++;
+
+ spin_lock_bh(&dev->queue_lock);
+ q = dev->qdisc;
+ if (q->enqueue) {
+ q->enqueue(skb_get(skb), q);
+ if (skb_shared(skb)) {
+ skb->destructor = imq_skb_destructor;
+ kfree_skb(skb);
+ ret = 0;
+ }
+ }
+ if (spin_is_locked(&dev->xmit_lock))
+ netif_schedule(dev);
+ else
+
+ while (!netif_queue_stopped(dev) &&
+ qdisc_restart(dev)<0)
+ /* NOTHING */;
+
+ spin_unlock_bh(&dev->queue_lock);
+
+ if (skb2)
+ kfree_skb(ret ? skb : skb2);
+
+ return ret;
+}
+
+static unsigned int imq_nf_hook(unsigned int hook, struct sk_buff **pskb,
+ const struct net_device *indev,
+ const struct net_device *outdev,
+ int (*okfn)(struct sk_buff *))
+{
+ if ((*pskb)->imq_flags & IMQ_F_ENQUEUE)
+ return NF_QUEUE;
+
+ return NF_ACCEPT;
+}
+
+
+static int __init imq_init_hooks(void)
+{
+ int err;
+
+ err = nf_register_queue_handler(PF_INET, imq_nf_queue, NULL);
+ if (err > 0)
+ goto err1;
+ if ((err = nf_register_hook(&imq_ingress_ipv4)))
+ goto err2;
+ if ((err = nf_register_hook(&imq_egress_ipv4)))
+ goto err3;
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+ if ((err = nf_register_queue_handler(PF_INET6, imq_nf_queue, NULL)))
+ goto err4;
+ if ((err = nf_register_hook(&imq_ingress_ipv6)))
+ goto err5;
+ if ((err = nf_register_hook(&imq_egress_ipv6)))
+ goto err6;
+#endif
+
+ return 0;
+
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+err6:
+ nf_unregister_hook(&imq_ingress_ipv6);
+err5:
+ nf_unregister_queue_handler(PF_INET6);
+err4:
+ nf_unregister_hook(&imq_egress_ipv4);
+#endif
+err3:
+ nf_unregister_hook(&imq_ingress_ipv4);
+err2:
+ nf_unregister_queue_handler(PF_INET);
+err1:
+ return err;
+}
+
+static void __exit imq_unhook(void)
+{
+ nf_unregister_hook(&imq_ingress_ipv4);
+ nf_unregister_hook(&imq_egress_ipv4);
+ nf_unregister_queue_handler(PF_INET);
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+ nf_unregister_hook(&imq_ingress_ipv6);
+ nf_unregister_hook(&imq_egress_ipv6);
+ nf_unregister_queue_handler(PF_INET6);
+#endif
+}
+
+static int __init imq_dev_init(struct net_device *dev)
+{
+ dev->hard_start_xmit = imq_dev_xmit;
+ dev->type = ARPHRD_VOID;
+ dev->mtu = 1500;
+ dev->tx_queue_len = 30;
+ dev->flags = IFF_NOARP;
+ dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);
+ if (dev->priv == NULL)
+ return -ENOMEM;
+ memset(dev->priv, 0, sizeof(struct net_device_stats));
+ dev->get_stats = imq_get_stats;
+
+ return 0;
+}
+
+static void imq_dev_uninit(struct net_device *dev)
+{
+ kfree(dev->priv);
+}
+
+static int __init imq_init_devs(void)
+{
+ struct net_device *dev;
+ int i,j;
+ j = numdevs;
+
+ if (!numdevs || numdevs > IMQ_MAX_DEVS) {
+ printk(KERN_ERR "IMQ: numdevs has to be betweed 1 and %u\n",
+ IMQ_MAX_DEVS);
+ return -EINVAL;
+ }
+
+ imq_devs = kmalloc(sizeof(struct net_device) * numdevs, GFP_KERNEL);
+ if (!imq_devs)
+ return -ENOMEM;
+ memset(imq_devs, 0, sizeof(struct net_device) * numdevs);
+
+ /* we start counting at zero */
+ numdevs--;
+
+ for (i = 0, dev = imq_devs; i <= numdevs; i++, dev++) {
+ SET_MODULE_OWNER(dev);
+ strcpy(dev->name, "imq%d");
+ dev->init = imq_dev_init;
+ dev->uninit = imq_dev_uninit;
+
+ if (register_netdev(dev) < 0)
+ goto err_register;
+ }
+ printk(KERN_INFO "IMQ starting with %u devices...\n", j);
+ return 0;
+
+err_register:
+ for (; i; i--)
+ unregister_netdev(--dev);
+ kfree(imq_devs);
+ return -EIO;
+}
+
+static void imq_cleanup_devs(void)
+{
+ int i;
+ struct net_device *dev = imq_devs;
+
+ for (i = 0; i <= numdevs; i++)
+ unregister_netdev(dev++);
+
+ kfree(imq_devs);
+}
+
+static int __init imq_init_module(void)
+{
+ int err;
+
+ if ((err = imq_init_devs())) {
+ printk(KERN_ERR "IMQ: Error trying imq_init_devs()\n");
+ return err;
+ }
+ if ((err = imq_init_hooks())) {
+ printk(KERN_ERR "IMQ: Error trying imq_init_hooks()\n");
+ imq_cleanup_devs();
+ return err;
+ }
+
+ printk(KERN_INFO "IMQ driver loaded successfully.\n");
+
+#if defined(CONFIG_IMQ_BEHAVIOR_BA) || defined(CONFIG_IMQ_BEHAVIOR_BB)
+ printk(KERN_INFO "\tHooking IMQ before NAT on PREROUTING.\n");
+#else
+ printk(KERN_INFO "\tHooking IMQ after NAT on PREROUTING.\n");
+#endif
+#if defined(CONFIG_IMQ_BEHAVIOR_AB) || defined(CONFIG_IMQ_BEHAVIOR_BB)
+ printk(KERN_INFO "\tHooking IMQ before NAT on POSTROUTING.\n");
+#else
+ printk(KERN_INFO "\tHooking IMQ after NAT on POSTROUTING.\n");
+#endif
+
+ return 0;
+}
+
+static void __exit imq_cleanup_module(void)
+{
+ imq_unhook();
+ imq_cleanup_devs();
+ printk(KERN_INFO "IMQ driver unloaded successfully.\n");
+}
+
+
+module_init(imq_init_module);
+module_exit(imq_cleanup_module);
+
+module_param(numdevs, int, 0);
+MODULE_PARM_DESC(numdevs, "number of IMQ devices (how many imq* devices will be created)");
+MODULE_AUTHOR("");
+MODULE_DESCRIPTION("Pseudo-driver for the intermediate queue device. See http://www.linuximq.net/ for more information.");
+MODULE_LICENSE("GPL");
+
+
diff -urN linux-2.6.11/drivers/net/Kconfig linux.sinabox/drivers/net/Kconfig
--- linux-2.6.11/drivers/net/Kconfig 2005-03-02 08:38:25.000000000 +0100
+++ linux.sinabox/drivers/net/Kconfig 2005-03-26 00:49:04.000000000 +0100
@@ -81,6 +81,129 @@
To compile this driver as a module, choose M here: the module
will be called eql. If unsure, say N.
+config IMQ
+ tristate "IMQ (intermediate queueing device) support"
+ depends on NETDEVICES && NETFILTER
+ ---help---
+ The IMQ device(s) is used as placeholder for QoS queueing disciplines.
+ Every packet entering/leaving the IP stack can be directed through
+ the IMQ device where it's enqueued/dequeued to the attached qdisc.
+ This allows you to treat network devices as classes and distribute
+ bandwidth among them. Iptables is used to specify through which IMQ
+ device, if any, packets travel.
+
+ More information at: http://www.linuximq.net/
+
+ To compile this driver as a module, choose M here: the module
+ will be called imq. If unsure, say N.
+
+choice
+ prompt "IMQ behavior (PRE/POSTROUTING)"
+ depends on IMQ
+ default IMQ_BEHAVIOR_BA
+ help
+
+ This settings defines how IMQ behaves in respect to its
+ hooking in PREROUTING and POSTROUTING.
+
+ IMQ can work in any of the following ways:
+
+ PREROUTING | POSTROUTING
+ -----------------|-------------------
+ #1 After NAT | After NAT
+ #2 After NAT | Before NAT
+ #3 Before NAT | After NAT
+ #4 Before NAT | Before NAT
+
+ The default behavior is to hook before NAT on PREROUTING
+ and after NAT on POSTROUTING (#3).
+
+ This settings are specially usefull when trying to use IMQ
+ to shape NATed clients.
+
+ More information can be found at: www.linuximq.net
+
+ If not sure leave the default settings alone.
+
+config IMQ_BEHAVIOR_AA
+ bool "IMQ AA"
+ help
+ This settings defines how IMQ behaves in respect to its
+ hooking in PREROUTING and POSTROUTING.
+
+ Choosing this option will make IMQ hook like this:
+
+ PREROUTING: After NAT
+ POSTROUTING: After NAT
+
+ More information can be found at: www.linuximq.net
+
+ If not sure leave the default settings alone.
+
+config IMQ_BEHAVIOR_AB
+ bool "IMQ AB"
+ help
+ This settings defines how IMQ behaves in respect to its
+ hooking in PREROUTING and POSTROUTING.
+
+ Choosing this option will make IMQ hook like this:
+
+ PREROUTING: After NAT
+ POSTROUTING: Before NAT
+
+ More information can be found at: www.linuximq.net
+
+ If not sure leave the default settings alone.
+
+config IMQ_BEHAVIOR_BA
+ bool "IMQ BA"
+ help
+ This settings defines how IMQ behaves in respect to its
+ hooking in PREROUTING and POSTROUTING.
+
+ Choosing this option will make IMQ hook like this:
+
+ PREROUTING: Before NAT
+ POSTROUTING: After NAT
+
+ More information can be found at: www.linuximq.net
+
+ If not sure leave the default settings alone.
+
+config IMQ_BEHAVIOR_BB
+ bool "IMQ BB"
+ help
+ This settings defines how IMQ behaves in respect to its
+ hooking in PREROUTING and POSTROUTING.
+
+ Choosing this option will make IMQ hook like this:
+
+ PREROUTING: Before NAT
+ POSTROUTING: Before NAT
+
+ More information can be found at: www.linuximq.net
+
+ If not sure leave the default settings alone.
+
+endchoice
+
+config IMQ_NUM_DEVS
+
+ int "Number of IMQ devices"
+ range 2 8
+ depends on IMQ
+ default "2"
+ help
+
+ This settings defines how many IMQ devices will be
+ created.
+
+ The default value is 2.
+
+ More information can be found at: www.linuximq.net
+
+ If not sure leave the default settings alone.
+
config TUN
tristate "Universal TUN/TAP device driver support"
depends on NETDEVICES
diff -urN linux-2.6.11/drivers/net/Makefile linux.sinabox/drivers/net/Makefile
--- linux-2.6.11/drivers/net/Makefile 2005-03-02 08:37:52.000000000 +0100
+++ linux.sinabox/drivers/net/Makefile 2005-03-26 00:49:04.000000000 +0100
@@ -113,6 +113,7 @@
endif
obj-$(CONFIG_DUMMY) += dummy.o
+obj-$(CONFIG_IMQ) += imq.o
obj-$(CONFIG_DE600) += de600.o
obj-$(CONFIG_DE620) += de620.o
obj-$(CONFIG_LANCE) += lance.o
diff -urN linux-2.6.11/drivers/net/ppp_async.c linux.sinabox/drivers/net/ppp_async.c
--- linux-2.6.11/drivers/net/ppp_async.c 2005-03-02 08:38:17.000000000 +0100
+++ linux.sinabox/drivers/net/ppp_async.c 2005-03-19 07:35:01.000000000 +0100
@@ -1000,7 +1000,7 @@
data += 4;
dlen -= 4;
/* data[0] is code, data[1] is length */
- while (dlen >= 2 && dlen >= data[1]) {
+ while (dlen >= 2 && dlen >= data[1] && data[1] >= 2) {
switch (data[0]) {
case LCP_MRU:
val = (data[2] << 8) + data[3];
diff -urN linux-2.6.11/drivers/net/r8169.c linux.sinabox/drivers/net/r8169.c
--- linux-2.6.11/drivers/net/r8169.c 2005-03-02 08:38:09.000000000 +0100
+++ linux.sinabox/drivers/net/r8169.c 2005-03-19 07:34:57.000000000 +0100
@@ -1683,16 +1683,19 @@
rtl8169_make_unusable_by_asic(desc);
}
-static inline void rtl8169_return_to_asic(struct RxDesc *desc, int rx_buf_sz)
+static inline void rtl8169_mark_to_asic(struct RxDesc *desc, u32 rx_buf_sz)
{
- desc->opts1 |= cpu_to_le32(DescOwn + rx_buf_sz);
+ u32 eor = le32_to_cpu(desc->opts1) & RingEnd;
+
+ desc->opts1 = cpu_to_le32(DescOwn | eor | rx_buf_sz);
}
-static inline void rtl8169_give_to_asic(struct RxDesc *desc, dma_addr_t mapping,
- int rx_buf_sz)
+static inline void rtl8169_map_to_asic(struct RxDesc *desc, dma_addr_t mapping,
+ u32 rx_buf_sz)
{
desc->addr = cpu_to_le64(mapping);
- desc->opts1 |= cpu_to_le32(DescOwn + rx_buf_sz);
+ wmb();
+ rtl8169_mark_to_asic(desc, rx_buf_sz);
}
static int rtl8169_alloc_rx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff,
@@ -1712,7 +1715,7 @@
mapping = pci_map_single(pdev, skb->tail, rx_buf_sz,
PCI_DMA_FROMDEVICE);
- rtl8169_give_to_asic(desc, mapping, rx_buf_sz);
+ rtl8169_map_to_asic(desc, mapping, rx_buf_sz);
out:
return ret;
@@ -2150,7 +2153,7 @@
skb_reserve(skb, NET_IP_ALIGN);
eth_copy_and_sum(skb, sk_buff[0]->tail, pkt_size, 0);
*sk_buff = skb;
- rtl8169_return_to_asic(desc, rx_buf_sz);
+ rtl8169_mark_to_asic(desc, rx_buf_sz);
ret = 0;
}
}
diff -urN linux-2.6.11/drivers/net/sis900.c linux.sinabox/drivers/net/sis900.c
--- linux-2.6.11/drivers/net/sis900.c 2005-03-02 08:38:08.000000000 +0100
+++ linux.sinabox/drivers/net/sis900.c 2005-03-19 07:34:56.000000000 +0100
@@ -236,7 +236,7 @@
signature = (u16) read_eeprom(ioaddr, EEPROMSignature);
if (signature == 0xffff || signature == 0x0000) {
printk (KERN_INFO "%s: Error EERPOM read %x\n",
- net_dev->name, signature);
+ pci_name(pci_dev), signature);
return 0;
}
@@ -268,7 +268,7 @@
if (!isa_bridge)
isa_bridge = pci_get_device(PCI_VENDOR_ID_SI, 0x0018, isa_bridge);
if (!isa_bridge) {
- printk("%s: Can not find ISA bridge\n", net_dev->name);
+ printk("%s: Can not find ISA bridge\n", pci_name(pci_dev));
return 0;
}
pci_read_config_byte(isa_bridge, 0x48, &reg);
@@ -456,10 +456,6 @@
net_dev->tx_timeout = sis900_tx_timeout;
net_dev->watchdog_timeo = TX_TIMEOUT;
net_dev->ethtool_ops = &sis900_ethtool_ops;
-
- ret = register_netdev(net_dev);
- if (ret)
- goto err_unmap_rx;
/* Get Mac address according to the chip revision */
pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision);
@@ -476,7 +472,7 @@
if (ret == 0) {
ret = -ENODEV;
- goto err_out_unregister;
+ goto err_unmap_rx;
}
/* 630ET : set the mii access mode as software-mode */
@@ -486,7 +482,7 @@
/* probe for mii transceiver */
if (sis900_mii_probe(net_dev) == 0) {
ret = -ENODEV;
- goto err_out_unregister;
+ goto err_unmap_rx;
}
/* save our host bridge revision */
@@ -496,6 +492,10 @@
pci_dev_put(dev);
}
+ ret = register_netdev(net_dev);
+ if (ret)
+ goto err_unmap_rx;
+
/* print some information about our NIC */
printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", net_dev->name,
card_name, ioaddr, net_dev->irq);
@@ -505,8 +505,6 @@
return 0;
- err_out_unregister:
- unregister_netdev(net_dev);
err_unmap_rx:
pci_free_consistent(pci_dev, RX_TOTAL_SIZE, sis_priv->rx_ring,
sis_priv->rx_ring_dma);
@@ -533,6 +531,7 @@
static int __init sis900_mii_probe(struct net_device * net_dev)
{
struct sis900_private * sis_priv = net_dev->priv;
+ const char *dev_name = pci_name(sis_priv->pci_dev);
u16 poll_bit = MII_STAT_LINK, status = 0;
unsigned long timeout = jiffies + 5 * HZ;
int phy_addr;
@@ -582,21 +581,20 @@
mii_phy->phy_types =
(mii_status & (MII_STAT_CAN_TX_FDX | MII_STAT_CAN_TX)) ? LAN : HOME;
printk(KERN_INFO "%s: %s transceiver found at address %d.\n",
- net_dev->name, mii_chip_table[i].name,
+ dev_name, mii_chip_table[i].name,
phy_addr);
break;
}
if( !mii_chip_table[i].phy_id1 ) {
printk(KERN_INFO "%s: Unknown PHY transceiver found at address %d.\n",
- net_dev->name, phy_addr);
+ dev_name, phy_addr);
mii_phy->phy_types = UNKNOWN;
}
}
if (sis_priv->mii == NULL) {
- printk(KERN_INFO "%s: No MII transceivers found!\n",
- net_dev->name);
+ printk(KERN_INFO "%s: No MII transceivers found!\n", dev_name);
return 0;
}
@@ -621,7 +619,7 @@
poll_bit ^= (mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS) & poll_bit);
if (time_after_eq(jiffies, timeout)) {
printk(KERN_WARNING "%s: reset phy and link down now\n",
- net_dev->name);
+ dev_name);
return -ETIME;
}
}
@@ -691,7 +689,7 @@
sis_priv->mii = default_phy;
sis_priv->cur_phy = default_phy->phy_addr;
printk(KERN_INFO "%s: Using transceiver found at address %d as default\n",
- net_dev->name,sis_priv->cur_phy);
+ pci_name(sis_priv->pci_dev), sis_priv->cur_phy);
}
status = mdio_read(net_dev, sis_priv->cur_phy, MII_CONTROL);
diff -urN linux-2.6.11/drivers/net/tun.c linux.sinabox/drivers/net/tun.c
--- linux-2.6.11/drivers/net/tun.c 2005-03-02 08:38:08.000000000 +0100
+++ linux.sinabox/drivers/net/tun.c 2005-03-19 07:34:56.000000000 +0100
@@ -229,7 +229,7 @@
size_t len = count;
if (!(tun->flags & TUN_NO_PI)) {
- if ((len -= sizeof(pi)) > len)
+ if ((len -= sizeof(pi)) > count)
return -EINVAL;
if(memcpy_fromiovec((void *)&pi, iv, sizeof(pi)))
diff -urN linux-2.6.11/drivers/net/via-rhine.c linux.sinabox/drivers/net/via-rhine.c
--- linux-2.6.11/drivers/net/via-rhine.c 2005-03-02 08:38:32.000000000 +0100
+++ linux.sinabox/drivers/net/via-rhine.c 2005-03-19 07:35:04.000000000 +0100
@@ -1197,8 +1197,10 @@
dev->name, rp->pdev->irq);
rc = alloc_ring(dev);
- if (rc)
+ if (rc) {
+ free_irq(rp->pdev->irq, dev);
return rc;
+ }
alloc_rbufs(dev);
alloc_tbufs(dev);
rhine_chip_reset(dev);
@@ -1899,6 +1901,9 @@
struct rhine_private *rp = netdev_priv(dev);
void __iomem *ioaddr = rp->base;
+ if (!(rp->quirks & rqWOL))
+ return; /* Nothing to do for non-WOL adapters */
+
rhine_power_init(dev);
/* Make sure we use pattern 0, 1 and not 4, 5 */
diff -urN linux-2.6.11/drivers/net/wan/hd6457x.c linux.sinabox/drivers/net/wan/hd6457x.c
--- linux-2.6.11/drivers/net/wan/hd6457x.c 2005-03-02 08:37:50.000000000 +0100
+++ linux.sinabox/drivers/net/wan/hd6457x.c 2005-03-19 07:34:53.000000000 +0100
@@ -315,7 +315,7 @@
#endif
stats->rx_packets++;
stats->rx_bytes += skb->len;
- skb->dev->last_rx = jiffies;
+ dev->last_rx = jiffies;
skb->protocol = hdlc_type_trans(skb, dev);
netif_rx(skb);
}
diff -urN linux-2.6.11/drivers/pci/hotplug/pciehp_ctrl.c linux.sinabox/drivers/pci/hotplug/pciehp_ctrl.c
--- linux-2.6.11/drivers/pci/hotplug/pciehp_ctrl.c 2005-03-02 08:37:49.000000000 +0100
+++ linux.sinabox/drivers/pci/hotplug/pciehp_ctrl.c 2005-03-19 07:34:52.000000000 +0100
@@ -1354,10 +1354,11 @@
dbg("PCI Bridge Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n",
ctrl->seg, func->bus, func->device, func->function);
bridge_slot_remove(func);
- } else
+ } else {
dbg("PCI Function Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n",
ctrl->seg, func->bus, func->device, func->function);
slot_remove(func);
+ }
func = pciehp_slot_find(ctrl->slot_bus, device, 0);
}
diff -urN linux-2.6.11/fs/cramfs/inode.c linux.sinabox/fs/cramfs/inode.c
--- linux-2.6.11/fs/cramfs/inode.c 2005-03-02 08:37:47.000000000 +0100
+++ linux.sinabox/fs/cramfs/inode.c 2005-03-19 07:34:50.000000000 +0100
@@ -70,6 +70,7 @@
inode->i_data.a_ops = &cramfs_aops;
} else {
inode->i_size = 0;
+ inode->i_blocks = 0;
init_special_inode(inode, inode->i_mode,
old_decode_dev(cramfs_inode->size));
}
diff -urN linux-2.6.11/fs/eventpoll.c linux.sinabox/fs/eventpoll.c
--- linux-2.6.11/fs/eventpoll.c 2005-03-02 08:38:07.000000000 +0100
+++ linux.sinabox/fs/eventpoll.c 2005-03-19 07:34:55.000000000 +0100
@@ -619,6 +619,7 @@
return error;
}
+#define MAX_EVENTS (INT_MAX / sizeof(struct epoll_event))
/*
* Implement the event wait interface for the eventpoll file. It is the kernel
@@ -635,7 +636,7 @@
current, epfd, events, maxevents, timeout));
/* The maximum number of event must be greater than zero */
- if (maxevents <= 0)
+ if (maxevents <= 0 || maxevents > MAX_EVENTS)
return -EINVAL;
/* Verify that the area passed by the user is writeable */
diff -urN linux-2.6.11/fs/exec.c linux.sinabox/fs/exec.c
--- linux-2.6.11/fs/exec.c 2005-03-02 08:38:06.000000000 +0100
+++ linux.sinabox/fs/exec.c 2005-03-19 07:34:55.000000000 +0100
@@ -814,7 +814,7 @@
{
/* buf must be at least sizeof(tsk->comm) in size */
task_lock(tsk);
- memcpy(buf, tsk->comm, sizeof(tsk->comm));
+ strncpy(buf, tsk->comm, sizeof(tsk->comm));
task_unlock(tsk);
}
diff -urN linux-2.6.11/include/linux/icmpv6.h linux.sinabox/include/linux/icmpv6.h
--- linux-2.6.11/include/linux/icmpv6.h 2005-03-02 08:37:50.000000000 +0100
+++ linux.sinabox/include/linux/icmpv6.h 2005-03-26 19:02:06.000000000 +0100
@@ -40,14 +40,18 @@
struct icmpv6_nd_ra {
__u8 hop_limit;
#if defined(__LITTLE_ENDIAN_BITFIELD)
- __u8 reserved:6,
+ __u8 reserved:3,
+ router_pref:2,
+ home_agent:1,
other:1,
managed:1;
#elif defined(__BIG_ENDIAN_BITFIELD)
__u8 managed:1,
other:1,
- reserved:6;
+ home_agent:1,
+ router_pref:2,
+ reserved:3;
#else
#error "Please fix <asm/byteorder.h>"
#endif
@@ -70,6 +74,8 @@
#define icmp6_addrconf_managed icmp6_dataun.u_nd_ra.managed
#define icmp6_addrconf_other icmp6_dataun.u_nd_ra.other
#define icmp6_rt_lifetime icmp6_dataun.u_nd_ra.rt_lifetime
+#define icmp6_home_agent icmp6_dataun.u_nd_ra.home_agent
+#define icmp6_router_pref icmp6_dataun.u_nd_ra.router_pref
};
diff -urN linux-2.6.11/include/linux/imq.h linux.sinabox/include/linux/imq.h
--- linux-2.6.11/include/linux/imq.h 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/include/linux/imq.h 2005-03-26 00:49:04.000000000 +0100
@@ -0,0 +1,9 @@
+#ifndef _IMQ_H
+#define _IMQ_H
+
+#define IMQ_MAX_DEVS 16
+
+#define IMQ_F_IFMASK 0x7f
+#define IMQ_F_ENQUEUE 0x80
+
+#endif /* _IMQ_H */
diff -urN linux-2.6.11/include/linux/in6.h linux.sinabox/include/linux/in6.h
--- linux-2.6.11/include/linux/in6.h 2005-03-02 08:38:12.000000000 +0100
+++ linux.sinabox/include/linux/in6.h 2005-03-26 19:02:06.000000000 +0100
@@ -40,14 +40,14 @@
#define s6_addr32 in6_u.u6_addr32
};
-/* IPv6 Wildcard Address (::) and Loopback Address (::1) defined in RFC2553
+/* IPv6 Wildcard Address (::) and Loopback Address (::1) defined in RFC3493
* NOTE: Be aware the IN6ADDR_* constants and in6addr_* externals are defined
* in network byte order, not in host byte order as are the IPv4 equivalents
*/
#if 0
extern const struct in6_addr in6addr_any;
-#define IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }
#endif
+#define IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }
extern const struct in6_addr in6addr_loopback;
#define IN6ADDR_LOOPBACK_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } }
@@ -56,7 +56,7 @@
__u16 sin6_port; /* Transport layer port # */
__u32 sin6_flowinfo; /* IPv6 flow information */
struct in6_addr sin6_addr; /* IPv6 address */
- __u32 sin6_scope_id; /* scope id (new in RFC2553) */
+ __u32 sin6_scope_id; /* scope id */
};
struct ipv6_mreq {
@@ -198,4 +198,7 @@
* MCAST_MSFILTER 48
*/
+/* Netfilter */
+#define IPV6_NF_ORIGINAL_DST 80
+
#endif
diff -urN linux-2.6.11/include/linux/ip.h linux.sinabox/include/linux/ip.h
--- linux-2.6.11/include/linux/ip.h 2005-03-02 08:37:52.000000000 +0100
+++ linux.sinabox/include/linux/ip.h 2005-03-26 19:02:06.000000000 +0100
@@ -152,6 +152,7 @@
};
#define IPCORK_OPT 1 /* ip-options has been held in ipcork.opt */
+#define IPCORK_ALLFRAG 2 /* IPv6: always fragment */
static inline struct inet_sock *inet_sk(const struct sock *sk)
{
diff -urN linux-2.6.11/include/linux/ipv6.h linux.sinabox/include/linux/ipv6.h
--- linux-2.6.11/include/linux/ipv6.h 2005-03-02 08:38:13.000000000 +0100
+++ linux.sinabox/include/linux/ipv6.h 2005-03-26 19:02:06.000000000 +0100
@@ -145,6 +145,9 @@
__s32 max_desync_factor;
#endif
__s32 max_addresses;
+#ifdef CONFIG_IPV6_MROUTE
+ __s32 mc_forwarding;
+#endif
void *sysctl;
};
@@ -167,6 +170,9 @@
DEVCONF_MAX_DESYNC_FACTOR,
DEVCONF_MAX_ADDRESSES,
DEVCONF_FORCE_MLD_VERSION,
+#ifdef CONFIG_IPV6_MROUTE
+ DEVCONF_MCFORWARDING,
+#endif
DEVCONF_MAX
};
diff -urN linux-2.6.11/include/linux/ipv6_route.h linux.sinabox/include/linux/ipv6_route.h
--- linux-2.6.11/include/linux/ipv6_route.h 2005-03-02 08:37:50.000000000 +0100
+++ linux.sinabox/include/linux/ipv6_route.h 2005-03-26 19:02:06.000000000 +0100
@@ -19,6 +19,12 @@
#define RTF_ADDRCONF 0x00040000 /* addrconf route - RA */
#define RTF_PREFIX_RT 0x00080000 /* A prefix only route - RA */
+#define RTF_PREF_HIGH 0x08000000
+#define RTF_PREF_LOW 0x18000000
+#define RTF_PREF_INVAL 0x10000000
+#define RTF_PREF_MASK 0x18000000
+#define RTF_PREF(pref) (((pref)&3)<<27)
+
#define RTF_NONEXTHOP 0x00200000 /* route with no nexthop */
#define RTF_EXPIRES 0x00400000
@@ -28,6 +34,11 @@
#define RTF_LOCAL 0x80000000
+#ifdef __KERNEL__
+#define IPV6_UNSHIFT_PREF(flag) (((flag)&RTF_PREF_MASK)>>27)
+#define IPV6_SIGNEDPREF(pref) ((((pref)+2)&3)-2)
+#endif
+
struct in6_rtmsg {
struct in6_addr rtmsg_dst;
struct in6_addr rtmsg_src;
diff -urN linux-2.6.11/include/linux/mroute6.h linux.sinabox/include/linux/mroute6.h
--- linux-2.6.11/include/linux/mroute6.h 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/include/linux/mroute6.h 2005-03-26 19:02:06.000000000 +0100
@@ -0,0 +1,296 @@
+#ifndef __LINUX_MROUTE6_H
+#define __LINUX_MROUTE6_H
+
+#include <linux/sockios.h>
+
+/*
+ * Based on the MROUTING 3.5 defines primarily to keep
+ * source compatibility with BSD.
+ *
+ * See the pim6sd code for the original history.
+ *
+ * Protocol Independent Multicast (PIM) data structures included
+ * Carlos Picoto (cap@di.fc.ul.pt)
+ *
+ */
+
+#define MRT6_BASE 200
+#define MRT6_INIT (MRT6_BASE) /* Activate the kernel mroute code */
+#define MRT6_DONE (MRT6_BASE+1) /* Shutdown the kernel mroute */
+#define MRT6_ADD_MIF (MRT6_BASE+2) /* Add a virtual interface */
+#define MRT6_DEL_MIF (MRT6_BASE+3) /* Delete a virtual interface */
+#define MRT6_ADD_MFC (MRT6_BASE+4) /* Add a multicast forwarding entry */
+#define MRT6_DEL_MFC (MRT6_BASE+5) /* Delete a multicast forwarding entry */
+#define MRT6_VERSION (MRT6_BASE+6) /* Get the kernel multicast version */
+#define MRT6_ASSERT (MRT6_BASE+7) /* Activate PIM assert mode */
+#define MRT6_PIM (MRT6_BASE+8) /* enable PIM code */
+
+#define SIOCGETMIFCNT_IN6 SIOCPROTOPRIVATE /* IP protocol privates */
+#define SIOCGETSGCNT_IN6 (SIOCPROTOPRIVATE+1)
+#define SIOCGETRPF (SIOCPROTOPRIVATE+2)
+
+#define MAXMIFS 32
+typedef unsigned long mifbitmap_t; /* User mode code depends on this lot */
+typedef unsigned short mifi_t;
+#define ALL_MIFS ((mifi_t)(-1))
+
+#ifndef IF_SETSIZE
+#define IF_SETSIZE 256
+#endif
+
+typedef u_int32_t if_mask;
+#define NIFBITS (sizeof(if_mask) * 8) /* bits per mask */
+
+#ifndef howmany
+#define howmany(x, y) (((x) + ((y) - 1)) / (y))
+#endif
+
+typedef struct if_set {
+ if_mask ifs_bits[howmany(IF_SETSIZE, NIFBITS)];
+} if_set;
+
+#define IF_SET(n, p) ((p)->ifs_bits[(n)/NIFBITS] |= (1 << ((n) % NIFBITS)))
+#define IF_CLR(n, p) ((p)->ifs_bits[(n)/NIFBITS] &= ~(1 << ((n) % NIFBITS)))
+#define IF_ISSET(n, p) ((p)->ifs_bits[(n)/NIFBITS] & (1 << ((n) % NIFBITS)))
+#define IF_COPY(f, t) bcopy(f, t, sizeof(*(f)))
+#define IF_ZERO(p) bzero(p, sizeof(*(p)))
+
+/*
+ Same idea as select
+
+#define VIFM_SET(n,m) ((m)|=(1<<(n)))
+#define VIFM_CLR(n,m) ((m)&=~(1<<(n)))
+#define VIFM_ISSET(n,m) ((m)&(1<<(n)))
+#define VIFM_CLRALL(m) ((m)=0)
+#define VIFM_COPY(mfrom,mto) ((mto)=(mfrom))
+#define VIFM_SAME(m1,m2) ((m1)==(m2))
+*/
+
+/*
+ * Passed by mrouted for an MRT_ADD_MIF - again we use the
+ * mrouted 3.6 structures for compatibility
+ */
+
+struct mif6ctl {
+ mifi_t mif6c_mifi; /* Index of MIF */
+ unsigned char mif6c_flags; /* MIFF_ flags */
+ unsigned char vifc_threshold; /* ttl limit */
+ unsigned int vifc_rate_limit; /* Rate limiter values (NI) */
+ u_short mif6c_pifi; /* the index of the physical IF */
+};
+
+#define MIFF_REGISTER 0x1 /* register vif */
+
+/*
+ * Cache manipulation structures for mrouted and PIMd
+ */
+
+struct mf6cctl
+{
+ struct sockaddr_in6 mf6cc_origin; /* Origin of mcast */
+ struct sockaddr_in6 mf6cc_mcastgrp; /* Group in question */
+ mifi_t mf6cc_parent; /* Where it arrived */
+ struct if_set mf6cc_ifset; /* Where it is going */
+ unsigned int mfcc_pkt_cnt; /* pkt count for src-grp */
+ unsigned int mfcc_byte_cnt;
+ unsigned int mfcc_wrong_if;
+ int mfcc_expire;
+};
+
+/*
+ * Group count retrieval for pim6sd
+ */
+
+struct sioc_sg_req6
+{
+ struct sockaddr_in6 src;
+ struct sockaddr_in6 grp;
+ unsigned long pktcnt;
+ unsigned long bytecnt;
+ unsigned long wrong_if;
+};
+
+/*
+ * To get vif packet counts
+ */
+
+struct sioc_mif_req6
+{
+ mifi_t mifi; /* Which iface */
+ unsigned long icount; /* In packets */
+ unsigned long ocount; /* Out packets */
+ unsigned long ibytes; /* In bytes */
+ unsigned long obytes; /* Out bytes */
+};
+
+/*
+ * That's all usermode folks
+ */
+
+#ifdef __KERNEL__
+struct inet6_dev * ipv6_find_idev(struct net_device *dev);
+#include <net/sock.h>
+
+extern int ip6_mroute_setsockopt(struct sock *, int, char __user *, int);
+extern int ip6_mroute_getsockopt(struct sock *, int, char __user *, int __user *);
+extern int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg);
+extern void ip6_mr_init(void);
+
+struct mif_device
+{
+ struct net_device *dev; /* Device we are using */
+ unsigned long bytes_in,bytes_out;
+ unsigned long pkt_in,pkt_out; /* Statistics */
+ unsigned long rate_limit; /* Traffic shaping (NI) */
+ unsigned char threshold; /* TTL threshold */
+ unsigned short flags; /* Control flags */
+ int link; /* Physical interface index */
+};
+
+#define VIFF_STATIC 0x8000
+
+struct mfc6_cache
+{
+ struct mfc6_cache *next; /* Next entry on cache line */
+ struct in6_addr mf6c_mcastgrp; /* Group the entry belongs to */
+ struct in6_addr mf6c_origin; /* Source of packet */
+ mifi_t mf6c_parent; /* Source interface */
+ int mfc_flags; /* Flags on line */
+
+ union {
+ struct {
+ unsigned long expires;
+ struct sk_buff_head unresolved; /* Unresolved buffers */
+ } unres;
+ struct {
+ unsigned long last_assert;
+ int minvif;
+ int maxvif;
+ unsigned long bytes;
+ unsigned long pkt;
+ unsigned long wrong_if;
+ unsigned char ttls[MAXMIFS]; /* TTL thresholds */
+ } res;
+ } mfc_un;
+};
+
+#define MFC_STATIC 1
+#define MFC_NOTIFY 2
+
+#define MFC6_LINES 64
+
+#if (MFC6_LINES & (MFC6_LINES -1 )) == 0
+#define MF6CHASHMOD(h) ((h) & (MFC6_LINES -1))
+#else
+#define MF6CHASHMOD(h) ((h) % MFC6_LINES)
+#endif
+
+#define MFC6_HASH(a, g) MF6CHASHMOD((a).s6_addr32[0] ^ (a).s6_addr32[1] ^ \
+ (a).s6_addr32[2] ^ (a).s6_addr32[3] ^ \
+ (a).s6_addr32[0] ^ (a).s6_addr32[1] ^ \
+ (a).s6_addr32[2] ^ (a).s6_addr32[3])
+
+#endif
+
+
+
+#define MFC_ASSERT_THRESH (3*HZ) /* Maximal freq. of asserts */
+
+/*
+ * Pseudo messages used by mrouted
+ */
+
+#define IGMPMSG_NOCACHE 1 /* Kern cache fill request to mrouted */
+#define IGMPMSG_WRONGVIF 2 /* For PIM assert processing (unused) */
+#define IGMPMSG_WHOLEPKT 3 /* For PIM Register processing */
+
+#define PIM_REGISTER 1
+
+#ifdef __KERNEL__
+
+#define PIM_V1_VERSION __constant_htonl(0x10000000)
+#define PIM_V1_REGISTER 1
+
+#define PIM_VERSION 2
+
+#define PIM_NULL_REGISTER __constant_htonl(0x40000000)
+
+/* PIMv2 register message header layout (ietf-draft-idmr-pimvsm-v2-00.ps */
+
+struct pim6reghdr
+{
+ __u8 type;
+ __u8 reserved;
+ __u16 csum;
+ __u32 flags;
+};
+
+
+struct rtmsg;
+extern int ip6mr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait);
+#endif
+
+#ifdef __KERNEL__
+
+extern struct sock *mroute6_socket;
+
+#define IN6_ARE_ADDR_EQUAL(a,b) \
+ (memcmp(&(a)->s6_addr[0], &(b)->s6_addr[0], sizeof(struct in6_addr)) == 0)
+#endif
+
+/*
+ * Structure used to communicate from kernel to multicast router.
+ * We'll overlay the structure onto an MLD header (not an IPv6 heder like igmpmsg{}
+ * used for IPv4 implementation). This is because this structure will be passed via an
+ * IPv6 raw socket, on wich an application will only receiver the payload i.e the data after
+ * the IPv6 header and all the extension headers. (See section 3 of RFC 3542)
+ */
+
+struct mrt6msg {
+#define MRT6MSG_NOCACHE 1
+#define MRT6MSG_WRONGMIF 2
+#define MRT6MSG_WHOLEPKT 3 /* used for use level encap */
+ u_char im6_mbz; /* must be zero */
+ u_char im6_msgtype; /* what type of message */
+ u_int16_t im6_mif; /* mif rec'd on */
+ u_int32_t im6_pad; /* padding for 64 bit arch */
+ struct in6_addr im6_src, im6_dst;
+};
+
+/*
+ * PIM packet header
+ */
+#define PIM_VERSION 2
+struct pim {
+#if defined(BYTE_ORDER) && (BYTE_ORDER == LITTLE_ENDIAN)
+ u_char pim_type:4, /* the PIM message type, currently they are:
+ * Hello, Register, Register-Stop, Join/Prune,
+ * Bootstrap, Assert, Graft (PIM-DM only),
+ * Graft-Ack (PIM-DM only), C-RP-Adv
+ */
+ pim_ver:4; /* PIM version number; 2 for PIMv2 */
+#else
+ u_char pim_ver:4, /* PIM version */
+ pim_type:4; /* PIM type */
+#endif
+ u_char pim_rsv; /* Reserved */
+ u_short pim_cksum; /* IP style check sum */
+};
+
+#define PIM_MINLEN 8 /* The header min. length is 8 */
+#define PIM6_REG_MINLEN (PIM_MINLEN+40) /* Register message + inner IP6 header */
+
+#define IPV6_VERSION 0x60
+#define IPV6_VERSION_MASK 0xf0
+
+/* XXX :there should not be there */
+#include <linux/icmpv6.h>
+
+struct mld_hdr {
+ struct icmp6hdr mld_icmp6_hdr;
+ struct in6_addr mld_addr;
+};
+
+#define mld_type mld_icmp6_hdr.icmp6_type
+
+#endif
diff -urN linux-2.6.11/include/linux/netfilter.h linux.sinabox/include/linux/netfilter.h
--- linux-2.6.11/include/linux/netfilter.h 2005-03-02 08:38:09.000000000 +0100
+++ linux.sinabox/include/linux/netfilter.h 2005-03-26 19:02:06.000000000 +0100
@@ -175,6 +175,10 @@
extern void (*ip_ct_attach)(struct sk_buff *, struct sk_buff *);
extern void nf_ct_attach(struct sk_buff *, struct sk_buff *);
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+extern void (*ip6_ct_attach)(struct sk_buff *, struct sk_buff *);
+#endif
+
/* FIXME: Before cache is ever used, this must be implemented for real. */
extern void nf_invalidate_cache(int pf);
diff -urN linux-2.6.11/include/linux/netfilter_ipv4/ip_set.h linux.sinabox/include/linux/netfilter_ipv4/ip_set.h
--- linux-2.6.11/include/linux/netfilter_ipv4/ip_set.h 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/include/linux/netfilter_ipv4/ip_set.h 2005-03-24 19:22:37.000000000 +0100
@@ -0,0 +1,489 @@
+#ifndef _IP_SET_H
+#define _IP_SET_H
+
+/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
+ * Patrick Schaaf <bof@bof.de>
+ * Martin Josefsson <gandalf@wlug.westbo.se>
+ * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * A sockopt of such quality has hardly ever been seen before on the open
+ * market! This little beauty, hardly ever used: above 64, so it's
+ * traditionally used for firewalling, not touched (even once!) by the
+ * 2.0, 2.2 and 2.4 kernels!
+ *
+ * Comes with its own certificate of authenticity, valid anywhere in the
+ * Free world!
+ *
+ * Rusty, 19.4.2000
+ */
+#define SO_IP_SET 83
+
+/*
+ * Heavily modify by Joakim Axelsson 08.03.2002
+ * - Made it more modulebased
+ *
+ * Additional heavy modifications by Jozsef Kadlecsik 22.02.2004
+ * - bindings added
+ * - in order to "deal with" backward compatibility, renamed to ipset
+ */
+
+/*
+ * Used so that the kernel module and ipset-binary can match their versions
+ */
+#define IP_SET_PROTOCOL_VERSION 2
+
+#define IP_SET_MAXNAMELEN 32 /* set names and set typenames */
+
+/* Lets work with our own typedef for representing an IP address.
+ * We hope to make the code more portable, possibly to IPv6...
+ *
+ * The representation works in HOST byte order, because most set types
+ * will perform arithmetic operations and compare operations.
+ *
+ * For now the type is an uint32_t.
+ *
+ * Make sure to ONLY use the functions when translating and parsing
+ * in order to keep the host byte order and make it more portable:
+ * parse_ip()
+ * parse_mask()
+ * parse_ipandmask()
+ * ip_tostring()
+ * (Joakim: where are they???)
+ */
+
+typedef uint32_t ip_set_ip_t;
+
+/* Sets are identified by an id in kernel space. Tweak with ip_set_id_t
+ * and IP_SET_INVALID_ID if you want to increase the max number of sets.
+ */
+typedef uint16_t ip_set_id_t;
+
+#define IP_SET_INVALID_ID 65535
+
+/* How deep we follow bindings */
+#define IP_SET_MAX_BINDINGS 6
+
+/*
+ * Option flags for kernel operations (ipt_set_info)
+ */
+#define IPSET_SRC 0x01 /* Source match/add */
+#define IPSET_DST 0x02 /* Destination match/add */
+#define IPSET_MATCH_INV 0x04 /* Inverse matching */
+
+/*
+ * Set types (flavours)
+ */
+#define IPSET_TYPE_IP 0 /* IP address type of set */
+#define IPSET_TYPE_PORT 1 /* Port type of set */
+
+/* Reserved keywords */
+#define IPSET_TOKEN_DEFAULT ":default:"
+#define IPSET_TOKEN_ALL ":all:"
+
+/* SO_IP_SET operation constants, and their request struct types.
+ *
+ * Operation ids:
+ * 0-99: commands with version checking
+ * 100-199: add/del/test/bind/unbind
+ * 200-299: list, save, restore
+ */
+
+/* Single shot operations:
+ * version, create, destroy, flush, rename and swap
+ *
+ * Sets are identified by name.
+ */
+
+#define IP_SET_REQ_STD \
+ unsigned op; \
+ unsigned version; \
+ char name[IP_SET_MAXNAMELEN]
+
+#define IP_SET_OP_CREATE 0x00000001 /* Create a new (empty) set */
+struct ip_set_req_create {
+ IP_SET_REQ_STD;
+ char typename[IP_SET_MAXNAMELEN];
+};
+
+#define IP_SET_OP_DESTROY 0x00000002 /* Remove a (empty) set */
+struct ip_set_req_std {
+ IP_SET_REQ_STD;
+};
+
+#define IP_SET_OP_FLUSH 0x00000003 /* Remove all IPs in a set */
+/* Uses ip_set_req_std */
+
+#define IP_SET_OP_RENAME 0x00000004 /* Rename a set */
+/* Uses ip_set_req_create */
+
+#define IP_SET_OP_SWAP 0x00000005 /* Swap two sets */
+/* Uses ip_set_req_create */
+
+union ip_set_name_index {
+ char name[IP_SET_MAXNAMELEN];
+ ip_set_id_t index;
+};
+
+#define IP_SET_OP_GET_BYNAME 0x00000006 /* Get set index by name */
+struct ip_set_req_get_set {
+ unsigned op;
+ unsigned version;
+ union ip_set_name_index set;
+};
+
+#define IP_SET_OP_GET_BYINDEX 0x00000007 /* Get set name by index */
+/* Uses ip_set_req_get_set */
+
+#define IP_SET_OP_VERSION 0x00000100 /* Ask kernel version */
+struct ip_set_req_version {
+ unsigned op;
+ unsigned version;
+};
+
+/* Double shots operations:
+ * add, del, test, bind and unbind.
+ *
+ * First we query the kernel to get the index and type of the target set,
+ * then issue the command. Validity of IP is checked in kernel in order
+ * to minimalize sockopt operations.
+ */
+
+/* Get minimal set data for add/del/test/bind/unbind IP */
+#define IP_SET_OP_ADT_GET 0x00000010 /* Get set and type */
+struct ip_set_req_adt_get {
+ unsigned op;
+ unsigned version;
+ union ip_set_name_index set;
+ char typename[IP_SET_MAXNAMELEN];
+};
+
+#define IP_SET_REQ_BYINDEX \
+ unsigned op; \
+ ip_set_id_t index;
+
+struct ip_set_req_adt {
+ IP_SET_REQ_BYINDEX;
+};
+
+#define IP_SET_OP_ADD_IP 0x00000101 /* Add an IP to a set */
+/* Uses ip_set_req_adt, with type specific addage */
+
+#define IP_SET_OP_DEL_IP 0x00000102 /* Remove an IP from a set */
+/* Uses ip_set_req_adt, with type specific addage */
+
+#define IP_SET_OP_TEST_IP 0x00000103 /* Test an IP in a set */
+/* Uses ip_set_req_adt, with type specific addage */
+
+#define IP_SET_OP_BIND_SET 0x00000104 /* Bind an IP to a set */
+/* Uses ip_set_req_bind, with type specific addage */
+struct ip_set_req_bind {
+ IP_SET_REQ_BYINDEX;
+ char binding[IP_SET_MAXNAMELEN];
+};
+
+#define IP_SET_OP_UNBIND_SET 0x00000105 /* Unbind an IP from a set */
+/* Uses ip_set_req_bind, with type speficic addage
+ * index = 0 means unbinding for all sets */
+
+#define IP_SET_OP_TEST_BIND_SET 0x00000106 /* Test binding an IP to a set */
+/* Uses ip_set_req_bind, with type specific addage */
+
+/* Multiple shots operations: list, save, restore.
+ *
+ * - check kernel version and query the max number of sets
+ * - get the basic information on all sets
+ * and size required for the next step
+ * - get actual set data: header, data, bindings
+ */
+
+/* Get max_sets and the index of a queried set
+ */
+#define IP_SET_OP_MAX_SETS 0x00000020
+struct ip_set_req_max_sets {
+ unsigned op;
+ unsigned version;
+ ip_set_id_t max_sets; /* max_sets */
+ ip_set_id_t sets; /* real number of sets */
+ union ip_set_name_index set; /* index of set if name used */
+};
+
+/* Get the id and name of the sets plus size for next step */
+#define IP_SET_OP_LIST_SIZE 0x00000201
+#define IP_SET_OP_SAVE_SIZE 0x00000202
+struct ip_set_req_setnames {
+ unsigned op;
+ ip_set_id_t index; /* set to list/save */
+ size_t size; /* size to get setdata/bindings */
+ /* followed by sets number of struct ip_set_name_list */
+};
+
+struct ip_set_name_list {
+ char name[IP_SET_MAXNAMELEN];
+ char typename[IP_SET_MAXNAMELEN];
+ ip_set_id_t index;
+ ip_set_id_t id;
+};
+
+/* The actual list operation */
+#define IP_SET_OP_LIST 0x00000203
+struct ip_set_req_list {
+ IP_SET_REQ_BYINDEX;
+ /* sets number of struct ip_set_list in reply */
+};
+
+struct ip_set_list {
+ ip_set_id_t index;
+ ip_set_id_t binding;
+ u_int32_t ref;
+ size_t header_size; /* Set header data of header_size */
+ size_t members_size; /* Set members data of members_size */
+ size_t bindings_size; /* Set bindings data of bindings_size */
+};
+
+struct ip_set_hash_list {
+ ip_set_ip_t ip;
+ ip_set_id_t binding;
+};
+
+/* The save operation */
+#define IP_SET_OP_SAVE 0x00000204
+/* Uses ip_set_req_list, in the reply replaced by
+ * sets number of struct ip_set_save plus a marker
+ * ip_set_save followed by ip_set_hash_save structures.
+ */
+struct ip_set_save {
+ ip_set_id_t index;
+ ip_set_id_t binding;
+ size_t header_size; /* Set header data of header_size */
+ size_t members_size; /* Set members data of members_size */
+};
+
+/* At restoring, ip == 0 means default binding for the given set: */
+struct ip_set_hash_save {
+ ip_set_ip_t ip;
+ ip_set_id_t id;
+ ip_set_id_t binding;
+};
+
+/* The restore operation */
+#define IP_SET_OP_RESTORE 0x00000205
+/* Uses ip_set_req_setnames followed by ip_set_restore structures
+ * plus a marker ip_set_restore, followed by ip_set_hash_save
+ * structures.
+ */
+struct ip_set_restore {
+ char name[IP_SET_MAXNAMELEN];
+ char typename[IP_SET_MAXNAMELEN];
+ ip_set_id_t index;
+ size_t header_size; /* Create data of header_size */
+ size_t members_size; /* Set members data of members_size */
+};
+
+static inline int bitmap_bytes(ip_set_ip_t a, ip_set_ip_t b)
+{
+ return 4 * ((((b - a + 8) / 8) + 3) / 4);
+}
+
+#ifdef __KERNEL__
+
+#define ip_set_printk(format, args...) \
+ do { \
+ printk("%s: %s: ", __FILE__, __FUNCTION__); \
+ printk(format "\n" , ## args); \
+ } while (0)
+
+#if defined(IP_SET_DEBUG)
+#define DP(format, args...) \
+ do { \
+ printk("%s: %s (DBG): ", __FILE__, __FUNCTION__);\
+ printk(format "\n" , ## args); \
+ } while (0)
+#define IP_SET_ASSERT(x) \
+ do { \
+ if (!(x)) \
+ printk("IP_SET_ASSERT: %s:%i(%s)\n", \
+ __FILE__, __LINE__, __FUNCTION__); \
+ } while (0)
+#else
+#define DP(format, args...)
+#define IP_SET_ASSERT(x)
+#endif
+
+struct ip_set;
+
+/*
+ * The ip_set_type definition - one per set type, e.g. "ipmap".
+ *
+ * Each individual set has a pointer, set->type, going to one
+ * of these structures. Function pointers inside the structure implement
+ * the real behaviour of the sets.
+ *
+ * If not mentioned differently, the implementation behind the function
+ * pointers of a set_type, is expected to return 0 if ok, and a negative
+ * errno (e.g. -EINVAL) on error.
+ */
+struct ip_set_type {
+ struct list_head list; /* next in list of set types */
+
+ /* test for IP in set (kernel: iptables -m set src|dst)
+ * return 0 if not in set, 1 if in set.
+ */
+ int (*testip_kernel) (struct ip_set *set,
+ const struct sk_buff * skb,
+ u_int32_t flags,
+ ip_set_ip_t *ip);
+
+ /* test for IP in set (userspace: ipset -T set IP)
+ * return 0 if not in set, 1 if in set.
+ */
+ int (*testip) (struct ip_set *set,
+ const void *data, size_t size,
+ ip_set_ip_t *ip);
+
+ /*
+ * Size of the data structure passed by when
+ * adding/deletin/testing an entry.
+ */
+ size_t reqsize;
+
+ /* Add IP into set (userspace: ipset -A set IP)
+ * Return -EEXIST if the address is already in the set,
+ * and -ERANGE if the address lies outside the set bounds.
+ * If the address was not already in the set, 0 is returned.
+ */
+ int (*addip) (struct ip_set *set,
+ const void *data, size_t size,
+ ip_set_ip_t *ip);
+
+ /* Add IP into set (kernel: iptables ... -j SET set src|dst)
+ * Return -EEXIST if the address is already in the set,
+ * and -ERANGE if the address lies outside the set bounds.
+ * If the address was not already in the set, 0 is returned.
+ */
+ int (*addip_kernel) (struct ip_set *set,
+ const struct sk_buff * skb,
+ u_int32_t flags,
+ ip_set_ip_t *ip);
+
+ /* remove IP from set (userspace: ipset -D set --entry x)
+ * Return -EEXIST if the address is NOT in the set,
+ * and -ERANGE if the address lies outside the set bounds.
+ * If the address really was in the set, 0 is returned.
+ */
+ int (*delip) (struct ip_set *set,
+ const void *data, size_t size,
+ ip_set_ip_t *ip);
+
+ /* remove IP from set (kernel: iptables ... -j SET --entry x)
+ * Return -EEXIST if the address is NOT in the set,
+ * and -ERANGE if the address lies outside the set bounds.
+ * If the address really was in the set, 0 is returned.
+ */
+ int (*delip_kernel) (struct ip_set *set,
+ const struct sk_buff * skb,
+ u_int32_t flags,
+ ip_set_ip_t *ip);
+
+ /* new set creation - allocated type specific items
+ */
+ int (*create) (struct ip_set *set,
+ const void *data, size_t size);
+
+ /* retry the operation after successfully tweaking the set
+ */
+ int (*retry) (struct ip_set *set);
+
+ /* set destruction - free type specific items
+ * There is no return value.
+ * Can be called only when child sets are destroyed.
+ */
+ void (*destroy) (struct ip_set *set);
+
+ /* set flushing - reset all bits in the set, or something similar.
+ * There is no return value.
+ */
+ void (*flush) (struct ip_set *set);
+
+ /* Listing: size needed for header
+ */
+ size_t header_size;
+
+ /* Listing: Get the header
+ *
+ * Fill in the information in "data".
+ * This function is always run after list_header_size() under a
+ * writelock on the set. Therefor is the length of "data" always
+ * correct.
+ */
+ void (*list_header) (const struct ip_set *set,
+ void *data);
+
+ /* Listing: Get the size for the set members
+ */
+ int (*list_members_size) (const struct ip_set *set);
+
+ /* Listing: Get the set members
+ *
+ * Fill in the information in "data".
+ * This function is always run after list_member_size() under a
+ * writelock on the set. Therefor is the length of "data" always
+ * correct.
+ */
+ void (*list_members) (const struct ip_set *set,
+ void *data);
+
+ char typename[IP_SET_MAXNAMELEN];
+ char typecode;
+ int protocol_version;
+
+ /* Set this to THIS_MODULE if you are a module, otherwise NULL */
+ struct module *me;
+};
+
+extern int ip_set_register_set_type(struct ip_set_type *set_type);
+extern void ip_set_unregister_set_type(struct ip_set_type *set_type);
+
+/* A generic ipset */
+struct ip_set {
+ char name[IP_SET_MAXNAMELEN]; /* the name of the set */
+ rwlock_t lock; /* lock for concurrency control */
+ ip_set_id_t id; /* set id for swapping */
+ ip_set_id_t binding; /* default binding for the set */
+ atomic_t ref; /* in kernel and in hash references */
+ struct ip_set_type *type; /* the set types */
+ void *data; /* pooltype specific data */
+};
+
+/* Structure to bind set elements to sets */
+struct ip_set_hash {
+ struct list_head list; /* list of clashing entries in hash */
+ ip_set_ip_t ip; /* ip from set */
+ ip_set_id_t id; /* set id */
+ ip_set_id_t binding; /* set we bind the element to */
+};
+
+/* register and unregister set references */
+extern ip_set_id_t ip_set_get_byname(const char name[IP_SET_MAXNAMELEN]);
+extern ip_set_id_t ip_set_get_byindex(ip_set_id_t id);
+extern void ip_set_put(ip_set_id_t id);
+
+/* API for iptables set match, and SET target */
+extern void ip_set_addip_kernel(ip_set_id_t id,
+ const struct sk_buff *skb,
+ const u_int32_t *flags);
+extern void ip_set_delip_kernel(ip_set_id_t id,
+ const struct sk_buff *skb,
+ const u_int32_t *flags);
+extern int ip_set_testip_kernel(ip_set_id_t id,
+ const struct sk_buff *skb,
+ const u_int32_t *flags);
+
+#endif /* __KERNEL__ */
+
+#endif /*_IP_SET_H*/
diff -urN linux-2.6.11/include/linux/netfilter_ipv4/ip_set_iphash.h linux.sinabox/include/linux/netfilter_ipv4/ip_set_iphash.h
--- linux-2.6.11/include/linux/netfilter_ipv4/ip_set_iphash.h 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/include/linux/netfilter_ipv4/ip_set_iphash.h 2005-03-24 19:22:37.000000000 +0100
@@ -0,0 +1,30 @@
+#ifndef __IP_SET_IPHASH_H
+#define __IP_SET_IPHASH_H
+
+#include <linux/netfilter_ipv4/ip_set.h>
+
+#define SETTYPE_NAME "iphash"
+#define MAX_RANGE 0x0000FFFF
+
+struct ip_set_iphash {
+ ip_set_ip_t *members; /* the iphash proper */
+ uint32_t initval; /* initval for jhash_1word */
+ uint32_t prime; /* prime for double hashing */
+ uint32_t hashsize; /* hash size */
+ uint16_t probes; /* max number of probes */
+ uint16_t resize; /* resize factor in percent */
+ ip_set_ip_t netmask; /* netmask */
+};
+
+struct ip_set_req_iphash_create {
+ uint32_t hashsize;
+ uint16_t probes;
+ uint16_t resize;
+ ip_set_ip_t netmask;
+};
+
+struct ip_set_req_iphash {
+ ip_set_ip_t ip;
+};
+
+#endif /* __IP_SET_IPHASH_H */
diff -urN linux-2.6.11/include/linux/netfilter_ipv4/ip_set_ipmap.h linux.sinabox/include/linux/netfilter_ipv4/ip_set_ipmap.h
--- linux-2.6.11/include/linux/netfilter_ipv4/ip_set_ipmap.h 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/include/linux/netfilter_ipv4/ip_set_ipmap.h 2005-03-24 19:22:37.000000000 +0100
@@ -0,0 +1,56 @@
+#ifndef __IP_SET_IPMAP_H
+#define __IP_SET_IPMAP_H
+
+#include <linux/netfilter_ipv4/ip_set.h>
+
+#define SETTYPE_NAME "ipmap"
+#define MAX_RANGE 0x0000FFFF
+
+struct ip_set_ipmap {
+ void *members; /* the ipmap proper */
+ ip_set_ip_t first_ip; /* host byte order, included in range */
+ ip_set_ip_t last_ip; /* host byte order, included in range */
+ ip_set_ip_t netmask; /* subnet netmask */
+ ip_set_ip_t sizeid; /* size of set in IPs */
+ u_int16_t hosts; /* number of hosts in a subnet */
+};
+
+struct ip_set_req_ipmap_create {
+ ip_set_ip_t from;
+ ip_set_ip_t to;
+ ip_set_ip_t netmask;
+};
+
+struct ip_set_req_ipmap {
+ ip_set_ip_t ip;
+};
+
+unsigned int
+mask_to_bits(ip_set_ip_t mask)
+{
+ unsigned int bits = 32;
+ ip_set_ip_t maskaddr;
+
+ if (mask == 0xFFFFFFFF)
+ return bits;
+
+ maskaddr = 0xFFFFFFFE;
+ while (--bits >= 0 && maskaddr != mask)
+ maskaddr <<= 1;
+
+ return bits;
+}
+
+ip_set_ip_t
+range_to_mask(ip_set_ip_t from, ip_set_ip_t to, unsigned int *bits)
+{
+ ip_set_ip_t mask = 0xFFFFFFFE;
+
+ *bits = 32;
+ while (--(*bits) >= 0 && mask && (to & mask) != from)
+ mask <<= 1;
+
+ return mask;
+}
+
+#endif /* __IP_SET_IPMAP_H */
diff -urN linux-2.6.11/include/linux/netfilter_ipv4/ip_set_jhash.h linux.sinabox/include/linux/netfilter_ipv4/ip_set_jhash.h
--- linux-2.6.11/include/linux/netfilter_ipv4/ip_set_jhash.h 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/include/linux/netfilter_ipv4/ip_set_jhash.h 2005-03-24 19:22:37.000000000 +0100
@@ -0,0 +1,148 @@
+#ifndef _LINUX_IPSET_JHASH_H
+#define _LINUX_IPSET_JHASH_H
+
+/* This is a copy of linux/jhash.h but the types u32/u8 are changed
+ * to __u32/__u8 so that the header file can be included into
+ * userspace code as well. Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
+ */
+
+/* jhash.h: Jenkins hash support.
+ *
+ * Copyright (C) 1996 Bob Jenkins (bob_jenkins@burtleburtle.net)
+ *
+ * http://burtleburtle.net/bob/hash/
+ *
+ * These are the credits from Bob's sources:
+ *
+ * lookup2.c, by Bob Jenkins, December 1996, Public Domain.
+ * hash(), hash2(), hash3, and mix() are externally useful functions.
+ * Routines to test the hash are included if SELF_TEST is defined.
+ * You can use this free for any purpose. It has no warranty.
+ *
+ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ *
+ * I've modified Bob's hash to be useful in the Linux kernel, and
+ * any bugs present are surely my fault. -DaveM
+ */
+
+/* NOTE: Arguments are modified. */
+#define __jhash_mix(a, b, c) \
+{ \
+ a -= b; a -= c; a ^= (c>>13); \
+ b -= c; b -= a; b ^= (a<<8); \
+ c -= a; c -= b; c ^= (b>>13); \
+ a -= b; a -= c; a ^= (c>>12); \
+ b -= c; b -= a; b ^= (a<<16); \
+ c -= a; c -= b; c ^= (b>>5); \
+ a -= b; a -= c; a ^= (c>>3); \
+ b -= c; b -= a; b ^= (a<<10); \
+ c -= a; c -= b; c ^= (b>>15); \
+}
+
+/* The golden ration: an arbitrary value */
+#define JHASH_GOLDEN_RATIO 0x9e3779b9
+
+/* The most generic version, hashes an arbitrary sequence
+ * of bytes. No alignment or length assumptions are made about
+ * the input key.
+ */
+static inline __u32 jhash(void *key, __u32 length, __u32 initval)
+{
+ __u32 a, b, c, len;
+ __u8 *k = key;
+
+ len = length;
+ a = b = JHASH_GOLDEN_RATIO;
+ c = initval;
+
+ while (len >= 12) {
+ a += (k[0] +((__u32)k[1]<<8) +((__u32)k[2]<<16) +((__u32)k[3]<<24));
+ b += (k[4] +((__u32)k[5]<<8) +((__u32)k[6]<<16) +((__u32)k[7]<<24));
+ c += (k[8] +((__u32)k[9]<<8) +((__u32)k[10]<<16)+((__u32)k[11]<<24));
+
+ __jhash_mix(a,b,c);
+
+ k += 12;
+ len -= 12;
+ }
+
+ c += length;
+ switch (len) {
+ case 11: c += ((__u32)k[10]<<24);
+ case 10: c += ((__u32)k[9]<<16);
+ case 9 : c += ((__u32)k[8]<<8);
+ case 8 : b += ((__u32)k[7]<<24);
+ case 7 : b += ((__u32)k[6]<<16);
+ case 6 : b += ((__u32)k[5]<<8);
+ case 5 : b += k[4];
+ case 4 : a += ((__u32)k[3]<<24);
+ case 3 : a += ((__u32)k[2]<<16);
+ case 2 : a += ((__u32)k[1]<<8);
+ case 1 : a += k[0];
+ };
+
+ __jhash_mix(a,b,c);
+
+ return c;
+}
+
+/* A special optimized version that handles 1 or more of __u32s.
+ * The length parameter here is the number of __u32s in the key.
+ */
+static inline __u32 jhash2(__u32 *k, __u32 length, __u32 initval)
+{
+ __u32 a, b, c, len;
+
+ a = b = JHASH_GOLDEN_RATIO;
+ c = initval;
+ len = length;
+
+ while (len >= 3) {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ __jhash_mix(a, b, c);
+ k += 3; len -= 3;
+ }
+
+ c += length * 4;
+
+ switch (len) {
+ case 2 : b += k[1];
+ case 1 : a += k[0];
+ };
+
+ __jhash_mix(a,b,c);
+
+ return c;
+}
+
+
+/* A special ultra-optimized versions that knows they are hashing exactly
+ * 3, 2 or 1 word(s).
+ *
+ * NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally
+ * done at the end is not done here.
+ */
+static inline __u32 jhash_3words(__u32 a, __u32 b, __u32 c, __u32 initval)
+{
+ a += JHASH_GOLDEN_RATIO;
+ b += JHASH_GOLDEN_RATIO;
+ c += initval;
+
+ __jhash_mix(a, b, c);
+
+ return c;
+}
+
+static inline __u32 jhash_2words(__u32 a, __u32 b, __u32 initval)
+{
+ return jhash_3words(a, b, 0, initval);
+}
+
+static inline __u32 jhash_1word(__u32 a, __u32 initval)
+{
+ return jhash_3words(a, 0, 0, initval);
+}
+
+#endif /* _LINUX_IPSET_JHASH_H */
diff -urN linux-2.6.11/include/linux/netfilter_ipv4/ip_set_macipmap.h linux.sinabox/include/linux/netfilter_ipv4/ip_set_macipmap.h
--- linux-2.6.11/include/linux/netfilter_ipv4/ip_set_macipmap.h 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/include/linux/netfilter_ipv4/ip_set_macipmap.h 2005-03-24 19:22:37.000000000 +0100
@@ -0,0 +1,38 @@
+#ifndef __IP_SET_MACIPMAP_H
+#define __IP_SET_MACIPMAP_H
+
+#include <linux/netfilter_ipv4/ip_set.h>
+
+#define SETTYPE_NAME "macipmap"
+#define MAX_RANGE 0x0000FFFF
+
+/* general flags */
+#define IPSET_MACIP_MATCHUNSET 1
+
+/* per ip flags */
+#define IPSET_MACIP_ISSET 1
+
+struct ip_set_macipmap {
+ void *members; /* the macipmap proper */
+ ip_set_ip_t first_ip; /* host byte order, included in range */
+ ip_set_ip_t last_ip; /* host byte order, included in range */
+ u_int32_t flags;
+};
+
+struct ip_set_req_macipmap_create {
+ ip_set_ip_t from;
+ ip_set_ip_t to;
+ u_int32_t flags;
+};
+
+struct ip_set_req_macipmap {
+ ip_set_ip_t ip;
+ unsigned char ethernet[ETH_ALEN];
+};
+
+struct ip_set_macip {
+ unsigned short flags;
+ unsigned char ethernet[ETH_ALEN];
+};
+
+#endif /* __IP_SET_MACIPMAP_H */
diff -urN linux-2.6.11/include/linux/netfilter_ipv4/ip_set_malloc.h linux.sinabox/include/linux/netfilter_ipv4/ip_set_malloc.h
--- linux-2.6.11/include/linux/netfilter_ipv4/ip_set_malloc.h 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/include/linux/netfilter_ipv4/ip_set_malloc.h 2005-03-24 19:22:37.000000000 +0100
@@ -0,0 +1,34 @@
+#ifndef _IP_SET_MALLOC_H
+#define _IP_SET_MALLOC_H
+
+#ifdef __KERNEL__
+
+/* Memory allocation and deallocation */
+static size_t max_malloc_size = 0;
+
+static inline void init_max_malloc_size(void)
+{
+#define CACHE(x) max_malloc_size = x;
+#include <linux/kmalloc_sizes.h>
+#undef CACHE
+}
+
+static inline void * ip_set_malloc(size_t bytes)
+{
+ if (bytes > max_malloc_size)
+ return vmalloc(bytes);
+ else
+ return kmalloc(bytes, GFP_KERNEL);
+}
+
+static inline void ip_set_free(void * data, size_t bytes)
+{
+ if (bytes > max_malloc_size)
+ vfree(data);
+ else
+ kfree(data);
+}
+
+#endif /* __KERNEL__ */
+
+#endif /*_IP_SET_MALLOC_H*/
diff -urN linux-2.6.11/include/linux/netfilter_ipv4/ip_set_nethash.h linux.sinabox/include/linux/netfilter_ipv4/ip_set_nethash.h
--- linux-2.6.11/include/linux/netfilter_ipv4/ip_set_nethash.h 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/include/linux/netfilter_ipv4/ip_set_nethash.h 2005-03-24 19:22:37.000000000 +0100
@@ -0,0 +1,55 @@
+#ifndef __IP_SET_NETHASH_H
+#define __IP_SET_NETHASH_H
+
+#include <linux/netfilter_ipv4/ip_set.h>
+
+#define SETTYPE_NAME "nethash"
+#define MAX_RANGE 0x0000FFFF
+
+struct ip_set_nethash {
+ ip_set_ip_t *members; /* the nethash proper */
+ uint32_t initval; /* initval for jhash_1word */
+ uint32_t prime; /* prime for double hashing */
+ uint32_t hashsize; /* hash size */
+ uint16_t probes; /* max number of probes */
+ uint16_t resize; /* resize factor in percent */
+ unsigned char cidr[30]; /* CIDR sizes */
+};
+
+struct ip_set_req_nethash_create {
+ uint32_t hashsize;
+ uint16_t probes;
+ uint16_t resize;
+};
+
+struct ip_set_req_nethash {
+ ip_set_ip_t ip;
+ unsigned char cidr;
+};
+
+static unsigned char shifts[] = {255, 253, 249, 242, 225, 193, 129, 1};
+
+static inline ip_set_ip_t
+pack(ip_set_ip_t ip, unsigned char cidr)
+{
+ ip_set_ip_t addr, *paddr = &addr;
+ unsigned char n, t, *a;
+
+ addr = htonl(ip & (0xFFFFFFFF << (32 - (cidr))));
+#ifdef __KERNEL__
+ DP("ip:%u.%u.%u.%u/%u", NIPQUAD(addr), cidr);
+#endif
+ n = cidr / 8;
+ t = cidr % 8;
+ a = &((unsigned char *)paddr)[n];
+ *a = *a /(1 << (8 - t)) + shifts[t];
+#ifdef __KERNEL__
+ DP("n: %u, t: %u, a: %u", n, t, *a);
+ DP("ip:%u.%u.%u.%u/%u, %u.%u.%u.%u",
+ HIPQUAD(ip), cidr, NIPQUAD(addr));
+#endif
+
+ return ntohl(addr);
+}
+
+#endif /* __IP_SET_NETHASH_H */
diff -urN linux-2.6.11/include/linux/netfilter_ipv4/ip_set_portmap.h linux.sinabox/include/linux/netfilter_ipv4/ip_set_portmap.h
--- linux-2.6.11/include/linux/netfilter_ipv4/ip_set_portmap.h 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/include/linux/netfilter_ipv4/ip_set_portmap.h 2005-03-24 19:22:37.000000000 +0100
@@ -0,0 +1,25 @@
+#ifndef __IP_SET_PORTMAP_H
+#define __IP_SET_PORTMAP_H
+
+#include <linux/netfilter_ipv4/ip_set.h>
+
+#define SETTYPE_NAME "portmap"
+#define MAX_RANGE 0x0000FFFF
+#define INVALID_PORT (MAX_RANGE + 1)
+
+struct ip_set_portmap {
+ void *members; /* the portmap proper */
+ ip_set_ip_t first_port; /* host byte order, included in range */
+ ip_set_ip_t last_port; /* host byte order, included in range */
+};
+
+struct ip_set_req_portmap_create {
+ ip_set_ip_t from;
+ ip_set_ip_t to;
+};
+
+struct ip_set_req_portmap {
+ ip_set_ip_t port;
+};
+
+#endif /* __IP_SET_PORTMAP_H */
diff -urN linux-2.6.11/include/linux/netfilter_ipv4/ip_set_prime.h linux.sinabox/include/linux/netfilter_ipv4/ip_set_prime.h
--- linux-2.6.11/include/linux/netfilter_ipv4/ip_set_prime.h 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/include/linux/netfilter_ipv4/ip_set_prime.h 2005-03-24 19:22:37.000000000 +0100
@@ -0,0 +1,34 @@
+#ifndef __IP_SET_PRIME_H
+#define __IP_SET_PRIME_H
+
+static inline unsigned make_prime_bound(unsigned nr)
+{
+ unsigned long long nr64 = nr;
+ unsigned long long x = 1;
+ nr = 1;
+ while (x <= nr64) { x <<= 2; nr <<= 1; }
+ return nr;
+}
+
+static inline int make_prime_check(unsigned nr)
+{
+ unsigned x = 3;
+ unsigned b = make_prime_bound(nr);
+ while (x <= b) {
+ if (0 == (nr % x)) return 0;
+ x += 2;
+ }
+ return 1;
+}
+
+static unsigned make_prime(unsigned nr)
+{
+ if (0 == (nr & 1)) nr--;
+ while (nr > 1) {
+ if (make_prime_check(nr)) return nr;
+ nr -= 2;
+ }
+ return 2;
+}
+
+#endif /* __IP_SET_PRIME_H */
diff -urN linux-2.6.11/include/linux/netfilter_ipv4/ipt_IMQ.h linux.sinabox/include/linux/netfilter_ipv4/ipt_IMQ.h
--- linux-2.6.11/include/linux/netfilter_ipv4/ipt_IMQ.h 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/include/linux/netfilter_ipv4/ipt_IMQ.h 2005-03-26 00:49:04.000000000 +0100
@@ -0,0 +1,8 @@
+#ifndef _IPT_IMQ_H
+#define _IPT_IMQ_H
+
+struct ipt_imq_info {
+ unsigned int todev; /* target imq device */
+};
+
+#endif /* _IPT_IMQ_H */
diff -urN linux-2.6.11/include/linux/netfilter_ipv4/ipt_ipp2p.h linux.sinabox/include/linux/netfilter_ipv4/ipt_ipp2p.h
--- linux-2.6.11/include/linux/netfilter_ipv4/ipt_ipp2p.h 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/include/linux/netfilter_ipv4/ipt_ipp2p.h 2005-03-24 19:26:06.000000000 +0100
@@ -0,0 +1,29 @@
+#ifndef __IPT_IPP2P_H
+#define __IPT_IPP2P_H
+#define IPP2P_VERSION "0.7.2"
+
+struct ipt_p2p_info {
+ int cmd;
+ int debug;
+};
+
+#endif //__IPT_IPP2P_H
+
+#define SHORT_HAND_IPP2P 1 /* --ipp2p switch*/
+#define SHORT_HAND_DATA 4 /* --ipp2p-data switch*/
+#define SHORT_HAND_NONE 5 /* no short hand*/
+
+#define IPP2P_EDK 2
+#define IPP2P_DATA_KAZAA 8
+#define IPP2P_DATA_EDK 16
+#define IPP2P_DATA_DC 32
+#define IPP2P_DC 64
+#define IPP2P_DATA_GNU 128
+#define IPP2P_GNU 256
+#define IPP2P_KAZAA 512
+#define IPP2P_BIT 1024
+#define IPP2P_APPLE 2048
+#define IPP2P_SOUL 4096
+#define IPP2P_WINMX 8192
+#define IPP2P_ARES 16384
+
diff -urN linux-2.6.11/include/linux/netfilter_ipv4/ipt_set.h linux.sinabox/include/linux/netfilter_ipv4/ipt_set.h
--- linux-2.6.11/include/linux/netfilter_ipv4/ipt_set.h 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/include/linux/netfilter_ipv4/ipt_set.h 2005-03-24 19:22:37.000000000 +0100
@@ -0,0 +1,21 @@
+#ifndef _IPT_SET_H
+#define _IPT_SET_H
+
+#include <linux/netfilter_ipv4/ip_set.h>
+
+struct ipt_set_info {
+ ip_set_id_t index;
+ u_int32_t flags[IP_SET_MAX_BINDINGS + 1];
+};
+
+/* match info */
+struct ipt_set_info_match {
+ struct ipt_set_info match_set;
+};
+
+struct ipt_set_info_target {
+ struct ipt_set_info add_set;
+ struct ipt_set_info del_set;
+};
+
+#endif /*_IPT_SET_H*/
diff -urN linux-2.6.11/include/linux/netfilter_ipv6/ip6_conntrack_core.h linux.sinabox/include/linux/netfilter_ipv6/ip6_conntrack_core.h
--- linux-2.6.11/include/linux/netfilter_ipv6/ip6_conntrack_core.h 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/include/linux/netfilter_ipv6/ip6_conntrack_core.h 2005-03-26 19:02:06.000000000 +0100
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C)2003 USAGI/WIDE Project
+ *
+ * Authors:
+ * Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
+ *
+ * Based on: include/linux/netfilter_ipv4/ip_conntrack_core.h
+ *
+ * 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.
+ */
+#ifndef _IP6_CONNTRACK_CORE_H
+#define _IP6_CONNTRACK_CORE_H
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4/lockhelp.h>
+
+/* This header is used to share core functionality between the
+ standalone connection tracking module, and the compatibility layer's use
+ of connection tracking. */
+extern unsigned int ip6_conntrack_in(unsigned int hooknum,
+ struct sk_buff **pskb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *));
+
+extern int ip6_conntrack_init(void);
+extern void ip6_conntrack_cleanup(void);
+
+struct ip6_conntrack_protocol;
+extern struct ip6_conntrack_protocol *ip6_ct_find_proto(u_int8_t protocol);
+/* Like above, but you already have conntrack read lock. */
+extern struct ip6_conntrack_protocol *__ip6_ct_find_proto(u_int8_t protocol);
+extern struct list_head ip6_protocol_list;
+
+/* Returns conntrack if it dealt with ICMP, and filled in skb->nfct */
+extern struct ip6_conntrack *icmp6_error_track(struct sk_buff *skb,
+ unsigned int icmp6off,
+ enum ip6_conntrack_info *ctinfo,
+ unsigned int hooknum);
+extern int ip6_get_tuple(const struct ipv6hdr *ipv6h,
+ const struct sk_buff *skb,
+ unsigned int protoff,
+ u_int8_t protonum,
+ struct ip6_conntrack_tuple *tuple,
+ const struct ip6_conntrack_protocol *protocol);
+
+/* Find a connection corresponding to a tuple. */
+struct ip6_conntrack_tuple_hash *
+ip6_conntrack_find_get(const struct ip6_conntrack_tuple *tuple,
+ const struct ip6_conntrack *ignored_conntrack);
+
+extern int __ip6_conntrack_confirm(struct sk_buff *skb);
+
+/* Confirm a connection: returns NF_DROP if packet must be dropped. */
+static inline int ip6_conntrack_confirm(struct sk_buff *skb)
+{
+ if (skb->nfct
+ && !is_confirmed((struct ip6_conntrack *)skb->nfct))
+ return __ip6_conntrack_confirm(skb);
+ return NF_ACCEPT;
+}
+
+extern struct list_head *ip6_conntrack_hash;
+extern struct list_head ip6_conntrack_expect_list;
+DECLARE_RWLOCK_EXTERN(ip6_conntrack_lock);
+#endif /* _IP6_CONNTRACK_CORE_H */
+
diff -urN linux-2.6.11/include/linux/netfilter_ipv6/ip6_conntrack_ftp.h linux.sinabox/include/linux/netfilter_ipv6/ip6_conntrack_ftp.h
--- linux-2.6.11/include/linux/netfilter_ipv6/ip6_conntrack_ftp.h 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/include/linux/netfilter_ipv6/ip6_conntrack_ftp.h 2005-03-26 19:02:06.000000000 +0100
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C)2003 USAGI/WIDE Project
+ *
+ * Authors:
+ * Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
+ *
+ * Based on: include/linux/netfilter_ipv4/ip_conntrack_ftp.h
+ *
+ * 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.
+ */
+#ifndef _IP6_CONNTRACK_FTP_H
+#define _IP6_CONNTRACK_FTP_H
+/* FTP tracking. */
+
+#ifdef __KERNEL__
+
+#include <linux/netfilter_ipv4/lockhelp.h>
+
+/* Protects ftp part of conntracks */
+DECLARE_LOCK_EXTERN(ip6_ftp_lock);
+
+#define FTP_PORT 21
+
+#endif /* __KERNEL__ */
+
+enum ip6_ct_ftp_type
+{
+ /* EPRT command from client */
+ IP6_CT_FTP_EPRT,
+ /* EPSV response from server */
+ IP6_CT_FTP_EPSV,
+};
+
+/* This structure is per expected connection */
+struct ip6_ct_ftp_expect
+{
+ /* We record seq number and length of ftp ip/port text here: all in
+ * host order. */
+
+ /* sequence number of IP address in packet is in ip_conntrack_expect */
+ u_int32_t len; /* length of IPv6 address */
+ enum ip6_ct_ftp_type ftptype; /* EPRT or EPSV ? */
+ u_int16_t port; /* Port that was to be used */
+};
+
+/* This structure exists only once per master */
+struct ip6_ct_ftp_master {
+ /* Next valid seq position for cmd matching after newline */
+ u_int32_t seq_aft_nl[IP6_CT_DIR_MAX];
+ /* 0 means seq_match_aft_nl not set */
+ int seq_aft_nl_set[IP6_CT_DIR_MAX];
+};
+
+#endif /* _IP6_CONNTRACK_FTP_H */
diff -urN linux-2.6.11/include/linux/netfilter_ipv6/ip6_conntrack.h linux.sinabox/include/linux/netfilter_ipv6/ip6_conntrack.h
--- linux-2.6.11/include/linux/netfilter_ipv6/ip6_conntrack.h 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/include/linux/netfilter_ipv6/ip6_conntrack.h 2005-03-26 19:02:06.000000000 +0100
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C)2003 USAGI/WIDE Project
+ *
+ * Authors:
+ * Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
+ *
+ * Based on: include/linux/netfilter_ipv4/ip_conntrack.h
+ *
+ * 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.
+ */
+#ifndef _IP6_CONNTRACK_H
+#define _IP6_CONNTRACK_H
+/* Connection state tracking for netfilter. This is separated from,
+ but required by, the NAT layer; it can also be used by an iptables
+ extension. */
+
+#include <linux/config.h>
+#include <linux/netfilter_ipv6/ip6_conntrack_tuple.h>
+#include <linux/bitops.h>
+#include <linux/compiler.h>
+#include <asm/atomic.h>
+
+enum ip6_conntrack_info
+{
+ /* Part of an established connection (either direction). */
+ IP6_CT_ESTABLISHED,
+
+ /* Like NEW, but related to an existing connection, or ICMP error
+ (in either direction). */
+ IP6_CT_RELATED,
+
+ /* Started a new connection to track (only
+ IP6_CT_DIR_ORIGINAL); may be a retransmission. */
+ IP6_CT_NEW,
+
+ /* >= this indicates reply direction */
+ IP6_CT_IS_REPLY,
+
+ /* Number of distinct IP6_CT types (no NEW in reply dirn). */
+ IP6_CT_NUMBER = IP6_CT_IS_REPLY * 2 - 1
+};
+
+/* Bitset representing status of connection. */
+enum ip6_conntrack_status {
+ /* It's an expected connection: bit 0 set. This bit never changed */
+ IP6S_EXPECTED_BIT = 0,
+ IP6S_EXPECTED = (1 << IP6S_EXPECTED_BIT),
+
+ /* We've seen packets both ways: bit 1 set. Can be set, not unset. */
+ IP6S_SEEN_REPLY_BIT = 1,
+ IP6S_SEEN_REPLY = (1 << IP6S_SEEN_REPLY_BIT),
+
+ /* Conntrack should never be early-expired. */
+ IP6S_ASSURED_BIT = 2,
+ IP6S_ASSURED = (1 << IP6S_ASSURED_BIT),
+
+ /* Connection is confirmed: originating packet has left box */
+ IP6S_CONFIRMED_BIT = 3,
+ IP6S_CONFIRMED = (1 << IP6S_CONFIRMED_BIT),
+};
+
+#include <linux/netfilter_ipv6/ip6_conntrack_tcp.h>
+#include <linux/netfilter_ipv6/ip6_conntrack_icmpv6.h>
+
+/* per conntrack: protocol private data */
+union ip6_conntrack_proto {
+ /* insert conntrack proto private data here */
+ struct ip6_ct_tcp tcp;
+ struct ip6_ct_icmpv6 icmpv6;
+};
+
+union ip6_conntrack_expect_proto {
+ /* insert expect proto private data here */
+};
+
+/* Add protocol helper include file here */
+#include <linux/netfilter_ipv6/ip6_conntrack_ftp.h>
+
+/* per expectation: application helper private data */
+union ip6_conntrack_expect_help {
+ /* insert conntrack helper private data (expect) here */
+ struct ip6_ct_ftp_expect exp_ftp_info;
+};
+
+/* per conntrack: application helper private data */
+union ip6_conntrack_help {
+ /* insert conntrack helper private data (master) here */
+ struct ip6_ct_ftp_master ct_ftp_info;
+};
+
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+#include <linux/skbuff.h>
+
+#ifdef CONFIG_NF_DEBUG
+#define IP6_NF_ASSERT(x) \
+do { \
+ if (!(x)) \
+ /* Wooah! I'm tripping my conntrack in a frenzy of \
+ netplay... */ \
+ printk("NF_IP6_ASSERT: %s:%i(%s)\n", \
+ __FILE__, __LINE__, __FUNCTION__); \
+} while(0)
+#else
+#define IP6_NF_ASSERT(x)
+#endif
+
+struct ip6_conntrack_expect
+{
+ /* Internal linked list (global expectation list) */
+ struct list_head list;
+
+ /* reference count */
+ atomic_t use;
+
+ /* expectation list for this master */
+ struct list_head expected_list;
+
+ /* The conntrack of the master connection */
+ struct ip6_conntrack *expectant;
+
+ /* The conntrack of the sibling connection, set after
+ * expectation arrived */
+ struct ip6_conntrack *sibling;
+
+ /* IPv6 packet is never NATed */
+ /* Tuple saved for conntrack */
+/*
+ struct ip6_conntrack_tuple ct_tuple;
+*/
+
+ /* Timer function; deletes the expectation. */
+ struct timer_list timeout;
+
+ /* Data filled out by the conntrack helpers follow: */
+
+ /* We expect this tuple, with the following mask */
+ struct ip6_conntrack_tuple tuple, mask;
+
+ /* Function to call after setup and insertion */
+ int (*expectfn)(struct ip6_conntrack *new);
+
+ /* At which sequence number did this expectation occur */
+ u_int32_t seq;
+
+ union ip6_conntrack_expect_proto proto;
+
+ union ip6_conntrack_expect_help help;
+};
+
+#include <linux/netfilter_ipv6/ip6_conntrack_helper.h>
+struct ip6_conntrack
+{
+ /* Usage count in here is 1 for hash table/destruct timer, 1 per skb,
+ plus 1 for any connection(s) we are `master' for */
+ struct nf_conntrack ct_general;
+
+ /* These are my tuples; original and reply */
+ struct ip6_conntrack_tuple_hash tuplehash[IP6_CT_DIR_MAX];
+
+ /* Have we seen traffic both ways yet? (bitset) */
+ unsigned long status;
+
+ /* Timer function; drops refcnt when it goes off. */
+ struct timer_list timeout;
+
+ /* If we're expecting another related connection, this will be
+ in expected linked list */
+ struct list_head sibling_list;
+
+ /* Current number of expected connections */
+ unsigned int expecting;
+
+ /* If we were expected by an expectation, this will be it */
+ struct ip6_conntrack_expect *master;
+
+ /* Helper, if any. */
+ struct ip6_conntrack_helper *helper;
+
+ /* Storage reserved for other modules: */
+ union ip6_conntrack_proto proto;
+
+ union ip6_conntrack_help help;
+};
+
+/* get master conntrack via master expectation */
+#define master_ct6(conntr) (conntr->master ? conntr->master->expectant : NULL)
+
+/* Alter reply tuple (maybe alter helper). If it's already taken,
+ return 0 and don't do alteration. */
+extern int
+ip6_conntrack_alter_reply(struct ip6_conntrack *conntrack,
+ const struct ip6_conntrack_tuple *newreply);
+
+/* Is this tuple taken? (ignoring any belonging to the given
+ conntrack). */
+extern int
+ip6_conntrack_tuple_taken(const struct ip6_conntrack_tuple *tuple,
+ const struct ip6_conntrack *ignored_conntrack);
+
+/* Return conntrack_info and tuple hash for given skb. */
+static inline struct ip6_conntrack *
+ip6_conntrack_get(const struct sk_buff *skb, enum ip6_conntrack_info *ctinfo)
+{
+ *ctinfo = skb->nfctinfo;
+ return (struct ip6_conntrack *)skb->nfct;
+}
+
+/* decrement reference count on a conntrack */
+extern inline void ip6_conntrack_put(struct ip6_conntrack *ct);
+
+/* find unconfirmed expectation based on tuple */
+struct ip6_conntrack_expect *
+ip6_conntrack_expect_find_get(const struct ip6_conntrack_tuple *tuple);
+
+/* decrement reference count on an expectation */
+void ip6_conntrack_expect_put(struct ip6_conntrack_expect *exp);
+
+/* call to create an explicit dependency on ip6_conntrack. */
+extern void need_ip6_conntrack(void);
+
+extern int ip6_invert_tuplepr(struct ip6_conntrack_tuple *inverse,
+ const struct ip6_conntrack_tuple *orig);
+
+/* Refresh conntrack for this many jiffies */
+extern void ip6_ct_refresh(struct ip6_conntrack *ct,
+ unsigned long extra_jiffies);
+
+/* Call me when a conntrack is destroyed. */
+extern void (*ip6_conntrack_destroyed)(struct ip6_conntrack *conntrack);
+
+/* Returns new sk_buff, or NULL */
+struct sk_buff *
+ip6_ct_gather_frags(struct sk_buff *skb);
+
+/* Delete all conntracks which match. */
+extern void
+ip6_ct_selective_cleanup(int (*kill)(const struct ip6_conntrack *i, void *data),
+ void *data);
+
+/* It's confirmed if it is, or has been in the hash table. */
+static inline int is_confirmed(struct ip6_conntrack *ct)
+{
+ return test_bit(IP6S_CONFIRMED_BIT, &ct->status);
+}
+
+extern unsigned int ip6_conntrack_htable_size;
+
+/* eg. PROVIDES_CONNTRACK6(ftp); */
+#define PROVIDES_CONNTRACK6(name) \
+ int needs_ip6_conntrack_##name; \
+ EXPORT_SYMBOL(needs_ip6_conntrack_##name)
+
+/*. eg. NEEDS_CONNTRACK6(ftp); */
+#define NEEDS_CONNTRACK6(name) \
+ extern int needs_ip6_conntrack_##name; \
+ static int *need_ip6_conntrack_##name __attribute_used__ = &needs_ip6_conntrack_##name
+
+#endif /* __KERNEL__ */
+#endif /* _IP6_CONNTRACK_H */
diff -urN linux-2.6.11/include/linux/netfilter_ipv6/ip6_conntrack_helper.h linux.sinabox/include/linux/netfilter_ipv6/ip6_conntrack_helper.h
--- linux-2.6.11/include/linux/netfilter_ipv6/ip6_conntrack_helper.h 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/include/linux/netfilter_ipv6/ip6_conntrack_helper.h 2005-03-26 19:02:06.000000000 +0100
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C)2003 USAGI/WIDE Project
+ *
+ * Authors:
+ * Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
+ *
+ * Based on: include/linux/netfilter_ipv4/ip_conntrack_helper.h
+ *
+ * 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.
+ */
+/* IP6 connection tracking helpers. */
+#ifndef _IP6_CONNTRACK_HELPER_H
+#define _IP6_CONNTRACK_HELPER_H
+#include <linux/netfilter_ipv6/ip6_conntrack.h>
+
+struct module;
+
+/* Reuse expectation when max_expected reached */
+#define IP6_CT_HELPER_F_REUSE_EXPECT 0x01
+
+struct ip6_conntrack_helper
+{
+ struct list_head list; /* Internal use. */
+
+ const char *name; /* name of the module */
+ unsigned char flags; /* Flags (see above) */
+ struct module *me; /* pointer to self */
+ unsigned int max_expected; /* Maximum number of concurrent
+ * expected connections */
+ unsigned int timeout; /* timeout for expecteds */
+
+ /* Mask of things we will help (compared against server response) */
+ struct ip6_conntrack_tuple tuple;
+ struct ip6_conntrack_tuple mask;
+
+ /* Function to call when data passes; return verdict, or -1 to
+ invalidate. */
+ int (*help)(const struct sk_buff *skb,
+ unsigned int protoff,
+ struct ip6_conntrack *ct,
+ enum ip6_conntrack_info conntrackinfo);
+};
+
+extern int ip6_conntrack_helper_register(struct ip6_conntrack_helper *);
+extern void ip6_conntrack_helper_unregister(struct ip6_conntrack_helper *);
+
+extern struct ip6_conntrack_helper *ip6_ct_find_helper(const struct ip6_conntrack_tuple *tuple);
+
+/* Add an expected connection: can have more than one per connection */
+extern int ip6_conntrack_expect_related(struct ip6_conntrack *related_to,
+ struct ip6_conntrack_expect *exp);
+extern void ip6_conntrack_unexpect_related(struct ip6_conntrack_expect *exp);
+
+#endif /*_IP6_CONNTRACK_HELPER_H*/
diff -urN linux-2.6.11/include/linux/netfilter_ipv6/ip6_conntrack_icmpv6.h linux.sinabox/include/linux/netfilter_ipv6/ip6_conntrack_icmpv6.h
--- linux-2.6.11/include/linux/netfilter_ipv6/ip6_conntrack_icmpv6.h 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/include/linux/netfilter_ipv6/ip6_conntrack_icmpv6.h 2005-03-26 19:02:06.000000000 +0100
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C)2003 USAGI/WIDE Project
+ *
+ * Authors:
+ * Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
+ *
+ * Based on: include/linux/netfilter_ipv4/ip_conntrack_icmp.h
+ *
+ * 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.
+ */
+#ifndef _IP6_CONNTRACK_ICMPV6_H
+#define _IP6_CONNTRACK_ICMPV6_H
+/* ICMPv6 tracking. */
+#include <asm/atomic.h>
+
+struct ip6_ct_icmpv6
+{
+ /* Optimization: when number in == number out, forget immediately. */
+ atomic_t count;
+};
+#endif /* _IP6_CONNTRACK_ICMPv6_H */
diff -urN linux-2.6.11/include/linux/netfilter_ipv6/ip6_conntrack_protocol.h linux.sinabox/include/linux/netfilter_ipv6/ip6_conntrack_protocol.h
--- linux-2.6.11/include/linux/netfilter_ipv6/ip6_conntrack_protocol.h 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/include/linux/netfilter_ipv6/ip6_conntrack_protocol.h 2005-03-26 19:02:06.000000000 +0100
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C)2003 USAGI/WIDE Project
+ *
+ * Authors:
+ * Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
+ *
+ * Based on: include/linux/netfilter_ipv4/ip_conntrack_protocol.h
+ *
+ * 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.
+ */
+/* Header for use in defining a given protocol for connection tracking. */
+#ifndef _IP6_CONNTRACK_PROTOCOL_H
+#define _IP6_CONNTRACK_PROTOCOL_H
+#include <linux/netfilter_ipv6/ip6_conntrack.h>
+#include <linux/skbuff.h>
+
+struct ip6_conntrack_protocol
+{
+ /* Next pointer. */
+ struct list_head list;
+
+ /* Protocol number. */
+ u_int8_t proto;
+
+ /* Protocol name */
+ const char *name;
+
+ /* Try to fill in the third arg: dataoff is offset past IPv6
+ hdr and IPv6 ext hdrs. Return true if possible. */
+ int (*pkt_to_tuple)(const struct sk_buff *skb,
+ unsigned int dataoff,
+ struct ip6_conntrack_tuple *tuple);
+
+ /* Invert the per-proto part of the tuple: ie. turn xmit into reply.
+ * Some packets can't be inverted: return 0 in that case.
+ */
+ int (*invert_tuple)(struct ip6_conntrack_tuple *inverse,
+ const struct ip6_conntrack_tuple *orig);
+
+ /* Print out the per-protocol part of the tuple. */
+ unsigned int (*print_tuple)(char *buffer,
+ const struct ip6_conntrack_tuple *);
+
+ /* Print out the private part of the conntrack. */
+ unsigned int (*print_conntrack)(char *buffer,
+ const struct ip6_conntrack *);
+
+ /* Returns verdict for packet, or -1 for invalid. */
+ int (*packet)(struct ip6_conntrack *conntrack,
+ const struct sk_buff *skb,
+ unsigned int dataoff,
+ enum ip6_conntrack_info ctinfo);
+
+ /* Called when a new connection for this protocol found;
+ * returns TRUE if it's OK. If so, packet() called next. */
+ int (*new)(struct ip6_conntrack *conntrack, const struct sk_buff *skb,
+ unsigned int dataoff);
+
+ /* Called when a conntrack entry is destroyed */
+ void (*destroy)(struct ip6_conntrack *conntrack);
+
+ /* Has to decide if a expectation matches one packet or not */
+ int (*exp_matches_pkt)(struct ip6_conntrack_expect *exp,
+ const struct sk_buff *skb,
+ unsigned int dataoff);
+
+ /* Module (if any) which this is connected to. */
+ struct module *me;
+};
+
+/* Protocol registration. */
+extern int ip6_conntrack_protocol_register(struct ip6_conntrack_protocol *proto);
+extern void ip6_conntrack_protocol_unregister(struct ip6_conntrack_protocol *proto);
+
+/* Existing built-in protocols */
+extern struct ip6_conntrack_protocol ip6_conntrack_protocol_tcp;
+extern struct ip6_conntrack_protocol ip6_conntrack_protocol_udp;
+extern struct ip6_conntrack_protocol ip6_conntrack_protocol_icmpv6;
+extern int ip6_conntrack_protocol_tcp_init(void);
+#endif /*_IP6_CONNTRACK_PROTOCOL_H*/
diff -urN linux-2.6.11/include/linux/netfilter_ipv6/ip6_conntrack_reasm.h linux.sinabox/include/linux/netfilter_ipv6/ip6_conntrack_reasm.h
--- linux-2.6.11/include/linux/netfilter_ipv6/ip6_conntrack_reasm.h 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/include/linux/netfilter_ipv6/ip6_conntrack_reasm.h 2005-03-26 19:02:06.000000000 +0100
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C)2003 USAGI/WIDE Project
+ *
+ * Authors:
+ * Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
+ *
+ * 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.
+ */
+#ifndef _IP6_CONNTRACK_REASM_H
+#define _IP6_CONNTRACK_REASM_H
+
+#include <linux/netfilter.h>
+extern struct sk_buff *
+ip6_ct_gather_frags(struct sk_buff *skb);
+
+extern int
+ip6_ct_output_frags(struct sk_buff *skb, struct nf_info *info);
+
+extern int ip6_ct_kfree_frags(struct sk_buff *skb);
+
+extern int ip6_ct_frags_init(void);
+extern void ip6_ct_frags_cleanup(void);
+
+#endif /* _IP6_CONNTRACK_REASM_H */
+
diff -urN linux-2.6.11/include/linux/netfilter_ipv6/ip6_conntrack_tcp.h linux.sinabox/include/linux/netfilter_ipv6/ip6_conntrack_tcp.h
--- linux-2.6.11/include/linux/netfilter_ipv6/ip6_conntrack_tcp.h 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/include/linux/netfilter_ipv6/ip6_conntrack_tcp.h 2005-03-26 19:02:06.000000000 +0100
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C)2003 USAGI/WIDE Project
+ *
+ * Authors:
+ * Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
+ *
+ * Based on: include/linux/netfilter_ipv4/ip_conntrack_tcp.h
+ *
+ * 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.
+ */
+#ifndef _IP6_CONNTRACK_TCP_H
+#define _IP6_CONNTRACK_TCP_H
+/* TCP tracking. */
+
+enum tcp_conntrack {
+ TCP_CONNTRACK_NONE,
+ TCP_CONNTRACK_ESTABLISHED,
+ TCP_CONNTRACK_SYN_SENT,
+ TCP_CONNTRACK_SYN_RECV,
+ TCP_CONNTRACK_FIN_WAIT,
+ TCP_CONNTRACK_TIME_WAIT,
+ TCP_CONNTRACK_CLOSE,
+ TCP_CONNTRACK_CLOSE_WAIT,
+ TCP_CONNTRACK_LAST_ACK,
+ TCP_CONNTRACK_LISTEN,
+ TCP_CONNTRACK_MAX
+};
+
+struct ip6_ct_tcp
+{
+ enum tcp_conntrack state;
+
+ /* Poor man's window tracking: sequence number of valid ACK
+ handshake completion packet */
+ u_int32_t handshake_ack;
+};
+
+#endif /* _IP6_CONNTRACK_TCP_H */
diff -urN linux-2.6.11/include/linux/netfilter_ipv6/ip6_conntrack_tuple.h linux.sinabox/include/linux/netfilter_ipv6/ip6_conntrack_tuple.h
--- linux-2.6.11/include/linux/netfilter_ipv6/ip6_conntrack_tuple.h 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/include/linux/netfilter_ipv6/ip6_conntrack_tuple.h 2005-03-26 19:02:06.000000000 +0100
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C)2003 USAGI/WIDE Project
+ *
+ * Authors:
+ * Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
+ *
+ * Based on: include/linux/netfilter_ipv4/ip_conntrack_tuple.h
+ *
+ * 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.
+ */
+#ifndef _IP6_CONNTRACK_TUPLE_H
+#define _IP6_CONNTRACK_TUPLE_H
+
+#ifdef __KERNEL__
+#include <linux/in6.h>
+#include <linux/kernel.h>
+#endif
+
+/* A `tuple' is a structure containing the information to uniquely
+ identify a connection. ie. if two packets have the same tuple, they
+ are in the same connection; if not, they are not.
+
+ We divide the structure along "manipulatable" and
+ "non-manipulatable" lines, for the benefit of the NAT code.
+*/
+
+/* The protocol-specific manipulable parts of the tuple: always in
+ network order! */
+union ip6_conntrack_manip_proto
+{
+ /* Add other protocols here. */
+ u_int16_t all;
+
+ struct {
+ u_int16_t port;
+ } tcp;
+ struct {
+ u_int16_t port;
+ } udp;
+ struct {
+ u_int16_t id;
+ } icmpv6;
+};
+
+/* The manipulable part of the tuple. */
+struct ip6_conntrack_manip
+{
+ struct in6_addr ip;
+ union ip6_conntrack_manip_proto u;
+};
+
+/* This contains the information to distinguish a connection. */
+struct ip6_conntrack_tuple
+{
+ struct ip6_conntrack_manip src;
+
+ /* These are the parts of the tuple which are fixed. */
+ struct {
+ struct in6_addr ip;
+ union {
+ /* Add other protocols here. */
+ u_int16_t all;
+
+ struct {
+ u_int16_t port;
+ } tcp;
+ struct {
+ u_int16_t port;
+ } udp;
+ struct {
+ u_int8_t type, code;
+ } icmpv6;
+ } u;
+
+ /* The protocol. */
+ u_int16_t protonum;
+ } dst;
+};
+
+enum ip6_conntrack_dir
+{
+ IP6_CT_DIR_ORIGINAL,
+ IP6_CT_DIR_REPLY,
+ IP6_CT_DIR_MAX
+};
+
+#ifdef __KERNEL__
+
+#define DUMP_TUPLE(tp) \
+{ \
+ DEBUGP("tuple %p: %u %x:%x:%x:%x:%x:%x:%x:%x, %hu -> %x:%x:%x:%x:%x:%x:%x:%x, %hu\n", \
+ (tp), (tp)->dst.protonum, \
+ NIP6((tp)->src.ip), ntohs((tp)->src.u.all), \
+ NIP6((tp)->dst.ip), ntohs((tp)->dst.u.all)); \
+}
+
+#define CTINFO2DIR(ctinfo) ((ctinfo) >= IP6_CT_IS_REPLY ? IP6_CT_DIR_REPLY : IP6_CT_DIR_ORIGINAL)
+
+/* If we're the first tuple, it's the original dir. */
+#define DIRECTION(h) ((enum ip6_conntrack_dir)(&(h)->ctrack->tuplehash[1] == (h)))
+
+/* Connections have two entries in the hash table: one for each way */
+struct ip6_conntrack_tuple_hash
+{
+ struct list_head list;
+
+ struct ip6_conntrack_tuple tuple;
+
+ /* this == &ctrack->tuplehash[DIRECTION(this)]. */
+ struct ip6_conntrack *ctrack;
+};
+
+#endif /* __KERNEL__ */
+
+extern int ip6_ct_tuple_src_equal(const struct ip6_conntrack_tuple *t1,
+ const struct ip6_conntrack_tuple *t2);
+
+extern int ip6_ct_tuple_dst_equal(const struct ip6_conntrack_tuple *t1,
+ const struct ip6_conntrack_tuple *t2);
+
+extern int ip6_ct_tuple_equal(const struct ip6_conntrack_tuple *t1,
+ const struct ip6_conntrack_tuple *t2);
+
+extern int ip6_ct_tuple_mask_cmp(const struct ip6_conntrack_tuple *t,
+ const struct ip6_conntrack_tuple *tuple,
+ const struct ip6_conntrack_tuple *mask);
+
+#endif /* _IP6_CONNTRACK_TUPLE_H */
diff -urN linux-2.6.11/include/linux/netfilter_ipv6/ip6t_IMQ.h linux.sinabox/include/linux/netfilter_ipv6/ip6t_IMQ.h
--- linux-2.6.11/include/linux/netfilter_ipv6/ip6t_IMQ.h 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/include/linux/netfilter_ipv6/ip6t_IMQ.h 2005-03-26 00:49:04.000000000 +0100
@@ -0,0 +1,8 @@
+#ifndef _IP6T_IMQ_H
+#define _IP6T_IMQ_H
+
+struct ip6t_imq_info {
+ unsigned int todev; /* target imq device */
+};
+
+#endif /* _IP6T_IMQ_H */
diff -urN linux-2.6.11/include/linux/netfilter_ipv6/ip6t_REJECT.h linux.sinabox/include/linux/netfilter_ipv6/ip6t_REJECT.h
--- linux-2.6.11/include/linux/netfilter_ipv6/ip6t_REJECT.h 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/include/linux/netfilter_ipv6/ip6t_REJECT.h 2005-03-26 19:02:06.000000000 +0100
@@ -0,0 +1,18 @@
+#ifndef _IP6T_REJECT_H
+#define _IP6T_REJECT_H
+
+enum ip6t_reject_with {
+ IP6T_ICMP6_NO_ROUTE,
+ IP6T_ICMP6_ADM_PROHIBITED,
+ IP6T_ICMP6_NOT_NEIGHBOUR,
+ IP6T_ICMP6_ADDR_UNREACH,
+ IP6T_ICMP6_PORT_UNREACH,
+ IP6T_ICMP6_ECHOREPLY,
+ IP6T_TCP_RESET
+};
+
+struct ip6t_reject_info {
+ enum ip6t_reject_with with; /* reject type */
+};
+
+#endif /*_IP6T_REJECT_H*/
diff -urN linux-2.6.11/include/linux/netfilter_ipv6/ip6t_state.h linux.sinabox/include/linux/netfilter_ipv6/ip6t_state.h
--- linux-2.6.11/include/linux/netfilter_ipv6/ip6t_state.h 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/include/linux/netfilter_ipv6/ip6t_state.h 2005-03-26 19:02:06.000000000 +0100
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C)2003 USAGI/WIDE Project
+ *
+ * Authors:
+ * Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
+ *
+ * Based on: include/linux/netfilter_ipv4/ipt_state.h
+ *
+ * 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.
+ */
+#ifndef _IP6T_STATE_H
+#define _IP6T_STATE_H
+
+#define IP6T_STATE_BIT(ctinfo) (1 << ((ctinfo)%IP6_CT_IS_REPLY+1))
+#define IP6T_STATE_INVALID (1 << 0)
+
+struct ip6t_state_info
+{
+ unsigned int statemask;
+};
+#endif /*_IP6T_STATE_H*/
diff -urN linux-2.6.11/include/linux/rtnetlink.h linux.sinabox/include/linux/rtnetlink.h
--- linux-2.6.11/include/linux/rtnetlink.h 2005-03-02 08:38:18.000000000 +0100
+++ linux.sinabox/include/linux/rtnetlink.h 2005-03-26 19:02:06.000000000 +0100
@@ -346,6 +346,7 @@
#define RTAX_FEATURE_ECN 0x00000001
#define RTAX_FEATURE_SACK 0x00000002
#define RTAX_FEATURE_TIMESTAMP 0x00000004
+#define RTAX_FEATURE_ALLFRAG 0x00000008
struct rta_session
{
diff -urN linux-2.6.11/include/linux/skbuff.h linux.sinabox/include/linux/skbuff.h
--- linux-2.6.11/include/linux/skbuff.h 2005-03-02 08:38:38.000000000 +0100
+++ linux.sinabox/include/linux/skbuff.h 2005-03-26 00:49:04.000000000 +0100
@@ -251,6 +251,11 @@
__u32 nfcache;
__u32 nfctinfo;
struct nf_conntrack *nfct;
+
+#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
+ unsigned char imq_flags;
+ struct nf_info *nf_info;
+#endif
#ifdef CONFIG_NETFILTER_DEBUG
unsigned int nf_debug;
#endif
diff -urN linux-2.6.11/include/linux/sysctl.h linux.sinabox/include/linux/sysctl.h
--- linux-2.6.11/include/linux/sysctl.h 2005-03-02 08:38:10.000000000 +0100
+++ linux.sinabox/include/linux/sysctl.h 2005-03-26 19:02:06.000000000 +0100
@@ -455,7 +455,8 @@
NET_IPV6_ROUTE_GC_INTERVAL=6,
NET_IPV6_ROUTE_GC_ELASTICITY=7,
NET_IPV6_ROUTE_MTU_EXPIRES=8,
- NET_IPV6_ROUTE_MIN_ADVMSS=9
+ NET_IPV6_ROUTE_MIN_ADVMSS=9,
+ NET_IPV6_ROUTE_GC_MIN_INTERVAL_MS=10
};
enum {
@@ -475,7 +476,8 @@
NET_IPV6_REGEN_MAX_RETRY=14,
NET_IPV6_MAX_DESYNC_FACTOR=15,
NET_IPV6_MAX_ADDRESSES=16,
- NET_IPV6_FORCE_MLD_VERSION=17
+ NET_IPV6_FORCE_MLD_VERSION=17,
+ NET_IPV6_MC_FORWARDING=18
};
/* /proc/sys/net/ipv6/icmp */
@@ -488,8 +490,8 @@
NET_NEIGH_MCAST_SOLICIT=1,
NET_NEIGH_UCAST_SOLICIT=2,
NET_NEIGH_APP_SOLICIT=3,
- NET_NEIGH_RETRANS_TIME=4,
- NET_NEIGH_REACHABLE_TIME=5,
+ NET_NEIGH_RETRANS_TIME=4, /* deprecated */
+ NET_NEIGH_REACHABLE_TIME=5, /* deprecated */
NET_NEIGH_DELAY_PROBE_TIME=6,
NET_NEIGH_GC_STALE_TIME=7,
NET_NEIGH_UNRES_QLEN=8,
@@ -500,7 +502,10 @@
NET_NEIGH_GC_INTERVAL=13,
NET_NEIGH_GC_THRESH1=14,
NET_NEIGH_GC_THRESH2=15,
- NET_NEIGH_GC_THRESH3=16
+ NET_NEIGH_GC_THRESH3=16,
+ NET_NEIGH_RETRANS_TIME_MS=17,
+ NET_NEIGH_REACHABLE_TIME_MS=18,
+ __NET_NEIGH_MAX
};
/* /proc/sys/net/ipx */
diff -urN linux-2.6.11/include/linux/xfrm.h linux.sinabox/include/linux/xfrm.h
--- linux-2.6.11/include/linux/xfrm.h 2005-03-02 08:38:37.000000000 +0100
+++ linux.sinabox/include/linux/xfrm.h 2005-03-26 19:02:06.000000000 +0100
@@ -90,8 +90,12 @@
{
XFRM_POLICY_IN = 0,
XFRM_POLICY_OUT = 1,
+#ifdef CONFIG_USE_POLICY_FWD
XFRM_POLICY_FWD = 2,
XFRM_POLICY_MAX = 3
+#else
+ XFRM_POLICY_MAX = 2
+#endif
};
enum
diff -urN linux-2.6.11/include/net/addrconf.h linux.sinabox/include/net/addrconf.h
--- linux-2.6.11/include/net/addrconf.h 2005-03-02 08:38:18.000000000 +0100
+++ linux.sinabox/include/net/addrconf.h 2005-03-26 19:02:06.000000000 +0100
@@ -102,6 +102,8 @@
extern void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len);
+extern int ipv6_get_hoplimit(struct net_device *dev);
+
/*
* anycast prototypes (anycast.c)
*/
diff -urN linux-2.6.11/include/net/dst.h linux.sinabox/include/net/dst.h
--- linux-2.6.11/include/net/dst.h 2005-03-02 08:38:38.000000000 +0100
+++ linux.sinabox/include/net/dst.h 2005-03-26 19:02:06.000000000 +0100
@@ -125,6 +125,18 @@
}
static inline int
+ip6_dst_allfrag(const struct dst_entry *dst)
+{
+#ifdef CONFIG_IPV6_ALLFRAG
+ int ret = dst_path_metric(dst, RTAX_FEATURES) & RTAX_FEATURE_ALLFRAG;
+ barrier();
+ return ret;
+#else
+ return 0;
+#endif
+};
+
+static inline int
dst_metric_locked(struct dst_entry *dst, int metric)
{
return dst_metric(dst, RTAX_LOCK) & (1<<metric);
diff -urN linux-2.6.11/include/net/if_inet6.h linux.sinabox/include/net/if_inet6.h
--- linux-2.6.11/include/net/if_inet6.h 2005-03-02 08:38:32.000000000 +0100
+++ linux.sinabox/include/net/if_inet6.h 2005-03-26 19:02:06.000000000 +0100
@@ -150,7 +150,13 @@
struct ipv6_devstat {
struct proc_dir_entry *proc_dir_entry;
+#ifdef CONFIG_IPV6_STATISTICS
+ DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics);
+#endif
DEFINE_SNMP_STAT(struct icmpv6_mib, icmpv6);
+#if 0
+ DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6);
+#endif
};
struct inet6_dev
@@ -178,11 +184,15 @@
#ifdef CONFIG_IPV6_PRIVACY
u8 rndid[8];
+#ifdef CONFIG_IPV6_PRIVACY_MD5
u8 entropy[8];
+#endif
struct timer_list regen_timer;
struct inet6_ifaddr *tempaddr_list;
+#ifdef CONFIG_IPV6_PRIVACY_MD5
__u8 work_eui64[8];
__u8 work_digest[16];
+#endif /* CONFIG_IPV6_PRIVACY_MD5 */
#endif
struct neigh_parms *nd_parms;
diff -urN linux-2.6.11/include/net/ip6_route.h linux.sinabox/include/net/ip6_route.h
--- linux-2.6.11/include/net/ip6_route.h 2005-03-02 08:37:50.000000000 +0100
+++ linux.sinabox/include/net/ip6_route.h 2005-03-26 19:02:06.000000000 +0100
@@ -2,9 +2,9 @@
#define _NET_IP6_ROUTE_H
#define IP6_RT_PRIO_FW 16
-#define IP6_RT_PRIO_USER 1024
#define IP6_RT_PRIO_ADDRCONF 256
#define IP6_RT_PRIO_KERN 512
+#define IP6_RT_PRIO_USER 1024
#define IP6_RT_FLOW_MASK 0x00ff
#ifdef __KERNEL__
@@ -85,7 +85,8 @@
extern struct rt6_info * rt6_get_dflt_router(struct in6_addr *addr,
struct net_device *dev);
extern struct rt6_info * rt6_add_dflt_router(struct in6_addr *gwaddr,
- struct net_device *dev);
+ struct net_device *dev,
+ int pref);
extern void rt6_purge_dflt_routers(void);
diff -urN linux-2.6.11/include/net/ipv6.h linux.sinabox/include/net/ipv6.h
--- linux-2.6.11/include/net/ipv6.h 2005-03-02 08:38:19.000000000 +0100
+++ linux.sinabox/include/net/ipv6.h 2005-03-26 19:02:06.000000000 +0100
@@ -112,9 +112,30 @@
/* MIBs */
DECLARE_SNMP_STAT(struct ipstats_mib, ipv6_statistics);
+#ifdef CONFIG_IPV6_STATISTICS
+#define IP6_INC_STATS(idev, field) ({ \
+ struct inet6_dev *_idev = (idev); \
+ if (likely(_idev != NULL)) \
+ SNMP_INC_STATS(idev->stats.ipv6_statistics, field); \
+ SNMP_INC_STATS(ipv6_statistics, field); \
+})
+#define IP6_INC_STATS_BH(idev, field) ({ \
+ struct inet6_dev *_idev = (idev); \
+ if (likely(_idev != NULL)) \
+ SNMP_INC_STATS_BH((_idev)->stats.ipv6_statistics, field); \
+ SNMP_INC_STATS_BH(ipv6_statistics, field); \
+})
+#define IP6_INC_STATS_USER(idev, field) ({ \
+ struct inet6_dev *_idev = (idev); \
+ if (likely(_idev != NULL)) \
+ SNMP_INC_STATS_USER(_idev->stats.ipv6_statistics, field); \
+ SNMP_INC_STATS_USER(ipv6_statistics, field); \
+})
+#else
#define IP6_INC_STATS(field) SNMP_INC_STATS(ipv6_statistics, field)
#define IP6_INC_STATS_BH(field) SNMP_INC_STATS_BH(ipv6_statistics, field)
#define IP6_INC_STATS_USER(field) SNMP_INC_STATS_USER(ipv6_statistics, field)
+#endif
DECLARE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics);
#define ICMP6_INC_STATS(idev, field) ({ \
struct inet6_dev *_idev = (idev); \
@@ -142,9 +163,30 @@
SNMP_INC_STATS_OFFSET_BH(icmpv6_statistics, field, _offset); \
})
DECLARE_SNMP_STAT(struct udp_mib, udp_stats_in6);
+#if 0
+#define UDP6_INC_STATS(idev, field) ({ \
+ struct inet6_dev *_idev = (idev); \
+ if (likely(_idev != NULL)) \
+ SNMP_INC_STATS(idev->stats.udp_stats_in6, field); \
+ SNMP_INC_STATS(udp_stats_in6, field); \
+})
+#define UDP6_INC_STATS_BH(idev, field) ({ \
+ struct inet6_dev *_idev = (idev); \
+ if (likely(_idev != NULL)) \
+ SNMP_INC_STATS_BH((_idev)->stats.udp_stats_in6, field); \
+ SNMP_INC_STATS_BH(udp_stats_in6, field); \
+})
+#define UDP6_INC_STATS_USER(idev, field) ({ \
+ struct inet6_dev *_idev = (idev); \
+ if (likely(_idev != NULL)) \
+ SNMP_INC_STATS_USER(_idev->stats.udp_stats_in6, field); \
+ SNMP_INC_STATS_USER(udp_stats_in6, field); \
+})
+#else
#define UDP6_INC_STATS(field) SNMP_INC_STATS(udp_stats_in6, field)
#define UDP6_INC_STATS_BH(field) SNMP_INC_STATS_BH(udp_stats_in6, field)
-#define UDP6_INC_STATS_USER(field) SNMP_INC_STATS_USER(udp_stats_in6, field)
+#define UDP6_INC_STATS_USER(field) SNMP_INC_STATS_USER(udp_stats_in6, field)
+#endif
extern atomic_t inet6_sock_nr;
int snmp6_register_dev(struct inet6_dev *idev);
@@ -231,7 +273,7 @@
void (*destructor)(struct sock *));
-extern int ipv6_parse_hopopts(struct sk_buff *skb, int);
+extern int ipv6_parse_hopopts(struct sk_buff **skb, unsigned int *nhoffp);
extern struct ipv6_txoptions * ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt);
@@ -249,12 +291,28 @@
char *,
unsigned int, unsigned int);
-
-extern int ipv6_addr_type(const struct in6_addr *addr);
+/*
+ * Address manipulation functions
+ */
+extern int __ipv6_addr_type(const struct in6_addr *addr);
+static inline int ipv6_addr_type(const struct in6_addr *addr)
+{
+ return __ipv6_addr_type(addr) & 0xffff;
+}
static inline int ipv6_addr_scope(const struct in6_addr *addr)
{
- return ipv6_addr_type(addr) & IPV6_ADDR_SCOPE_MASK;
+ return __ipv6_addr_type(addr) & IPV6_ADDR_SCOPE_MASK;
+}
+
+static inline int __ipv6_addr_src_scope(int type)
+{
+ return type == IPV6_ADDR_ANY ? __IPV6_ADDR_SCOPE_INVALID : type>>16;
+}
+
+static inline int ipv6_addr_src_scope(const struct in6_addr *addr)
+{
+ return __ipv6_addr_src_scope(__ipv6_addr_type(addr));
}
static inline int ipv6_addr_cmp(const struct in6_addr *a1, const struct in6_addr *a2)
@@ -305,6 +363,33 @@
a1->s6_addr32[3] == a2->s6_addr32[3]);
}
+/* compare "prefix length" bits of an address */
+static inline int __ipv6_prefix_equal(const u32 *a1, const u32 *a2,
+ unsigned int prefixlen)
+{
+ unsigned pdw, pbi;
+
+ /* check complete u32 in prefix */
+ pdw = prefixlen >> 5;
+ if (pdw && memcmp(a1, a2, pdw << 2))
+ return 0;
+
+ /* check incomplete u32 in prefix */
+ pbi = prefixlen & 0x1f;
+ if (pbi && ((a1[pdw] ^ a2[pdw]) & htonl((0xffffffff) << (32 - pbi))))
+ return 0;
+
+ return 1;
+}
+
+static inline int ipv6_prefix_equal(const struct in6_addr *a1,
+ const struct in6_addr *a2,
+ unsigned int prefixlen)
+{
+ return __ipv6_prefix_equal(a1->s6_addr32, a2->s6_addr32,
+ prefixlen);
+}
+
static inline int ipv6_addr_any(const struct in6_addr *a)
{
return ((a->s6_addr32[0] | a->s6_addr32[1] |
@@ -368,6 +453,7 @@
extern int ip6_forward(struct sk_buff *skb);
extern int ip6_input(struct sk_buff *skb);
extern int ip6_mc_input(struct sk_buff *skb);
+extern int ip6_mr_input(struct sk_buff *skb);
/*
* Extension header (options) processing
diff -urN linux-2.6.11/include/net/neighbour.h linux.sinabox/include/net/neighbour.h
--- linux-2.6.11/include/net/neighbour.h 2005-03-02 08:38:32.000000000 +0100
+++ linux.sinabox/include/net/neighbour.h 2005-03-26 19:02:06.000000000 +0100
@@ -54,6 +54,8 @@
#include <linux/rcupdate.h>
#include <linux/seq_file.h>
+#include <linux/config.h>
+
#include <linux/err.h>
#include <linux/sysctl.h>
@@ -158,7 +160,8 @@
struct pneigh_entry
{
struct pneigh_entry *next;
- struct net_device *dev;
+ struct net_device *dev;
+ struct neigh_table *tbl;
u8 key[0];
};
@@ -205,6 +208,27 @@
#endif
};
+struct neigh_notifier_parms {
+ void (*link_notifier)(void *);
+ void *link_notifier_data;
+};
+
+static __inline__ char * neigh_state(int state)
+{
+ switch (state) {
+ case NUD_NONE: return "NONE";
+ case NUD_INCOMPLETE: return "INCOMPLETE";
+ case NUD_REACHABLE: return "REACHABLE";
+ case NUD_STALE: return "STALE";
+ case NUD_DELAY: return "DELAY";
+ case NUD_PROBE: return "PROBE";
+ case NUD_FAILED: return "FAILED";
+ case NUD_NOARP: return "NOARP";
+ case NUD_PERMANENT: return "PERMANENT";
+ default: return "???";
+ }
+}
+
/* flags for neigh_update() */
#define NEIGH_UPDATE_F_OVERRIDE 0x00000001
#define NEIGH_UPDATE_F_WEAK_OVERRIDE 0x00000002
@@ -274,7 +298,8 @@
struct neigh_parms *p,
int p_id, int pdev_id,
char *p_name,
- proc_handler *proc_handler);
+ proc_handler *proc_handler,
+ void (*notifier)(void *));
extern void neigh_sysctl_unregister(struct neigh_parms *p);
static inline void __neigh_parms_put(struct neigh_parms *parms)
@@ -300,18 +325,35 @@
static inline void neigh_release(struct neighbour *neigh)
{
+#ifdef CONFIG_IPV6_NDISC_DEBUG
+ printk(KERN_DEBUG "%s(neigh=%p): refcnt=%d\n",
+ __FUNCTION__, neigh, atomic_read(&neigh->refcnt)-1);
+#endif
if (atomic_dec_and_test(&neigh->refcnt))
neigh_destroy(neigh);
}
static inline struct neighbour * neigh_clone(struct neighbour *neigh)
{
+#ifdef CONFIG_IPV6_NDISC_DEBUG
+ printk(KERN_DEBUG "%s(neigh=%p): refcnt=%d\n",
+ __FUNCTION__, neigh, neigh ? atomic_read(&neigh->refcnt)+1 : 0);
+#endif
if (neigh)
atomic_inc(&neigh->refcnt);
return neigh;
}
+#ifdef CONFIG_IPV6_NDISC_DEBUG
+#define neigh_hold(n) ({ \
+ struct neighbour *_n = (n); \
+ printk(KERN_DEBUG "%s(neigh=%p): refcnt=%d\n", \
+ __FUNCTION__, _n, atomic_read(&_n->refcnt)+1); \
+ atomic_inc(&_n->refcnt); \
+})
+#else
#define neigh_hold(n) atomic_inc(&(n)->refcnt)
+#endif
static inline void neigh_confirm(struct neighbour *neigh)
{
@@ -331,6 +373,11 @@
static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
{
+#ifdef CONFIG_IPV6_NDISC_DEBUG
+ printk(KERN_DEBUG
+ "%s(neigh=%p, skb=%p): %s, refcnt=%d\n",
+ __FUNCTION__, neigh, skb, neigh_state(neigh->nud_state), atomic_read(&neigh->refcnt));
+#endif
neigh->used = jiffies;
if (!(neigh->nud_state&(NUD_CONNECTED|NUD_DELAY|NUD_PROBE)))
return __neigh_event_send(neigh, skb);
diff -urN linux-2.6.11/include/net/xfrm.h linux.sinabox/include/net/xfrm.h
--- linux-2.6.11/include/net/xfrm.h 2005-03-02 08:38:25.000000000 +0100
+++ linux.sinabox/include/net/xfrm.h 2005-03-26 19:02:06.000000000 +0100
@@ -471,8 +471,12 @@
static inline int
__xfrm6_selector_match(struct xfrm_selector *sel, struct flowi *fl)
{
- return addr_match(&fl->fl6_dst, &sel->daddr, sel->prefixlen_d) &&
- addr_match(&fl->fl6_src, &sel->saddr, sel->prefixlen_s) &&
+ return __ipv6_prefix_equal(fl->fl6_dst.s6_addr32,
+ sel->daddr.a6,
+ sel->prefixlen_d) &&
+ __ipv6_prefix_equal(fl->fl6_src.s6_addr32,
+ sel->saddr.a6,
+ sel->prefixlen_s) &&
!((xfrm_flowi_dport(fl) ^ sel->dport) & sel->dport_mask) &&
!((xfrm_flowi_sport(fl) ^ sel->sport) & sel->sport_mask) &&
(fl->proto == sel->proto || !sel->proto) &&
@@ -863,7 +867,7 @@
extern void km_policy_expired(struct xfrm_policy *pol, int dir, int hard);
extern void xfrm_input_init(void);
-extern int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq);
+extern int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi);
extern void xfrm_probe_algs(void);
extern int xfrm_count_auth_supported(void);
diff -urN linux-2.6.11/include/video/tgafb.h linux.sinabox/include/video/tgafb.h
--- linux-2.6.11/include/video/tgafb.h 2005-03-02 08:38:19.000000000 +0100
+++ linux.sinabox/include/video/tgafb.h 2005-03-26 19:02:06.000000000 +0100
@@ -47,7 +47,6 @@
#define TGA_VALID_REG 0x0070
#define TGA_CURSOR_XY_REG 0x0074
#define TGA_INTR_STAT_REG 0x007c
-#define TGA_DATA_REG 0x0080
#define TGA_RAMDAC_SETUP_REG 0x00c0
#define TGA_BLOCK_COLOR0_REG 0x0140
#define TGA_BLOCK_COLOR1_REG 0x0144
diff -urN linux-2.6.11/kernel/signal.c linux.sinabox/kernel/signal.c
--- linux-2.6.11/kernel/signal.c 2005-03-02 08:38:07.000000000 +0100
+++ linux.sinabox/kernel/signal.c 2005-03-19 07:34:55.000000000 +0100
@@ -1728,6 +1728,7 @@
* with another processor delivering a stop signal,
* then the SIGCONT that wakes us up should clear it.
*/
+ read_unlock(&tasklist_lock);
return 0;
}
diff -urN linux-2.6.11/Makefile linux.sinabox/Makefile
--- linux-2.6.11/Makefile 2005-03-02 08:38:13.000000000 +0100
+++ linux.sinabox/Makefile 2005-03-27 04:28:15.000000000 +0200
@@ -1,7 +1,7 @@
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 11
-EXTRAVERSION =
+EXTRAVERSION = .5
NAME=Woozy Numbat
# *DOCUMENTATION*
diff -urN linux-2.6.11/net/core/neighbour.c linux.sinabox/net/core/neighbour.c
--- linux-2.6.11/net/core/neighbour.c 2005-03-02 08:37:47.000000000 +0100
+++ linux.sinabox/net/core/neighbour.c 2005-03-26 19:02:06.000000000 +0100
@@ -33,13 +33,18 @@
#include <linux/rtnetlink.h>
#include <linux/random.h>
+#ifdef CONFIG_IPV6_NDISC_DEBUG
+#define NEIGH_DEBUG 3
+#else
#define NEIGH_DEBUG 1
+#endif
#define NEIGH_PRINTK(x...) printk(x)
#define NEIGH_NOPRINTK(x...) do { ; } while(0)
#define NEIGH_PRINTK0 NEIGH_PRINTK
#define NEIGH_PRINTK1 NEIGH_NOPRINTK
#define NEIGH_PRINTK2 NEIGH_NOPRINTK
+#define NEIGH_PRINTK3 NEIGH_NOPRINTK
#if NEIGH_DEBUG >= 1
#undef NEIGH_PRINTK1
@@ -49,6 +54,10 @@
#undef NEIGH_PRINTK2
#define NEIGH_PRINTK2 NEIGH_PRINTK
#endif
+#if NEIGH_DEBUG >= 3
+#undef NEIGH_PRINTK3
+#define NEIGH_PRINTK3 NEIGH_PRINTK
+#endif
#define PNEIGH_HASHMASK 0xF
@@ -118,6 +127,10 @@
int shrunk = 0;
int i;
+ NEIGH_PRINTK3(KERN_DEBUG
+ "%s(tbl=%p)\n",
+ __FUNCTION__, tbl);
+
NEIGH_CACHE_STAT_INC(tbl, forced_gc_runs);
write_lock_bh(&tbl->lock);
@@ -156,9 +169,21 @@
{
if ((n->nud_state & NUD_IN_TIMER) &&
del_timer(&n->timer)) {
+
+ NEIGH_PRINTK3(KERN_DEBUG
+ "%s(n=%p): %s, refcnt=%d\n",
+ __FUNCTION__,
+ n, neigh_state(n->nud_state), atomic_read(&n->refcnt) -1);
+
neigh_release(n);
return 1;
}
+
+ NEIGH_PRINTK3(KERN_DEBUG
+ "%s(n=%p): %s, refcnt=%d\n",
+ __FUNCTION__,
+ n, neigh_state(n->nud_state), atomic_read(&n->refcnt));
+
return 0;
}
@@ -203,6 +228,11 @@
{
int i;
+ NEIGH_PRINTK3(KERN_DEBUG
+ "%s(tbl=%p, dev=%p)\n",
+ __FUNCTION__,
+ tbl, dev);
+
write_lock_bh(&tbl->lock);
for (i = 0; i <= tbl->hash_mask; i++) {
@@ -255,18 +285,30 @@
unsigned long now = jiffies;
int entries;
+ NEIGH_PRINTK3(KERN_DEBUG
+ "%s(tbl=%p)\n",
+ __FUNCTION__, tbl);
+
entries = atomic_inc_return(&tbl->entries) - 1;
if (entries >= tbl->gc_thresh3 ||
(entries >= tbl->gc_thresh2 &&
time_after(now, tbl->last_flush + 5 * HZ))) {
if (!neigh_forced_gc(tbl) &&
- entries >= tbl->gc_thresh3)
+ entries > tbl->gc_thresh3) {
+ NEIGH_PRINTK3(KERN_DEBUG
+ "%s(): failed to shrink table\n",
+ __FUNCTINO__);
goto out_entries;
+ }
}
n = kmem_cache_alloc(tbl->kmem_cachep, SLAB_ATOMIC);
- if (!n)
+ if (!n) {
+ NEIGH_PRINTK3(KERN_DEBUG
+ "%s(): failed to allocate memory\n",
+ __FUNCTION__);
goto out_entries;
+ }
memset(n, 0, tbl->entry_size);
@@ -364,11 +406,20 @@
NEIGH_CACHE_STAT_INC(tbl, lookups);
+ NEIGH_PRINTK3(KERN_DEBUG
+ "%s(tbl=%p, pkey=%p, dev=%p)\n",
+ __FUNCTION__,
+ tbl, pkey, dev);
+
read_lock_bh(&tbl->lock);
for (n = tbl->hash_buckets[hash_val]; n; n = n->next) {
if (dev == n->dev && !memcmp(n->primary_key, pkey, key_len)) {
neigh_hold(n);
NEIGH_CACHE_STAT_INC(tbl, hits);
+ NEIGH_PRINTK3(KERN_DEBUG
+ "%s() => %p (state=%s, refcnt=%d)\n",
+ __FUNCTION__,
+ n, neigh_state(n->nud_state), atomic_read(&n->refcnt));
break;
}
}
@@ -384,11 +435,20 @@
NEIGH_CACHE_STAT_INC(tbl, lookups);
+ NEIGH_PRINTK3(KERN_DEBUG
+ "%s(tbl=%p, pkey=%p)\n",
+ __FUNCTION__,
+ tbl, pkey);
+
read_lock_bh(&tbl->lock);
for (n = tbl->hash_buckets[hash_val]; n; n = n->next) {
if (!memcmp(n->primary_key, pkey, key_len)) {
neigh_hold(n);
NEIGH_CACHE_STAT_INC(tbl, hits);
+ NEIGH_PRINTK3(KERN_DEBUG
+ "%s() => %p (state=%s, refcnt=%d)\n",
+ __FUNCTION__,
+ n, neigh_state(n->nud_state), atomic_read(&n->refcnt));
break;
}
}
@@ -402,7 +462,14 @@
u32 hash_val;
int key_len = tbl->key_len;
int error;
- struct neighbour *n1, *rc, *n = neigh_alloc(tbl);
+ struct neighbour *n1, *rc, *n;
+
+ NEIGH_PRINTK3(KERN_DEBUG
+ "%s(tbl=%p, pkey=%p, dev=%p)\n",
+ __FUNCTION__,
+ tbl, pkey, dev);
+
+ n = neigh_alloc(tbl);
if (!n) {
rc = ERR_PTR(-ENOBUFS);
@@ -453,6 +520,10 @@
n->dead = 0;
neigh_hold(n);
write_unlock_bh(&tbl->lock);
+ NEIGH_PRINTK3(KERN_DEBUG
+ "%s(): => %p (state=%s, refnt=%d)\n",
+ __FUNCTION__,
+ n, neigh_state(n->nud_state), atomic_read(&n->refcnt));
NEIGH_PRINTK2("neigh %p is created.\n", n);
rc = n;
out:
@@ -496,6 +567,7 @@
memcpy(n->key, pkey, key_len);
n->dev = dev;
+ n->tbl = tbl;
if (dev)
dev_hold(dev);
@@ -578,6 +650,11 @@
{
struct hh_cache *hh;
+ NEIGH_PRINTK3(KERN_DEBUG
+ "%s(neigh=%p): %s, refcnt=%d, dead=%d\n",
+ __FUNCTION__,
+ neigh, neigh_state(neigh->nud_state), atomic_read(&neigh->refcnt), neigh->dead);
+
NEIGH_CACHE_STAT_INC(neigh->tbl, destroys);
if (!neigh->dead) {
@@ -623,6 +700,10 @@
{
struct hh_cache *hh;
+ NEIGH_PRINTK3(KERN_DEBUG
+ "%s(neigh=%p): %s, refcnt=%d\n",
+ __FUNCTION__,
+ neigh, neigh_state(neigh->nud_state), atomic_read(&neigh->refcnt));
NEIGH_PRINTK2("neigh %p is suspected.\n", neigh);
neigh->output = neigh->ops->output;
@@ -640,6 +721,10 @@
{
struct hh_cache *hh;
+ NEIGH_PRINTK3(KERN_DEBUG
+ "%s(neigh=%p): %s, refcnt=%d\n",
+ __FUNCTION__,
+ neigh, neigh_state(neigh->nud_state), atomic_read(&neigh->refcnt));
NEIGH_PRINTK2("neigh %p is connected.\n", neigh);
neigh->output = neigh->ops->connected_output;
@@ -654,6 +739,11 @@
struct neighbour *n, **np;
unsigned long expire, now = jiffies;
+ NEIGH_PRINTK3(KERN_DEBUG
+ "%s(arg=%p)\n",
+ __FUNCTION__,
+ tbl);
+
NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs);
write_lock(&tbl->lock);
@@ -678,6 +768,11 @@
write_lock(&n->lock);
+ NEIGH_PRINTK3(KERN_DEBUG
+ "%s(): - %p, state=%s, refcnt=%d\n",
+ __FUNCTION__,
+ n, neigh_state(n->nud_state), atomic_read(&n->refcnt));
+
state = n->nud_state;
if (state & (NUD_PERMANENT | NUD_IN_TIMER)) {
write_unlock(&n->lock);
@@ -733,17 +828,28 @@
struct neighbour *neigh = (struct neighbour *)arg;
unsigned state;
int notify = 0;
+ int refcnt;
write_lock(&neigh->lock);
-
state = neigh->nud_state;
+
+ NEIGH_PRINTK3(KERN_DEBUG
+ "%s(arg=%p): %s, refcnt=%d\n",
+ __FUNCTION__,
+ neigh, neigh_state(neigh->nud_state), atomic_read(&neigh->refcnt));
+
now = jiffies;
next = now + HZ;
+
if (!(state & NUD_IN_TIMER)) {
#ifndef CONFIG_SMP
printk(KERN_WARNING "neigh: timer & !nud_in_timer\n");
#endif
+ refcnt = atomic_read(&neigh->refcnt) - 1;
+ NEIGH_PRINTK3(KERN_DEBUG
+ "%s(): => state=%s, refcnt=%d\n",
+ __FUNCTION__, neigh_state(state), refcnt);
goto out;
}
@@ -788,6 +894,7 @@
neigh->nud_state = NUD_FAILED;
notify = 1;
NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed);
+
NEIGH_PRINTK2("neigh %p is failed.\n", neigh);
/* It is very thin place. report_unreachable is very complicated
@@ -840,6 +947,11 @@
write_lock_bh(&neigh->lock);
+ NEIGH_PRINTK3(KERN_DEBUG
+ "%s(neigh=%p, skb=%p): %s\n",
+ __FUNCTION__,
+ neigh, skb, neigh_state(neigh->nud_state));
+
rc = 0;
if (neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE))
goto out_unlock_bh;
@@ -936,17 +1048,33 @@
struct net_device *dev;
int update_isrouter = 0;
+ NEIGH_PRINTK3(KERN_DEBUG
+ "%s(neigh=%p, lladdr=%p, new=%u, flags=%08x): %s\n",
+ __FUNCTION__,
+ neigh, lladdr, new, flags, neigh_state(neigh->nud_state));
+
+ if (!neigh) {
+ NEIGH_PRINTK1(KERN_WARNING "neigh_update(): neigh==NULL\n");
+ return -EINVAL;
+ }
+
write_lock_bh(&neigh->lock);
dev = neigh->dev;
old = neigh->nud_state;
err = -EPERM;
+ if (!dev) {
+ NEIGH_PRINTK1(KERN_WARNING "neigh_update(): neigh->dev==NULL\n");
+ return -EINVAL;
+ }
+
if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
(old & (NUD_NOARP | NUD_PERMANENT)))
goto out;
if (!(new & NUD_VALID)) {
+ /* NONE,INCOMPLETE,FAILED */
neigh_del_timer(neigh);
if (old & NUD_CONNECTED)
neigh_suspect(neigh);
@@ -1021,11 +1149,11 @@
}
if (lladdr != neigh->ha) {
+ neigh->updated = jiffies;
memcpy(&neigh->ha, lladdr, dev->addr_len);
neigh_update_hhs(neigh);
if (!(new & NUD_CONNECTED))
- neigh->confirmed = jiffies -
- (neigh->parms->base_reachable_time << 1);
+ neigh->confirmed = jiffies - (neigh->parms->base_reachable_time<<1);
#ifdef CONFIG_ARPD
notify = 1;
#endif
@@ -1040,7 +1168,6 @@
struct sk_buff *skb;
/* Again: avoid dead loop if something went wrong */
-
while (neigh->nud_state & NUD_VALID &&
(skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
struct neighbour *n1 = neigh;
@@ -1071,8 +1198,15 @@
u8 *lladdr, void *saddr,
struct net_device *dev)
{
- struct neighbour *neigh = __neigh_lookup(tbl, saddr, dev,
- lladdr || !dev->addr_len);
+ struct neighbour *neigh;
+
+ NEIGH_PRINTK3(KERN_DEBUG
+ "%s(tbl=%p, lladdr=%p, saddr=%p, dev=%p)\n",
+ __FUNCTION__,
+ tbl, lladdr, saddr, dev);
+
+ neigh = __neigh_lookup(tbl, saddr, dev,
+ lladdr || !dev->addr_len);
if (neigh)
neigh_update(neigh, lladdr, NUD_STALE,
NEIGH_UPDATE_F_OVERRIDE);
@@ -1123,6 +1257,11 @@
{
struct net_device *dev = skb->dev;
+ NEIGH_PRINTK3(KERN_DEBUG
+ "%s(skb=%p)\n",
+ __FUNCTION__,
+ skb);
+
__skb_pull(skb, skb->nh.raw - skb->data);
if (dev->hard_header &&
@@ -1142,6 +1281,11 @@
struct neighbour *neigh;
int rc = 0;
+ NEIGH_PRINTK3(KERN_DEBUG
+ "%s(skb=%p)\n",
+ __FUNCTION__,
+ skb);
+
if (!dst || !(neigh = dst->neighbour))
goto discard;
@@ -1188,6 +1332,11 @@
struct neighbour *neigh = dst->neighbour;
struct net_device *dev = neigh->dev;
+ NEIGH_PRINTK3(KERN_DEBUG
+ "%s(skb=%p)\n",
+ __FUNCTION__,
+ skb);
+
__skb_pull(skb, skb->nh.raw - skb->data);
read_lock_bh(&neigh->lock);
@@ -1424,6 +1573,11 @@
struct net_device *dev = NULL;
int err = -ENODEV;
+ NEIGH_PRINTK3(KERN_DEBUG
+ "%s(skb=%p, nlh=%p, arg=%p)\n",
+ __FUNCTION__,
+ skb, nlh, arg);
+
if (ndm->ndm_ifindex &&
(dev = dev_get_by_index(ndm->ndm_ifindex)) == NULL)
goto out;
@@ -1476,6 +1630,11 @@
struct net_device *dev = NULL;
int err = -ENODEV;
+ NEIGH_PRINTK3(KERN_DEBUG
+ "%s(skb=%p, nlh=%p, arg=%p)\n",
+ __FUNCTION__,
+ skb, nlh, arg);
+
if (ndm->ndm_ifindex &&
(dev = dev_get_by_index(ndm->ndm_ifindex)) == NULL)
goto out;
@@ -1544,6 +1703,40 @@
return err;
}
+/*
+ * XXX: based on neigh_fill_info()
+ */
+static int pneigh_fill_info(struct sk_buff *skb, struct pneigh_entry *pn,
+ u32 pid, u32 seq, int event)
+{
+ int locked = 0;
+ unsigned char *b = skb->tail;
+ struct nlmsghdr *nlh = NLMSG_PUT(skb, pid, seq, event,
+ sizeof(struct ndmsg));
+ struct ndmsg *ndm = NLMSG_DATA(nlh);
+
+ read_lock_bh(&pn->tbl->lock);
+ locked = 1;
+ ndm->ndm_family = pn->tbl->family;
+ ndm->ndm_flags = NTF_PROXY;
+ ndm->ndm_type = 0;
+ ndm->ndm_ifindex = pn->dev->ifindex;
+ RTA_PUT(skb, NDA_DST, pn->tbl->key_len, pn->key);
+ read_unlock_bh(&pn->tbl->lock);
+ locked = 0;
+ ndm->ndm_state = 0;
+
+ nlh->nlmsg_len = skb->tail - b;
+ return skb->len;
+
+nlmsg_failure:
+rtattr_failure:
+ if (locked)
+ read_unlock_bh(&pn->tbl->lock);
+
+ skb_trim(skb, b - skb->data);
+ return -1;
+}
static int neigh_fill_info(struct sk_buff *skb, struct neighbour *n,
u32 pid, u32 seq, int event)
@@ -1585,6 +1778,42 @@
return -1;
}
+/*
+ * XXX: based on neigh_dump_table()
+ */
+static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
+ struct netlink_callback *cb)
+{
+ struct pneigh_entry *pn;
+ int rc, h, s_h = cb->args[1];
+ int idx, s_idx = idx = cb->args[2];
+
+ for (h = 0; h <= PNEIGH_HASHMASK; h++) {
+ if (h < s_h)
+ continue;
+ if (h > s_h)
+ s_idx = 0;
+ read_lock_bh(&tbl->lock);
+ for (pn = tbl->phash_buckets[h], idx = 0; pn; pn = pn->next, idx++) {
+ if (idx < s_idx)
+ continue;
+ if (pneigh_fill_info(skb, pn, NETLINK_CB(cb->skb).pid,
+ cb->nlh->nlmsg_seq,
+ RTM_NEWNEIGH) <= 0) {
+ read_unlock_bh(&tbl->lock);
+ rc = -1;
+ goto out;
+ }
+ }
+ read_unlock_bh(&tbl->lock);
+ }
+
+ rc = skb->len;
+out:
+ cb->args[1] = h;
+ cb->args[2] = idx;
+ return rc;
+}
static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
struct netlink_callback *cb)
@@ -1623,10 +1852,15 @@
{
struct neigh_table *tbl;
int t, family, s_t;
+ long a1, a2, pa1, pa2;
read_lock(&neigh_tbl_lock);
family = ((struct rtgenmsg *)NLMSG_DATA(cb->nlh))->rtgen_family;
s_t = cb->args[0];
+ a1 = cb->args[1];
+ a2 = cb->args[2];
+ pa1 = cb->args[1];
+ pa2 = cb->args[2];
for (tbl = neigh_tables, t = 0; tbl; tbl = tbl->next, t++) {
if (t < s_t || (family && tbl->family != family))
@@ -1634,12 +1868,28 @@
if (t > s_t)
memset(&cb->args[1], 0, sizeof(cb->args) -
sizeof(cb->args[0]));
+ cb->args[1] = a1;
+ cb->args[2] = a2;
if (neigh_dump_table(tbl, skb, cb) < 0)
break;
+ a1 = cb->args[1];
+ a2 = cb->args[2];
+
+ cb->args[1] = pa1;
+ cb->args[2] = pa2;
+ if (pneigh_dump_table(tbl, skb, cb) < 0)
+ break;
+ pa1 = cb->args[1];
+ pa2 = cb->args[2];
}
read_unlock(&neigh_tbl_lock);
cb->args[0] = t;
+ /*
+ * XXX: Fix me! currently only neigh's status is reported.
+ */
+ cb->args[1] = a1;
+ cb->args[2] = a2;
return skb->len;
}
@@ -2044,14 +2294,80 @@
#endif /* CONFIG_ARPD */
#ifdef CONFIG_SYSCTL
+static int
+ndisc_proc_dointvec_ms_jiffies(struct ctl_table *ctl,
+ int write,
+ struct file *filp,
+ void __user *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ struct neigh_notifier_parms *np = ctl->extra1;
+ int ret = proc_dointvec_ms_jiffies(ctl, write, filp, buffer, lenp, ppos);
+
+ if (write && np && np->link_notifier)
+ (np->link_notifier)(np->link_notifier_data);
+ return ret;
+}
+
+static int
+ndisc_proc_rtime_dointvec_ms_jiffies(struct ctl_table *ctl,
+ int write,
+ struct file *filp,
+ void __user *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ struct neigh_notifier_parms *np = ctl->extra1;
+ int ret = proc_dointvec_ms_jiffies(ctl, write, filp, buffer, lenp, ppos);
+
+ if (write) {
+ if (ctl->extra2)
+ *((unsigned int *)ctl->extra2) = neigh_rand_reach_time(*(unsigned int *)ctl->data);
+ if (np && np->link_notifier)
+ (np->link_notifier)(np->link_notifier_data);
+ }
+ return ret;
+}
+
+static int
+ndisc_sysctl_ms_jiffies(ctl_table *ctl, int __user *name, int nlen,
+ void __user *oldval, size_t __user *oldlenp,
+ void __user *newval, size_t newlen, void **context)
+{
+ struct neigh_notifier_parms *np = ctl->extra1;
+ int ret = sysctl_ms_jiffies(ctl, name, nlen,
+ oldval, oldlenp, newval, newlen,
+ context);
+ if (newval && newlen && ret > 0 && np && np->link_notifier)
+ (np->link_notifier)(np->link_notifier_data);
+ return ret;
+}
+
+static int
+ndisc_rtime_sysctl_ms_jiffies(ctl_table *ctl, int __user *name, int nlen,
+ void __user *oldval, size_t __user *oldlenp,
+ void __user *newval, size_t newlen, void **context)
+{
+ struct neigh_notifier_parms *np = ctl->extra1;
+ int ret = sysctl_ms_jiffies(ctl, name, nlen,
+ oldval, oldlenp, newval, newlen,
+ context);
+ if (newval && newlen && ret > 0 && np && np->link_notifier) {
+ if (ctl->extra2)
+ *((unsigned int *)ctl->extra2) = neigh_rand_reach_time(*(unsigned int *)ctl->data);
+ if (np && np->link_notifier)
+ (np->link_notifier)(np->link_notifier_data);
+ }
+ return ret;
+}
static struct neigh_sysctl_table {
struct ctl_table_header *sysctl_header;
- ctl_table neigh_vars[17];
+ ctl_table neigh_vars[__NET_NEIGH_MAX];
ctl_table neigh_dev[2];
ctl_table neigh_neigh_dir[2];
ctl_table neigh_proto_dir[2];
ctl_table neigh_root_dir[2];
+ struct neigh_notifier_parms notifier;
} neigh_sysctl_template = {
.neigh_vars = {
{
@@ -2170,6 +2486,23 @@
.mode = 0644,
.proc_handler = &proc_dointvec,
},
+ {
+ .ctl_name = NET_NEIGH_RETRANS_TIME_MS,
+ .procname = "retrans_time_ms",
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &ndisc_proc_dointvec_ms_jiffies,
+ .strategy = &ndisc_sysctl_ms_jiffies,
+ },
+ {
+ .ctl_name = NET_NEIGH_REACHABLE_TIME_MS,
+ .procname = "base_reachable_time_ms",
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &ndisc_proc_rtime_dointvec_ms_jiffies,
+ .strategy = &ndisc_rtime_sysctl_ms_jiffies,
+ },
+
},
.neigh_dev = {
{
@@ -2200,7 +2533,8 @@
int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
int p_id, int pdev_id, char *p_name,
- proc_handler *handler)
+ proc_handler *handler,
+ void (*neigh_notifier)(void *))
{
struct neigh_sysctl_table *t = kmalloc(sizeof(*t), GFP_KERNEL);
const char *dev_name_source = NULL;
@@ -2210,6 +2544,10 @@
if (!t)
return -ENOBUFS;
memcpy(t, &neigh_sysctl_template, sizeof(*t));
+
+ t->notifier.link_notifier = neigh_notifier;
+ t->notifier.link_notifier_data = dev;
+
t->neigh_vars[0].data = &p->mcast_probes;
t->neigh_vars[1].data = &p->ucast_probes;
t->neigh_vars[2].data = &p->app_probes;
@@ -2231,7 +2569,10 @@
if (dev) {
dev_name_source = dev->name;
t->neigh_dev[0].ctl_name = dev->ifindex;
- memset(&t->neigh_vars[12], 0, sizeof(ctl_table));
+ t->neigh_vars[12].procname = NULL;
+ t->neigh_vars[13].procname = NULL;
+ t->neigh_vars[14].procname = NULL;
+ t->neigh_vars[15].procname = NULL;
} else {
t->neigh_vars[12].data = (int *)(p + 1);
t->neigh_vars[13].data = (int *)(p + 1) + 1;
@@ -2239,6 +2580,13 @@
t->neigh_vars[15].data = (int *)(p + 1) + 3;
}
+ t->neigh_vars[16].data = &p->retrans_time;
+ t->neigh_vars[16].extra1 = &t->notifier;
+
+ t->neigh_vars[17].data = &p->base_reachable_time;
+ t->neigh_vars[17].extra1 = &t->notifier;
+ t->neigh_vars[17].extra2 = &p->reachable_time;
+
dev_name = net_sysctl_strdup(dev_name_source);
if (!dev_name) {
err = -ENOBUFS;
@@ -2313,6 +2661,7 @@
#ifdef CONFIG_ARPD
EXPORT_SYMBOL(neigh_app_ns);
+EXPORT_SYMBOL(neigh_app_notify);
#endif
#ifdef CONFIG_SYSCTL
EXPORT_SYMBOL(neigh_sysctl_register);
diff -urN linux-2.6.11/net/core/netfilter.c linux.sinabox/net/core/netfilter.c
--- linux-2.6.11/net/core/netfilter.c 2005-03-02 08:38:08.000000000 +0100
+++ linux.sinabox/net/core/netfilter.c 2005-03-26 19:02:06.000000000 +0100
@@ -806,6 +806,9 @@
tracking in use: without this, connection may not be in hash table, and hence
manufactured ICMP or RST packets will not be associated with it. */
void (*ip_ct_attach)(struct sk_buff *, struct sk_buff *);
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+void (*ip6_ct_attach)(struct sk_buff *, struct sk_buff *);
+#endif
void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb)
{
@@ -828,6 +831,9 @@
}
EXPORT_SYMBOL(ip_ct_attach);
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+EXPORT_SYMBOL(ip6_ct_attach);
+#endif
EXPORT_SYMBOL(nf_ct_attach);
EXPORT_SYMBOL(nf_getsockopt);
EXPORT_SYMBOL(nf_hook_slow);
diff -urN linux-2.6.11/net/ipv4/ah4.c linux.sinabox/net/ipv4/ah4.c
--- linux-2.6.11/net/ipv4/ah4.c 2005-03-02 08:38:25.000000000 +0100
+++ linux.sinabox/net/ipv4/ah4.c 2005-03-26 19:02:06.000000000 +0100
@@ -128,6 +128,8 @@
goto out;
ah = (struct ip_auth_hdr*)skb->data;
+ if (x->props.replay_window && xfrm_replay_check(x, ah->seq_no))
+ goto out;
ahp = x->data;
ah_hlen = (ah->hdrlen + 2) << 2;
@@ -171,6 +173,8 @@
goto out;
}
}
+ if (x->props.replay_window)
+ xfrm_replay_advance(x, ah->seq_no);
((struct iphdr*)work_buf)->protocol = ah->nexthdr;
skb->nh.raw = skb_pull(skb, ah_hlen);
memcpy(skb->nh.raw, work_buf, iph->ihl*4);
diff -urN linux-2.6.11/net/ipv4/arp.c linux.sinabox/net/ipv4/arp.c
--- linux-2.6.11/net/ipv4/arp.c 2005-03-02 08:38:25.000000000 +0100
+++ linux.sinabox/net/ipv4/arp.c 2005-03-26 19:02:06.000000000 +0100
@@ -1243,7 +1243,7 @@
arp_proc_init();
#ifdef CONFIG_SYSCTL
neigh_sysctl_register(NULL, &arp_tbl.parms, NET_IPV4,
- NET_IPV4_NEIGH, "ipv4", NULL);
+ NET_IPV4_NEIGH, "ipv4", NULL, NULL);
#endif
register_netdevice_notifier(&arp_netdev_notifier);
}
diff -urN linux-2.6.11/net/ipv4/devinet.c linux.sinabox/net/ipv4/devinet.c
--- linux-2.6.11/net/ipv4/devinet.c 2005-03-02 08:37:50.000000000 +0100
+++ linux.sinabox/net/ipv4/devinet.c 2005-03-26 19:02:06.000000000 +0100
@@ -153,7 +153,7 @@
dev_hold(dev);
#ifdef CONFIG_SYSCTL
neigh_sysctl_register(dev, in_dev->arp_parms, NET_IPV4,
- NET_IPV4_NEIGH, "ipv4", NULL);
+ NET_IPV4_NEIGH, "ipv4", NULL, NULL);
#endif
/* Account for reference dev->ip_ptr */
@@ -992,7 +992,7 @@
devinet_sysctl_unregister(&in_dev->cnf);
neigh_sysctl_unregister(in_dev->arp_parms);
neigh_sysctl_register(dev, in_dev->arp_parms, NET_IPV4,
- NET_IPV4_NEIGH, "ipv4", NULL);
+ NET_IPV4_NEIGH, "ipv4", NULL, NULL);
devinet_sysctl_register(in_dev, &in_dev->cnf);
#endif
break;
diff -urN linux-2.6.11/net/ipv4/esp4.c linux.sinabox/net/ipv4/esp4.c
--- linux-2.6.11/net/ipv4/esp4.c 2005-03-02 08:38:10.000000000 +0100
+++ linux.sinabox/net/ipv4/esp4.c 2005-03-26 19:02:06.000000000 +0100
@@ -153,6 +153,7 @@
if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr)))
goto out;
+ esph = (struct ip_esp_hdr*)skb->data;
if (elen <= 0 || (elen & (blksize-1)))
goto out;
@@ -161,7 +162,8 @@
if (esp->auth.icv_full_len) {
u8 sum[esp->auth.icv_full_len];
u8 sum1[alen];
-
+ if (x->props.replay_window && xfrm_replay_check(x, esph->seq_no))
+ goto out;
esp->auth.icv(esp, skb, 0, skb->len-alen, sum);
if (skb_copy_bits(skb, skb->len-alen, sum1, alen))
@@ -171,6 +173,9 @@
x->stats.integrity_failed++;
goto out;
}
+
+ if (x->props.replay_window)
+ xfrm_replay_advance(x, esph->seq_no);
}
if ((nfrags = skb_cow_data(skb, 0, &trailer)) < 0)
@@ -178,7 +183,6 @@
skb->ip_summed = CHECKSUM_NONE;
- esph = (struct ip_esp_hdr*)skb->data;
iph = skb->nh.iph;
/* Get ivec. This can be wrong, check against another impls. */
@@ -373,7 +377,7 @@
if (x->aalg->alg_key_len > 512)
goto error;
}
- if (x->ealg == NULL)
+ if (x->ealg == NULL || (x->ealg->alg_key_len == 0 && x->props.ealgo != SADB_EALG_NULL))
goto error;
esp = kmalloc(sizeof(*esp), GFP_KERNEL);
@@ -412,11 +416,13 @@
goto error;
}
esp->conf.key = x->ealg->alg_key;
- esp->conf.key_len = (x->ealg->alg_key_len+7)/8;
- if (x->props.ealgo == SADB_EALG_NULL)
+ if (x->props.ealgo == SADB_EALG_NULL) {
+ esp->conf.key_len = 0;
esp->conf.tfm = crypto_alloc_tfm(x->ealg->alg_name, CRYPTO_TFM_MODE_ECB);
- else
+ } else {
+ esp->conf.key_len = (x->ealg->alg_key_len+7)/8;
esp->conf.tfm = crypto_alloc_tfm(x->ealg->alg_name, CRYPTO_TFM_MODE_CBC);
+ }
if (esp->conf.tfm == NULL)
goto error;
esp->conf.ivlen = crypto_tfm_alg_ivsize(esp->conf.tfm);
diff -urN linux-2.6.11/net/ipv4/fib_hash.c linux.sinabox/net/ipv4/fib_hash.c
--- linux-2.6.11/net/ipv4/fib_hash.c 2005-03-02 08:38:09.000000000 +0100
+++ linux.sinabox/net/ipv4/fib_hash.c 2005-03-19 07:34:57.000000000 +0100
@@ -919,13 +919,23 @@
return fa;
}
+static struct fib_alias *fib_get_idx(struct seq_file *seq, loff_t pos)
+{
+ struct fib_alias *fa = fib_get_first(seq);
+
+ if (fa)
+ while (pos && (fa = fib_get_next(seq)))
+ --pos;
+ return pos ? NULL : fa;
+}
+
static void *fib_seq_start(struct seq_file *seq, loff_t *pos)
{
void *v = NULL;
read_lock(&fib_hash_lock);
if (ip_fib_main_table)
- v = *pos ? fib_get_next(seq) : SEQ_START_TOKEN;
+ v = *pos ? fib_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
return v;
}
diff -urN linux-2.6.11/net/ipv4/ip_forward.c linux.sinabox/net/ipv4/ip_forward.c
--- linux-2.6.11/net/ipv4/ip_forward.c 2005-03-02 08:37:30.000000000 +0100
+++ linux.sinabox/net/ipv4/ip_forward.c 2005-03-26 19:02:06.000000000 +0100
@@ -60,8 +60,13 @@
struct rtable *rt; /* Route we use */
struct ip_options * opt = &(IPCB(skb)->opt);
+#ifdef CONFIG_USE_POLICY_FWD
if (!xfrm4_policy_check(NULL, XFRM_POLICY_FWD, skb))
goto drop;
+#else
+ if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
+ goto drop;
+#endif
if (IPCB(skb)->opt.router_alert && ip_call_ra_chain(skb))
return NET_RX_SUCCESS;
diff -urN linux-2.6.11/net/ipv4/netfilter/ip_set.c linux.sinabox/net/ipv4/netfilter/ip_set.c
--- linux-2.6.11/net/ipv4/netfilter/ip_set.c 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/net/ipv4/netfilter/ip_set.c 2005-03-24 19:22:37.000000000 +0100
@@ -0,0 +1,1986 @@
+/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
+ * Patrick Schaaf <bof@bof.de>
+ * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/* Kernel module for IP set management */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kmod.h>
+#include <linux/ip.h>
+#include <linux/skbuff.h>
+#include <linux/random.h>
+#include <linux/jhash.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/errno.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <asm/semaphore.h>
+#include <linux/spinlock.h>
+#include <linux/vmalloc.h>
+
+#define ASSERT_READ_LOCK(x) /* dont use that */
+#define ASSERT_WRITE_LOCK(x)
+#include <linux/netfilter_ipv4/listhelp.h>
+#include <linux/netfilter_ipv4/ip_set.h>
+
+static struct list_head set_type_list; /* all registered sets */
+static struct ip_set **ip_set_list; /* all individual sets */
+static DECLARE_RWLOCK(ip_set_lock); /* protects the lists and the hash */
+static DECLARE_MUTEX(ip_set_app_mutex); /* serializes user access */
+static ip_set_id_t ip_set_max = CONFIG_IP_NF_SET_MAX;
+static ip_set_id_t ip_set_bindings_hash_size = CONFIG_IP_NF_SET_HASHSIZE;
+static struct list_head *ip_set_hash; /* hash of bindings */
+static unsigned int ip_set_hash_random; /* random seed */
+
+/*
+ * Sets are identified either by the index in ip_set_list or by id.
+ * The id never changes and is used to find a key in the hash.
+ * The index may change by swapping and used at all other places
+ * (set/SET netfilter modules, binding value, etc.)
+ *
+ * Userspace requests are serialized by ip_set_mutex and sets can
+ * be deleted only from userspace. Therefore ip_set_list locking
+ * must obey the following rules:
+ *
+ * - kernel requests: read and write locking mandatory
+ * - user requests: read locking optional, write locking mandatory
+ */
+
+static inline void
+__ip_set_get(ip_set_id_t index)
+{
+ atomic_inc(&ip_set_list[index]->ref);
+}
+
+static inline void
+__ip_set_put(ip_set_id_t index)
+{
+ atomic_dec(&ip_set_list[index]->ref);
+}
+
+/*
+ * Binding routines
+ */
+
+static inline int
+ip_hash_cmp(const struct ip_set_hash *set_hash,
+ ip_set_id_t id, ip_set_ip_t ip)
+{
+ return set_hash->id == id && set_hash->ip == ip;
+}
+
+static ip_set_id_t
+ip_set_find_in_hash(ip_set_id_t id, ip_set_ip_t ip)
+{
+ u_int32_t key = jhash_2words(id, ip, ip_set_hash_random)
+ % ip_set_bindings_hash_size;
+ struct ip_set_hash *set_hash;
+
+ MUST_BE_READ_LOCKED(&ip_set_lock);
+ IP_SET_ASSERT(ip_set_list[id]);
+ DP("set: %s, ip: %u.%u.%u.%u", ip_set_list[id]->name, HIPQUAD(ip));
+
+ set_hash = LIST_FIND(&ip_set_hash[key], ip_hash_cmp,
+ struct ip_set_hash *, id, ip);
+
+ DP("set: %s, ip: %u.%u.%u.%u, binding: %s", ip_set_list[id]->name,
+ HIPQUAD(ip),
+ set_hash != NULL ? ip_set_list[set_hash->binding]->name : "");
+
+ return (set_hash != NULL ? set_hash->binding : IP_SET_INVALID_ID);
+}
+
+static inline void
+__set_hash_del(struct ip_set_hash *set_hash)
+{
+ MUST_BE_WRITE_LOCKED(&ip_set_lock);
+ IP_SET_ASSERT(ip_set_list[set_hash->binding]);
+
+ __ip_set_put(set_hash->binding);
+ list_del(&set_hash->list);
+ kfree(set_hash);
+}
+
+static int
+ip_set_hash_del(ip_set_id_t id, ip_set_ip_t ip)
+{
+ u_int32_t key = jhash_2words(id, ip, ip_set_hash_random)
+ % ip_set_bindings_hash_size;
+ struct ip_set_hash *set_hash;
+
+ IP_SET_ASSERT(ip_set_list[id]);
+ DP("set: %s, ip: %u.%u.%u.%u", ip_set_list[id]->name, HIPQUAD(ip));
+ WRITE_LOCK(&ip_set_lock);
+ set_hash = LIST_FIND(&ip_set_hash[key], ip_hash_cmp,
+ struct ip_set_hash *, id, ip);
+ DP("set: %s, ip: %u.%u.%u.%u, binding: %s", ip_set_list[id]->name,
+ HIPQUAD(ip),
+ set_hash != NULL ? ip_set_list[set_hash->binding]->name : "");
+
+ if (set_hash != NULL)
+ __set_hash_del(set_hash);
+ WRITE_UNLOCK(&ip_set_lock);
+ return 0;
+}
+
+static int
+ip_set_hash_add(ip_set_id_t id, ip_set_ip_t ip, ip_set_id_t binding)
+{
+ u_int32_t key = jhash_2words(id, ip, ip_set_hash_random)
+ % ip_set_bindings_hash_size;
+ struct ip_set_hash *set_hash;
+ int ret = 0;
+
+ IP_SET_ASSERT(ip_set_list[id]);
+ IP_SET_ASSERT(ip_set_list[binding]);
+ DP("set: %s, ip: %u.%u.%u.%u, binding: %s", ip_set_list[id]->name,
+ HIPQUAD(ip), ip_set_list[binding]->name);
+ WRITE_LOCK(&ip_set_lock);
+ set_hash = LIST_FIND(&ip_set_hash[key], ip_hash_cmp,
+ struct ip_set_hash *, id, ip);
+ if (!set_hash) {
+ set_hash = kmalloc(sizeof(struct ip_set_hash), GFP_KERNEL);
+ if (!set_hash) {
+ ret = -ENOMEM;
+ goto unlock;
+ }
+ INIT_LIST_HEAD(&set_hash->list);
+ set_hash->id = id;
+ set_hash->ip = ip;
+ list_add(&ip_set_hash[key], &set_hash->list);
+ } else {
+ IP_SET_ASSERT(ip_set_list[set_hash->binding]);
+ DP("overwrite binding: %s",
+ ip_set_list[set_hash->binding]->name);
+ __ip_set_put(set_hash->binding);
+ }
+ set_hash->binding = binding;
+ __ip_set_get(set_hash->binding);
+ unlock:
+ WRITE_UNLOCK(&ip_set_lock);
+ return ret;
+}
+
+#define FOREACH_HASH_DO(fn, args...) \
+({ \
+ ip_set_id_t __key; \
+ struct ip_set_hash *__set_hash; \
+ \
+ for (__key = 0; __key < ip_set_bindings_hash_size; __key++) { \
+ list_for_each_entry(__set_hash, &ip_set_hash[__key], list) \
+ fn(__set_hash , ## args); \
+ } \
+})
+
+#define FOREACH_HASH_RW_DO(fn, args...) \
+({ \
+ ip_set_id_t __key; \
+ struct ip_set_hash *__set_hash, *__n; \
+ \
+ MUST_BE_WRITE_LOCKED(&ip_set_lock); \
+ for (__key = 0; __key < ip_set_bindings_hash_size; __key++) { \
+ list_for_each_entry_safe(__set_hash, __n, &ip_set_hash[__key], list)\
+ fn(__set_hash , ## args); \
+ } \
+})
+
+/* Add, del and test set entries from kernel */
+
+#define follow_bindings(index, set, ip) \
+((index = ip_set_find_in_hash((set)->id, ip)) != IP_SET_INVALID_ID \
+ || (index = (set)->binding) != IP_SET_INVALID_ID)
+
+int
+ip_set_testip_kernel(ip_set_id_t index,
+ const struct sk_buff *skb,
+ const u_int32_t *flags)
+{
+ struct ip_set *set;
+ ip_set_ip_t ip;
+ int res, i = 0;
+
+ IP_SET_ASSERT(flags[i]);
+ READ_LOCK(&ip_set_lock);
+ do {
+ set = ip_set_list[index];
+ IP_SET_ASSERT(set);
+ DP("set %s, index %u", set->name, index);
+ read_lock_bh(&set->lock);
+ res = set->type->testip_kernel(set, skb, flags[i], &ip);
+ read_unlock_bh(&set->lock);
+ } while (res > 0
+ && flags[++i]
+ && follow_bindings(index, set, ip));
+ READ_UNLOCK(&ip_set_lock);
+
+ return res;
+}
+
+void
+ip_set_addip_kernel(ip_set_id_t index,
+ const struct sk_buff *skb,
+ const u_int32_t *flags)
+{
+ struct ip_set *set;
+ ip_set_ip_t ip;
+ int res, i= 0;
+
+ IP_SET_ASSERT(flags[i]);
+ READ_LOCK(&ip_set_lock);
+ do {
+ set = ip_set_list[index];
+ IP_SET_ASSERT(set);
+ DP("set %s, index %u", set->name, index);
+ write_lock_bh(&set->lock);
+ res = set->type->addip_kernel(set, skb, flags[i], &ip);
+ write_unlock_bh(&set->lock);
+ } while ((res == -EAGAIN
+ && set->type->retry
+ && (res = set->type->retry(set)) == 0)
+ || ((res == 0 || res == -EEXIST)
+ && flags[++i]
+ && follow_bindings(index, set, ip)));
+ READ_UNLOCK(&ip_set_lock);
+}
+
+void
+ip_set_delip_kernel(ip_set_id_t index,
+ const struct sk_buff *skb,
+ const u_int32_t *flags)
+{
+ struct ip_set *set;
+ ip_set_ip_t ip;
+ int res, i = 0;
+
+ IP_SET_ASSERT(flags[i]);
+ READ_LOCK(&ip_set_lock);
+ do {
+ set = ip_set_list[index];
+ IP_SET_ASSERT(set);
+ DP("set %s, index %u", set->name, index);
+ write_lock_bh(&set->lock);
+ res = set->type->delip_kernel(set, skb, flags[i], &ip);
+ write_unlock_bh(&set->lock);
+ } while ((res == 0 || res == -EEXIST)
+ && flags[++i]
+ && follow_bindings(index, set, ip));
+ READ_UNLOCK(&ip_set_lock);
+}
+
+/* Register and deregister settype */
+
+static inline int
+set_type_equal(const struct ip_set_type *set_type, const char *str2)
+{
+ return !strncmp(set_type->typename, str2, IP_SET_MAXNAMELEN - 1);
+}
+
+static inline struct ip_set_type *
+find_set_type(const char *name)
+{
+ return LIST_FIND(&set_type_list,
+ set_type_equal,
+ struct ip_set_type *,
+ name);
+}
+
+int
+ip_set_register_set_type(struct ip_set_type *set_type)
+{
+ int ret = 0;
+
+ if (set_type->protocol_version != IP_SET_PROTOCOL_VERSION) {
+ ip_set_printk("'%s' uses wrong protocol version %u (want %u)",
+ set_type->typename,
+ set_type->protocol_version,
+ IP_SET_PROTOCOL_VERSION);
+ return -EINVAL;
+ }
+
+ WRITE_LOCK(&ip_set_lock);
+ if (find_set_type(set_type->typename)) {
+ /* Duplicate! */
+ ip_set_printk("'%s' already registered!",
+ set_type->typename);
+ ret = -EINVAL;
+ goto unlock;
+ }
+ if (!try_module_get(THIS_MODULE)) {
+ ret = -EFAULT;
+ goto unlock;
+ }
+ list_append(&set_type_list, set_type);
+ DP("'%s' registered.", set_type->typename);
+ unlock:
+ WRITE_UNLOCK(&ip_set_lock);
+ return ret;
+}
+
+void
+ip_set_unregister_set_type(struct ip_set_type *set_type)
+{
+ WRITE_LOCK(&ip_set_lock);
+ if (!find_set_type(set_type->typename)) {
+ ip_set_printk("'%s' not registered?",
+ set_type->typename);
+ goto unlock;
+ }
+ LIST_DELETE(&set_type_list, set_type);
+ module_put(THIS_MODULE);
+ DP("'%s' unregistered.", set_type->typename);
+ unlock:
+ WRITE_UNLOCK(&ip_set_lock);
+
+}
+
+/*
+ * Userspace routines
+ */
+
+/*
+ * Find set by name, reference it once. The reference makes sure the
+ * thing pointed to, does not go away under our feet. Drop the reference
+ * later, using ip_set_put().
+ */
+ip_set_id_t
+ip_set_get_byname(const char *name)
+{
+ ip_set_id_t i, index = IP_SET_INVALID_ID;
+
+ down(&ip_set_app_mutex);
+ for (i = 0; i < ip_set_max; i++) {
+ if (ip_set_list[i] != NULL
+ && strcmp(ip_set_list[i]->name, name) == 0) {
+ __ip_set_get(i);
+ index = i;
+ break;
+ }
+ }
+ up(&ip_set_app_mutex);
+ return index;
+}
+
+/*
+ * Find set by index, reference it once. The reference makes sure the
+ * thing pointed to, does not go away under our feet. Drop the reference
+ * later, using ip_set_put().
+ */
+ip_set_id_t
+ip_set_get_byindex(ip_set_id_t index)
+{
+ down(&ip_set_app_mutex);
+
+ if (index >= ip_set_max)
+ return IP_SET_INVALID_ID;
+
+ if (ip_set_list[index])
+ __ip_set_get(index);
+ else
+ index = IP_SET_INVALID_ID;
+
+ up(&ip_set_app_mutex);
+ return index;
+}
+
+/*
+ * If the given set pointer points to a valid set, decrement
+ * reference count by 1. The caller shall not assume the index
+ * to be valid, after calling this function.
+ */
+void ip_set_put(ip_set_id_t index)
+{
+ down(&ip_set_app_mutex);
+ if (ip_set_list[index])
+ __ip_set_put(index);
+ up(&ip_set_app_mutex);
+}
+
+/* Find a set by name or index */
+static ip_set_id_t
+ip_set_find_byname(const char *name)
+{
+ ip_set_id_t i, index = IP_SET_INVALID_ID;
+
+ for (i = 0; i < ip_set_max; i++) {
+ if (ip_set_list[i] != NULL
+ && strcmp(ip_set_list[i]->name, name) == 0) {
+ index = i;
+ break;
+ }
+ }
+ return index;
+}
+
+static ip_set_id_t
+ip_set_find_byindex(ip_set_id_t index)
+{
+ if (index >= ip_set_max || ip_set_list[index] == NULL)
+ index = IP_SET_INVALID_ID;
+
+ return index;
+}
+
+/*
+ * Add, del, test, bind and unbind
+ */
+
+static inline int
+__ip_set_testip(struct ip_set *set,
+ const void *data,
+ size_t size,
+ ip_set_ip_t *ip)
+{
+ int res;
+
+ read_lock_bh(&set->lock);
+ res = set->type->testip(set, data, size, ip);
+ read_unlock_bh(&set->lock);
+
+ return res;
+}
+
+static int
+__ip_set_addip(ip_set_id_t index,
+ const void *data,
+ size_t size)
+{
+ struct ip_set *set = ip_set_list[index];
+ ip_set_ip_t ip;
+ int res;
+
+ IP_SET_ASSERT(set);
+ do {
+ write_lock_bh(&set->lock);
+ res = set->type->addip(set, data, size, &ip);
+ write_unlock_bh(&set->lock);
+ } while (res == -EAGAIN
+ && set->type->retry
+ && (res = set->type->retry(set)) == 0);
+
+ return res;
+}
+
+static int
+ip_set_addip(ip_set_id_t index,
+ const void *data,
+ size_t size)
+{
+
+ return __ip_set_addip(index,
+ data + sizeof(struct ip_set_req_adt),
+ size - sizeof(struct ip_set_req_adt));
+}
+
+static int
+ip_set_delip(ip_set_id_t index,
+ const void *data,
+ size_t size)
+{
+ struct ip_set *set = ip_set_list[index];
+ ip_set_ip_t ip;
+ int res;
+
+ IP_SET_ASSERT(set);
+ write_lock_bh(&set->lock);
+ res = set->type->delip(set,
+ data + sizeof(struct ip_set_req_adt),
+ size - sizeof(struct ip_set_req_adt),
+ &ip);
+ write_unlock_bh(&set->lock);
+
+ return res;
+}
+
+static int
+ip_set_testip(ip_set_id_t index,
+ const void *data,
+ size_t size)
+{
+ struct ip_set *set = ip_set_list[index];
+ ip_set_ip_t ip;
+ int res;
+
+ IP_SET_ASSERT(set);
+ res = __ip_set_testip(set,
+ data + sizeof(struct ip_set_req_adt),
+ size - sizeof(struct ip_set_req_adt),
+ &ip);
+
+ return (res > 0 ? -EEXIST : res);
+}
+
+static int
+ip_set_bindip(ip_set_id_t index,
+ const void *data,
+ size_t size)
+{
+ struct ip_set *set = ip_set_list[index];
+ struct ip_set_req_bind *req_bind;
+ ip_set_id_t binding;
+ ip_set_ip_t ip;
+ int res;
+
+ IP_SET_ASSERT(set);
+ if (size < sizeof(struct ip_set_req_bind))
+ return -EINVAL;
+
+ req_bind = (struct ip_set_req_bind *) data;
+ req_bind->binding[IP_SET_MAXNAMELEN - 1] = '\0';
+
+ if (strcmp(req_bind->binding, IPSET_TOKEN_DEFAULT) == 0) {
+ /* Default binding of a set */
+ char *binding_name;
+
+ if (size != sizeof(struct ip_set_req_bind) + IP_SET_MAXNAMELEN)
+ return -EINVAL;
+
+ binding_name = (char *)(data + sizeof(struct ip_set_req_bind));
+ binding_name[IP_SET_MAXNAMELEN - 1] = '\0';
+
+ binding = ip_set_find_byname(binding_name);
+ if (binding == IP_SET_INVALID_ID)
+ return -ENOENT;
+
+ WRITE_LOCK(&ip_set_lock);
+ /* Sets as binding values are referenced */
+ if (set->binding != IP_SET_INVALID_ID)
+ __ip_set_put(set->binding);
+ set->binding = binding;
+ __ip_set_get(set->binding);
+ WRITE_UNLOCK(&ip_set_lock);
+
+ return 0;
+ }
+ binding = ip_set_find_byname(req_bind->binding);
+ if (binding == IP_SET_INVALID_ID)
+ return -ENOENT;
+
+ res = __ip_set_testip(set,
+ data + sizeof(struct ip_set_req_bind),
+ size - sizeof(struct ip_set_req_bind),
+ &ip);
+ DP("set %s, ip: %u.%u.%u.%u, binding %s",
+ set->name, HIPQUAD(ip), ip_set_list[binding]->name);
+
+ if (res >= 0)
+ res = ip_set_hash_add(set->id, ip, binding);
+
+ return res;
+}
+
+#define FOREACH_SET_DO(fn, args...) \
+({ \
+ ip_set_id_t __i; \
+ struct ip_set *__set; \
+ \
+ for (__i = 0; __i < ip_set_max; __i++) { \
+ __set = ip_set_list[__i]; \
+ if (__set != NULL) \
+ fn(__set , ##args); \
+ } \
+})
+
+static inline void
+__set_hash_del_byid(struct ip_set_hash *set_hash, ip_set_id_t id)
+{
+ if (set_hash->id == id)
+ __set_hash_del(set_hash);
+}
+
+static inline void
+__unbind_default(struct ip_set *set)
+{
+ if (set->binding != IP_SET_INVALID_ID) {
+ /* Sets as binding values are referenced */
+ __ip_set_put(set->binding);
+ set->binding = IP_SET_INVALID_ID;
+ }
+}
+
+static int
+ip_set_unbindip(ip_set_id_t index,
+ const void *data,
+ size_t size)
+{
+ struct ip_set *set;
+ struct ip_set_req_bind *req_bind;
+ ip_set_ip_t ip;
+ int res;
+
+ DP("");
+ if (size < sizeof(struct ip_set_req_bind))
+ return -EINVAL;
+
+ req_bind = (struct ip_set_req_bind *) data;
+ req_bind->binding[IP_SET_MAXNAMELEN - 1] = '\0';
+
+ DP("%u %s", index, req_bind->binding);
+ if (index == IP_SET_INVALID_ID) {
+ /* unbind :all: */
+ if (strcmp(req_bind->binding, IPSET_TOKEN_DEFAULT) == 0) {
+ /* Default binding of sets */
+ WRITE_LOCK(&ip_set_lock);
+ FOREACH_SET_DO(__unbind_default);
+ WRITE_UNLOCK(&ip_set_lock);
+ return 0;
+ } else if (strcmp(req_bind->binding, IPSET_TOKEN_ALL) == 0) {
+ /* Flush all bindings of all sets*/
+ WRITE_LOCK(&ip_set_lock);
+ FOREACH_HASH_RW_DO(__set_hash_del);
+ WRITE_UNLOCK(&ip_set_lock);
+ return 0;
+ }
+ DP("unreachable reached!");
+ return -EINVAL;
+ }
+
+ set = ip_set_list[index];
+ IP_SET_ASSERT(set);
+ if (strcmp(req_bind->binding, IPSET_TOKEN_DEFAULT) == 0) {
+ /* Default binding of set */
+ ip_set_id_t binding = ip_set_find_byindex(set->binding);
+
+ if (binding == IP_SET_INVALID_ID)
+ return -ENOENT;
+
+ WRITE_LOCK(&ip_set_lock);
+ /* Sets in hash values are referenced */
+ __ip_set_put(set->binding);
+ set->binding = IP_SET_INVALID_ID;
+ WRITE_UNLOCK(&ip_set_lock);
+
+ return 0;
+ } else if (strcmp(req_bind->binding, IPSET_TOKEN_ALL) == 0) {
+ /* Flush all bindings */
+
+ WRITE_LOCK(&ip_set_lock);
+ FOREACH_HASH_RW_DO(__set_hash_del_byid, set->id);
+ WRITE_UNLOCK(&ip_set_lock);
+ return 0;
+ }
+
+ res = __ip_set_testip(set,
+ data + sizeof(struct ip_set_req_bind),
+ size - sizeof(struct ip_set_req_bind),
+ &ip);
+
+ DP("set %s, ip: %u.%u.%u.%u", set->name, HIPQUAD(ip));
+ if (res >= 0)
+ res = ip_set_hash_del(set->id, ip);
+
+ return res;
+}
+
+static int
+ip_set_testbind(ip_set_id_t index,
+ const void *data,
+ size_t size)
+{
+ struct ip_set *set = ip_set_list[index];
+ struct ip_set_req_bind *req_bind;
+ ip_set_id_t binding;
+ ip_set_ip_t ip;
+ int res;
+
+ IP_SET_ASSERT(set);
+ if (size < sizeof(struct ip_set_req_bind))
+ return -EINVAL;
+
+ req_bind = (struct ip_set_req_bind *) data;
+ req_bind->binding[IP_SET_MAXNAMELEN - 1] = '\0';
+
+ if (strcmp(req_bind->binding, IPSET_TOKEN_DEFAULT) == 0) {
+ /* Default binding of set */
+ char *binding_name;
+
+ if (size != sizeof(struct ip_set_req_bind) + IP_SET_MAXNAMELEN)
+ return -EINVAL;
+
+ binding_name = (char *)(data + sizeof(struct ip_set_req_bind));
+ binding_name[IP_SET_MAXNAMELEN - 1] = '\0';
+
+ binding = ip_set_find_byname(binding_name);
+ if (binding == IP_SET_INVALID_ID)
+ return -ENOENT;
+
+ res = (set->binding == binding) ? -EEXIST : 0;
+
+ return res;
+ }
+ binding = ip_set_find_byname(req_bind->binding);
+ if (binding == IP_SET_INVALID_ID)
+ return -ENOENT;
+
+
+ res = __ip_set_testip(set,
+ data + sizeof(struct ip_set_req_bind),
+ size - sizeof(struct ip_set_req_bind),
+ &ip);
+ DP("set %s, ip: %u.%u.%u.%u, binding %s",
+ set->name, HIPQUAD(ip), ip_set_list[binding]->name);
+
+ if (res >= 0)
+ res = (ip_set_find_in_hash(set->id, ip) == binding)
+ ? -EEXIST : 0;
+
+ return res;
+}
+
+static struct ip_set_type *
+find_set_type_rlock(const char *typename)
+{
+ struct ip_set_type *type;
+
+ READ_LOCK(&ip_set_lock);
+ type = find_set_type(typename);
+ if (type == NULL)
+ READ_UNLOCK(&ip_set_lock);
+
+ return type;
+}
+
+static int
+find_free_id(const char *name,
+ ip_set_id_t *index,
+ ip_set_id_t *id)
+{
+ ip_set_id_t i;
+
+ *id = IP_SET_INVALID_ID;
+ for (i = 0; i < ip_set_max; i++) {
+ if (ip_set_list[i] == NULL) {
+ if (*id == IP_SET_INVALID_ID)
+ *id = *index = i;
+ } else if (strcmp(name, ip_set_list[i]->name) == 0)
+ /* Name clash */
+ return -EEXIST;
+ }
+ if (*id == IP_SET_INVALID_ID)
+ /* No free slot remained */
+ return -ERANGE;
+ /* Check that index is usable as id (swapping) */
+ check:
+ for (i = 0; i < ip_set_max; i++) {
+ if (ip_set_list[i] != NULL
+ && ip_set_list[i]->id == *id) {
+ *id = i;
+ goto check;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Create a set
+ */
+static int
+ip_set_create(const char *name,
+ const char *typename,
+ ip_set_id_t restore,
+ const void *data,
+ size_t size)
+{
+ struct ip_set *set;
+ ip_set_id_t index, id;
+ int res = 0;
+
+ DP("setname: %s, typename: %s, id: %u", name, typename, restore);
+ /*
+ * First, and without any locks, allocate and initialize
+ * a normal base set structure.
+ */
+ set = kmalloc(sizeof(struct ip_set), GFP_KERNEL);
+ if (!set)
+ return -ENOMEM;
+ set->lock = RW_LOCK_UNLOCKED;
+ strncpy(set->name, name, IP_SET_MAXNAMELEN);
+ set->binding = IP_SET_INVALID_ID;
+ atomic_set(&set->ref, 0);
+
+ /*
+ * Next, take the &ip_set_lock, check that we know the type,
+ * and take a reference on the type, to make sure it
+ * stays available while constructing our new set.
+ *
+ * After referencing the type, we drop the &ip_set_lock,
+ * and let the new set construction run without locks.
+ */
+ set->type = find_set_type_rlock(typename);
+ if (set->type == NULL) {
+ /* Try loading the module */
+ char modulename[IP_SET_MAXNAMELEN + strlen("ip_set_") + 1];
+ strcpy(modulename, "ip_set_");
+ strcat(modulename, typename);
+ DP("try to load %s", modulename);
+ request_module(modulename);
+ set->type = find_set_type_rlock(typename);
+ }
+ if (set->type == NULL) {
+ ip_set_printk("no set type '%s', set '%s' not created",
+ typename, name);
+ res = -ENOENT;
+ goto out;
+ }
+ if (!try_module_get(set->type->me)) {
+ READ_UNLOCK(&ip_set_lock);
+ res = -EFAULT;
+ goto out;
+ }
+ READ_UNLOCK(&ip_set_lock);
+
+ /*
+ * Without holding any locks, create private part.
+ */
+ res = set->type->create(set, data, size);
+ if (res != 0)
+ goto put_out;
+
+ /* BTW, res==0 here. */
+
+ /*
+ * Here, we have a valid, constructed set. &ip_set_lock again,
+ * find free id/index and check that it is not already in
+ * ip_set_list.
+ */
+ WRITE_LOCK(&ip_set_lock);
+ if ((res = find_free_id(set->name, &index, &id)) != 0) {
+ DP("no free id!");
+ goto cleanup;
+ }
+
+ /* Make sure restore gets the same index */
+ if (restore != IP_SET_INVALID_ID && index != restore) {
+ DP("Can't restore, sets are screwed up");
+ res = -ERANGE;
+ goto cleanup;
+ }
+
+ /*
+ * Finally! Add our shiny new set to the list, and be done.
+ */
+ DP("create: '%s' created with index %u, id %u!", set->name, index, id);
+ set->id = id;
+ ip_set_list[index] = set;
+ WRITE_UNLOCK(&ip_set_lock);
+ return res;
+
+ cleanup:
+ WRITE_UNLOCK(&ip_set_lock);
+ set->type->destroy(set);
+ put_out:
+ module_put(set->type->me);
+ out:
+ kfree(set);
+ return res;
+}
+
+/*
+ * Destroy a given existing set
+ */
+static void
+ip_set_destroy_set(ip_set_id_t index)
+{
+ struct ip_set *set = ip_set_list[index];
+
+ IP_SET_ASSERT(set);
+ DP("set: %s", set->name);
+ WRITE_LOCK(&ip_set_lock);
+ FOREACH_HASH_RW_DO(__set_hash_del_byid, set->id);
+ if (set->binding != IP_SET_INVALID_ID)
+ __ip_set_put(set->binding);
+ ip_set_list[index] = NULL;
+ WRITE_UNLOCK(&ip_set_lock);
+
+ /* Must call it without holding any lock */
+ set->type->destroy(set);
+ module_put(set->type->me);
+ kfree(set);
+}
+
+/*
+ * Destroy a set - or all sets
+ * Sets must not be referenced/used.
+ */
+static int
+ip_set_destroy(ip_set_id_t index)
+{
+ ip_set_id_t i;
+
+ /* ref modification always protected by the mutex */
+ if (index != IP_SET_INVALID_ID) {
+ if (atomic_read(&ip_set_list[index]->ref))
+ return -EBUSY;
+ ip_set_destroy_set(index);
+ } else {
+ for (i = 0; i < ip_set_max; i++) {
+ if (ip_set_list[i] != NULL
+ && (atomic_read(&ip_set_list[i]->ref)))
+ return -EBUSY;
+ }
+
+ for (i = 0; i < ip_set_max; i++) {
+ if (ip_set_list[i] != NULL)
+ ip_set_destroy_set(i);
+ }
+ }
+ return 0;
+}
+
+static void
+ip_set_flush_set(struct ip_set *set)
+{
+ DP("set: %s %u", set->name, set->id);
+
+ write_lock_bh(&set->lock);
+ set->type->flush(set);
+ write_unlock_bh(&set->lock);
+}
+
+/*
+ * Flush data in a set - or in all sets
+ */
+static int
+ip_set_flush(ip_set_id_t index)
+{
+ if (index != IP_SET_INVALID_ID) {
+ IP_SET_ASSERT(ip_set_list[index]);
+ ip_set_flush_set(ip_set_list[index]);
+ } else
+ FOREACH_SET_DO(ip_set_flush_set);
+
+ return 0;
+}
+
+/* Rename a set */
+static int
+ip_set_rename(ip_set_id_t index, const char *name)
+{
+ struct ip_set *set = ip_set_list[index];
+ ip_set_id_t i;
+ int res = 0;
+
+ DP("set: %s to %s", set->name, name);
+ WRITE_LOCK(&ip_set_lock);
+ for (i = 0; i < ip_set_max; i++) {
+ if (ip_set_list[i] != NULL
+ && strncmp(ip_set_list[i]->name,
+ name,
+ IP_SET_MAXNAMELEN - 1) == 0) {
+ res = -EEXIST;
+ goto unlock;
+ }
+ }
+ strncpy(set->name, name, IP_SET_MAXNAMELEN);
+ unlock:
+ WRITE_UNLOCK(&ip_set_lock);
+ return res;
+}
+
+/*
+ * Swap two sets so that name/index points to the other.
+ * References are also swapped.
+ */
+static int
+ip_set_swap(ip_set_id_t from_index, ip_set_id_t to_index)
+{
+ struct ip_set *from = ip_set_list[from_index];
+ struct ip_set *to = ip_set_list[to_index];
+ char from_name[IP_SET_MAXNAMELEN];
+ u_int32_t from_ref;
+
+ DP("set: %s to %s", from->name, to->name);
+ /* Type can't be changed. Artifical restriction. */
+ if (from->type->typecode != to->type->typecode)
+ return -ENOEXEC;
+
+ /* No magic here: ref munging protected by the mutex */
+ WRITE_LOCK(&ip_set_lock);
+ strncpy(from_name, from->name, IP_SET_MAXNAMELEN);
+ from_ref = atomic_read(&from->ref);
+
+ strncpy(from->name, to->name, IP_SET_MAXNAMELEN);
+ atomic_set(&from->ref, atomic_read(&to->ref));
+ strncpy(to->name, from_name, IP_SET_MAXNAMELEN);
+ atomic_set(&to->ref, from_ref);
+
+ ip_set_list[from_index] = to;
+ ip_set_list[to_index] = from;
+
+ WRITE_UNLOCK(&ip_set_lock);
+ return 0;
+}
+
+/*
+ * List set data
+ */
+
+static inline void
+__set_hash_bindings_size_list(struct ip_set_hash *set_hash,
+ ip_set_id_t id, size_t *size)
+{
+ if (set_hash->id == id)
+ *size += sizeof(struct ip_set_hash_list);
+}
+
+static inline void
+__set_hash_bindings_size_save(struct ip_set_hash *set_hash,
+ ip_set_id_t id, size_t *size)
+{
+ if (set_hash->id == id)
+ *size += sizeof(struct ip_set_hash_save);
+}
+
+static inline void
+__set_hash_bindings(struct ip_set_hash *set_hash,
+ ip_set_id_t id, void *data, int *used)
+{
+ if (set_hash->id == id) {
+ struct ip_set_hash_list *hash_list =
+ (struct ip_set_hash_list *)(data + *used);
+
+ hash_list->ip = set_hash->ip;
+ hash_list->binding = set_hash->binding;
+ *used += sizeof(struct ip_set_hash_list);
+ }
+}
+
+static int ip_set_list_set(ip_set_id_t index,
+ void *data,
+ int *used,
+ int len)
+{
+ struct ip_set *set = ip_set_list[index];
+ struct ip_set_list *set_list;
+
+ /* Pointer to our header */
+ set_list = (struct ip_set_list *) (data + *used);
+
+ DP("set: %s, used: %d %p %p", set->name, *used, data, data + *used);
+
+ /* Get and ensure header size */
+ if (*used + sizeof(struct ip_set_list) > len)
+ goto not_enough_mem;
+ *used += sizeof(struct ip_set_list);
+
+ read_lock_bh(&set->lock);
+ /* Get and ensure set specific header size */
+ set_list->header_size = set->type->header_size;
+ if (*used + set_list->header_size > len)
+ goto unlock_set;
+
+ /* Fill in the header */
+ set_list->index = index;
+ set_list->binding = set->binding;
+ set_list->ref = atomic_read(&set->ref);
+
+ /* Fill in set spefific header data */
+ set->type->list_header(set, data + *used);
+ *used += set_list->header_size;
+
+ /* Get and ensure set specific members size */
+ set_list->members_size = set->type->list_members_size(set);
+ if (*used + set_list->members_size > len)
+ goto unlock_set;
+
+ /* Fill in set spefific members data */
+ set->type->list_members(set, data + *used);
+ *used += set_list->members_size;
+ read_unlock_bh(&set->lock);
+
+ /* Bindings */
+
+ /* Get and ensure set specific bindings size */
+ set_list->bindings_size = 0;
+ FOREACH_HASH_DO(__set_hash_bindings_size_list,
+ set->id, &set_list->bindings_size);
+ if (*used + set_list->bindings_size > len)
+ goto not_enough_mem;
+
+ /* Fill in set spefific bindings data */
+ FOREACH_HASH_DO(__set_hash_bindings, set->id, data, used);
+
+ return 0;
+
+ unlock_set:
+ read_unlock_bh(&set->lock);
+ not_enough_mem:
+ DP("not enough mem, try again");
+ return -EAGAIN;
+}
+
+/*
+ * Save sets
+ */
+static int ip_set_save_set(ip_set_id_t index,
+ void *data,
+ int *used,
+ int len)
+{
+ struct ip_set *set;
+ struct ip_set_save *set_save;
+
+ /* Pointer to our header */
+ set_save = (struct ip_set_save *) (data + *used);
+
+ /* Get and ensure header size */
+ if (*used + sizeof(struct ip_set_save) > len)
+ goto not_enough_mem;
+ *used += sizeof(struct ip_set_save);
+
+ set = ip_set_list[index];
+ DP("set: %s, used: %u(%u) %p %p", set->name, *used, len,
+ data, data + *used);
+
+ read_lock_bh(&set->lock);
+ /* Get and ensure set specific header size */
+ set_save->header_size = set->type->header_size;
+ if (*used + set_save->header_size > len)
+ goto unlock_set;
+
+ /* Fill in the header */
+ set_save->index = index;
+ set_save->binding = set->binding;
+
+ /* Fill in set spefific header data */
+ set->type->list_header(set, data + *used);
+ *used += set_save->header_size;
+
+ DP("set header filled: %s, used: %u %p %p", set->name, *used,
+ data, data + *used);
+ /* Get and ensure set specific members size */
+ set_save->members_size = set->type->list_members_size(set);
+ if (*used + set_save->members_size > len)
+ goto unlock_set;
+
+ /* Fill in set spefific members data */
+ set->type->list_members(set, data + *used);
+ *used += set_save->members_size;
+ read_unlock_bh(&set->lock);
+ DP("set members filled: %s, used: %u %p %p", set->name, *used,
+ data, data + *used);
+ return 0;
+
+ unlock_set:
+ read_unlock_bh(&set->lock);
+ not_enough_mem:
+ DP("not enough mem, try again");
+ return -EAGAIN;
+}
+
+static inline void
+__set_hash_save_bindings(struct ip_set_hash *set_hash,
+ ip_set_id_t id,
+ void *data,
+ int *used,
+ int len,
+ int *res)
+{
+ if (*res == 0
+ && (id == IP_SET_INVALID_ID || set_hash->id == id)) {
+ struct ip_set_hash_save *hash_save =
+ (struct ip_set_hash_save *)(data + *used);
+ /* Ensure bindings size */
+ if (*used + sizeof(struct ip_set_hash_save) > len) {
+ *res = -ENOMEM;
+ return;
+ }
+ hash_save->id = set_hash->id;
+ hash_save->ip = set_hash->ip;
+ hash_save->binding = set_hash->binding;
+ *used += sizeof(struct ip_set_hash_save);
+ }
+}
+
+static int ip_set_save_bindings(ip_set_id_t index,
+ void *data,
+ int *used,
+ int len)
+{
+ int res = 0;
+ struct ip_set_save *set_save;
+
+ DP("used %u, len %u", *used, len);
+ /* Get and ensure header size */
+ if (*used + sizeof(struct ip_set_save) > len)
+ return -ENOMEM;
+
+ /* Marker */
+ set_save = (struct ip_set_save *) (data + *used);
+ set_save->index = IP_SET_INVALID_ID;
+ *used += sizeof(struct ip_set_save);
+
+ DP("marker added used %u, len %u", *used, len);
+ /* Fill in bindings data */
+ if (index != IP_SET_INVALID_ID)
+ /* Sets are identified by id in hash */
+ index = ip_set_list[index]->id;
+ FOREACH_HASH_DO(__set_hash_save_bindings, index, data, used, len, &res);
+
+ return res;
+}
+
+/*
+ * Restore sets
+ */
+static int ip_set_restore(void *data,
+ int len)
+{
+ int res = 0;
+ int line = 0, used = 0, members_size;
+ struct ip_set *set;
+ struct ip_set_hash_save *hash_save;
+ struct ip_set_restore *set_restore;
+ ip_set_id_t index;
+
+ /* Loop to restore sets */
+ while (1) {
+ line++;
+
+ DP("%u %u %u", used, sizeof(struct ip_set_restore), len);
+ /* Get and ensure header size */
+ if (used + sizeof(struct ip_set_restore) > len)
+ return line;
+ set_restore = (struct ip_set_restore *) (data + used);
+ used += sizeof(struct ip_set_restore);
+
+ /* Ensure data size */
+ if (used
+ + set_restore->header_size
+ + set_restore->members_size > len)
+ return line;
+
+ /* Check marker */
+ if (set_restore->index == IP_SET_INVALID_ID) {
+ line--;
+ goto bindings;
+ }
+
+ /* Try to create the set */
+ DP("restore %s %s", set_restore->name, set_restore->typename);
+ res = ip_set_create(set_restore->name,
+ set_restore->typename,
+ set_restore->index,
+ data + used,
+ set_restore->header_size);
+
+ if (res != 0)
+ return line;
+ used += set_restore->header_size;
+
+ index = ip_set_find_byindex(set_restore->index);
+ DP("index %u, restore_index %u", index, set_restore->index);
+ if (index != set_restore->index)
+ return line;
+ /* Try to restore members data */
+ set = ip_set_list[index];
+ members_size = 0;
+ DP("members_size %u reqsize %u",
+ set_restore->members_size, set->type->reqsize);
+ while (members_size + set->type->reqsize <=
+ set_restore->members_size) {
+ line++;
+ DP("members: %u, line %u", members_size, line);
+ if (__ip_set_addip(index,
+ data + used + members_size,
+ set->type->reqsize)) {
+ return line;
+ }
+ members_size += set->type->reqsize;
+ }
+
+ DP("members_size %u %u",
+ set_restore->members_size, members_size);
+ if (members_size != set_restore->members_size)
+ return line++;
+ used += set_restore->members_size;
+ }
+
+ bindings:
+ /* Loop to restore bindings */
+ while (used < len) {
+ line++;
+
+ DP("restore binding, line %u", line);
+ /* Get and ensure size */
+ if (used + sizeof(struct ip_set_hash_save) > len)
+ return line;
+ hash_save = (struct ip_set_hash_save *) (data + used);
+ used += sizeof(struct ip_set_hash_save);
+
+ /* hash_save->id is used to store the index */
+ index = ip_set_find_byindex(hash_save->id);
+ DP("restore binding index %u, id %u, %u -> %u",
+ index, hash_save->id, hash_save->ip, hash_save->binding);
+ if (index != hash_save->id)
+ return line;
+
+ set = ip_set_list[hash_save->id];
+ /* Null valued IP means default binding */
+ if (hash_save->ip)
+ res = ip_set_hash_add(set->id,
+ hash_save->ip,
+ hash_save->binding);
+ else {
+ IP_SET_ASSERT(set->binding == IP_SET_INVALID_ID);
+ WRITE_LOCK(&ip_set_lock);
+ set->binding = hash_save->binding;
+ __ip_set_get(set->binding);
+ WRITE_UNLOCK(&ip_set_lock);
+ DP("default binding: %u", set->binding);
+ }
+ if (res != 0)
+ return line;
+ }
+ if (used != len)
+ return line;
+
+ return 0;
+}
+
+static int
+ip_set_sockfn_set(struct sock *sk, int optval, void *user, unsigned int len)
+{
+ void *data;
+ int res = 0; /* Assume OK */
+ unsigned *op;
+ struct ip_set_req_adt *req_adt;
+ ip_set_id_t index = IP_SET_INVALID_ID;
+ int (*adtfn)(ip_set_id_t index,
+ const void *data, size_t size);
+ struct fn_table {
+ int (*fn)(ip_set_id_t index,
+ const void *data, size_t size);
+ } adtfn_table[] =
+ { { ip_set_addip }, { ip_set_delip }, { ip_set_testip},
+ { ip_set_bindip}, { ip_set_unbindip }, { ip_set_testbind },
+ };
+
+ DP("optval=%d, user=%p, len=%d", optval, user, len);
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (optval != SO_IP_SET)
+ return -EBADF;
+ if (len <= sizeof(unsigned)) {
+ ip_set_printk("short userdata (want >%d, got %d)",
+ sizeof(unsigned), len);
+ return -EINVAL;
+ }
+ data = vmalloc(len);
+ if (!data) {
+ DP("out of mem for %d bytes", len);
+ return -ENOMEM;
+ }
+ if (copy_from_user(data, user, len) != 0) {
+ res = -EFAULT;
+ goto done;
+ }
+ if (down_interruptible(&ip_set_app_mutex)) {
+ res = -EINTR;
+ goto done;
+ }
+
+ op = (unsigned *)data;
+ DP("op=%x", *op);
+
+ if (*op < IP_SET_OP_VERSION) {
+ /* Check the version at the beginning of operations */
+ struct ip_set_req_version *req_version =
+ (struct ip_set_req_version *) data;
+ if (req_version->version != IP_SET_PROTOCOL_VERSION) {
+ res = -EPROTO;
+ goto done;
+ }
+ }
+
+ switch (*op) {
+ case IP_SET_OP_CREATE:{
+ struct ip_set_req_create *req_create
+ = (struct ip_set_req_create *) data;
+
+ if (len <= sizeof(struct ip_set_req_create)) {
+ ip_set_printk("short CREATE data (want >%d, got %d)",
+ sizeof(struct ip_set_req_create), len);
+ res = -EINVAL;
+ goto done;
+ }
+ req_create->name[IP_SET_MAXNAMELEN - 1] = '\0';
+ req_create->typename[IP_SET_MAXNAMELEN - 1] = '\0';
+ res = ip_set_create(req_create->name,
+ req_create->typename,
+ IP_SET_INVALID_ID,
+ data + sizeof(struct ip_set_req_create),
+ len - sizeof(struct ip_set_req_create));
+ goto done;
+ }
+ case IP_SET_OP_DESTROY:{
+ struct ip_set_req_std *req_destroy
+ = (struct ip_set_req_std *) data;
+
+ if (len != sizeof(struct ip_set_req_std)) {
+ ip_set_printk("invalid DESTROY data (want %d, got %d)",
+ sizeof(struct ip_set_req_std), len);
+ res = -EINVAL;
+ goto done;
+ }
+ if (strcmp(req_destroy->name, IPSET_TOKEN_ALL) == 0) {
+ /* Destroy all sets */
+ index = IP_SET_INVALID_ID;
+ } else {
+ req_destroy->name[IP_SET_MAXNAMELEN - 1] = '\0';
+ index = ip_set_find_byname(req_destroy->name);
+
+ if (index == IP_SET_INVALID_ID) {
+ res = -ENOENT;
+ goto done;
+ }
+ }
+
+ res = ip_set_destroy(index);
+ goto done;
+ }
+ case IP_SET_OP_FLUSH:{
+ struct ip_set_req_std *req_flush =
+ (struct ip_set_req_std *) data;
+
+ if (len != sizeof(struct ip_set_req_std)) {
+ ip_set_printk("invalid FLUSH data (want %d, got %d)",
+ sizeof(struct ip_set_req_std), len);
+ res = -EINVAL;
+ goto done;
+ }
+ if (strcmp(req_flush->name, IPSET_TOKEN_ALL) == 0) {
+ /* Flush all sets */
+ index = IP_SET_INVALID_ID;
+ } else {
+ req_flush->name[IP_SET_MAXNAMELEN - 1] = '\0';
+ index = ip_set_find_byname(req_flush->name);
+
+ if (index == IP_SET_INVALID_ID) {
+ res = -ENOENT;
+ goto done;
+ }
+ }
+ res = ip_set_flush(index);
+ goto done;
+ }
+ case IP_SET_OP_RENAME:{
+ struct ip_set_req_create *req_rename
+ = (struct ip_set_req_create *) data;
+
+ if (len != sizeof(struct ip_set_req_create)) {
+ ip_set_printk("invalid RENAME data (want %d, got %d)",
+ sizeof(struct ip_set_req_create), len);
+ res = -EINVAL;
+ goto done;
+ }
+
+ req_rename->name[IP_SET_MAXNAMELEN - 1] = '\0';
+ req_rename->typename[IP_SET_MAXNAMELEN - 1] = '\0';
+
+ index = ip_set_find_byname(req_rename->name);
+ if (index == IP_SET_INVALID_ID) {
+ res = -ENOENT;
+ goto done;
+ }
+ res = ip_set_rename(index, req_rename->typename);
+ goto done;
+ }
+ case IP_SET_OP_SWAP:{
+ struct ip_set_req_create *req_swap
+ = (struct ip_set_req_create *) data;
+ ip_set_id_t to_index;
+
+ if (len != sizeof(struct ip_set_req_create)) {
+ ip_set_printk("invalid SWAP data (want %d, got %d)",
+ sizeof(struct ip_set_req_create), len);
+ res = -EINVAL;
+ goto done;
+ }
+
+ req_swap->name[IP_SET_MAXNAMELEN - 1] = '\0';
+ req_swap->typename[IP_SET_MAXNAMELEN - 1] = '\0';
+
+ index = ip_set_find_byname(req_swap->name);
+ if (index == IP_SET_INVALID_ID) {
+ res = -ENOENT;
+ goto done;
+ }
+ to_index = ip_set_find_byname(req_swap->typename);
+ if (to_index == IP_SET_INVALID_ID) {
+ res = -ENOENT;
+ goto done;
+ }
+ res = ip_set_swap(index, to_index);
+ goto done;
+ }
+ default:
+ break; /* Set identified by id */
+ }
+
+ /* There we may have add/del/test/bind/unbind/test_bind operations */
+ if (*op < IP_SET_OP_ADD_IP || *op > IP_SET_OP_TEST_BIND_SET) {
+ res = -EBADMSG;
+ goto done;
+ }
+ adtfn = adtfn_table[*op - IP_SET_OP_ADD_IP].fn;
+
+ if (len < sizeof(struct ip_set_req_adt)) {
+ ip_set_printk("short data in adt request (want >=%d, got %d)",
+ sizeof(struct ip_set_req_adt), len);
+ res = -EINVAL;
+ goto done;
+ }
+ req_adt = (struct ip_set_req_adt *) data;
+
+ /* -U :all: :all:|:default: uses IP_SET_INVALID_ID */
+ if (!(*op == IP_SET_OP_UNBIND_SET
+ && req_adt->index == IP_SET_INVALID_ID)) {
+ index = ip_set_find_byindex(req_adt->index);
+ if (index == IP_SET_INVALID_ID) {
+ res = -ENOENT;
+ goto done;
+ }
+ }
+ res = adtfn(index, data, len);
+
+ done:
+ up(&ip_set_app_mutex);
+ vfree(data);
+ if (res > 0)
+ res = 0;
+ DP("final result %d", res);
+ return res;
+}
+
+static int
+ip_set_sockfn_get(struct sock *sk, int optval, void *user, int *len)
+{
+ int res = 0;
+ unsigned *op;
+ ip_set_id_t index = IP_SET_INVALID_ID;
+ void *data;
+ int copylen = *len;
+
+ DP("optval=%d, user=%p, len=%d", optval, user, *len);
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (optval != SO_IP_SET)
+ return -EBADF;
+ if (*len < sizeof(unsigned)) {
+ ip_set_printk("short userdata (want >=%d, got %d)",
+ sizeof(unsigned), *len);
+ return -EINVAL;
+ }
+ data = vmalloc(*len);
+ if (!data) {
+ DP("out of mem for %d bytes", *len);
+ return -ENOMEM;
+ }
+ if (copy_from_user(data, user, *len) != 0) {
+ res = -EFAULT;
+ goto done;
+ }
+ if (down_interruptible(&ip_set_app_mutex)) {
+ res = -EINTR;
+ goto done;
+ }
+
+ op = (unsigned *) data;
+ DP("op=%x", *op);
+
+ if (*op < IP_SET_OP_VERSION) {
+ /* Check the version at the beginning of operations */
+ struct ip_set_req_version *req_version =
+ (struct ip_set_req_version *) data;
+ if (req_version->version != IP_SET_PROTOCOL_VERSION) {
+ res = -EPROTO;
+ goto done;
+ }
+ }
+
+ switch (*op) {
+ case IP_SET_OP_VERSION: {
+ struct ip_set_req_version *req_version =
+ (struct ip_set_req_version *) data;
+
+ if (*len != sizeof(struct ip_set_req_version)) {
+ ip_set_printk("invalid VERSION (want %d, got %d)",
+ sizeof(struct ip_set_req_version),
+ *len);
+ res = -EINVAL;
+ goto done;
+ }
+
+ req_version->version = IP_SET_PROTOCOL_VERSION;
+ res = copy_to_user(user, req_version,
+ sizeof(struct ip_set_req_version));
+ goto done;
+ }
+ case IP_SET_OP_GET_BYNAME: {
+ struct ip_set_req_get_set *req_get
+ = (struct ip_set_req_get_set *) data;
+
+ if (*len != sizeof(struct ip_set_req_get_set)) {
+ ip_set_printk("invalid GET_BYNAME (want %d, got %d)",
+ sizeof(struct ip_set_req_get_set), *len);
+ res = -EINVAL;
+ goto done;
+ }
+ req_get->set.name[IP_SET_MAXNAMELEN - 1] = '\0';
+ index = ip_set_find_byname(req_get->set.name);
+ req_get->set.index = index;
+ goto copy;
+ }
+ case IP_SET_OP_GET_BYINDEX: {
+ struct ip_set_req_get_set *req_get
+ = (struct ip_set_req_get_set *) data;
+
+ if (*len != sizeof(struct ip_set_req_get_set)) {
+ ip_set_printk("invalid GET_BYINDEX (want %d, got %d)",
+ sizeof(struct ip_set_req_get_set), *len);
+ res = -EINVAL;
+ goto done;
+ }
+ req_get->set.name[IP_SET_MAXNAMELEN - 1] = '\0';
+ index = ip_set_find_byindex(req_get->set.index);
+ strncpy(req_get->set.name,
+ index == IP_SET_INVALID_ID ? ""
+ : ip_set_list[index]->name, IP_SET_MAXNAMELEN);
+ goto copy;
+ }
+ case IP_SET_OP_ADT_GET: {
+ struct ip_set_req_adt_get *req_get
+ = (struct ip_set_req_adt_get *) data;
+
+ if (*len != sizeof(struct ip_set_req_adt_get)) {
+ ip_set_printk("invalid ADT_GET (want %d, got %d)",
+ sizeof(struct ip_set_req_adt_get), *len);
+ res = -EINVAL;
+ goto done;
+ }
+ req_get->set.name[IP_SET_MAXNAMELEN - 1] = '\0';
+ index = ip_set_find_byname(req_get->set.name);
+ if (index != IP_SET_INVALID_ID) {
+ req_get->set.index = index;
+ strncpy(req_get->typename,
+ ip_set_list[index]->type->typename,
+ IP_SET_MAXNAMELEN - 1);
+ } else {
+ res = -ENOENT;
+ goto done;
+ }
+ goto copy;
+ }
+ case IP_SET_OP_MAX_SETS: {
+ struct ip_set_req_max_sets *req_max_sets
+ = (struct ip_set_req_max_sets *) data;
+ ip_set_id_t i;
+
+ if (*len != sizeof(struct ip_set_req_max_sets)) {
+ ip_set_printk("invalid MAX_SETS (want %d, got %d)",
+ sizeof(struct ip_set_req_max_sets), *len);
+ res = -EINVAL;
+ goto done;
+ }
+
+ if (strcmp(req_max_sets->set.name, IPSET_TOKEN_ALL) == 0) {
+ req_max_sets->set.index = IP_SET_INVALID_ID;
+ } else {
+ req_max_sets->set.name[IP_SET_MAXNAMELEN - 1] = '\0';
+ req_max_sets->set.index =
+ ip_set_find_byname(req_max_sets->set.name);
+ if (req_max_sets->set.index == IP_SET_INVALID_ID) {
+ res = -ENOENT;
+ goto done;
+ }
+ }
+ req_max_sets->max_sets = ip_set_max;
+ req_max_sets->sets = 0;
+ for (i = 0; i < ip_set_max; i++) {
+ if (ip_set_list[i] != NULL)
+ req_max_sets->sets++;
+ }
+ goto copy;
+ }
+ case IP_SET_OP_LIST_SIZE:
+ case IP_SET_OP_SAVE_SIZE: {
+ struct ip_set_req_setnames *req_setnames
+ = (struct ip_set_req_setnames *) data;
+ struct ip_set_name_list *name_list;
+ struct ip_set *set;
+ ip_set_id_t i;
+ int used;
+
+ if (*len < sizeof(struct ip_set_req_setnames)) {
+ ip_set_printk("short LIST_SIZE (want >=%d, got %d)",
+ sizeof(struct ip_set_req_setnames), *len);
+ res = -EINVAL;
+ goto done;
+ }
+
+ req_setnames->size = 0;
+ used = sizeof(struct ip_set_req_setnames);
+ for (i = 0; i < ip_set_max; i++) {
+ if (ip_set_list[i] == NULL)
+ continue;
+ name_list = (struct ip_set_name_list *)
+ (data + used);
+ used += sizeof(struct ip_set_name_list);
+ if (used > copylen) {
+ res = -EAGAIN;
+ goto done;
+ }
+ set = ip_set_list[i];
+ /* Fill in index, name, etc. */
+ name_list->index = i;
+ name_list->id = set->id;
+ strncpy(name_list->name,
+ set->name,
+ IP_SET_MAXNAMELEN - 1);
+ strncpy(name_list->typename,
+ set->type->typename,
+ IP_SET_MAXNAMELEN - 1);
+ DP("filled %s of type %s, index %u\n",
+ name_list->name, name_list->typename,
+ name_list->index);
+ if (!(req_setnames->index == IP_SET_INVALID_ID
+ || req_setnames->index == i))
+ continue;
+ /* Update size */
+ switch (*op) {
+ case IP_SET_OP_LIST_SIZE: {
+ req_setnames->size += sizeof(struct ip_set_list)
+ + set->type->header_size
+ + set->type->list_members_size(set);
+ FOREACH_HASH_DO(__set_hash_bindings_size_list,
+ i, &req_setnames->size);
+ break;
+ }
+ case IP_SET_OP_SAVE_SIZE: {
+ req_setnames->size += sizeof(struct ip_set_save)
+ + set->type->header_size
+ + set->type->list_members_size(set);
+ FOREACH_HASH_DO(__set_hash_bindings_size_save,
+ i, &req_setnames->size);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ if (copylen != used) {
+ res = -EAGAIN;
+ goto done;
+ }
+ goto copy;
+ }
+ case IP_SET_OP_LIST: {
+ struct ip_set_req_list *req_list
+ = (struct ip_set_req_list *) data;
+ ip_set_id_t i;
+ int used;
+
+ if (*len < sizeof(struct ip_set_req_list)) {
+ ip_set_printk("short LIST (want >=%d, got %d)",
+ sizeof(struct ip_set_req_list), *len);
+ res = -EINVAL;
+ goto done;
+ }
+ index = req_list->index;
+ if (index != IP_SET_INVALID_ID
+ && ip_set_find_byindex(index) != index) {
+ res = -ENOENT;
+ goto done;
+ }
+ used = 0;
+ if (index == IP_SET_INVALID_ID) {
+ /* List all sets */
+ for (i = 0; i < ip_set_max && res == 0; i++) {
+ if (ip_set_list[i] != NULL)
+ res = ip_set_list_set(i, data, &used, *len);
+ }
+ } else {
+ /* List an individual set */
+ res = ip_set_list_set(index, data, &used, *len);
+ }
+ if (res != 0)
+ goto done;
+ else if (copylen != used) {
+ res = -EAGAIN;
+ goto done;
+ }
+ goto copy;
+ }
+ case IP_SET_OP_SAVE: {
+ struct ip_set_req_list *req_save
+ = (struct ip_set_req_list *) data;
+ ip_set_id_t i;
+ int used;
+
+ if (*len < sizeof(struct ip_set_req_list)) {
+ ip_set_printk("short SAVE (want >=%d, got %d)",
+ sizeof(struct ip_set_req_list), *len);
+ res = -EINVAL;
+ goto done;
+ }
+ index = req_save->index;
+ if (index != IP_SET_INVALID_ID
+ && ip_set_find_byindex(index) != index) {
+ res = -ENOENT;
+ goto done;
+ }
+ used = 0;
+ if (index == IP_SET_INVALID_ID) {
+ /* Save all sets */
+ for (i = 0; i < ip_set_max && res == 0; i++) {
+ if (ip_set_list[i] != NULL)
+ res = ip_set_save_set(i, data, &used, *len);
+ }
+ } else {
+ /* Save an individual set */
+ res = ip_set_save_set(index, data, &used, *len);
+ }
+ if (res == 0)
+ res = ip_set_save_bindings(index, data, &used, *len);
+
+ if (res != 0)
+ goto done;
+ else if (copylen != used) {
+ res = -EAGAIN;
+ goto done;
+ }
+ goto copy;
+ }
+ case IP_SET_OP_RESTORE: {
+ struct ip_set_req_setnames *req_restore
+ = (struct ip_set_req_setnames *) data;
+ int line;
+
+ if (*len < sizeof(struct ip_set_req_setnames)
+ || *len != req_restore->size) {
+ ip_set_printk("invalid RESTORE (want =%d, got %d)",
+ req_restore->size, *len);
+ res = -EINVAL;
+ goto done;
+ }
+ line = ip_set_restore(data + sizeof(struct ip_set_req_setnames),
+ req_restore->size - sizeof(struct ip_set_req_setnames));
+ DP("ip_set_restore: %u", line);
+ if (line != 0) {
+ res = -EAGAIN;
+ req_restore->size = line;
+ copylen = sizeof(struct ip_set_req_setnames);
+ goto copy;
+ }
+ goto done;
+ }
+ default:
+ res = -EBADMSG;
+ goto done;
+ } /* end of switch(op) */
+
+ copy:
+ DP("set %s, copylen %u", index != IP_SET_INVALID_ID
+ && ip_set_list[index]
+ ? ip_set_list[index]->name
+ : ":all:", copylen);
+ if (res == 0)
+ res = copy_to_user(user, data, copylen);
+ else
+ copy_to_user(user, data, copylen);
+
+ done:
+ up(&ip_set_app_mutex);
+ vfree(data);
+ if (res > 0)
+ res = 0;
+ DP("final result %d", res);
+ return res;
+}
+
+static struct nf_sockopt_ops so_set = {
+ .pf = PF_INET,
+ .set_optmin = SO_IP_SET,
+ .set_optmax = SO_IP_SET + 1,
+ .set = &ip_set_sockfn_set,
+ .get_optmin = SO_IP_SET,
+ .get_optmax = SO_IP_SET + 1,
+ .get = &ip_set_sockfn_get,
+ .use = 0
+};
+
+static int max_sets, hash_size;
+module_param(max_sets, int, 0600);
+MODULE_PARM_DESC(max_sets, "maximal number of sets");
+module_param(hash_size, int, 0600);
+MODULE_PARM_DESC(hash_size, "hash size for bindings");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_DESCRIPTION("module implementing core IP set support");
+
+static int __init init(void)
+{
+ int res;
+ ip_set_id_t i;
+
+ get_random_bytes(&ip_set_hash_random, 4);
+ if (max_sets)
+ ip_set_max = max_sets;
+ ip_set_list = vmalloc(sizeof(struct ip_set *) * ip_set_max);
+ if (!ip_set_list) {
+ printk(KERN_ERR "Unable to create ip_set_list\n");
+ return -ENOMEM;
+ }
+ memset(ip_set_list, 0, sizeof(struct ip_set *) * ip_set_max);
+ if (hash_size)
+ ip_set_bindings_hash_size = hash_size;
+ ip_set_hash = vmalloc(sizeof(struct list_head) * ip_set_bindings_hash_size);
+ if (!ip_set_hash) {
+ printk(KERN_ERR "Unable to create ip_set_hash\n");
+ vfree(ip_set_list);
+ return -ENOMEM;
+ }
+ for (i = 0; i < ip_set_bindings_hash_size; i++)
+ INIT_LIST_HEAD(&ip_set_hash[i]);
+
+ INIT_LIST_HEAD(&set_type_list);
+
+ res = nf_register_sockopt(&so_set);
+ if (res != 0) {
+ ip_set_printk("SO_SET registry failed: %d", res);
+ vfree(ip_set_list);
+ vfree(ip_set_hash);
+ return res;
+ }
+ return 0;
+}
+
+static void __exit fini(void)
+{
+ /* There can't be any existing set or binding */
+ nf_unregister_sockopt(&so_set);
+ vfree(ip_set_list);
+ vfree(ip_set_hash);
+ DP("these are the famous last words");
+}
+
+EXPORT_SYMBOL(ip_set_register_set_type);
+EXPORT_SYMBOL(ip_set_unregister_set_type);
+
+EXPORT_SYMBOL(ip_set_get_byname);
+EXPORT_SYMBOL(ip_set_get_byindex);
+EXPORT_SYMBOL(ip_set_put);
+
+EXPORT_SYMBOL(ip_set_addip_kernel);
+EXPORT_SYMBOL(ip_set_delip_kernel);
+EXPORT_SYMBOL(ip_set_testip_kernel);
+
+module_init(init);
+module_exit(fini);
diff -urN linux-2.6.11/net/ipv4/netfilter/ip_set_iphash.c linux.sinabox/net/ipv4/netfilter/ip_set_iphash.c
--- linux-2.6.11/net/ipv4/netfilter/ip_set_iphash.c 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/net/ipv4/netfilter/ip_set_iphash.c 2005-03-24 19:22:37.000000000 +0100
@@ -0,0 +1,379 @@
+/* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/* Kernel module implementing an ip hash set */
+
+#include <linux/module.h>
+#include <linux/ip.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ip_set.h>
+#include <linux/errno.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <linux/spinlock.h>
+#include <linux/vmalloc.h>
+#include <linux/random.h>
+
+#include <net/ip.h>
+
+#include <linux/netfilter_ipv4/ip_set_malloc.h>
+#include <linux/netfilter_ipv4/ip_set_iphash.h>
+#include <linux/netfilter_ipv4/ip_set_jhash.h>
+#include <linux/netfilter_ipv4/ip_set_prime.h>
+
+static inline __u32
+jhash_ip(const struct ip_set_iphash *map, ip_set_ip_t ip)
+{
+ return jhash_1word(ip, map->initval);
+}
+
+static inline __u32
+randhash_ip(const struct ip_set_iphash *map, ip_set_ip_t ip)
+{
+ return (1 + ip % map->prime);
+}
+
+static inline __u32
+hash_id(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+{
+ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data;
+ __u32 jhash, randhash, id;
+ u_int16_t i;
+
+ *hash_ip = ip & map->netmask;
+ jhash = jhash_ip(map, *hash_ip);
+ randhash = randhash_ip(map, *hash_ip);
+ DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u, %u.%u.%u.%u",
+ set->name, HIPQUAD(ip), HIPQUAD(*hash_ip), HIPQUAD(map->netmask));
+
+ for (i = 0; i < map->probes; i++) {
+ id = (jhash + i * randhash) % map->hashsize;
+ DP("hash key: %u", id);
+ if (map->members[id] == *hash_ip)
+ return id;
+ /* No shortcut at testing - there can be deleted
+ * entries. */
+ }
+ return UINT_MAX;
+}
+
+static inline int
+__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+{
+ return (hash_id(set, ip, hash_ip) != UINT_MAX);
+}
+
+static int
+testip(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_ip)
+{
+ struct ip_set_req_iphash *req =
+ (struct ip_set_req_iphash *) data;
+
+ if (size != sizeof(struct ip_set_req_iphash)) {
+ ip_set_printk("data length wrong (want %d, have %d)",
+ sizeof(struct ip_set_req_iphash),
+ size);
+ return -EINVAL;
+ }
+ return __testip(set, req->ip, hash_ip);
+}
+
+static int
+testip_kernel(struct ip_set *set, const struct sk_buff *skb,
+ u_int32_t flags, ip_set_ip_t *hash_ip)
+{
+ return __testip(set,
+ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
+ : skb->nh.iph->daddr),
+ hash_ip);
+}
+
+static inline int
+__addip(struct ip_set_iphash *map, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+{
+ __u32 jhash, randhash, probe;
+ u_int16_t i;
+
+ *hash_ip = ip & map->netmask;
+ jhash = jhash_ip(map, *hash_ip);
+ randhash = randhash_ip(map, *hash_ip);
+
+ for (i = 0; i < map->probes; i++) {
+ probe = (jhash + i * randhash) % map->hashsize;
+ if (map->members[probe] == *hash_ip)
+ return -EEXIST;
+ if (!map->members[probe]) {
+ map->members[probe] = *hash_ip;
+ return 0;
+ }
+ }
+ /* Trigger rehashing */
+ return -EAGAIN;
+}
+
+static int
+addip(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_ip)
+{
+ struct ip_set_req_iphash *req =
+ (struct ip_set_req_iphash *) data;
+
+ if (size != sizeof(struct ip_set_req_iphash)) {
+ ip_set_printk("data length wrong (want %d, have %d)",
+ sizeof(struct ip_set_req_iphash),
+ size);
+ return -EINVAL;
+ }
+ return __addip((struct ip_set_iphash *) set->data, req->ip, hash_ip);
+}
+
+static int
+addip_kernel(struct ip_set *set, const struct sk_buff *skb,
+ u_int32_t flags, ip_set_ip_t *hash_ip)
+{
+ return __addip((struct ip_set_iphash *) set->data,
+ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
+ : skb->nh.iph->daddr),
+ hash_ip);
+}
+
+static int retry(struct ip_set *set)
+{
+ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data;
+ ip_set_ip_t hash_ip, *members;
+ u_int32_t i, hashsize;
+ unsigned newbytes;
+ int res;
+ struct ip_set_iphash tmp = {
+ .hashsize = map->hashsize,
+ .probes = map->probes,
+ .resize = map->resize,
+ .netmask = map->netmask,
+ };
+
+ if (map->resize == 0)
+ return -ERANGE;
+
+ again:
+ res = 0;
+
+ /* Calculate new parameters */
+ get_random_bytes(&tmp.initval, 4);
+ hashsize = tmp.hashsize + (tmp.hashsize * map->resize)/100;
+ if (hashsize == tmp.hashsize)
+ hashsize++;
+ tmp.prime = make_prime(hashsize);
+
+ ip_set_printk("rehashing of set %s triggered: "
+ "hashsize grows from %u to %u",
+ set->name, tmp.hashsize, hashsize);
+ tmp.hashsize = hashsize;
+
+ newbytes = hashsize * sizeof(ip_set_ip_t);
+ tmp.members = ip_set_malloc(newbytes);
+ if (!tmp.members) {
+ DP("out of memory for %d bytes", newbytes);
+ return -ENOMEM;
+ }
+ memset(tmp.members, 0, newbytes);
+
+ write_lock_bh(&set->lock);
+ map = (struct ip_set_iphash *) set->data; /* Play safe */
+ for (i = 0; i < map->hashsize && res == 0; i++) {
+ if (map->members[i])
+ res = __addip(&tmp, map->members[i], &hash_ip);
+ }
+ if (res) {
+ /* Failure, try again */
+ write_unlock_bh(&set->lock);
+ ip_set_free(tmp.members, newbytes);
+ goto again;
+ }
+
+ /* Success at resizing! */
+ members = map->members;
+ hashsize = map->hashsize;
+
+ map->initval = tmp.initval;
+ map->prime = tmp.prime;
+ map->hashsize = tmp.hashsize;
+ map->members = tmp.members;
+ write_unlock_bh(&set->lock);
+
+ ip_set_free(members, hashsize * sizeof(ip_set_ip_t));
+
+ return 0;
+}
+
+static inline int
+__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+{
+ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data;
+ ip_set_ip_t id = hash_id(set, ip, hash_ip);
+
+ if (id == UINT_MAX)
+ return -EEXIST;
+
+ map->members[id] = 0;
+ return 0;
+}
+
+static int
+delip(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_ip)
+{
+ struct ip_set_req_iphash *req =
+ (struct ip_set_req_iphash *) data;
+
+ if (size != sizeof(struct ip_set_req_iphash)) {
+ ip_set_printk("data length wrong (want %d, have %d)",
+ sizeof(struct ip_set_req_iphash),
+ size);
+ return -EINVAL;
+ }
+ return __delip(set, req->ip, hash_ip);
+}
+
+static int
+delip_kernel(struct ip_set *set, const struct sk_buff *skb,
+ u_int32_t flags, ip_set_ip_t *hash_ip)
+{
+ return __delip(set,
+ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
+ : skb->nh.iph->daddr),
+ hash_ip);
+}
+
+static int create(struct ip_set *set, const void *data, size_t size)
+{
+ unsigned newbytes;
+ struct ip_set_req_iphash_create *req =
+ (struct ip_set_req_iphash_create *) data;
+ struct ip_set_iphash *map;
+
+ if (size != sizeof(struct ip_set_req_iphash_create)) {
+ ip_set_printk("data length wrong (want %d, have %d)",
+ sizeof(struct ip_set_req_iphash_create),
+ size);
+ return -EINVAL;
+ }
+
+ if (req->hashsize < 1) {
+ ip_set_printk("hashsize too small");
+ return -ENOEXEC;
+ }
+
+ map = kmalloc(sizeof(struct ip_set_iphash), GFP_KERNEL);
+ if (!map) {
+ DP("out of memory for %d bytes",
+ sizeof(struct ip_set_iphash));
+ return -ENOMEM;
+ }
+ get_random_bytes(&map->initval, 4);
+ map->prime = make_prime(req->hashsize);
+ map->hashsize = req->hashsize;
+ map->probes = req->probes;
+ map->resize = req->resize;
+ map->netmask = req->netmask;
+ newbytes = map->hashsize * sizeof(ip_set_ip_t);
+ map->members = ip_set_malloc(newbytes);
+ if (!map->members) {
+ DP("out of memory for %d bytes", newbytes);
+ kfree(map);
+ return -ENOMEM;
+ }
+ memset(map->members, 0, newbytes);
+
+ set->data = map;
+ return 0;
+}
+
+static void destroy(struct ip_set *set)
+{
+ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data;
+
+ ip_set_free(map->members, map->hashsize * sizeof(ip_set_ip_t));
+ kfree(map);
+
+ set->data = NULL;
+}
+
+static void flush(struct ip_set *set)
+{
+ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data;
+ memset(map->members, 0, map->hashsize * sizeof(ip_set_ip_t));
+}
+
+static void list_header(const struct ip_set *set, void *data)
+{
+ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data;
+ struct ip_set_req_iphash_create *header =
+ (struct ip_set_req_iphash_create *) data;
+
+ header->hashsize = map->hashsize;
+ header->probes = map->probes;
+ header->resize = map->resize;
+ header->netmask = map->netmask;
+}
+
+static int list_members_size(const struct ip_set *set)
+{
+ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data;
+
+ return (map->hashsize * sizeof(ip_set_ip_t));
+}
+
+static void list_members(const struct ip_set *set, void *data)
+{
+ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data;
+ int bytes = map->hashsize * sizeof(ip_set_ip_t);
+
+ memcpy(data, map->members, bytes);
+}
+
+static struct ip_set_type ip_set_iphash = {
+ .typename = SETTYPE_NAME,
+ .typecode = IPSET_TYPE_IP,
+ .protocol_version = IP_SET_PROTOCOL_VERSION,
+ .create = &create,
+ .destroy = &destroy,
+ .flush = &flush,
+ .reqsize = sizeof(struct ip_set_req_iphash),
+ .addip = &addip,
+ .addip_kernel = &addip_kernel,
+ .retry = &retry,
+ .delip = &delip,
+ .delip_kernel = &delip_kernel,
+ .testip = &testip,
+ .testip_kernel = &testip_kernel,
+ .header_size = sizeof(struct ip_set_req_iphash_create),
+ .list_header = &list_header,
+ .list_members_size = &list_members_size,
+ .list_members = &list_members,
+ .me = THIS_MODULE,
+};
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_DESCRIPTION("iphash type of IP sets");
+
+static int __init init(void)
+{
+ init_max_malloc_size();
+ return ip_set_register_set_type(&ip_set_iphash);
+}
+
+static void __exit fini(void)
+{
+ /* FIXME: possible race with ip_set_create() */
+ ip_set_unregister_set_type(&ip_set_iphash);
+}
+
+module_init(init);
+module_exit(fini);
diff -urN linux-2.6.11/net/ipv4/netfilter/ip_set_ipmap.c linux.sinabox/net/ipv4/netfilter/ip_set_ipmap.c
--- linux-2.6.11/net/ipv4/netfilter/ip_set_ipmap.c 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/net/ipv4/netfilter/ip_set_ipmap.c 2005-03-24 19:22:37.000000000 +0100
@@ -0,0 +1,313 @@
+/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
+ * Patrick Schaaf <bof@bof.de>
+ * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/* Kernel module implementing an IP set type: the single bitmap type */
+
+#include <linux/module.h>
+#include <linux/ip.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ip_set.h>
+#include <linux/errno.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <linux/spinlock.h>
+
+#include <linux/netfilter_ipv4/ip_set_ipmap.h>
+
+static inline ip_set_ip_t
+ip_to_id(const struct ip_set_ipmap *map, ip_set_ip_t ip)
+{
+ return (ip - map->first_ip)/map->hosts;
+}
+
+static inline int
+__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+{
+ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
+
+ if (ip < map->first_ip || ip > map->last_ip)
+ return -ERANGE;
+
+ *hash_ip = ip & map->netmask;
+ DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u",
+ set->name, HIPQUAD(ip), HIPQUAD(*hash_ip));
+ return !!test_bit(ip_to_id(map, *hash_ip), map->members);
+}
+
+static int
+testip(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_ip)
+{
+ struct ip_set_req_ipmap *req =
+ (struct ip_set_req_ipmap *) data;
+
+ if (size != sizeof(struct ip_set_req_ipmap)) {
+ ip_set_printk("data length wrong (want %d, have %d)",
+ sizeof(struct ip_set_req_ipmap),
+ size);
+ return -EINVAL;
+ }
+ return __testip(set, req->ip, hash_ip);
+}
+
+static int
+testip_kernel(struct ip_set *set,
+ const struct sk_buff *skb,
+ u_int32_t flags,
+ ip_set_ip_t *hash_ip)
+{
+ int res;
+
+ DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u",
+ flags & IPSET_SRC ? "SRC" : "DST",
+ NIPQUAD(skb->nh.iph->saddr),
+ NIPQUAD(skb->nh.iph->daddr));
+
+ res = __testip(set,
+ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
+ : skb->nh.iph->daddr),
+ hash_ip);
+ return (res < 0 ? 0 : res);
+}
+
+static inline int
+__addip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+{
+ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
+
+ if (ip < map->first_ip || ip > map->last_ip)
+ return -ERANGE;
+
+ *hash_ip = ip & map->netmask;
+ DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip));
+ if (test_and_set_bit(ip_to_id(map, *hash_ip), map->members))
+ return -EEXIST;
+
+ return 0;
+}
+
+static int
+addip(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_ip)
+{
+ struct ip_set_req_ipmap *req =
+ (struct ip_set_req_ipmap *) data;
+
+ if (size != sizeof(struct ip_set_req_ipmap)) {
+ ip_set_printk("data length wrong (want %d, have %d)",
+ sizeof(struct ip_set_req_ipmap),
+ size);
+ return -EINVAL;
+ }
+ DP("%u.%u.%u.%u", HIPQUAD(req->ip));
+ return __addip(set, req->ip, hash_ip);
+}
+
+static int
+addip_kernel(struct ip_set *set, const struct sk_buff *skb,
+ u_int32_t flags, ip_set_ip_t *hash_ip)
+{
+ return __addip(set,
+ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
+ : skb->nh.iph->daddr),
+ hash_ip);
+}
+
+static inline int
+__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+{
+ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
+
+ if (ip < map->first_ip || ip > map->last_ip)
+ return -ERANGE;
+
+ *hash_ip = ip & map->netmask;
+ DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip));
+ if (!test_and_clear_bit(ip_to_id(map, *hash_ip), map->members))
+ return -EEXIST;
+
+ return 0;
+}
+
+static int
+delip(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_ip)
+{
+ struct ip_set_req_ipmap *req =
+ (struct ip_set_req_ipmap *) data;
+
+ if (size != sizeof(struct ip_set_req_ipmap)) {
+ ip_set_printk("data length wrong (want %d, have %d)",
+ sizeof(struct ip_set_req_ipmap),
+ size);
+ return -EINVAL;
+ }
+ return __delip(set, req->ip, hash_ip);
+}
+
+static int
+delip_kernel(struct ip_set *set, const struct sk_buff *skb,
+ u_int32_t flags, ip_set_ip_t *hash_ip)
+{
+ return __delip(set,
+ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
+ : skb->nh.iph->daddr),
+ hash_ip);
+}
+
+static int create(struct ip_set *set, const void *data, size_t size)
+{
+ int newbytes;
+ struct ip_set_req_ipmap_create *req =
+ (struct ip_set_req_ipmap_create *) data;
+ struct ip_set_ipmap *map;
+
+ if (size != sizeof(struct ip_set_req_ipmap_create)) {
+ ip_set_printk("data length wrong (want %d, have %d)",
+ sizeof(struct ip_set_req_ipmap_create),
+ size);
+ return -EINVAL;
+ }
+
+ DP("from %u.%u.%u.%u to %u.%u.%u.%u",
+ HIPQUAD(req->from), HIPQUAD(req->to));
+
+ if (req->from > req->to) {
+ DP("bad ip range");
+ return -ENOEXEC;
+ }
+
+ if (req->to - req->from > MAX_RANGE) {
+ ip_set_printk("range too big (max %d addresses)",
+ MAX_RANGE);
+ return -ENOEXEC;
+ }
+
+ map = kmalloc(sizeof(struct ip_set_ipmap), GFP_KERNEL);
+ if (!map) {
+ DP("out of memory for %d bytes",
+ sizeof(struct ip_set_ipmap));
+ return -ENOMEM;
+ }
+ map->first_ip = req->from;
+ map->last_ip = req->to;
+ map->netmask = req->netmask;
+
+ if (req->netmask == 0xFFFFFFFF) {
+ map->hosts = 1;
+ map->sizeid = map->last_ip - map->first_ip + 1;
+ } else {
+ unsigned int mask_bits, netmask_bits;
+ ip_set_ip_t mask;
+
+ map->first_ip &= map->netmask; /* Should we better bark? */
+
+ mask = range_to_mask(map->first_ip, map->last_ip, &mask_bits);
+ netmask_bits = mask_to_bits(map->netmask);
+
+ if (!mask || netmask_bits <= mask_bits)
+ return -ENOEXEC;
+
+ map->hosts = 2 << (32 - netmask_bits - 1);
+ map->sizeid = 2 << (netmask_bits - mask_bits - 1);
+ }
+ newbytes = bitmap_bytes(0, map->sizeid - 1);
+ map->members = kmalloc(newbytes, GFP_KERNEL);
+ if (!map->members) {
+ DP("out of memory for %d bytes", newbytes);
+ kfree(map);
+ return -ENOMEM;
+ }
+ memset(map->members, 0, newbytes);
+
+ set->data = map;
+ return 0;
+}
+
+static void destroy(struct ip_set *set)
+{
+ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
+
+ kfree(map->members);
+ kfree(map);
+
+ set->data = NULL;
+}
+
+static void flush(struct ip_set *set)
+{
+ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
+ memset(map->members, 0, bitmap_bytes(0, map->sizeid - 1));
+}
+
+static void list_header(const struct ip_set *set, void *data)
+{
+ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
+ struct ip_set_req_ipmap_create *header =
+ (struct ip_set_req_ipmap_create *) data;
+
+ header->from = map->first_ip;
+ header->to = map->last_ip;
+ header->netmask = map->netmask;
+}
+
+static int list_members_size(const struct ip_set *set)
+{
+ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
+
+ return bitmap_bytes(0, map->sizeid - 1);
+}
+
+static void list_members(const struct ip_set *set, void *data)
+{
+ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
+ int bytes = bitmap_bytes(0, map->sizeid - 1);
+
+ memcpy(data, map->members, bytes);
+}
+
+static struct ip_set_type ip_set_ipmap = {
+ .typename = SETTYPE_NAME,
+ .typecode = IPSET_TYPE_IP,
+ .protocol_version = IP_SET_PROTOCOL_VERSION,
+ .create = &create,
+ .destroy = &destroy,
+ .flush = &flush,
+ .reqsize = sizeof(struct ip_set_req_ipmap),
+ .addip = &addip,
+ .addip_kernel = &addip_kernel,
+ .delip = &delip,
+ .delip_kernel = &delip_kernel,
+ .testip = &testip,
+ .testip_kernel = &testip_kernel,
+ .header_size = sizeof(struct ip_set_req_ipmap_create),
+ .list_header = &list_header,
+ .list_members_size = &list_members_size,
+ .list_members = &list_members,
+ .me = THIS_MODULE,
+};
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_DESCRIPTION("ipmap type of IP sets");
+
+static int __init init(void)
+{
+ return ip_set_register_set_type(&ip_set_ipmap);
+}
+
+static void __exit fini(void)
+{
+ /* FIXME: possible race with ip_set_create() */
+ ip_set_unregister_set_type(&ip_set_ipmap);
+}
+
+module_init(init);
+module_exit(fini);
diff -urN linux-2.6.11/net/ipv4/netfilter/ip_set_macipmap.c linux.sinabox/net/ipv4/netfilter/ip_set_macipmap.c
--- linux-2.6.11/net/ipv4/netfilter/ip_set_macipmap.c 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/net/ipv4/netfilter/ip_set_macipmap.c 2005-03-24 19:22:37.000000000 +0100
@@ -0,0 +1,338 @@
+/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
+ * Patrick Schaaf <bof@bof.de>
+ * Martin Josefsson <gandalf@wlug.westbo.se>
+ * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/* Kernel module implementing an IP set type: the macipmap type */
+
+#include <linux/module.h>
+#include <linux/ip.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ip_set.h>
+#include <linux/errno.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <linux/spinlock.h>
+#include <linux/if_ether.h>
+#include <linux/vmalloc.h>
+
+#include <linux/netfilter_ipv4/ip_set_malloc.h>
+#include <linux/netfilter_ipv4/ip_set_macipmap.h>
+
+static int
+testip(struct ip_set *set, const void *data, size_t size, ip_set_ip_t *hash_ip)
+{
+ struct ip_set_macipmap *map = (struct ip_set_macipmap *) set->data;
+ struct ip_set_macip *table = (struct ip_set_macip *) map->members;
+ struct ip_set_req_macipmap *req = (struct ip_set_req_macipmap *) data;
+
+ if (size != sizeof(struct ip_set_req_macipmap)) {
+ ip_set_printk("data length wrong (want %d, have %d)",
+ sizeof(struct ip_set_req_macipmap),
+ size);
+ return -EINVAL;
+ }
+
+ if (req->ip < map->first_ip || req->ip > map->last_ip)
+ return -ERANGE;
+
+ *hash_ip = req->ip;
+ DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u",
+ set->name, HIPQUAD(req->ip), HIPQUAD(*hash_ip));
+ if (test_bit(IPSET_MACIP_ISSET,
+ (void *) &table[req->ip - map->first_ip].flags)) {
+ return (memcmp(req->ethernet,
+ &table[req->ip - map->first_ip].ethernet,
+ ETH_ALEN) == 0);
+ } else {
+ return (map->flags & IPSET_MACIP_MATCHUNSET ? 1 : 0);
+ }
+}
+
+static int
+testip_kernel(struct ip_set *set, const struct sk_buff *skb,
+ u_int32_t flags, ip_set_ip_t *hash_ip)
+{
+ struct ip_set_macipmap *map =
+ (struct ip_set_macipmap *) set->data;
+ struct ip_set_macip *table =
+ (struct ip_set_macip *) map->members;
+ ip_set_ip_t ip;
+
+ ip = ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
+ : skb->nh.iph->daddr);
+ DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u",
+ flags & IPSET_SRC ? "SRC" : "DST",
+ NIPQUAD(skb->nh.iph->saddr),
+ NIPQUAD(skb->nh.iph->daddr));
+
+ if (ip < map->first_ip || ip > map->last_ip)
+ return 0;
+
+ *hash_ip = ip;
+ DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u",
+ set->name, HIPQUAD(ip), HIPQUAD(*hash_ip));
+ if (test_bit(IPSET_MACIP_ISSET,
+ (void *) &table[ip - map->first_ip].flags)) {
+ /* Is mac pointer valid?
+ * If so, compare... */
+ return (skb->mac.raw >= skb->head
+ && (skb->mac.raw + ETH_HLEN) <= skb->data
+ && (memcmp(eth_hdr(skb)->h_source,
+ &table[ip - map->first_ip].ethernet,
+ ETH_ALEN) == 0));
+ } else {
+ return (map->flags & IPSET_MACIP_MATCHUNSET ? 1 : 0);
+ }
+}
+
+/* returns 0 on success */
+static inline int
+__addip(struct ip_set *set,
+ ip_set_ip_t ip, unsigned char *ethernet, ip_set_ip_t *hash_ip)
+{
+ struct ip_set_macipmap *map =
+ (struct ip_set_macipmap *) set->data;
+ struct ip_set_macip *table =
+ (struct ip_set_macip *) map->members;
+
+ if (ip < map->first_ip || ip > map->last_ip)
+ return -ERANGE;
+ if (test_and_set_bit(IPSET_MACIP_ISSET,
+ (void *) &table[ip - map->first_ip].flags))
+ return -EEXIST;
+
+ *hash_ip = ip;
+ DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip));
+ memcpy(&table[ip - map->first_ip].ethernet, ethernet, ETH_ALEN);
+ return 0;
+}
+
+static int
+addip(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_ip)
+{
+ struct ip_set_req_macipmap *req =
+ (struct ip_set_req_macipmap *) data;
+
+ if (size != sizeof(struct ip_set_req_macipmap)) {
+ ip_set_printk("data length wrong (want %d, have %d)",
+ sizeof(struct ip_set_req_macipmap),
+ size);
+ return -EINVAL;
+ }
+ return __addip(set, req->ip, req->ethernet, hash_ip);
+}
+
+static int
+addip_kernel(struct ip_set *set, const struct sk_buff *skb,
+ u_int32_t flags, ip_set_ip_t *hash_ip)
+{
+ ip_set_ip_t ip;
+
+ ip = ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
+ : skb->nh.iph->daddr);
+
+ if (!(skb->mac.raw >= skb->head
+ && (skb->mac.raw + ETH_HLEN) <= skb->data))
+ return -EINVAL;
+
+ return __addip(set, ip, eth_hdr(skb)->h_source, hash_ip);
+}
+
+static inline int
+__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+{
+ struct ip_set_macipmap *map =
+ (struct ip_set_macipmap *) set->data;
+ struct ip_set_macip *table =
+ (struct ip_set_macip *) map->members;
+
+ if (ip < map->first_ip || ip > map->last_ip)
+ return -ERANGE;
+ if (!test_and_clear_bit(IPSET_MACIP_ISSET,
+ (void *)&table[ip - map->first_ip].flags))
+ return -EEXIST;
+
+ *hash_ip = ip;
+ DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip));
+ return 0;
+}
+
+static int
+delip(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_ip)
+{
+ struct ip_set_req_macipmap *req =
+ (struct ip_set_req_macipmap *) data;
+
+ if (size != sizeof(struct ip_set_req_macipmap)) {
+ ip_set_printk("data length wrong (want %d, have %d)",
+ sizeof(struct ip_set_req_macipmap),
+ size);
+ return -EINVAL;
+ }
+ return __delip(set, req->ip, hash_ip);
+}
+
+static int
+delip_kernel(struct ip_set *set, const struct sk_buff *skb,
+ u_int32_t flags, ip_set_ip_t *hash_ip)
+{
+ return __delip(set,
+ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
+ : skb->nh.iph->daddr),
+ hash_ip);
+}
+
+static inline size_t members_size(ip_set_id_t from, ip_set_id_t to)
+{
+ return (size_t)((to - from + 1) * sizeof(struct ip_set_macip));
+}
+
+static int create(struct ip_set *set, const void *data, size_t size)
+{
+ int newbytes;
+ struct ip_set_req_macipmap_create *req =
+ (struct ip_set_req_macipmap_create *) data;
+ struct ip_set_macipmap *map;
+
+ if (size != sizeof(struct ip_set_req_macipmap_create)) {
+ ip_set_printk("data length wrong (want %d, have %d)",
+ sizeof(struct ip_set_req_macipmap_create),
+ size);
+ return -EINVAL;
+ }
+
+ DP("from %u.%u.%u.%u to %u.%u.%u.%u",
+ HIPQUAD(req->from), HIPQUAD(req->to));
+
+ if (req->from > req->to) {
+ DP("bad ip range");
+ return -ENOEXEC;
+ }
+
+ if (req->to - req->from > MAX_RANGE) {
+ ip_set_printk("range too big (max %d addresses)",
+ MAX_RANGE);
+ return -ENOEXEC;
+ }
+
+ map = kmalloc(sizeof(struct ip_set_macipmap), GFP_KERNEL);
+ if (!map) {
+ DP("out of memory for %d bytes",
+ sizeof(struct ip_set_macipmap));
+ return -ENOMEM;
+ }
+ map->flags = req->flags;
+ map->first_ip = req->from;
+ map->last_ip = req->to;
+ newbytes = members_size(map->first_ip, map->last_ip);
+ map->members = ip_set_malloc(newbytes);
+ if (!map->members) {
+ DP("out of memory for %d bytes", newbytes);
+ kfree(map);
+ return -ENOMEM;
+ }
+ memset(map->members, 0, newbytes);
+
+ set->data = map;
+ return 0;
+}
+
+static void destroy(struct ip_set *set)
+{
+ struct ip_set_macipmap *map =
+ (struct ip_set_macipmap *) set->data;
+
+ ip_set_free(map->members, members_size(map->first_ip, map->last_ip));
+ kfree(map);
+
+ set->data = NULL;
+}
+
+static void flush(struct ip_set *set)
+{
+ struct ip_set_macipmap *map =
+ (struct ip_set_macipmap *) set->data;
+ memset(map->members, 0, members_size(map->first_ip, map->last_ip));
+}
+
+static void list_header(const struct ip_set *set, void *data)
+{
+ struct ip_set_macipmap *map =
+ (struct ip_set_macipmap *) set->data;
+ struct ip_set_req_macipmap_create *header =
+ (struct ip_set_req_macipmap_create *) data;
+
+ DP("list_header %x %x %u", map->first_ip, map->last_ip,
+ map->flags);
+
+ header->from = map->first_ip;
+ header->to = map->last_ip;
+ header->flags = map->flags;
+}
+
+static int list_members_size(const struct ip_set *set)
+{
+ struct ip_set_macipmap *map =
+ (struct ip_set_macipmap *) set->data;
+
+ return members_size(map->first_ip, map->last_ip);
+}
+
+static void list_members(const struct ip_set *set, void *data)
+{
+ struct ip_set_macipmap *map =
+ (struct ip_set_macipmap *) set->data;
+
+ int bytes = members_size(map->first_ip, map->last_ip);
+
+ memcpy(data, map->members, bytes);
+}
+
+static struct ip_set_type ip_set_macipmap = {
+ .typename = SETTYPE_NAME,
+ .typecode = IPSET_TYPE_IP,
+ .protocol_version = IP_SET_PROTOCOL_VERSION,
+ .create = &create,
+ .destroy = &destroy,
+ .flush = &flush,
+ .reqsize = sizeof(struct ip_set_req_macipmap),
+ .addip = &addip,
+ .addip_kernel = &addip_kernel,
+ .delip = &delip,
+ .delip_kernel = &delip_kernel,
+ .testip = &testip,
+ .testip_kernel = &testip_kernel,
+ .header_size = sizeof(struct ip_set_req_macipmap_create),
+ .list_header = &list_header,
+ .list_members_size = &list_members_size,
+ .list_members = &list_members,
+ .me = THIS_MODULE,
+};
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_DESCRIPTION("macipmap type of IP sets");
+
+static int __init init(void)
+{
+ init_max_malloc_size();
+ return ip_set_register_set_type(&ip_set_macipmap);
+}
+
+static void __exit fini(void)
+{
+ /* FIXME: possible race with ip_set_create() */
+ ip_set_unregister_set_type(&ip_set_macipmap);
+}
+
+module_init(init);
+module_exit(fini);
diff -urN linux-2.6.11/net/ipv4/netfilter/ip_set_nethash.c linux.sinabox/net/ipv4/netfilter/ip_set_nethash.c
--- linux-2.6.11/net/ipv4/netfilter/ip_set_nethash.c 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/net/ipv4/netfilter/ip_set_nethash.c 2005-03-24 19:22:37.000000000 +0100
@@ -0,0 +1,448 @@
+/* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/* Kernel module implementing a cidr nethash set */
+
+#include <linux/module.h>
+#include <linux/ip.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ip_set.h>
+#include <linux/errno.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <linux/spinlock.h>
+#include <linux/vmalloc.h>
+#include <linux/random.h>
+
+#include <net/ip.h>
+
+#include <linux/netfilter_ipv4/ip_set_malloc.h>
+#include <linux/netfilter_ipv4/ip_set_nethash.h>
+#include <linux/netfilter_ipv4/ip_set_jhash.h>
+#include <linux/netfilter_ipv4/ip_set_prime.h>
+
+static inline __u32
+jhash_ip(const struct ip_set_nethash *map, ip_set_ip_t ip)
+{
+ return jhash_1word(ip, map->initval);
+}
+
+static inline __u32
+randhash_ip(const struct ip_set_nethash *map, ip_set_ip_t ip)
+{
+ return (1 + ip % map->prime);
+}
+
+static inline __u32
+hash_id_cidr(struct ip_set_nethash *map,
+ ip_set_ip_t ip,
+ unsigned char cidr,
+ ip_set_ip_t *hash_ip)
+{
+ __u32 jhash, randhash, id;
+ u_int16_t i;
+
+ *hash_ip = pack(ip, cidr);
+ jhash = jhash_ip(map, *hash_ip);
+ randhash = randhash_ip(map, *hash_ip);
+
+ for (i = 0; i < map->probes; i++) {
+ id = (jhash + i * randhash) % map->hashsize;
+ DP("hash key: %u", id);
+ if (map->members[id] == *hash_ip)
+ return id;
+ }
+ return UINT_MAX;
+}
+
+static inline __u32
+hash_id(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+{
+ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
+ __u32 id = UINT_MAX;
+ int i;
+
+ for (i = 0; i < 30 && map->cidr[i]; i++) {
+ id = hash_id_cidr(map, ip, map->cidr[i], hash_ip);
+ if (id != UINT_MAX)
+ break;
+ }
+ return id;
+}
+
+static inline int
+__testip_cidr(struct ip_set *set, ip_set_ip_t ip, unsigned char cidr,
+ ip_set_ip_t *hash_ip)
+{
+ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
+
+ return (hash_id_cidr(map, ip, cidr, hash_ip) != UINT_MAX);
+}
+
+static inline int
+__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+{
+ return (hash_id(set, ip, hash_ip) != UINT_MAX);
+}
+
+static int
+testip(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_ip)
+{
+ struct ip_set_req_nethash *req =
+ (struct ip_set_req_nethash *) data;
+
+ if (size != sizeof(struct ip_set_req_nethash)) {
+ ip_set_printk("data length wrong (want %d, have %d)",
+ sizeof(struct ip_set_req_nethash),
+ size);
+ return -EINVAL;
+ }
+ return __testip_cidr(set, req->ip, req->cidr, hash_ip);
+}
+
+static int
+testip_kernel(struct ip_set *set, const struct sk_buff *skb,
+ u_int32_t flags, ip_set_ip_t *hash_ip)
+{
+ return __testip(set,
+ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
+ : skb->nh.iph->daddr),
+ hash_ip);
+}
+
+static inline int
+__addip_base(struct ip_set_nethash *map, ip_set_ip_t ip)
+{
+ __u32 jhash, randhash, probe;
+ u_int16_t i;
+
+ jhash = jhash_ip(map, ip);
+ randhash = randhash_ip(map, ip);
+
+ for (i = 0; i < map->probes; i++) {
+ probe = (jhash + i * randhash) % map->hashsize;
+ if (map->members[probe] == ip)
+ return -EEXIST;
+ if (!map->members[probe]) {
+ map->members[probe] = ip;
+ return 0;
+ }
+ }
+ /* Trigger rehashing */
+ return -EAGAIN;
+}
+
+static inline int
+__addip(struct ip_set_nethash *map, ip_set_ip_t ip, unsigned char cidr,
+ ip_set_ip_t *hash_ip)
+{
+ *hash_ip = pack(ip, cidr);
+ DP("%u.%u.%u.%u/%u, %u.%u.%u.%u", HIPQUAD(ip), cidr, HIPQUAD(*hash_ip));
+
+ return __addip_base(map, *hash_ip);
+}
+
+static void
+update_cidr_sizes(struct ip_set_nethash *map, unsigned char cidr)
+{
+ unsigned char next;
+ int i;
+
+ for (i = 0; i < 30 && map->cidr[i]; i++) {
+ if (map->cidr[i] == cidr) {
+ return;
+ } else if (map->cidr[i] < cidr) {
+ next = map->cidr[i];
+ map->cidr[i] = cidr;
+ cidr = next;
+ }
+ }
+ if (i < 30)
+ map->cidr[i] = cidr;
+}
+
+static int
+addip(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_ip)
+{
+ struct ip_set_req_nethash *req =
+ (struct ip_set_req_nethash *) data;
+ int ret;
+
+ if (size != sizeof(struct ip_set_req_nethash)) {
+ ip_set_printk("data length wrong (want %d, have %d)",
+ sizeof(struct ip_set_req_nethash),
+ size);
+ return -EINVAL;
+ }
+ ret = __addip((struct ip_set_nethash *) set->data,
+ req->ip, req->cidr, hash_ip);
+
+ if (ret == 0)
+ update_cidr_sizes((struct ip_set_nethash *) set->data,
+ req->cidr);
+
+ return ret;
+}
+
+static int
+addip_kernel(struct ip_set *set, const struct sk_buff *skb,
+ u_int32_t flags, ip_set_ip_t *hash_ip)
+{
+ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
+ int ret = -ERANGE;
+ ip_set_ip_t ip = ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
+ : skb->nh.iph->daddr);
+
+ if (map->cidr[0])
+ ret = __addip(map, ip, map->cidr[0], hash_ip);
+
+ return ret;
+}
+
+static int retry(struct ip_set *set)
+{
+ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
+ ip_set_ip_t *members;
+ u_int32_t i, hashsize;
+ unsigned newbytes;
+ int res;
+ struct ip_set_nethash tmp = {
+ .hashsize = map->hashsize,
+ .probes = map->probes,
+ .resize = map->resize
+ };
+
+ if (map->resize == 0)
+ return -ERANGE;
+
+ memcpy(tmp.cidr, map->cidr, 30 * sizeof(unsigned char));
+ again:
+ res = 0;
+
+ /* Calculate new parameters */
+ get_random_bytes(&tmp.initval, 4);
+ hashsize = tmp.hashsize + (tmp.hashsize * map->resize)/100;
+ if (hashsize == tmp.hashsize)
+ hashsize++;
+ tmp.prime = make_prime(hashsize);
+
+ ip_set_printk("rehashing of set %s triggered: "
+ "hashsize grows from %u to %u",
+ set->name, tmp.hashsize, hashsize);
+ tmp.hashsize = hashsize;
+
+ newbytes = hashsize * sizeof(ip_set_ip_t);
+ tmp.members = ip_set_malloc(newbytes);
+ if (!tmp.members) {
+ DP("out of memory for %d bytes", newbytes);
+ return -ENOMEM;
+ }
+ memset(tmp.members, 0, newbytes);
+
+ write_lock_bh(&set->lock);
+ map = (struct ip_set_nethash *) set->data; /* Play safe */
+ for (i = 0; i < map->hashsize && res == 0; i++) {
+ if (map->members[i])
+ res = __addip_base(&tmp, map->members[i]);
+ }
+ if (res) {
+ /* Failure, try again */
+ ip_set_free(tmp.members, newbytes);
+ write_unlock_bh(&set->lock);
+ goto again;
+ }
+
+ /* Success at resizing! */
+ members = map->members;
+ hashsize = map->hashsize;
+
+ map->initval = tmp.initval;
+ map->prime = tmp.prime;
+ map->hashsize = tmp.hashsize;
+ map->members = tmp.members;
+ write_unlock_bh(&set->lock);
+
+ ip_set_free(members, hashsize * sizeof(ip_set_ip_t));
+
+ return 0;
+}
+
+static inline int
+__delip(struct ip_set_nethash *map, ip_set_ip_t ip, unsigned char cidr,
+ ip_set_ip_t *hash_ip)
+{
+ ip_set_ip_t id = hash_id_cidr(map, ip, cidr, hash_ip);
+
+ if (id == UINT_MAX)
+ return -EEXIST;
+
+ map->members[id] = 0;
+ return 0;
+}
+
+static int
+delip(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_ip)
+{
+ struct ip_set_req_nethash *req =
+ (struct ip_set_req_nethash *) data;
+
+ if (size != sizeof(struct ip_set_req_nethash)) {
+ ip_set_printk("data length wrong (want %d, have %d)",
+ sizeof(struct ip_set_req_nethash),
+ size);
+ return -EINVAL;
+ }
+ /* TODO: no garbage collection in map->cidr */
+ return __delip((struct ip_set_nethash *) set->data,
+ req->ip, req->cidr, hash_ip);
+}
+
+static int
+delip_kernel(struct ip_set *set, const struct sk_buff *skb,
+ u_int32_t flags, ip_set_ip_t *hash_ip)
+{
+ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
+ int ret = -ERANGE;
+ ip_set_ip_t ip = ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
+ : skb->nh.iph->daddr);
+
+ if (map->cidr[0])
+ ret = __delip(map, ip, map->cidr[0], hash_ip);
+
+ return ret;
+}
+
+static int create(struct ip_set *set, const void *data, size_t size)
+{
+ unsigned newbytes;
+ struct ip_set_req_nethash_create *req =
+ (struct ip_set_req_nethash_create *) data;
+ struct ip_set_nethash *map;
+
+ if (size != sizeof(struct ip_set_req_nethash_create)) {
+ ip_set_printk("data length wrong (want %d, have %d)",
+ sizeof(struct ip_set_req_nethash_create),
+ size);
+ return -EINVAL;
+ }
+
+ if (req->hashsize < 1) {
+ ip_set_printk("hashsize too small");
+ return -ENOEXEC;
+ }
+
+ map = kmalloc(sizeof(struct ip_set_nethash), GFP_KERNEL);
+ if (!map) {
+ DP("out of memory for %d bytes",
+ sizeof(struct ip_set_nethash));
+ return -ENOMEM;
+ }
+ get_random_bytes(&map->initval, 4);
+ map->prime = make_prime(req->hashsize);
+ map->hashsize = req->hashsize;
+ map->probes = req->probes;
+ map->resize = req->resize;
+ memset(map->cidr, 0, 30 * sizeof(unsigned char));
+ newbytes = map->hashsize * sizeof(ip_set_ip_t);
+ map->members = ip_set_malloc(newbytes);
+ if (!map->members) {
+ DP("out of memory for %d bytes", newbytes);
+ kfree(map);
+ return -ENOMEM;
+ }
+ memset(map->members, 0, newbytes);
+
+ set->data = map;
+ return 0;
+}
+
+static void destroy(struct ip_set *set)
+{
+ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
+
+ ip_set_free(map->members, map->hashsize * sizeof(ip_set_ip_t));
+ kfree(map);
+
+ set->data = NULL;
+}
+
+static void flush(struct ip_set *set)
+{
+ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
+ memset(map->members, 0, map->hashsize * sizeof(ip_set_ip_t));
+ memset(map->cidr, 0, 30 * sizeof(unsigned char));
+}
+
+static void list_header(const struct ip_set *set, void *data)
+{
+ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
+ struct ip_set_req_nethash_create *header =
+ (struct ip_set_req_nethash_create *) data;
+
+ header->hashsize = map->hashsize;
+ header->probes = map->probes;
+ header->resize = map->resize;
+}
+
+static int list_members_size(const struct ip_set *set)
+{
+ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
+
+ return (map->hashsize * sizeof(ip_set_ip_t));
+}
+
+static void list_members(const struct ip_set *set, void *data)
+{
+ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
+ int bytes = map->hashsize * sizeof(ip_set_ip_t);
+
+ memcpy(data, map->members, bytes);
+}
+
+static struct ip_set_type ip_set_nethash = {
+ .typename = SETTYPE_NAME,
+ .typecode = IPSET_TYPE_IP,
+ .protocol_version = IP_SET_PROTOCOL_VERSION,
+ .create = &create,
+ .destroy = &destroy,
+ .flush = &flush,
+ .reqsize = sizeof(struct ip_set_req_nethash),
+ .addip = &addip,
+ .addip_kernel = &addip_kernel,
+ .retry = &retry,
+ .delip = &delip,
+ .delip_kernel = &delip_kernel,
+ .testip = &testip,
+ .testip_kernel = &testip_kernel,
+ .header_size = sizeof(struct ip_set_req_nethash_create),
+ .list_header = &list_header,
+ .list_members_size = &list_members_size,
+ .list_members = &list_members,
+ .me = THIS_MODULE,
+};
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_DESCRIPTION("nethash type of IP sets");
+
+static int __init init(void)
+{
+ return ip_set_register_set_type(&ip_set_nethash);
+}
+
+static void __exit fini(void)
+{
+ /* FIXME: possible race with ip_set_create() */
+ ip_set_unregister_set_type(&ip_set_nethash);
+}
+
+module_init(init);
+module_exit(fini);
diff -urN linux-2.6.11/net/ipv4/netfilter/ip_set_portmap.c linux.sinabox/net/ipv4/netfilter/ip_set_portmap.c
--- linux-2.6.11/net/ipv4/netfilter/ip_set_portmap.c 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/net/ipv4/netfilter/ip_set_portmap.c 2005-03-24 19:22:37.000000000 +0100
@@ -0,0 +1,325 @@
+/* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/* Kernel module implementing a port set type as a bitmap */
+
+#include <linux/module.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ip_set.h>
+#include <linux/errno.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <linux/spinlock.h>
+
+#include <net/ip.h>
+
+#include <linux/netfilter_ipv4/ip_set_portmap.h>
+
+/* We must handle non-linear skbs */
+static inline ip_set_ip_t
+get_port(const struct sk_buff *skb, u_int32_t flags)
+{
+ struct iphdr *iph = skb->nh.iph;
+ u_int16_t offset = ntohs(iph->frag_off) & IP_OFFSET;
+
+ switch (iph->protocol) {
+ case IPPROTO_TCP: {
+ struct tcphdr tcph;
+
+ /* See comments at tcp_match in ip_tables.c */
+ if (offset)
+ return INVALID_PORT;
+
+ if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &tcph, sizeof(tcph)) < 0)
+ /* No choice either */
+ return INVALID_PORT;
+
+ return ntohs(flags & IPSET_SRC ?
+ tcph.source : tcph.dest);
+ }
+ case IPPROTO_UDP: {
+ struct udphdr udph;
+
+ if (offset)
+ return INVALID_PORT;
+
+ if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &udph, sizeof(udph)) < 0)
+ /* No choice either */
+ return INVALID_PORT;
+
+ return ntohs(flags & IPSET_SRC ?
+ udph.source : udph.dest);
+ }
+ default:
+ return INVALID_PORT;
+ }
+}
+
+static inline int
+__testport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port)
+{
+ struct ip_set_portmap *map = (struct ip_set_portmap *) set->data;
+
+ if (port < map->first_port || port > map->last_port)
+ return -ERANGE;
+
+ *hash_port = port;
+ DP("set: %s, port:%u, %u", set->name, port, *hash_port);
+ return !!test_bit(port - map->first_port, map->members);
+}
+
+static int
+testport(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_port)
+{
+ struct ip_set_req_portmap *req =
+ (struct ip_set_req_portmap *) data;
+
+ if (size != sizeof(struct ip_set_req_portmap)) {
+ ip_set_printk("data length wrong (want %d, have %d)",
+ sizeof(struct ip_set_req_portmap),
+ size);
+ return -EINVAL;
+ }
+ return __testport(set, req->port, hash_port);
+}
+
+static int
+testport_kernel(struct ip_set *set, const struct sk_buff *skb,
+ u_int32_t flags, ip_set_ip_t *hash_port)
+{
+ int res;
+ ip_set_ip_t port = get_port(skb, flags);
+
+ DP("flag %s port %u", flags & IPSET_SRC ? "SRC" : "DST", port);
+ if (port == INVALID_PORT)
+ return 0;
+
+ res = __testport(set, port, hash_port);
+
+ return (res < 0 ? 0 : res);
+}
+
+static inline int
+__addport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port)
+{
+ struct ip_set_portmap *map = (struct ip_set_portmap *) set->data;
+
+ if (port < map->first_port || port > map->last_port)
+ return -ERANGE;
+ if (test_and_set_bit(port - map->first_port, map->members))
+ return -EEXIST;
+
+ *hash_port = port;
+ DP("port %u", port);
+ return 0;
+}
+
+static int
+addport(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_port)
+{
+ struct ip_set_req_portmap *req =
+ (struct ip_set_req_portmap *) data;
+
+ if (size != sizeof(struct ip_set_req_portmap)) {
+ ip_set_printk("data length wrong (want %d, have %d)",
+ sizeof(struct ip_set_req_portmap),
+ size);
+ return -EINVAL;
+ }
+ return __addport(set, req->port, hash_port);
+}
+
+static int
+addport_kernel(struct ip_set *set, const struct sk_buff *skb,
+ u_int32_t flags, ip_set_ip_t *hash_port)
+{
+ ip_set_ip_t port = get_port(skb, flags);
+
+ if (port == INVALID_PORT)
+ return -EINVAL;
+
+ return __addport(set, port, hash_port);
+}
+
+static inline int
+__delport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port)
+{
+ struct ip_set_portmap *map = (struct ip_set_portmap *) set->data;
+
+ if (port < map->first_port || port > map->last_port)
+ return -ERANGE;
+ if (!test_and_clear_bit(port - map->first_port, map->members))
+ return -EEXIST;
+
+ *hash_port = port;
+ DP("port %u", port);
+ return 0;
+}
+
+static int
+delport(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_port)
+{
+ struct ip_set_req_portmap *req =
+ (struct ip_set_req_portmap *) data;
+
+ if (size != sizeof(struct ip_set_req_portmap)) {
+ ip_set_printk("data length wrong (want %d, have %d)",
+ sizeof(struct ip_set_req_portmap),
+ size);
+ return -EINVAL;
+ }
+ return __delport(set, req->port, hash_port);
+}
+
+static int
+delport_kernel(struct ip_set *set, const struct sk_buff *skb,
+ u_int32_t flags, ip_set_ip_t *hash_port)
+{
+ ip_set_ip_t port = get_port(skb, flags);
+
+ if (port == INVALID_PORT)
+ return -EINVAL;
+
+ return __delport(set, port, hash_port);
+}
+
+static int create(struct ip_set *set, const void *data, size_t size)
+{
+ int newbytes;
+ struct ip_set_req_portmap_create *req =
+ (struct ip_set_req_portmap_create *) data;
+ struct ip_set_portmap *map;
+
+ if (size != sizeof(struct ip_set_req_portmap_create)) {
+ ip_set_printk("data length wrong (want %d, have %d)",
+ sizeof(struct ip_set_req_portmap_create),
+ size);
+ return -EINVAL;
+ }
+
+ DP("from %u to %u", req->from, req->to);
+
+ if (req->from > req->to) {
+ DP("bad port range");
+ return -ENOEXEC;
+ }
+
+ if (req->to - req->from > MAX_RANGE) {
+ ip_set_printk("range too big (max %d ports)",
+ MAX_RANGE);
+ return -ENOEXEC;
+ }
+
+ map = kmalloc(sizeof(struct ip_set_portmap), GFP_KERNEL);
+ if (!map) {
+ DP("out of memory for %d bytes",
+ sizeof(struct ip_set_portmap));
+ return -ENOMEM;
+ }
+ map->first_port = req->from;
+ map->last_port = req->to;
+ newbytes = bitmap_bytes(req->from, req->to);
+ map->members = kmalloc(newbytes, GFP_KERNEL);
+ if (!map->members) {
+ DP("out of memory for %d bytes", newbytes);
+ kfree(map);
+ return -ENOMEM;
+ }
+ memset(map->members, 0, newbytes);
+
+ set->data = map;
+ return 0;
+}
+
+static void destroy(struct ip_set *set)
+{
+ struct ip_set_portmap *map = (struct ip_set_portmap *) set->data;
+
+ kfree(map->members);
+ kfree(map);
+
+ set->data = NULL;
+}
+
+static void flush(struct ip_set *set)
+{
+ struct ip_set_portmap *map = (struct ip_set_portmap *) set->data;
+ memset(map->members, 0, bitmap_bytes(map->first_port, map->last_port));
+}
+
+static void list_header(const struct ip_set *set, void *data)
+{
+ struct ip_set_portmap *map = (struct ip_set_portmap *) set->data;
+ struct ip_set_req_portmap_create *header =
+ (struct ip_set_req_portmap_create *) data;
+
+ DP("list_header %u %u", map->first_port, map->last_port);
+
+ header->from = map->first_port;
+ header->to = map->last_port;
+}
+
+static int list_members_size(const struct ip_set *set)
+{
+ struct ip_set_portmap *map = (struct ip_set_portmap *) set->data;
+
+ return bitmap_bytes(map->first_port, map->last_port);
+}
+
+static void list_members(const struct ip_set *set, void *data)
+{
+ struct ip_set_portmap *map = (struct ip_set_portmap *) set->data;
+ int bytes = bitmap_bytes(map->first_port, map->last_port);
+
+ memcpy(data, map->members, bytes);
+}
+
+static struct ip_set_type ip_set_portmap = {
+ .typename = SETTYPE_NAME,
+ .typecode = IPSET_TYPE_PORT,
+ .protocol_version = IP_SET_PROTOCOL_VERSION,
+ .create = &create,
+ .destroy = &destroy,
+ .flush = &flush,
+ .reqsize = sizeof(struct ip_set_req_portmap),
+ .addip = &addport,
+ .addip_kernel = &addport_kernel,
+ .delip = &delport,
+ .delip_kernel = &delport_kernel,
+ .testip = &testport,
+ .testip_kernel = &testport_kernel,
+ .header_size = sizeof(struct ip_set_req_portmap_create),
+ .list_header = &list_header,
+ .list_members_size = &list_members_size,
+ .list_members = &list_members,
+ .me = THIS_MODULE,
+};
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_DESCRIPTION("portmap type of IP sets");
+
+static int __init init(void)
+{
+ return ip_set_register_set_type(&ip_set_portmap);
+}
+
+static void __exit fini(void)
+{
+ /* FIXME: possible race with ip_set_create() */
+ ip_set_unregister_set_type(&ip_set_portmap);
+}
+
+module_init(init);
+module_exit(fini);
diff -urN linux-2.6.11/net/ipv4/netfilter/ipt_IMQ.c linux.sinabox/net/ipv4/netfilter/ipt_IMQ.c
--- linux-2.6.11/net/ipv4/netfilter/ipt_IMQ.c 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/net/ipv4/netfilter/ipt_IMQ.c 2005-03-26 00:49:04.000000000 +0100
@@ -0,0 +1,78 @@
+/*
+ * This target marks packets to be enqueued to an imq device
+ */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_IMQ.h>
+#include <linux/imq.h>
+
+static unsigned int imq_target(struct sk_buff **pskb,
+ const struct net_device *in,
+ const struct net_device *out,
+ unsigned int hooknum,
+ const void *targinfo,
+ void *userdata)
+{
+ struct ipt_imq_info *mr = (struct ipt_imq_info*)targinfo;
+
+ (*pskb)->imq_flags = mr->todev | IMQ_F_ENQUEUE;
+ (*pskb)->nfcache |= NFC_ALTERED;
+
+ return IPT_CONTINUE;
+}
+
+static int imq_checkentry(const char *tablename,
+ const struct ipt_entry *e,
+ void *targinfo,
+ unsigned int targinfosize,
+ unsigned int hook_mask)
+{
+ struct ipt_imq_info *mr;
+
+ if (targinfosize != IPT_ALIGN(sizeof(struct ipt_imq_info))) {
+ printk(KERN_WARNING "IMQ: invalid targinfosize\n");
+ return 0;
+ }
+ mr = (struct ipt_imq_info*)targinfo;
+
+ if (strcmp(tablename, "mangle") != 0) {
+ printk(KERN_WARNING
+ "IMQ: IMQ can only be called from \"mangle\" table, not \"%s\"\n",
+ tablename);
+ return 0;
+ }
+
+ if (mr->todev > IMQ_MAX_DEVS) {
+ printk(KERN_WARNING
+ "IMQ: invalid device specified, highest is %u\n",
+ IMQ_MAX_DEVS);
+ return 0;
+ }
+
+ return 1;
+}
+
+static struct ipt_target ipt_imq_reg = {
+ .name = "IMQ",
+ .target = imq_target,
+ .checkentry = imq_checkentry,
+ .me = THIS_MODULE
+};
+
+static int __init init(void)
+{
+ if (ipt_register_target(&ipt_imq_reg))
+ return -EINVAL;
+
+ return 0;
+}
+
+static void __exit fini(void)
+{
+ ipt_unregister_target(&ipt_imq_reg);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
diff -urN linux-2.6.11/net/ipv4/netfilter/ipt_ipp2p.c linux.sinabox/net/ipv4/netfilter/ipt_ipp2p.c
--- linux-2.6.11/net/ipv4/netfilter/ipt_ipp2p.c 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/net/ipv4/netfilter/ipt_ipp2p.c 2005-03-24 19:26:06.000000000 +0100
@@ -0,0 +1,640 @@
+#include <linux/module.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/version.h>
+#include <linux/netfilter_ipv4/ipt_ipp2p.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+
+#define get_u8(X,O) (*(__u8 *)(X + O))
+#define get_u16(X,O) (*(__u16 *)(X + O))
+#define get_u32(X,O) (*(__u32 *)(X + O))
+
+MODULE_AUTHOR("Eicke Friedrich <ipp2p@ipp2p.org>");
+MODULE_DESCRIPTION("An extension to iptables to identify P2P traffic.");
+MODULE_LICENSE("GPL");
+
+
+/*Search for UDP eDonkey/eMule/Kad commands*/
+int
+udp_search_edk (unsigned char *haystack, int packet_len)
+{
+ unsigned char *t = haystack;
+ t += 8;
+
+ switch (t[0]) {
+ case 0xe3: { /*edonkey*/
+ switch (t[1]) {
+ /* e3 9a + 16Bytes Hash | size == 26 */
+ case 0x9a: if (packet_len == 26) return ((IPP2P_EDK * 100) + 1);
+ /* e3 96 xx yy zz kk | size == 14 | server status request */
+ case 0x96: if (packet_len == 14) return ((IPP2P_EDK * 100) + 2);
+ /* e3 a2 | size == 10 or 14 <-- recheck*/
+ }
+ }
+
+ case 0xc5: { /*emule*/
+ switch (t[1]) {
+ /* c5 91 xx yy | size == 12 (8+4) | xx != 0x00 -- xx yy queue rating */
+ case 0x91: if ((packet_len == 12) && (t[2] != 0x00)) return ((IPP2P_EDK * 100) + 3);
+ /* c5 90 xx .. yy | size == 26 (8+2+16) | xx .. yy == hash -- file ping */
+ case 0x90: if ((packet_len == 26) && (t[2] != 0x00)) return ((IPP2P_EDK * 100) + 4);
+ /* c5 92 | size == 10 (8+2) -- file not found */
+ case 0x92: if (packet_len == 10) return ((IPP2P_EDK * 100) + 5);
+ /* c5 93 | size == 10 (8+2) -- queue full */
+ case 0x93: if (packet_len == 10) return ((IPP2P_EDK * 100) + 6);
+ }
+ }
+
+ case 0xe4: { /*kad*/
+ switch (t[1]) {
+ /* e4 50 | size == 12 */
+ case 0x50: if (packet_len == 12) return ((IPP2P_EDK * 100) + 7);
+ /* e4 58 | size == 14 */
+ case 0x58: if ((packet_len == 14) && (t[2] != 0x00)) return ((IPP2P_EDK * 100) + 8);
+ /* e4 59 | size == 10 */
+ case 0x59: if (packet_len == 10) return ((IPP2P_EDK * 100) + 9);
+ /* e4 30 .. | t[18] == 0x01 | size > 26 | --> search */
+ case 0x30: if ((packet_len > 26) && (t[18] == 0x01)) return ((IPP2P_EDK * 100) + 10);
+ /* e4 28 .. 00 | t[68] == 0x00 | size > 76 */
+ case 0x28: if ((packet_len > 76) && (t[68] == 0x00)) return ((IPP2P_EDK * 100) + 11);
+ /* e4 20 .. | size == 43 */
+ case 0x20: if ((packet_len == 43) && (t[2] != 0x00) && (t[34] != 0x00)) return ((IPP2P_EDK * 100) + 12);
+ /* e4 00 .. 00 | size == 35 ? */
+ case 0x00: if ((packet_len == 35) && (t[26] == 0x00)) return ((IPP2P_EDK * 100) + 13);
+ /* e4 10 .. 00 | size == 35 ? */
+ case 0x10: if ((packet_len == 35) && (t[26] == 0x00)) return ((IPP2P_EDK * 100) + 14);
+ /* e4 18 .. 00 | size == 35 ? */
+ case 0x18: if ((packet_len == 35) && (t[26] == 0x00)) return ((IPP2P_EDK * 100) + 15);
+ /* e4 40 .. | t[18] == 0x01 | t[19] == 0x00 | size > 40 */
+ case 0x40: if ((packet_len > 40) && (t[18] == 0x01) && (t[19] == 0x00)) return ((IPP2P_EDK * 100) + 16);
+ }
+ }
+
+ default: return 0;
+ } /* end of switch (t[0]) */
+}/*udp_search_edk*/
+
+
+/*Search for UDP Gnutella commands*/
+int
+udp_search_gnu (unsigned char *haystack, int packet_len)
+{
+ unsigned char *t = haystack;
+ t += 8;
+
+ if (memcmp(t, "GND", 3) == 0) return ((IPP2P_GNU * 100) + 1);
+ if (memcmp(t, "GNUTELLA ", 9) == 0) return ((IPP2P_GNU * 100) + 2);
+ return 0;
+}/*udp_search_gnu*/
+
+
+/*Search for UDP KaZaA commands*/
+int
+udp_search_kazaa (unsigned char *haystack, int packet_len)
+{
+ unsigned char *t = haystack;
+
+ if (t[packet_len-1] == 0x00){
+ t += (packet_len - 6);
+ if (memcmp(t, "KaZaA", 5) == 0) return (IPP2P_KAZAA * 100);
+ }
+ return 0;
+}/*udp_search_kazaa*/
+
+
+/*Search for UDP BitTorrent commands*/
+int
+udp_search_bit (unsigned char *haystack, int packet_len)
+{
+ unsigned char *t = haystack;
+
+ /* packet_len has to be 24 */
+ if (packet_len != 24) return 0;
+
+ t += 8;
+
+ /* ^ 00 00 04 17 27 10 19 80 */
+ if ((ntohl(get_u32(t, 0)) == 0x00000417) && (ntohl(get_u32(t, 4)) == 0x27101980)) return (IPP2P_BIT * 100);
+
+ return 0;
+}/*udp_search_bit*/
+
+
+
+/*Search for Ares commands*/
+int
+search_ares (unsigned char *haystack, int packet_len, int head_len)
+{
+ unsigned char *t = haystack;
+ t += head_len;
+
+ if ((packet_len - head_len) == 6){ /* possible connect command*/
+ if ((t[0] == 0x03) && (t[1] == 0x00) && (t[2] == 0x5a) && (t[3] == 0x04) && (t[4] == 0x03) && (t[5] == 0x05))
+ return ((IPP2P_ARES * 100) + 1); /* found connect packet: 03 00 5a 04 03 05 */
+ }
+ if ((packet_len - head_len) == 60){ /* possible download command*/
+ if ((t[59] == 0x0a) && (t[58] == 0x0a)){
+ if (memcmp(t, "PUSH SHA1:", 10) == 0) /* found download command */
+ return ((IPP2P_ARES * 100) + 2);
+ }
+ }
+ return 0;
+} /*search_ares*/
+
+
+/*Search for SoulSeek commands*/
+int
+search_soul (unsigned char *haystack, int packet_len, int head_len)
+{
+ unsigned char *t = haystack;
+ t += head_len;
+
+ if (get_u16(t, 0) == (packet_len - head_len - 4)){
+ /* xx xx 00 00 yy zz 00 00 .. | xx = sizeof(payload) - 4 */
+ if ((get_u16(t,2) == 0x0000) &&(t[4] != 0x00) && (get_u16(t,6) == 0x0000))
+ return ((IPP2P_SOUL * 100) + 1);
+ } else {
+ /* 00 00 00 00 00 00 00 00 + sizeof(payload) == 8*/
+ if (((packet_len - head_len) == 8) && (get_u32(t, 0) == 0x00000000) && (get_u32(t, 4) == 0x00000000))
+ return ((IPP2P_SOUL * 100) + 2);
+ }
+
+ /* 01 xx 00 00 00 yy .. zz 00 00 00 .. | xx == sizeof(nick) | yy .. zz == nick */
+ if ((t[0] == 0x01) && (t[2] == 0x00) && (get_u16(t,3) == 0x0000) && ((packet_len - head_len) > ((get_u8(t,1))+6)) &&
+ (t[(get_u8(t,1))+4] != 0x00) && (t[(get_u8(t,1))+5] == 0x01) && (t[(get_u8(t,1))+6] == 0x00))
+ return ((IPP2P_SOUL * 100) + 3);
+ return 0;
+}
+
+
+/*Search for WinMX commands*/
+int
+search_winmx (unsigned char *haystack, int packet_len, int head_len)
+{
+ unsigned char *t = haystack;
+ int c;
+ t += head_len;
+
+ if (((packet_len - head_len) == 4) && (memcmp(t, "SEND", 4) == 0)) return ((IPP2P_WINMX * 100) + 1);
+ if (((packet_len - head_len) == 3) && (memcmp(t, "GET", 3) == 0)) return ((IPP2P_WINMX * 100) + 2);
+ if (packet_len < (head_len + 10)) return 0;
+
+ if ((memcmp(t, "SEND", 4) == 0) || (memcmp(t, "GET", 3) == 0)){
+ c = head_len + 4;
+ t += 4;
+ while (c < packet_len - 5) {
+ if ((t[0] == 0x20) && (t[1] == 0x22)){
+ c += 2;
+ t += 2;
+ while (c < packet_len - 2) {
+ if ((t[0] == 0x22) && (t[1] == 0x20)) return ((IPP2P_WINMX * 100) + 3);
+ t++;
+ c++;
+ }
+ }
+ t++;
+ c++;
+ }
+ }
+ return 0;
+} /*search_winmx*/
+
+
+/*Search for appleJuice commands*/
+int
+search_apple (unsigned char *haystack, int packet_len, int head_len)
+{
+ unsigned char *t = haystack;
+ t += head_len;
+
+ if ((memcmp(t, "ajprot", 6) == 0) && (t[6] == 0x0d) && (t[7] == 0x0a)) return (IPP2P_APPLE * 100);
+
+ return 0;
+}
+
+
+/*Search for BitTorrent commands*/
+int
+search_bittorrent (unsigned char *haystack, int packet_len, int head_len)
+{
+
+ unsigned char *t = haystack;
+ if (*(haystack+head_len) != 0x13) return 0; /*Bail out of first byte != 0x13*/
+
+ t += head_len + 1;
+
+ if (memcmp(t, "BitTorrent protocol", 19) == 0) return (IPP2P_BIT * 100);
+ return 0;
+}
+
+
+
+/*check for Kazaa get command*/
+int
+search_kazaa (unsigned char *haystack, int packet_len, int head_len)
+{
+ unsigned char *t = haystack;
+
+ if (!((*(haystack + packet_len - 2) == 0x0d) && (*(haystack + packet_len - 1) == 0x0a))) return 0;
+
+ t += head_len;
+ if (memcmp(t, "GET /.hash=", 11) == 0)
+ return (IPP2P_DATA_KAZAA * 100);
+ else
+ return 0;
+}
+
+
+/*check for gnutella get command*/
+int
+search_gnu (unsigned char *haystack, int packet_len, int head_len)
+{
+ unsigned char *t = haystack;
+
+ if (!((*(haystack + packet_len - 2) == 0x0d) && (*(haystack + packet_len - 1) == 0x0a))) return 0;
+
+ t += head_len;
+ if (memcmp(t, "GET /get/", 9) == 0) return ((IPP2P_DATA_GNU * 100) + 1);
+ if (memcmp(t, "GET /uri-res/", 13) == 0) return ((IPP2P_DATA_GNU * 100) + 2);
+
+ return 0;
+}
+
+
+/*check for gnutella get commands and other typical data*/
+int
+search_all_gnu (unsigned char *haystack, int packet_len, int head_len)
+{
+ unsigned char *t = haystack;
+ int c;
+
+ if (!((*(haystack + packet_len - 2) == 0x0d) && (*(haystack + packet_len - 1) == 0x0a))) return 0;
+
+ t += head_len;
+
+ if (memcmp(t, "GNUTELLA CONNECT/", 17) == 0) return ((IPP2P_GNU * 100) + 1);
+ if (memcmp(t, "GNUTELLA/", 9) == 0) return ((IPP2P_GNU * 100) + 2);
+
+ if ((memcmp(t, "GET /get/", 9) == 0) || (memcmp(t, "GET /uri-res/", 13) == 0))
+ {
+ c = head_len + 8;
+ t += 8;
+ while (c < packet_len - 22) {
+ if ((t[0] == 0x0d) && (t[1] == 0x0a)) {
+ if ((memcmp(t, "X-Gnutella-", 11) == 0) || (memcmp(t, "X-Queue:", 8) == 0)) return ((IPP2P_GNU * 100) + 3);
+ t += 2;
+ c += 2;
+ } else {
+ t++;
+ c++;
+ }
+ }
+ }
+ return 0;
+}
+
+
+/*check for KaZaA download commands and other typical data*/
+int
+search_all_kazaa (unsigned char *haystack, int packet_len, int head_len)
+{
+ unsigned char *t = haystack;
+ int c;
+
+ if (!((*(haystack + packet_len - 2) == 0x0d) && (*(haystack + packet_len - 1) == 0x0a))) return 0;
+
+ t += head_len;
+ if (memcmp(t, "GIVE ", 5) == 0) return ((IPP2P_KAZAA * 100) + 1);
+
+ if (memcmp(t, "GET /", 5) == 0) {
+ c = head_len + 8;
+ t += 8;
+ while (c < packet_len - 22) {
+ if ((t[0] == 0x0d) && (t[1] == 0x0a)) {
+ if ( memcmp(t, "X-Kazaa-Username: ", 18) == 0 ) return ((IPP2P_KAZAA * 100) + 2);
+ t += 2;
+ c += 2;
+ } else {
+ t++;
+ c++;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*fast check for edonkey file segment transfer command*/
+int
+search_edk (unsigned char *haystack, int packet_len, int head_len)
+{
+ if (*(haystack+head_len) != 0xe3)
+ return 0;
+ else {
+ if (*(haystack+head_len+5) == 0x47)
+ return (IPP2P_DATA_EDK * 100);
+ else
+ return 0;
+ }
+}
+
+
+
+/*intensive but slower search for some edonkey packets including size-check*/
+int
+search_all_edk (unsigned char *haystack, int packet_len, int head_len)
+{
+ unsigned char *t = haystack;
+ int cmd;
+
+ if (*(haystack+head_len) == 0xd4) {
+ t += head_len;
+ cmd = get_u16(t, 1);
+ if (cmd == (packet_len - head_len - 5)) {
+ switch (t[5]) {
+ case 0x82: return ((IPP2P_EDK * 100) + 42);
+ case 0x15: return ((IPP2P_EDK * 100) + 43);
+ default: return 0;
+ }
+ }
+ return 0;
+ }
+
+
+ if (*(haystack+head_len) == 0xc5) { /*search for additional eMule packets*/
+ t += head_len;
+ cmd = get_u16(t, 1);
+
+ if (cmd == (packet_len - head_len - 5)) {
+ switch (t[5]) {
+ case 0x01: return ((IPP2P_EDK * 100) + 30);
+ case 0x02: return ((IPP2P_EDK * 100) + 31);
+ case 0x60: return ((IPP2P_EDK * 100) + 32);
+ case 0x81: return ((IPP2P_EDK * 100) + 33);
+ case 0x82: return ((IPP2P_EDK * 100) + 34);
+ case 0x85: return ((IPP2P_EDK * 100) + 35);
+ case 0x86: return ((IPP2P_EDK * 100) + 36);
+ case 0x87: return ((IPP2P_EDK * 100) + 37);
+ case 0x40: return ((IPP2P_EDK * 100) + 38);
+ case 0x92: return ((IPP2P_EDK * 100) + 39);
+ case 0x93: return ((IPP2P_EDK * 100) + 40);
+ case 0x12: return ((IPP2P_EDK * 100) + 41);
+ default: return 0;
+ }
+ }
+
+ return 0;
+ }
+
+
+ if (*(haystack+head_len) != 0xe3)
+ return 0;
+ else {
+ t += head_len;
+ cmd = get_u16(t, 1);
+ if (cmd == (packet_len - head_len - 5)) {
+ switch (t[5]) {
+ case 0x01: return ((IPP2P_EDK * 100) + 1); /*Client: hello or Server:hello*/
+ case 0x50: return ((IPP2P_EDK * 100) + 2); /*Client: file status*/
+ case 0x16: return ((IPP2P_EDK * 100) + 3); /*Client: search*/
+ case 0x58: return ((IPP2P_EDK * 100) + 4); /*Client: file request*/
+ case 0x48: return ((IPP2P_EDK * 100) + 5); /*???*/
+ case 0x54: return ((IPP2P_EDK * 100) + 6); /*???*/
+ case 0x47: return ((IPP2P_EDK * 100) + 7); /*Client: file segment request*/
+ case 0x46: return ((IPP2P_EDK * 100) + 8); /*Client: download segment*/
+ case 0x4c: return ((IPP2P_EDK * 100) + 9); /*Client: Hello-Answer*/
+ case 0x4f: return ((IPP2P_EDK * 100) + 10); /*Client: file status request*/
+ case 0x59: return ((IPP2P_EDK * 100) + 11); /*Client: file request answer*/
+ case 0x65: return ((IPP2P_EDK * 100) + 12); /*Client: ???*/
+ case 0x66: return ((IPP2P_EDK * 100) + 13); /*Client: ???*/
+ case 0x51: return ((IPP2P_EDK * 100) + 14); /*Client: ???*/
+ case 0x52: return ((IPP2P_EDK * 100) + 15); /*Client: ???*/
+ case 0x4d: return ((IPP2P_EDK * 100) + 16); /*Client: ???*/
+ case 0x5c: return ((IPP2P_EDK * 100) + 17); /*Client: ???*/
+ case 0x38: return ((IPP2P_EDK * 100) + 18); /*Client: ???*/
+ case 0x69: return ((IPP2P_EDK * 100) + 19); /*Client: ???*/
+ case 0x19: return ((IPP2P_EDK * 100) + 20); /*Client: ???*/
+ case 0x42: return ((IPP2P_EDK * 100) + 21); /*Client: ???*/
+ case 0x34: return ((IPP2P_EDK * 100) + 22); /*Client: ???*/
+ case 0x94: return ((IPP2P_EDK * 100) + 23); /*Client: ???*/
+ case 0x1c: return ((IPP2P_EDK * 100) + 24); /*Client: ???*/
+ case 0x6a: return ((IPP2P_EDK * 100) + 25); /*Client: ???*/
+ default: return 0;
+ }
+ } else {
+ if (cmd > packet_len - head_len - 5) {
+ if ((t[3] == 0x00) && (t[4] == 0x00)) {
+ if (t[5] == 0x01) return ((IPP2P_EDK * 100) + 26);
+ if (t[5] == 0x4c) return ((IPP2P_EDK * 100) + 27);
+ }
+ return 0;
+
+ } /*non edk packet*/
+ if (t[cmd+5] == 0xe3) return ((IPP2P_EDK * 100) + 28);/*found another edk-command*/
+ if (t[cmd+5] == 0xc5) return ((IPP2P_EDK * 100) + 29);/*found an emule-command*/
+ return 0;
+ }
+ }
+}
+
+
+/*fast check for Direct Connect send command*/
+int
+search_dc (unsigned char *haystack, int packet_len, int head_len)
+{
+ unsigned char *t = haystack;
+
+ if (*(haystack+head_len) != 0x24 )
+ return 0;
+ else {
+ t += head_len + 1;
+ if (memcmp(t, "Send|", 5) == 0)
+ return (IPP2P_DATA_DC * 100);
+ else
+ return 0;
+ }
+
+}
+
+
+/*intensive but slower check for all direct connect packets*/
+int
+search_all_dc (unsigned char *haystack, int packet_len, int head_len)
+{
+ unsigned char *t = haystack;
+
+ if ((*(haystack + head_len) == 0x24) && (*(haystack + packet_len - 1) == 0x7c)) {
+ t += head_len + 1;
+ if (memcmp(t, "Lock ", 5) == 0) return ((IPP2P_DC * 100) + 1); /*hub: hello*/
+ if (memcmp(t, "Key ", 4) == 0) return ((IPP2P_DC * 100) + 2); /*client: hello*/
+ if (memcmp(t, "Hello ", 6) == 0) return ((IPP2P_DC * 100) + 3); /*hub:connected*/
+ if (memcmp(t, "MyNick ", 7) == 0) return ((IPP2P_DC * 100) + 4); /*client-client: hello*/
+ if (memcmp(t, "Search ", 7) == 0) return ((IPP2P_DC * 100) + 5); /*client: search*/
+ if (memcmp(t, "Send", 4) == 0) return ((IPP2P_DC * 100) + 6); /*client: start download*/
+ return 0;
+ } else
+ return 0;
+}
+
+
+static struct {
+ int command;
+ __u8 short_hand; /*for fucntions included in short hands*/
+ int packet_len;
+ int (*function_name) (unsigned char *, int, int);
+} matchlist[] = {
+ {IPP2P_EDK,SHORT_HAND_IPP2P,40, &search_all_edk},
+ {IPP2P_DATA_KAZAA,SHORT_HAND_DATA,200, &search_kazaa},
+ {IPP2P_DATA_EDK,SHORT_HAND_DATA,60, &search_edk},
+ {IPP2P_DATA_DC,SHORT_HAND_DATA,26, &search_dc},
+ {IPP2P_DC,SHORT_HAND_IPP2P,25, search_all_dc},
+ {IPP2P_DATA_GNU,SHORT_HAND_DATA,40, &search_gnu},
+ {IPP2P_GNU,SHORT_HAND_IPP2P,35, &search_all_gnu},
+ {IPP2P_KAZAA,SHORT_HAND_IPP2P,35, &search_all_kazaa},
+ {IPP2P_BIT,SHORT_HAND_NONE,40, &search_bittorrent},
+ {IPP2P_APPLE,SHORT_HAND_NONE,20, &search_apple},
+ {IPP2P_SOUL,SHORT_HAND_NONE,25, &search_soul},
+ {IPP2P_WINMX,SHORT_HAND_NONE,20, &search_winmx},
+ {IPP2P_ARES,SHORT_HAND_NONE,25, &search_ares},
+ {0,0,0,NULL}
+};
+
+
+static struct {
+ int command;
+ __u8 short_hand; /*for fucntions included in short hands*/
+ int packet_len;
+ int (*function_name) (unsigned char *, int);
+} udp_list[] = {
+ {IPP2P_KAZAA,SHORT_HAND_IPP2P,14, &udp_search_kazaa},
+ {IPP2P_BIT,SHORT_HAND_NONE,23, &udp_search_bit},
+ {IPP2P_GNU,SHORT_HAND_IPP2P,11, &udp_search_gnu},
+ {IPP2P_EDK,SHORT_HAND_IPP2P,9, &udp_search_edk},
+ {0,0,0,NULL}
+};
+
+
+static int
+match(const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ const void *matchinfo,
+ int offset,
+ int *hotdrop)
+{
+ const struct ipt_p2p_info *info = matchinfo;
+ unsigned char *haystack;
+ struct iphdr *ip = skb->nh.iph;
+ int p2p_result = 0, i = 0;
+ int head_len;
+ int hlen = ntohs(ip->tot_len)-(ip->ihl*4); /*hlen = packet-data length*/
+
+ /*must not be a fragment*/
+ if (offset) {
+ if (info->debug) printk("IPP2P.match: offset found %i \n",offset);
+ return 0;
+ }
+
+ /*make sure that skb is linear*/
+ if(skb_is_nonlinear(skb)){
+ if (info->debug) printk("IPP2P.match: nonlinear skb found\n");
+ return 0;
+ }
+
+
+ haystack=(char *)ip+(ip->ihl*4); /*haystack = packet data*/
+
+ switch (ip->protocol){
+ case IPPROTO_TCP: /*what to do with a TCP packet*/
+ {
+ struct tcphdr *tcph = (void *) ip + ip->ihl * 4;
+
+ if (tcph->fin) return 0; /*if FIN bit is set bail out*/
+ if (tcph->syn) return 0; /*if SYN bit is set bail out*/
+ if (tcph->rst) return 0; /*if RST bit is set bail out*/
+ head_len = tcph->doff * 4; /*get TCP-Header-Size*/
+ while (matchlist[i].command) {
+ if ((((info->cmd & matchlist[i].command) == matchlist[i].command) ||
+ ((info->cmd & matchlist[i].short_hand) == matchlist[i].short_hand)) &&
+ (hlen > matchlist[i].packet_len)) {
+ p2p_result = matchlist[i].function_name(haystack, hlen, head_len);
+ if (p2p_result)
+ {
+ if (info->debug) printk("IPP2P.debug:TCP-match: %i from: %u.%u.%u.%u:%i to: %u.%u.%u.%u:%i Length: %i\n",
+ p2p_result, NIPQUAD(ip->saddr),ntohs(tcph->source), NIPQUAD(ip->daddr),ntohs(tcph->dest),hlen);
+ return p2p_result;
+ }
+ }
+ i++;
+ }
+ return p2p_result;
+ }
+
+ case IPPROTO_UDP: /*what to do with an UDP packet*/
+ {
+ struct udphdr *udph = (void *) ip + ip->ihl * 4;
+
+ while (udp_list[i].command){
+ if ((((info->cmd & udp_list[i].command) == udp_list[i].command) ||
+ ((info->cmd & udp_list[i].short_hand) == udp_list[i].short_hand)) &&
+ (hlen > udp_list[i].packet_len)) {
+ p2p_result = udp_list[i].function_name(haystack, hlen);
+ if (p2p_result){
+ if (info->debug) printk("IPP2P.debug:UDP-match: %i from: %u.%u.%u.%u:%i to: %u.%u.%u.%u:%i Length: %i\n",
+ p2p_result, NIPQUAD(ip->saddr),ntohs(udph->source), NIPQUAD(ip->daddr),ntohs(udph->dest),hlen);
+ return p2p_result;
+ }
+ }
+ i++;
+ }
+ return p2p_result;
+ }
+
+ default: return 0;
+ }
+}
+
+
+
+static int
+checkentry(const char *tablename,
+ const struct ipt_ip *ip,
+ void *matchinfo,
+ unsigned int matchsize,
+ unsigned int hook_mask)
+{
+ /* Must specify -p tcp */
+/* if (ip->proto != IPPROTO_TCP || (ip->invflags & IPT_INV_PROTO)) {
+ * printk("ipp2p: Only works on TCP packets, use -p tcp\n");
+ * return 0;
+ * }*/
+ return 1;
+}
+
+
+
+
+static struct ipt_match ipp2p_match = {
+ .name = "ipp2p",
+ .match = &match,
+ .checkentry = &checkentry,
+ .me = THIS_MODULE,
+};
+
+
+static int __init init(void)
+{
+ printk(KERN_INFO "IPP2P v%s loading\n", IPP2P_VERSION);
+ return ipt_register_match(&ipp2p_match);
+}
+
+static void __exit fini(void)
+{
+ ipt_unregister_match(&ipp2p_match);
+ printk(KERN_INFO "IPP2P v%s unloaded\n", IPP2P_VERSION);
+}
+
+module_init(init);
+module_exit(fini);
+
+
diff -urN linux-2.6.11/net/ipv4/netfilter/ipt_set.c linux.sinabox/net/ipv4/netfilter/ipt_set.c
--- linux-2.6.11/net/ipv4/netfilter/ipt_set.c 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/net/ipv4/netfilter/ipt_set.c 2005-03-24 19:22:37.000000000 +0100
@@ -0,0 +1,112 @@
+/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
+ * Patrick Schaaf <bof@bof.de>
+ * Martin Josefsson <gandalf@wlug.westbo.se>
+ * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/* Kernel module to match an IP set. */
+
+#include <linux/module.h>
+#include <linux/ip.h>
+#include <linux/skbuff.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ip_set.h>
+#include <linux/netfilter_ipv4/ipt_set.h>
+
+static inline int
+match_set(const struct ipt_set_info *info,
+ const struct sk_buff *skb,
+ int inv)
+{
+ if (ip_set_testip_kernel(info->index, skb, info->flags))
+ inv = !inv;
+ return inv;
+}
+
+static int
+match(const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ const void *matchinfo,
+ int offset,
+ int *hotdrop)
+{
+ const struct ipt_set_info_match *info = matchinfo;
+
+ return match_set(&info->match_set,
+ skb,
+ info->match_set.flags[0] & IPSET_MATCH_INV);
+}
+
+static int
+checkentry(const char *tablename,
+ const struct ipt_ip *ip,
+ void *matchinfo,
+ unsigned int matchsize,
+ unsigned int hook_mask)
+{
+ struct ipt_set_info_match *info =
+ (struct ipt_set_info_match *) matchinfo;
+ ip_set_id_t index;
+
+ if (matchsize != IPT_ALIGN(sizeof(struct ipt_set_info_match))) {
+ ip_set_printk("invalid matchsize %d", matchsize);
+ return 0;
+ }
+
+ index = ip_set_get_byindex(info->match_set.index);
+
+ if (index == IP_SET_INVALID_ID) {
+ ip_set_printk("Cannot find set indentified by id %u to match",
+ info->match_set.index);
+ return 0; /* error */
+ }
+ if (info->match_set.flags[IP_SET_MAX_BINDINGS] != 0) {
+ ip_set_printk("That's nasty!");
+ return 0; /* error */
+ }
+
+ return 1;
+}
+
+static void destroy(void *matchinfo, unsigned int matchsize)
+{
+ struct ipt_set_info_match *info = matchinfo;
+
+ if (matchsize != IPT_ALIGN(sizeof(struct ipt_set_info_match))) {
+ ip_set_printk("invalid matchsize %d", matchsize);
+ return;
+ }
+
+ ip_set_put(info->match_set.index);
+}
+
+static struct ipt_match set_match = {
+ .name = "set",
+ .match = &match,
+ .checkentry = &checkentry,
+ .destroy = &destroy,
+ .me = THIS_MODULE
+};
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_DESCRIPTION("iptables IP set match module");
+
+static int __init init(void)
+{
+ return ipt_register_match(&set_match);
+}
+
+static void __exit fini(void)
+{
+ ipt_unregister_match(&set_match);
+}
+
+module_init(init);
+module_exit(fini);
diff -urN linux-2.6.11/net/ipv4/netfilter/ipt_SET.c linux.sinabox/net/ipv4/netfilter/ipt_SET.c
--- linux-2.6.11/net/ipv4/netfilter/ipt_SET.c 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/net/ipv4/netfilter/ipt_SET.c 2005-03-24 19:22:37.000000000 +0100
@@ -0,0 +1,128 @@
+/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
+ * Patrick Schaaf <bof@bof.de>
+ * Martin Josefsson <gandalf@wlug.westbo.se>
+ * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/* ipt_SET.c - netfilter target to manipulate IP sets */
+
+#include <linux/types.h>
+#include <linux/ip.h>
+#include <linux/timer.h>
+#include <linux/module.h>
+#include <linux/netfilter.h>
+#include <linux/netdevice.h>
+#include <linux/if.h>
+#include <linux/inetdevice.h>
+#include <net/protocol.h>
+#include <net/checksum.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter_ipv4/ip_nat_rule.h>
+#include <linux/netfilter_ipv4/ipt_set.h>
+
+static unsigned int
+target(struct sk_buff **pskb,
+ const struct net_device *in,
+ const struct net_device *out,
+ unsigned int hooknum,
+ const void *targinfo,
+ void *userinfo)
+{
+ const struct ipt_set_info_target *info = targinfo;
+
+ if (info->add_set.index != IP_SET_INVALID_ID)
+ ip_set_addip_kernel(info->add_set.index,
+ *pskb,
+ info->add_set.flags);
+ if (info->del_set.index != IP_SET_INVALID_ID)
+ ip_set_delip_kernel(info->del_set.index,
+ *pskb,
+ info->del_set.flags);
+
+ return IPT_CONTINUE;
+}
+
+static int
+checkentry(const char *tablename,
+ const struct ipt_entry *e,
+ void *targinfo,
+ unsigned int targinfosize, unsigned int hook_mask)
+{
+ struct ipt_set_info_target *info =
+ (struct ipt_set_info_target *) targinfo;
+ ip_set_id_t index;
+
+ if (targinfosize != IPT_ALIGN(sizeof(*info))) {
+ DP("bad target info size %u", targinfosize);
+ return 0;
+ }
+
+ if (info->add_set.index != IP_SET_INVALID_ID) {
+ index = ip_set_get_byindex(info->add_set.index);
+ if (index == IP_SET_INVALID_ID) {
+ ip_set_printk("cannot find add_set index %u as target",
+ info->add_set.index);
+ return 0; /* error */
+ }
+ }
+
+ if (info->del_set.index != IP_SET_INVALID_ID) {
+ index = ip_set_get_byindex(info->del_set.index);
+ if (index == IP_SET_INVALID_ID) {
+ ip_set_printk("cannot find del_set index %u as target",
+ info->del_set.index);
+ return 0; /* error */
+ }
+ }
+ if (info->add_set.flags[IP_SET_MAX_BINDINGS] != 0
+ || info->del_set.flags[IP_SET_MAX_BINDINGS] != 0) {
+ ip_set_printk("That's nasty!");
+ return 0; /* error */
+ }
+
+ return 1;
+}
+
+static void destroy(void *targetinfo, unsigned int targetsize)
+{
+ struct ipt_set_info_target *info = targetinfo;
+
+ if (targetsize != IPT_ALIGN(sizeof(struct ipt_set_info_target))) {
+ ip_set_printk("invalid targetsize %d", targetsize);
+ return;
+ }
+
+ if (info->add_set.index != IP_SET_INVALID_ID)
+ ip_set_put(info->add_set.index);
+ if (info->del_set.index != IP_SET_INVALID_ID)
+ ip_set_put(info->del_set.index);
+}
+
+static struct ipt_target SET_target = {
+ .name = "SET",
+ .target = target,
+ .checkentry = checkentry,
+ .destroy = destroy,
+ .me = THIS_MODULE
+};
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_DESCRIPTION("iptables IP set target module");
+
+static int __init init(void)
+{
+ return ipt_register_target(&SET_target);
+}
+
+static void __exit fini(void)
+{
+ ipt_unregister_target(&SET_target);
+}
+
+module_init(init);
+module_exit(fini);
diff -urN linux-2.6.11/net/ipv4/netfilter/ipt_TARPIT.c linux.sinabox/net/ipv4/netfilter/ipt_TARPIT.c
--- linux-2.6.11/net/ipv4/netfilter/ipt_TARPIT.c 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/net/ipv4/netfilter/ipt_TARPIT.c 2005-03-24 19:24:07.000000000 +0100
@@ -0,0 +1,290 @@
+/*
+ * Kernel module to capture and hold incoming TCP connections using
+ * no local per-connection resources.
+ *
+ * Based on ipt_REJECT.c and offering functionality similar to
+ * LaBrea <http://www.hackbusters.net/LaBrea/>.
+ *
+ * Copyright (c) 2002 Aaron Hopkins <tools@die.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Goal:
+ * - Allow incoming TCP connections to be established.
+ * - Passing data should result in the connection being switched to the
+ * persist state (0 byte window), in which the remote side stops sending
+ * data and asks to continue every 60 seconds.
+ * - Attempts to shut down the connection should be ignored completely, so
+ * the remote side ends up having to time it out.
+ *
+ * This means:
+ * - Reply to TCP SYN,!ACK,!RST,!FIN with SYN-ACK, window 5 bytes
+ * - Reply to TCP SYN,ACK,!RST,!FIN with RST to prevent spoofing
+ * - Reply to TCP !SYN,!RST,!FIN with ACK, window 0 bytes, rate-limited
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <net/ip.h>
+#include <net/tcp.h>
+#include <net/icmp.h>
+struct in_device;
+#include <net/route.h>
+#include <linux/random.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Aaron Hopkins <tools@die.net>");
+
+/* Stolen from ip_finish_output2 */
+static int ip_direct_send(struct sk_buff *skb)
+{
+ struct dst_entry *dst = skb->dst;
+ struct hh_cache *hh = dst->hh;
+
+ if (hh) {
+ read_lock_bh(&hh->hh_lock);
+ memcpy(skb->data - 16, hh->hh_data, 16);
+ read_unlock_bh(&hh->hh_lock);
+ skb_push(skb, hh->hh_len);
+ return hh->hh_output(skb);
+ } else if (dst->neighbour)
+ return dst->neighbour->output(skb);
+
+ if (net_ratelimit())
+ printk(KERN_DEBUG "TARPIT ip_direct_send: no header cache and no neighbor!\n");
+ kfree_skb(skb);
+ return -EINVAL;
+}
+
+
+/* Send reply */
+static void tarpit_tcp(struct sk_buff *oskb,struct rtable *ort,int local)
+{
+ struct sk_buff *nskb;
+ struct rtable *nrt;
+ struct tcphdr *otcph, *ntcph;
+ struct flowi fl = {};
+ unsigned int otcplen;
+ u_int16_t tmp;
+
+ /* A truncated TCP header isn't going to be useful */
+ if (oskb->len < (oskb->nh.iph->ihl*4) + sizeof(struct tcphdr))
+ return;
+
+ otcph = (struct tcphdr *)((u_int32_t*)oskb->nh.iph
+ + oskb->nh.iph->ihl);
+ otcplen = oskb->len - oskb->nh.iph->ihl*4;
+
+ /* No replies for RST or FIN */
+ if (otcph->rst || otcph->fin)
+ return;
+
+ /* No reply to !SYN,!ACK. Rate-limit replies to !SYN,ACKs */
+ if (!otcph->syn && (!otcph->ack || !xrlim_allow(&ort->u.dst, 1*HZ)))
+ return;
+
+ /* Check checksum. */
+ if (tcp_v4_check(otcph, otcplen, oskb->nh.iph->saddr,
+ oskb->nh.iph->daddr,
+ csum_partial((char *)otcph, otcplen, 0)) != 0)
+ return;
+
+ /* Copy skb (even if skb is about to be dropped, we can't just
+ clone it because there may be other things, such as tcpdump,
+ interested in it) */
+ nskb = skb_copy(oskb, GFP_ATOMIC);
+ if (!nskb)
+ return;
+
+ /* This packet will not be the same as the other: clear nf fields */
+ nf_conntrack_put(nskb->nfct);
+ nskb->nfct = NULL;
+ nskb->nfcache = 0;
+#ifdef CONFIG_NETFILTER_DEBUG
+ nskb->nf_debug = 0;
+#endif
+
+ ntcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl);
+
+ /* Truncate to length (no data) */
+ ntcph->doff = sizeof(struct tcphdr)/4;
+ skb_trim(nskb, nskb->nh.iph->ihl*4 + sizeof(struct tcphdr));
+ nskb->nh.iph->tot_len = htons(nskb->len);
+
+ /* Swap source and dest */
+ nskb->nh.iph->daddr = xchg(&nskb->nh.iph->saddr, nskb->nh.iph->daddr);
+ tmp = ntcph->source;
+ ntcph->source = ntcph->dest;
+ ntcph->dest = tmp;
+
+ /* Use supplied sequence number or make a new one */
+ ntcph->seq = otcph->ack ? otcph->ack_seq
+ : htonl(secure_tcp_sequence_number(nskb->nh.iph->saddr,
+ nskb->nh.iph->daddr,
+ ntcph->source,
+ ntcph->dest));
+
+ /* Our SYN-ACKs must have a >0 window */
+ ntcph->window = (otcph->syn && !otcph->ack) ? htons(5) : 0;
+
+ ntcph->urg_ptr = 0;
+
+ /* Reset flags */
+ ((u_int8_t *)ntcph)[13] = 0;
+
+ if (otcph->syn && otcph->ack) {
+ ntcph->rst = 1;
+ ntcph->ack_seq = 0;
+ } else {
+ ntcph->syn = otcph->syn;
+ ntcph->ack = 1;
+ ntcph->ack_seq = htonl(ntohl(otcph->seq) + otcph->syn);
+ }
+
+ /* Adjust TCP checksum */
+ ntcph->check = 0;
+ ntcph->check = tcp_v4_check(ntcph, sizeof(struct tcphdr),
+ nskb->nh.iph->saddr,
+ nskb->nh.iph->daddr,
+ csum_partial((char *)ntcph,
+ sizeof(struct tcphdr), 0));
+
+ /* Adjust IP TTL */
+ nskb->nh.iph->ttl = sysctl_ip_default_ttl;
+
+ /* Set DF, id = 0 */
+ nskb->nh.iph->frag_off = htons(IP_DF);
+ nskb->nh.iph->id = 0;
+
+ /* Adjust IP checksum */
+ nskb->nh.iph->check = 0;
+ nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph,
+ nskb->nh.iph->ihl);
+
+ fl.nl_u.ip4_u.daddr = nskb->nh.iph->daddr;
+ fl.nl_u.ip4_u.saddr = local ? nskb->nh.iph->saddr : 0;
+ fl.nl_u.ip4_u.tos = RT_TOS(nskb->nh.iph->tos) | RTO_CONN;
+ fl.oif = 0;
+
+ if (ip_route_output_key(&nrt, &fl))
+ goto free_nskb;
+
+ dst_release(nskb->dst);
+ nskb->dst = &nrt->u.dst;
+
+ /* "Never happens" */
+ if (nskb->len > dst_pmtu(nskb->dst))
+ goto free_nskb;
+
+ ip_direct_send (nskb);
+
+ return;
+
+ free_nskb:
+ kfree_skb(nskb);
+}
+
+
+static unsigned int tarpit(struct sk_buff **pskb,
+ const struct net_device *in,
+ const struct net_device *out,
+ unsigned int hooknum,
+ const void *targinfo,
+ void *userinfo)
+{
+ struct sk_buff *skb = *pskb;
+ struct rtable *rt = (struct rtable*)skb->dst;
+
+ /* Do we have an input route cache entry? */
+ if (!rt)
+ return NF_DROP;
+
+ /* No replies to physical multicast/broadcast */
+ if (skb->pkt_type != PACKET_HOST && skb->pkt_type != PACKET_OTHERHOST)
+ return NF_DROP;
+
+ /* Now check at the protocol level */
+ if (rt->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST))
+ return NF_DROP;
+
+ /* Our naive response construction doesn't deal with IP
+ options, and probably shouldn't try. */
+ if (skb->nh.iph->ihl*4 != sizeof(struct iphdr))
+ return NF_DROP;
+
+ /* We aren't interested in fragments */
+ if (skb->nh.iph->frag_off & htons(IP_OFFSET))
+ return NF_DROP;
+
+ tarpit_tcp(skb,rt,hooknum == NF_IP_LOCAL_IN);
+
+ return NF_DROP;
+}
+
+
+static int check(const char *tablename,
+ const struct ipt_entry *e,
+ void *targinfo,
+ unsigned int targinfosize,
+ unsigned int hook_mask)
+{
+ /* Only allow these for input/forward packet filtering. */
+ if (strcmp(tablename, "filter") != 0) {
+ DEBUGP("TARPIT: bad table %s'.\n", tablename);
+ return 0;
+ }
+ if ((hook_mask & ~((1 << NF_IP_LOCAL_IN)
+ | (1 << NF_IP_FORWARD))) != 0) {
+ DEBUGP("TARPIT: bad hook mask %X\n", hook_mask);
+ return 0;
+ }
+
+ /* Must specify that it's a TCP packet */
+ if (e->ip.proto != IPPROTO_TCP || (e->ip.invflags & IPT_INV_PROTO)) {
+ DEBUGP("TARPIT: not valid for non-tcp\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+static struct ipt_target ipt_tarpit_reg = {
+ .name = "TARPIT",
+ .target = tarpit,
+ .checkentry = check,
+ .me = THIS_MODULE
+};
+
+static int __init init(void)
+{
+ return ipt_register_target(&ipt_tarpit_reg);
+}
+
+static void __exit fini(void)
+{
+ ipt_unregister_target(&ipt_tarpit_reg);
+}
+
+module_init(init);
+module_exit(fini);
diff -urN linux-2.6.11/net/ipv4/netfilter/ipt_ULOG.c linux.sinabox/net/ipv4/netfilter/ipt_ULOG.c
--- linux-2.6.11/net/ipv4/netfilter/ipt_ULOG.c 2005-03-02 08:37:55.000000000 +0100
+++ linux.sinabox/net/ipv4/netfilter/ipt_ULOG.c 2005-03-24 19:24:16.000000000 +0100
@@ -164,7 +164,7 @@
return skb;
}
-static void ipt_ulog_packet(unsigned int hooknum,
+void ipt_ulog_packet(unsigned int hooknum,
const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -415,5 +415,7 @@
}
+EXPORT_SYMBOL(ipt_ulog_packet);
+
module_init(init);
module_exit(fini);
diff -urN linux-2.6.11/net/ipv4/netfilter/Kconfig linux.sinabox/net/ipv4/netfilter/Kconfig
--- linux-2.6.11/net/ipv4/netfilter/Kconfig 2005-03-02 08:38:20.000000000 +0100
+++ linux.sinabox/net/ipv4/netfilter/Kconfig 2005-03-26 00:49:04.000000000 +0100
@@ -396,6 +396,17 @@
To compile it as a module, choose M here. If unsure, say N.
+config IP_NF_TARGET_IMQ
+ tristate "IMQ target support"
+ depends on IP_NF_MANGLE
+ help
+ This option adds a `IMQ' target which is used to specify if and
+ to which IMQ device packets should get enqueued/dequeued.
+
+ For more information visit: http://www.linuximq.net/
+
+ To compile it as a module, choose M here. If unsure, say N.
+
config IP_NF_TARGET_LOG
tristate "LOG target support"
depends on IP_NF_IPTABLES
@@ -692,5 +703,125 @@
Allows altering the ARP packet payload: source and destination
hardware and network addresses.
+config IP_NF_SET
+ tristate "IP set support"
+ depends on INET && NETFILTER
+ help
+ This option adds IP set support to the kernel.
+ In order to define and use sets, you need the userspace utility
+ ipset(8).
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_SET_MAX
+ int "Maximum number of IP sets"
+ default 256
+ range 2 65534
+ depends on IP_NF_SET
+ help
+ You can define here default value of the maximum number
+ of IP sets for the kernel.
+
+ The value can be overriden by the 'max_sets' module
+ parameter of the 'ip_set' module.
+
+config IP_NF_SET_HASHSIZE
+ int "Hash size for bindings of IP sets"
+ default 1024
+ depends on IP_NF_SET
+ help
+ You can define here default value of the hash size for
+ bindings of IP sets.
+
+ The value can be overriden by the 'hash_size' module
+ parameter of the 'ip_set' module.
+
+config IP_NF_SET_IPMAP
+ tristate "ipmap set support"
+ depends on IP_NF_SET
+ help
+ This option adds the ipmap set type support.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_SET_MACIPMAP
+ tristate "macipmap set support"
+ depends on IP_NF_SET
+ help
+ This option adds the macipmap set type support.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_SET_PORTMAP
+ tristate "portmap set support"
+ depends on IP_NF_SET
+ help
+ This option adds the portmap set type support.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_SET_IPHASH
+ tristate "iphash set support"
+ depends on IP_NF_SET
+ help
+ This option adds the iphash set type support.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_SET_NETHASH
+ tristate "nethash set support"
+ depends on IP_NF_SET
+ help
+ This option adds the nethash set type support.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_MATCH_SET
+ tristate "set match support"
+ depends on IP_NF_SET
+ help
+ Set matching matches against given IP sets.
+ You need the ipset utility to create and set up the sets.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_TARGET_SET
+ tristate "SET target support"
+ depends on IP_NF_SET
+ help
+ The SET target makes possible to add/delete entries
+ in IP sets.
+ You need the ipset utility to create and set up the sets.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+
+config IP_NF_TARGET_TARPIT
+ tristate 'TARPIT target support'
+ depends on IP_NF_FILTER
+ help
+ Adds a TARPIT target to iptables, which captures and holds
+ incoming TCP connections using no local per-connection resources.
+ Connections are accepted, but immediately switched to the persist
+ state (0 byte window), in which the remote side stops sending data
+ and asks to continue every 60-240 seconds. Attempts to close the
+ connection are ignored, forcing the remote side to time out the
+ connection in 12-24 minutes.
+
+ This offers similar functionality to LaBrea
+ <http://www.hackbusters.net/LaBrea/> but doesn't require dedicated
+ hardware or IPs. Any TCP port that you would normally DROP or REJECT
+ can instead become a tarpit.
+
+config IP_NF_MATCH_IPP2P
+ tristate 'IPP2P match support'
+ depends on IP_NF_IPTABLES
+ help
+ This option makes possible to match some P2P packets
+ therefore helps controlling such traffic.
+
+ If you want to compile it as a module, say M here and read
+ <file:Documentation/modules.txt>. If unsure, say `N'.
+
endmenu
diff -urN linux-2.6.11/net/ipv4/netfilter/Kconfig.orig linux.sinabox/net/ipv4/netfilter/Kconfig.orig
--- linux-2.6.11/net/ipv4/netfilter/Kconfig.orig 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/net/ipv4/netfilter/Kconfig.orig 2005-03-24 19:26:06.000000000 +0100
@@ -0,0 +1,816 @@
+#
+# IP netfilter configuration
+#
+
+menu "IP: Netfilter Configuration"
+ depends on INET && NETFILTER
+
+# connection tracking, helpers and protocols
+config IP_NF_CONNTRACK
+ tristate "Connection tracking (required for masq/NAT)"
+ ---help---
+ Connection tracking keeps a record of what packets have passed
+ through your machine, in order to figure out how they are related
+ into connections.
+
+ This is required to do Masquerading or other kinds of Network
+ Address Translation (except for Fast NAT). It can also be used to
+ enhance packet filtering (see `Connection state match support'
+ below).
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_CT_ACCT
+ bool "Connection tracking flow accounting"
+ depends on IP_NF_CONNTRACK
+ help
+ If this option is enabled, the connection tracking code will
+ keep per-flow packet and byte counters.
+
+ Those counters can be used for flow-based accounting or the
+ `connbytes' match.
+
+ If unsure, say `N'.
+
+config IP_NF_CONNTRACK_MARK
+ bool 'Connection mark tracking support'
+ help
+ This option enables support for connection marks, used by the
+ `CONNMARK' target and `connmark' match. Similar to the mark value
+ of packets, but this mark value is kept in the conntrack session
+ instead of the individual packets.
+
+config IP_NF_CT_PROTO_SCTP
+ tristate 'SCTP protocol connection tracking support (EXPERIMENTAL)'
+ depends on IP_NF_CONNTRACK && EXPERIMENTAL
+ help
+ With this option enabled, the connection tracking code will
+ be able to do state tracking on SCTP connections.
+
+ If you want to compile it as a module, say M here and read
+ <file:Documentation/modules.txt>. If unsure, say `N'.
+
+config IP_NF_FTP
+ tristate "FTP protocol support"
+ depends on IP_NF_CONNTRACK
+ help
+ Tracking FTP connections is problematic: special helpers are
+ required for tracking them, and doing masquerading and other forms
+ of Network Address Translation on them.
+
+ To compile it as a module, choose M here. If unsure, say Y.
+
+config IP_NF_IRC
+ tristate "IRC protocol support"
+ depends on IP_NF_CONNTRACK
+ ---help---
+ There is a commonly-used extension to IRC called
+ Direct Client-to-Client Protocol (DCC). This enables users to send
+ files to each other, and also chat to each other without the need
+ of a server. DCC Sending is used anywhere you send files over IRC,
+ and DCC Chat is most commonly used by Eggdrop bots. If you are
+ using NAT, this extension will enable you to send files and initiate
+ chats. Note that you do NOT need this extension to get files or
+ have others initiate chats, or everything else in IRC.
+
+ To compile it as a module, choose M here. If unsure, say Y.
+
+config IP_NF_TFTP
+ tristate "TFTP protocol support"
+ depends on IP_NF_CONNTRACK
+ help
+ TFTP connection tracking helper, this is required depending
+ on how restrictive your ruleset is.
+ If you are using a tftp client behind -j SNAT or -j MASQUERADING
+ you will need this.
+
+ To compile it as a module, choose M here. If unsure, say Y.
+
+config IP_NF_AMANDA
+ tristate "Amanda backup protocol support"
+ depends on IP_NF_CONNTRACK
+ help
+ If you are running the Amanda backup package <http://www.amanda.org/>
+ on this machine or machines that will be MASQUERADED through this
+ machine, then you may want to enable this feature. This allows the
+ connection tracking and natting code to allow the sub-channels that
+ Amanda requires for communication of the backup data, messages and
+ index.
+
+ To compile it as a module, choose M here. If unsure, say Y.
+
+config IP_NF_QUEUE
+ tristate "Userspace queueing via NETLINK"
+ help
+ Netfilter has the ability to queue packets to user space: the
+ netlink device can be used to access them using this driver.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_IPTABLES
+ tristate "IP tables support (required for filtering/masq/NAT)"
+ help
+ iptables is a general, extensible packet identification framework.
+ The packet filtering and full NAT (masquerading, port forwarding,
+ etc) subsystems now use this: say `Y' or `M' here if you want to use
+ either of those.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+# The matches.
+config IP_NF_MATCH_LIMIT
+ tristate "limit match support"
+ depends on IP_NF_IPTABLES
+ help
+ limit matching allows you to control the rate at which a rule can be
+ matched: mainly useful in combination with the LOG target ("LOG
+ target support", below) and to avoid some Denial of Service attacks.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_MATCH_IPRANGE
+ tristate "IP range match support"
+ depends on IP_NF_IPTABLES
+ help
+ This option makes possible to match IP addresses against IP address
+ ranges.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_MATCH_MAC
+ tristate "MAC address match support"
+ depends on IP_NF_IPTABLES
+ help
+ MAC matching allows you to match packets based on the source
+ Ethernet address of the packet.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_MATCH_PKTTYPE
+ tristate "Packet type match support"
+ depends on IP_NF_IPTABLES
+ help
+ Packet type matching allows you to match a packet by
+ its "class", eg. BROADCAST, MULTICAST, ...
+
+ Typical usage:
+ iptables -A INPUT -m pkttype --pkt-type broadcast -j LOG
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_MATCH_MARK
+ tristate "netfilter MARK match support"
+ depends on IP_NF_IPTABLES
+ help
+ Netfilter mark matching allows you to match packets based on the
+ `nfmark' value in the packet. This can be set by the MARK target
+ (see below).
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_MATCH_MULTIPORT
+ tristate "Multiple port match support"
+ depends on IP_NF_IPTABLES
+ help
+ Multiport matching allows you to match TCP or UDP packets based on
+ a series of source or destination ports: normally a rule can only
+ match a single range of ports.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_MATCH_TOS
+ tristate "TOS match support"
+ depends on IP_NF_IPTABLES
+ help
+ TOS matching allows you to match packets based on the Type Of
+ Service fields of the IP packet.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_MATCH_RECENT
+ tristate "recent match support"
+ depends on IP_NF_IPTABLES
+ help
+ This match is used for creating one or many lists of recently
+ used addresses and then matching against that/those list(s).
+
+ Short options are available by using 'iptables -m recent -h'
+ Official Website: <http://snowman.net/projects/ipt_recent/>
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_MATCH_ECN
+ tristate "ECN match support"
+ depends on IP_NF_IPTABLES
+ help
+ This option adds a `ECN' match, which allows you to match against
+ the IPv4 and TCP header ECN fields.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_MATCH_DSCP
+ tristate "DSCP match support"
+ depends on IP_NF_IPTABLES
+ help
+ This option adds a `DSCP' match, which allows you to match against
+ the IPv4 header DSCP field (DSCP codepoint).
+
+ The DSCP codepoint can have any value between 0x0 and 0x4f.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_MATCH_AH_ESP
+ tristate "AH/ESP match support"
+ depends on IP_NF_IPTABLES
+ help
+ These two match extensions (`ah' and `esp') allow you to match a
+ range of SPIs inside AH or ESP headers of IPSec packets.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_MATCH_LENGTH
+ tristate "LENGTH match support"
+ depends on IP_NF_IPTABLES
+ help
+ This option allows you to match the length of a packet against a
+ specific value or range of values.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_MATCH_TTL
+ tristate "TTL match support"
+ depends on IP_NF_IPTABLES
+ help
+ This adds CONFIG_IP_NF_MATCH_TTL option, which enabled the user
+ to match packets by their TTL value.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_MATCH_TCPMSS
+ tristate "tcpmss match support"
+ depends on IP_NF_IPTABLES
+ help
+ This option adds a `tcpmss' match, which allows you to examine the
+ MSS value of TCP SYN packets, which control the maximum packet size
+ for that connection.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_MATCH_HELPER
+ tristate "Helper match support"
+ depends on IP_NF_CONNTRACK && IP_NF_IPTABLES
+ help
+ Helper matching allows you to match packets in dynamic connections
+ tracked by a conntrack-helper, ie. ip_conntrack_ftp
+
+ To compile it as a module, choose M here. If unsure, say Y.
+
+config IP_NF_MATCH_STATE
+ tristate "Connection state match support"
+ depends on IP_NF_CONNTRACK && IP_NF_IPTABLES
+ help
+ Connection state matching allows you to match packets based on their
+ relationship to a tracked connection (ie. previous packets). This
+ is a powerful tool for packet classification.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_MATCH_CONNTRACK
+ tristate "Connection tracking match support"
+ depends on IP_NF_CONNTRACK && IP_NF_IPTABLES
+ help
+ This is a general conntrack match module, a superset of the state match.
+
+ It allows matching on additional conntrack information, which is
+ useful in complex configurations, such as NAT gateways with multiple
+ internet links or tunnels.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_MATCH_OWNER
+ tristate "Owner match support"
+ depends on IP_NF_IPTABLES
+ help
+ Packet owner matching allows you to match locally-generated packets
+ based on who created them: the user, group, process or session.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_MATCH_PHYSDEV
+ tristate "Physdev match support"
+ depends on IP_NF_IPTABLES && BRIDGE_NETFILTER
+ help
+ Physdev packet matching matches against the physical bridge ports
+ the IP packet arrived on or will leave by.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_MATCH_ADDRTYPE
+ tristate 'address type match support'
+ depends on IP_NF_IPTABLES
+ help
+ This option allows you to match what routing thinks of an address,
+ eg. UNICAST, LOCAL, BROADCAST, ...
+
+ If you want to compile it as a module, say M here and read
+ <file:Documentation/modules.txt>. If unsure, say `N'.
+
+config IP_NF_MATCH_REALM
+ tristate 'realm match support'
+ depends on IP_NF_IPTABLES
+ select NET_CLS_ROUTE
+ help
+ This option adds a `realm' match, which allows you to use the realm
+ key from the routing subsystem inside iptables.
+
+ This match pretty much resembles the CONFIG_NET_CLS_ROUTE4 option
+ in tc world.
+
+ If you want to compile it as a module, say M here and read
+ <file:Documentation/modules.txt>. If unsure, say `N'.
+
+config IP_NF_MATCH_SCTP
+ tristate 'SCTP protocol match support'
+ depends on IP_NF_IPTABLES
+ help
+ With this option enabled, you will be able to use the iptables
+ `sctp' match in order to match on SCTP source/destination ports
+ and SCTP chunk types.
+
+ If you want to compile it as a module, say M here and read
+ <file:Documentation/modules.txt>. If unsure, say `N'.
+
+config IP_NF_MATCH_COMMENT
+ tristate 'comment match support'
+ depends on IP_NF_IPTABLES
+ help
+ This option adds a `comment' dummy-match, which allows you to put
+ comments in your iptables ruleset.
+
+ If you want to compile it as a module, say M here and read
+ <file:Documentation/modules.txt>. If unsure, say `N'.
+
+config IP_NF_MATCH_CONNMARK
+ tristate 'Connection mark match support'
+ depends on IP_NF_CONNTRACK_MARK && IP_NF_IPTABLES
+ help
+ This option adds a `connmark' match, which allows you to match the
+ connection mark value previously set for the session by `CONNMARK'.
+
+ If you want to compile it as a module, say M here and read
+ <file:Documentation/modules.txt>. The module will be called
+ ipt_connmark.o. If unsure, say `N'.
+
+config IP_NF_MATCH_HASHLIMIT
+ tristate 'hashlimit match support'
+ depends on IP_NF_IPTABLES
+ help
+ This option adds a new iptables `hashlimit' match.
+
+ As opposed to `limit', this match dynamically crates a hash table
+ of limit buckets, based on your selection of source/destination
+ ip addresses and/or ports.
+
+ It enables you to express policies like `10kpps for any given
+ destination IP' or `500pps from any given source IP' with a single
+ IPtables rule.
+
+# `filter', generic and specific targets
+config IP_NF_FILTER
+ tristate "Packet filtering"
+ depends on IP_NF_IPTABLES
+ help
+ Packet filtering defines a table `filter', which has a series of
+ rules for simple packet filtering at local input, forwarding and
+ local output. See the man page for iptables(8).
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_TARGET_REJECT
+ tristate "REJECT target support"
+ depends on IP_NF_FILTER
+ help
+ The REJECT target allows a filtering rule to specify that an ICMP
+ error should be issued in response to an incoming packet, rather
+ than silently being dropped.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_TARGET_LOG
+ tristate "LOG target support"
+ depends on IP_NF_IPTABLES
+ help
+ This option adds a `LOG' target, which allows you to create rules in
+ any iptables table which records the packet header to the syslog.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_TARGET_ULOG
+ tristate "ULOG target support"
+ depends on IP_NF_IPTABLES
+ ---help---
+ This option adds a `ULOG' target, which allows you to create rules in
+ any iptables table. The packet is passed to a userspace logging
+ daemon using netlink multicast sockets; unlike the LOG target
+ which can only be viewed through syslog.
+
+ The apropriate userspace logging daemon (ulogd) may be obtained from
+ <http://www.gnumonks.org/projects/ulogd/>
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_TARGET_TCPMSS
+ tristate "TCPMSS target support"
+ depends on IP_NF_IPTABLES
+ ---help---
+ This option adds a `TCPMSS' target, which allows you to alter the
+ MSS value of TCP SYN packets, to control the maximum size for that
+ connection (usually limiting it to your outgoing interface's MTU
+ minus 40).
+
+ This is used to overcome criminally braindead ISPs or servers which
+ block ICMP Fragmentation Needed packets. The symptoms of this
+ problem are that everything works fine from your Linux
+ firewall/router, but machines behind it can never exchange large
+ packets:
+ 1) Web browsers connect, then hang with no data received.
+ 2) Small mail works fine, but large emails hang.
+ 3) ssh works fine, but scp hangs after initial handshaking.
+
+ Workaround: activate this option and add a rule to your firewall
+ configuration like:
+
+ iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
+ -j TCPMSS --clamp-mss-to-pmtu
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+# NAT + specific targets
+config IP_NF_NAT
+ tristate "Full NAT"
+ depends on IP_NF_IPTABLES && IP_NF_CONNTRACK
+ help
+ The Full NAT option allows masquerading, port forwarding and other
+ forms of full Network Address Port Translation. It is controlled by
+ the `nat' table in iptables: see the man page for iptables(8).
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_NAT_NEEDED
+ bool
+ depends on IP_NF_NAT != n
+ default y
+
+config IP_NF_TARGET_MASQUERADE
+ tristate "MASQUERADE target support"
+ depends on IP_NF_NAT
+ help
+ Masquerading is a special case of NAT: all outgoing connections are
+ changed to seem to come from a particular interface's address, and
+ if the interface goes down, those connections are lost. This is
+ only useful for dialup accounts with dynamic IP address (ie. your IP
+ address will be different on next dialup).
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_TARGET_REDIRECT
+ tristate "REDIRECT target support"
+ depends on IP_NF_NAT
+ help
+ REDIRECT is a special case of NAT: all incoming connections are
+ mapped onto the incoming interface's address, causing the packets to
+ come to the local machine instead of passing through. This is
+ useful for transparent proxies.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_TARGET_NETMAP
+ tristate "NETMAP target support"
+ depends on IP_NF_NAT
+ help
+ NETMAP is an implementation of static 1:1 NAT mapping of network
+ addresses. It maps the network address part, while keeping the host
+ address part intact. It is similar to Fast NAT, except that
+ Netfilter's connection tracking doesn't work well with Fast NAT.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_TARGET_SAME
+ tristate "SAME target support"
+ depends on IP_NF_NAT
+ help
+ This option adds a `SAME' target, which works like the standard SNAT
+ target, but attempts to give clients the same IP for all connections.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_NAT_SNMP_BASIC
+ tristate "Basic SNMP-ALG support (EXPERIMENTAL)"
+ depends on EXPERIMENTAL && IP_NF_NAT
+ ---help---
+
+ This module implements an Application Layer Gateway (ALG) for
+ SNMP payloads. In conjunction with NAT, it allows a network
+ management system to access multiple private networks with
+ conflicting addresses. It works by modifying IP addresses
+ inside SNMP payloads to match IP-layer NAT mapping.
+
+ This is the "basic" form of SNMP-ALG, as described in RFC 2962
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_NAT_IRC
+ tristate
+ depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
+ default IP_NF_NAT if IP_NF_IRC=y
+ default m if IP_NF_IRC=m
+
+# If they want FTP, set to $CONFIG_IP_NF_NAT (m or y),
+# or $CONFIG_IP_NF_FTP (m or y), whichever is weaker. Argh.
+config IP_NF_NAT_FTP
+ tristate
+ depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
+ default IP_NF_NAT if IP_NF_FTP=y
+ default m if IP_NF_FTP=m
+
+config IP_NF_NAT_TFTP
+ tristate
+ depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
+ default IP_NF_NAT if IP_NF_TFTP=y
+ default m if IP_NF_TFTP=m
+
+config IP_NF_NAT_AMANDA
+ tristate
+ depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
+ default IP_NF_NAT if IP_NF_AMANDA=y
+ default m if IP_NF_AMANDA=m
+
+# mangle + specific targets
+config IP_NF_MANGLE
+ tristate "Packet mangling"
+ depends on IP_NF_IPTABLES
+ help
+ This option adds a `mangle' table to iptables: see the man page for
+ iptables(8). This table is used for various packet alterations
+ which can effect how the packet is routed.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_TARGET_TOS
+ tristate "TOS target support"
+ depends on IP_NF_MANGLE
+ help
+ This option adds a `TOS' target, which allows you to create rules in
+ the `mangle' table which alter the Type Of Service field of an IP
+ packet prior to routing.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_TARGET_ECN
+ tristate "ECN target support"
+ depends on IP_NF_MANGLE
+ ---help---
+ This option adds a `ECN' target, which can be used in the iptables mangle
+ table.
+
+ You can use this target to remove the ECN bits from the IPv4 header of
+ an IP packet. This is particularly useful, if you need to work around
+ existing ECN blackholes on the internet, but don't want to disable
+ ECN support in general.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_TARGET_DSCP
+ tristate "DSCP target support"
+ depends on IP_NF_MANGLE
+ help
+ This option adds a `DSCP' match, which allows you to match against
+ the IPv4 header DSCP field (DSCP codepoint).
+
+ The DSCP codepoint can have any value between 0x0 and 0x4f.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_TARGET_MARK
+ tristate "MARK target support"
+ depends on IP_NF_MANGLE
+ help
+ This option adds a `MARK' target, which allows you to create rules
+ in the `mangle' table which alter the netfilter mark (nfmark) field
+ associated with the packet prior to routing. This can change
+ the routing method (see `Use netfilter MARK value as routing
+ key') and can also be used by other subsystems to change their
+ behavior.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_TARGET_CLASSIFY
+ tristate "CLASSIFY target support"
+ depends on IP_NF_MANGLE
+ help
+ This option adds a `CLASSIFY' target, which enables the user to set
+ the priority of a packet. Some qdiscs can use this value for
+ classification, among these are:
+
+ atm, cbq, dsmark, pfifo_fast, htb, prio
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_TARGET_CONNMARK
+ tristate 'CONNMARK target support'
+ depends on IP_NF_CONNTRACK_MARK && IP_NF_MANGLE
+ help
+ This option adds a `CONNMARK' target, which allows one to manipulate
+ the connection mark value. Similar to the MARK target, but
+ affects the connection mark value rather than the packet mark value.
+
+ If you want to compile it as a module, say M here and read
+ <file:Documentation/modules.txt>. The module will be called
+ ipt_CONNMARK.o. If unsure, say `N'.
+
+config IP_NF_TARGET_CLUSTERIP
+ tristate "CLUSTERIP target support (EXPERIMENTAL)"
+ depends on IP_NF_CONNTRACK_MARK && IP_NF_IPTABLES && EXPERIMENTAL
+ help
+ The CLUSTERIP target allows you to build load-balancing clusters of
+ network servers without having a dedicated load-balancing
+ router/server/switch.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+# raw + specific targets
+config IP_NF_RAW
+ tristate 'raw table support (required for NOTRACK/TRACE)'
+ depends on IP_NF_IPTABLES
+ help
+ This option adds a `raw' table to iptables. This table is the very
+ first in the netfilter framework and hooks in at the PREROUTING
+ and OUTPUT chains.
+
+ If you want to compile it as a module, say M here and read
+ <file:Documentation/modules.txt>. If unsure, say `N'.
+
+config IP_NF_TARGET_NOTRACK
+ tristate 'NOTRACK target support'
+ depends on IP_NF_RAW
+ depends on IP_NF_CONNTRACK
+ help
+ The NOTRACK target allows a select rule to specify
+ which packets *not* to enter the conntrack/NAT
+ subsystem with all the consequences (no ICMP error tracking,
+ no protocol helpers for the selected packets).
+
+ If you want to compile it as a module, say M here and read
+ <file:Documentation/modules.txt>. If unsure, say `N'.
+
+
+# ARP tables
+config IP_NF_ARPTABLES
+ tristate "ARP tables support"
+ help
+ arptables is a general, extensible packet identification framework.
+ The ARP packet filtering and mangling (manipulation)subsystems
+ use this: say Y or M here if you want to use either of those.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_ARPFILTER
+ tristate "ARP packet filtering"
+ depends on IP_NF_ARPTABLES
+ help
+ ARP packet filtering defines a table `filter', which has a series of
+ rules for simple ARP packet filtering at local input and
+ local output. On a bridge, you can also specify filtering rules
+ for forwarded ARP packets. See the man page for arptables(8).
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_ARP_MANGLE
+ tristate "ARP payload mangling"
+ depends on IP_NF_ARPTABLES
+ help
+ Allows altering the ARP packet payload: source and destination
+ hardware and network addresses.
+
+config IP_NF_SET
+ tristate "IP set support"
+ depends on INET && NETFILTER
+ help
+ This option adds IP set support to the kernel.
+ In order to define and use sets, you need the userspace utility
+ ipset(8).
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_SET_MAX
+ int "Maximum number of IP sets"
+ default 256
+ range 2 65534
+ depends on IP_NF_SET
+ help
+ You can define here default value of the maximum number
+ of IP sets for the kernel.
+
+ The value can be overriden by the 'max_sets' module
+ parameter of the 'ip_set' module.
+
+config IP_NF_SET_HASHSIZE
+ int "Hash size for bindings of IP sets"
+ default 1024
+ depends on IP_NF_SET
+ help
+ You can define here default value of the hash size for
+ bindings of IP sets.
+
+ The value can be overriden by the 'hash_size' module
+ parameter of the 'ip_set' module.
+
+config IP_NF_SET_IPMAP
+ tristate "ipmap set support"
+ depends on IP_NF_SET
+ help
+ This option adds the ipmap set type support.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_SET_MACIPMAP
+ tristate "macipmap set support"
+ depends on IP_NF_SET
+ help
+ This option adds the macipmap set type support.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_SET_PORTMAP
+ tristate "portmap set support"
+ depends on IP_NF_SET
+ help
+ This option adds the portmap set type support.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_SET_IPHASH
+ tristate "iphash set support"
+ depends on IP_NF_SET
+ help
+ This option adds the iphash set type support.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_SET_NETHASH
+ tristate "nethash set support"
+ depends on IP_NF_SET
+ help
+ This option adds the nethash set type support.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_MATCH_SET
+ tristate "set match support"
+ depends on IP_NF_SET
+ help
+ Set matching matches against given IP sets.
+ You need the ipset utility to create and set up the sets.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP_NF_TARGET_SET
+ tristate "SET target support"
+ depends on IP_NF_SET
+ help
+ The SET target makes possible to add/delete entries
+ in IP sets.
+ You need the ipset utility to create and set up the sets.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+
+config IP_NF_TARGET_TARPIT
+ tristate 'TARPIT target support'
+ depends on IP_NF_FILTER
+ help
+ Adds a TARPIT target to iptables, which captures and holds
+ incoming TCP connections using no local per-connection resources.
+ Connections are accepted, but immediately switched to the persist
+ state (0 byte window), in which the remote side stops sending data
+ and asks to continue every 60-240 seconds. Attempts to close the
+ connection are ignored, forcing the remote side to time out the
+ connection in 12-24 minutes.
+
+ This offers similar functionality to LaBrea
+ <http://www.hackbusters.net/LaBrea/> but doesn't require dedicated
+ hardware or IPs. Any TCP port that you would normally DROP or REJECT
+ can instead become a tarpit.
+
+config IP_NF_MATCH_IPP2P
+ tristate 'IPP2P match support'
+ depends on IP_NF_IPTABLES
+ help
+ This option makes possible to match some P2P packets
+ therefore helps controlling such traffic.
+
+ If you want to compile it as a module, say M here and read
+ <file:Documentation/modules.txt>. If unsure, say `N'.
+
+endmenu
+
diff -urN linux-2.6.11/net/ipv4/netfilter/Makefile linux.sinabox/net/ipv4/netfilter/Makefile
--- linux-2.6.11/net/ipv4/netfilter/Makefile 2005-03-02 08:37:50.000000000 +0100
+++ linux.sinabox/net/ipv4/netfilter/Makefile 2005-03-26 00:49:04.000000000 +0100
@@ -36,9 +36,11 @@
# matches
obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o
obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o
+obj-$(CONFIG_IP_NF_MATCH_IPP2P) += ipt_ipp2p.o
obj-$(CONFIG_IP_NF_MATCH_HASHLIMIT) += ipt_hashlimit.o
obj-$(CONFIG_IP_NF_MATCH_SCTP) += ipt_sctp.o
obj-$(CONFIG_IP_NF_MATCH_MARK) += ipt_mark.o
+obj-$(CONFIG_IP_NF_MATCH_SET) += ipt_set.o
obj-$(CONFIG_IP_NF_MATCH_MAC) += ipt_mac.o
obj-$(CONFIG_IP_NF_MATCH_IPRANGE) += ipt_iprange.o
obj-$(CONFIG_IP_NF_MATCH_PKTTYPE) += ipt_pkttype.o
@@ -62,10 +64,12 @@
# targets
obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
+obj-$(CONFIG_IP_NF_TARGET_TARPIT) += ipt_TARPIT.o
obj-$(CONFIG_IP_NF_TARGET_TOS) += ipt_TOS.o
obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o
obj-$(CONFIG_IP_NF_TARGET_DSCP) += ipt_DSCP.o
obj-$(CONFIG_IP_NF_TARGET_MARK) += ipt_MARK.o
+obj-$(CONFIG_IP_NF_TARGET_IMQ) += ipt_IMQ.o
obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o
@@ -77,6 +81,15 @@
obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o
obj-$(CONFIG_IP_NF_TARGET_NOTRACK) += ipt_NOTRACK.o
+obj-$(CONFIG_IP_NF_TARGET_SET) += ipt_SET.o
+
+# sets
+obj-$(CONFIG_IP_NF_SET) += ip_set.o
+obj-$(CONFIG_IP_NF_SET_IPMAP) += ip_set_ipmap.o
+obj-$(CONFIG_IP_NF_SET_PORTMAP) += ip_set_portmap.o
+obj-$(CONFIG_IP_NF_SET_MACIPMAP) += ip_set_macipmap.o
+obj-$(CONFIG_IP_NF_SET_IPHASH) += ip_set_iphash.o
+obj-$(CONFIG_IP_NF_SET_NETHASH) += ip_set_nethash.o
obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o
# generic ARP tables
diff -urN linux-2.6.11/net/ipv4/netfilter/Makefile.orig linux.sinabox/net/ipv4/netfilter/Makefile.orig
--- linux-2.6.11/net/ipv4/netfilter/Makefile.orig 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/net/ipv4/netfilter/Makefile.orig 2005-03-24 19:26:06.000000000 +0100
@@ -0,0 +1,101 @@
+#
+# Makefile for the netfilter modules on top of IPv4.
+#
+
+# objects for the standalone - connection tracking / NAT
+ip_conntrack-objs := ip_conntrack_standalone.o ip_conntrack_core.o ip_conntrack_proto_generic.o ip_conntrack_proto_tcp.o ip_conntrack_proto_udp.o ip_conntrack_proto_icmp.o
+iptable_nat-objs := ip_nat_standalone.o ip_nat_rule.o ip_nat_core.o ip_nat_helper.o ip_nat_proto_unknown.o ip_nat_proto_tcp.o ip_nat_proto_udp.o ip_nat_proto_icmp.o
+
+# connection tracking
+obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o
+
+# SCTP protocol connection tracking
+obj-$(CONFIG_IP_NF_CT_PROTO_SCTP) += ip_conntrack_proto_sctp.o
+
+# connection tracking helpers
+obj-$(CONFIG_IP_NF_AMANDA) += ip_conntrack_amanda.o
+obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o
+obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o
+obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o
+
+# NAT helpers
+obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o
+obj-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_tftp.o
+obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o
+obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o
+
+# generic IP tables
+obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
+
+# the three instances of ip_tables
+obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o
+obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o
+obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o
+obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o
+
+# matches
+obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o
+obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o
+obj-$(CONFIG_IP_NF_MATCH_IPP2P) += ipt_ipp2p.o
+obj-$(CONFIG_IP_NF_MATCH_HASHLIMIT) += ipt_hashlimit.o
+obj-$(CONFIG_IP_NF_MATCH_SCTP) += ipt_sctp.o
+obj-$(CONFIG_IP_NF_MATCH_MARK) += ipt_mark.o
+obj-$(CONFIG_IP_NF_MATCH_SET) += ipt_set.o
+obj-$(CONFIG_IP_NF_MATCH_MAC) += ipt_mac.o
+obj-$(CONFIG_IP_NF_MATCH_IPRANGE) += ipt_iprange.o
+obj-$(CONFIG_IP_NF_MATCH_PKTTYPE) += ipt_pkttype.o
+obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o
+obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o
+obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
+obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o
+obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o
+obj-$(CONFIG_IP_NF_MATCH_DSCP) += ipt_dscp.o
+obj-$(CONFIG_IP_NF_MATCH_AH_ESP) += ipt_ah.o ipt_esp.o
+obj-$(CONFIG_IP_NF_MATCH_LENGTH) += ipt_length.o
+obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
+obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o
+obj-$(CONFIG_IP_NF_MATCH_CONNMARK) += ipt_connmark.o
+obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o
+obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o
+obj-$(CONFIG_IP_NF_MATCH_REALM) += ipt_realm.o
+obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o
+obj-$(CONFIG_IP_NF_MATCH_PHYSDEV) += ipt_physdev.o
+obj-$(CONFIG_IP_NF_MATCH_COMMENT) += ipt_comment.o
+
+# targets
+obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
+obj-$(CONFIG_IP_NF_TARGET_TARPIT) += ipt_TARPIT.o
+obj-$(CONFIG_IP_NF_TARGET_TOS) += ipt_TOS.o
+obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o
+obj-$(CONFIG_IP_NF_TARGET_DSCP) += ipt_DSCP.o
+obj-$(CONFIG_IP_NF_TARGET_MARK) += ipt_MARK.o
+obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
+obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
+obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o
+obj-$(CONFIG_IP_NF_TARGET_SAME) += ipt_SAME.o
+obj-$(CONFIG_IP_NF_TARGET_CLASSIFY) += ipt_CLASSIFY.o
+obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o
+obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
+obj-$(CONFIG_IP_NF_TARGET_CONNMARK) += ipt_CONNMARK.o
+obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
+obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o
+obj-$(CONFIG_IP_NF_TARGET_NOTRACK) += ipt_NOTRACK.o
+obj-$(CONFIG_IP_NF_TARGET_SET) += ipt_SET.o
+
+# sets
+obj-$(CONFIG_IP_NF_SET) += ip_set.o
+obj-$(CONFIG_IP_NF_SET_IPMAP) += ip_set_ipmap.o
+obj-$(CONFIG_IP_NF_SET_PORTMAP) += ip_set_portmap.o
+obj-$(CONFIG_IP_NF_SET_MACIPMAP) += ip_set_macipmap.o
+obj-$(CONFIG_IP_NF_SET_IPHASH) += ip_set_iphash.o
+obj-$(CONFIG_IP_NF_SET_NETHASH) += ip_set_nethash.o
+obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o
+
+# generic ARP tables
+obj-$(CONFIG_IP_NF_ARPTABLES) += arp_tables.o
+obj-$(CONFIG_IP_NF_ARP_MANGLE) += arpt_mangle.o
+
+# just filtering instance of ARP tables for now
+obj-$(CONFIG_IP_NF_ARPFILTER) += arptable_filter.o
+
+obj-$(CONFIG_IP_NF_QUEUE) += ip_queue.o
diff -urN linux-2.6.11/net/ipv4/tcp_timer.c linux.sinabox/net/ipv4/tcp_timer.c
--- linux-2.6.11/net/ipv4/tcp_timer.c 2005-03-02 08:38:26.000000000 +0100
+++ linux.sinabox/net/ipv4/tcp_timer.c 2005-03-19 07:35:03.000000000 +0100
@@ -38,6 +38,7 @@
#ifdef TCP_DEBUG
const char tcp_timer_bug_msg[] = KERN_DEBUG "tcpbug: unknown timer value\n";
+EXPORT_SYMBOL(tcp_timer_bug_msg);
#endif
/*
diff -urN linux-2.6.11/net/ipv4/xfrm4_input.c linux.sinabox/net/ipv4/xfrm4_input.c
--- linux-2.6.11/net/ipv4/xfrm4_input.c 2005-03-02 08:37:48.000000000 +0100
+++ linux.sinabox/net/ipv4/xfrm4_input.c 2005-03-26 19:02:06.000000000 +0100
@@ -31,30 +31,29 @@
IP_ECN_set_ce(inner_iph);
}
-static int xfrm4_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq)
+static int xfrm4_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi)
{
switch (nexthdr) {
case IPPROTO_IPIP:
if (!pskb_may_pull(skb, sizeof(struct iphdr)))
return -EINVAL;
*spi = skb->nh.iph->saddr;
- *seq = 0;
return 0;
}
- return xfrm_parse_spi(skb, nexthdr, spi, seq);
+ return xfrm_parse_spi(skb, nexthdr, spi);
}
int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
{
int err;
- u32 spi, seq;
+ u32 spi;
struct sec_decap_state xfrm_vec[XFRM_MAX_DEPTH];
struct xfrm_state *x;
int xfrm_nr = 0;
int decaps = 0;
- if ((err = xfrm4_parse_spi(skb, skb->nh.iph->protocol, &spi, &seq)) != 0)
+ if ((err = xfrm4_parse_spi(skb, skb->nh.iph->protocol, &spi)) != 0)
goto drop;
do {
@@ -71,9 +70,6 @@
if (unlikely(x->km.state != XFRM_STATE_VALID))
goto drop_unlock;
- if (x->props.replay_window && xfrm_replay_check(x, seq))
- goto drop_unlock;
-
if (xfrm_state_check_expire(x))
goto drop_unlock;
@@ -84,9 +80,6 @@
/* only the first xfrm gets the encap type */
encap_type = 0;
- if (x->props.replay_window)
- xfrm_replay_advance(x, seq);
-
x->curlft.bytes += skb->len;
x->curlft.packets++;
@@ -116,8 +109,9 @@
break;
}
- if ((err = xfrm_parse_spi(skb, skb->nh.iph->protocol, &spi, &seq)) < 0)
+ if ((err = xfrm_parse_spi(skb, skb->nh.iph->protocol, &spi)) < 0)
goto drop;
+
} while (!err);
/* Allocate new secpath or COW existing one. */
diff -urN linux-2.6.11/net/ipv6/addrconf.c linux.sinabox/net/ipv6/addrconf.c
--- linux-2.6.11/net/ipv6/addrconf.c 2005-03-02 08:38:26.000000000 +0100
+++ linux.sinabox/net/ipv6/addrconf.c 2005-03-26 19:02:06.000000000 +0100
@@ -35,6 +35,10 @@
* YOSHIFUJI Hideaki @USAGI : ARCnet support
* YOSHIFUJI Hideaki @USAGI : convert /proc/net/if_inet6 to
* seq_file.
+ * YOSHIFUJI Hideaki @USAGI : improved source address
+ * selection; consider scope,
+ * status etc.
+ * Hoerdt Mickael : Added Multicast routing support.
*/
#include <linux/config.h>
@@ -105,8 +109,10 @@
static void ipv6_regen_rndid(unsigned long data);
static int desync_factor = MAX_DESYNC_FACTOR * HZ;
+#ifdef CONFIG_IPV6_PRIVACY_MD5
static struct crypto_tfm *md5_tfm;
static DEFINE_SPINLOCK(md5_tfm_lock);
+#endif /* CONFIG_IPV6_PRIVACY_MD5 */
#endif
static int ipv6_count_addresses(struct inet6_dev *idev);
@@ -144,6 +150,8 @@
static struct notifier_block *inet6addr_chain;
+static u32 ipv6_addrselect_label_lookup(const struct in6_addr *addr, int ifindex);
+
struct ipv6_devconf ipv6_devconf = {
.forwarding = 0,
.hop_limit = IPV6_DEFAULT_HOPLIMIT,
@@ -164,6 +172,9 @@
.max_desync_factor = MAX_DESYNC_FACTOR,
#endif
.max_addresses = IPV6_MAX_ADDRESSES,
+#ifdef CONFIG_IPV6_MROUTE
+ .mc_forwarding = 0,
+#endif
};
static struct ipv6_devconf ipv6_devconf_dflt = {
@@ -185,54 +196,58 @@
.max_desync_factor = MAX_DESYNC_FACTOR,
#endif
.max_addresses = IPV6_MAX_ADDRESSES,
+#ifdef CONFIG_IPV6_MROUTE
+ .mc_forwarding = 0,
+#endif
};
-/* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */
+/* IPv6 Wildcard Address and Loopback Address defined by RFC3493 */
#if 0
const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
#endif
const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
-int ipv6_addr_type(const struct in6_addr *addr)
+int __ipv6_addr_type(const struct in6_addr *addr)
{
- int type;
- u32 st;
+ u32 st = addr->s6_addr32[0];
- st = addr->s6_addr32[0];
+ /* Consider all addresses with the first three bits different of
+ 000 and 111 as unicasts.
+ */
+ if ((st & htonl(0xE0000000)) != htonl(0x00000000) &&
+ (st & htonl(0xE0000000)) != htonl(0xE0000000))
+ return (IPV6_ADDR_UNICAST |
+ IPV6_ADDR_SCOPE_GLOBAL<<16);
if ((st & htonl(0xFF000000)) == htonl(0xFF000000)) {
- type = IPV6_ADDR_MULTICAST;
+ /* multicast */
+ /* addr-select 3.1 */
+ int type = IPV6_ADDR_MC_SCOPE(addr)<<16;
- switch((st & htonl(0x00FF0000))) {
- case __constant_htonl(0x00010000):
+ switch(type) {
+ case IPV6_ADDR_SCOPE_NODELOCAL<<16:
type |= IPV6_ADDR_LOOPBACK;
break;
- case __constant_htonl(0x00020000):
+ case IPV6_ADDR_SCOPE_LINKLOCAL<<16:
type |= IPV6_ADDR_LINKLOCAL;
break;
- case __constant_htonl(0x00050000):
+ case IPV6_ADDR_SCOPE_SITELOCAL<<16:
type |= IPV6_ADDR_SITELOCAL;
break;
};
+ type |= IPV6_ADDR_MULTICAST;
return type;
}
- type = IPV6_ADDR_UNICAST;
-
- /* Consider all addresses with the first three bits different of
- 000 and 111 as finished.
- */
- if ((st & htonl(0xE0000000)) != htonl(0x00000000) &&
- (st & htonl(0xE0000000)) != htonl(0xE0000000))
- return type;
-
if ((st & htonl(0xFFC00000)) == htonl(0xFE800000))
- return (IPV6_ADDR_LINKLOCAL | type);
+ return (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST |
+ IPV6_ADDR_SCOPE_LINKLOCAL<<16); /* addr-select 3.1 */
if ((st & htonl(0xFFC00000)) == htonl(0xFEC00000))
- return (IPV6_ADDR_SITELOCAL | type);
+ return (IPV6_ADDR_SITELOCAL | IPV6_ADDR_UNICAST |
+ IPV6_ADDR_SCOPE_SITELOCAL<<16); /* addr-select 3.1 */
if ((addr->s6_addr32[0] | addr->s6_addr32[1]) == 0) {
if (addr->s6_addr32[2] == 0) {
@@ -240,24 +255,50 @@
return IPV6_ADDR_ANY;
if (addr->s6_addr32[3] == htonl(0x00000001))
- return (IPV6_ADDR_LOOPBACK | type);
+ return (IPV6_ADDR_LOOPBACK | IPV6_ADDR_UNICAST |
+ IPV6_ADDR_SCOPE_LINKLOCAL<<16); /* addr-select 3.4 */
- return (IPV6_ADDR_COMPATv4 | type);
+ return (IPV6_ADDR_COMPATv4 | IPV6_ADDR_UNICAST |
+ IPV6_ADDR_SCOPE_GLOBAL<<16); /* addr-select 3.3 */
}
if (addr->s6_addr32[2] == htonl(0x0000ffff))
- return IPV6_ADDR_MAPPED;
+ return (IPV6_ADDR_MAPPED |
+ IPV6_ADDR_SCOPE_GLOBAL<<16); /* addr-select 3.3 */
+ }
+
+ return (IPV6_ADDR_RESERVED |
+ IPV6_ADDR_SCOPE_GLOBAL<<16); /* addr-select 3.4 */
+}
+
+/* find 1st bit in difference between the 2 addrs */
+static inline int addr_diff(const void *__a1, const void *__a2, int addrlen)
+{
+ /* find 1st bit in difference between the 2 addrs.
+ * bit may be an invalid value,
+ * but if it is >= plen, the value is ignored in any case.
+ */
+ const u32 *a1 = __a1;
+ const u32 *a2 = __a2;
+ int i;
+
+ addrlen >>= 2;
+ for (i = 0; i < addrlen; i++) {
+ u32 xb = a1[i] ^ a2[i];
+ if (xb) {
+ int j = 31;
+ xb = ntohl(xb);
+ while ((xb & (1 << j)) == 0)
+ j--;
+ return (i * 32 + 31 - j);
+ }
}
+ return addrlen<<5;
+}
- st &= htonl(0xFF000000);
- if (st == 0)
- return IPV6_ADDR_RESERVED;
- st &= htonl(0xFE000000);
- if (st == htonl(0x02000000))
- return IPV6_ADDR_RESERVED; /* for NSAP */
- if (st == htonl(0x04000000))
- return IPV6_ADDR_RESERVED; /* for IPX */
- return type;
+static inline int ipv6_addr_diff(const struct in6_addr *a1, const struct in6_addr *a2)
+{
+ return addr_diff(a1->s6_addr, a2->s6_addr, sizeof(struct in6_addr));
}
static void addrconf_del_timer(struct inet6_ifaddr *ifp)
@@ -366,7 +407,9 @@
#ifdef CONFIG_IPV6_PRIVACY
get_random_bytes(ndev->rndid, sizeof(ndev->rndid));
+#ifdef CONFIG_IPV6_PRIVACY_MD5
get_random_bytes(ndev->entropy, sizeof(ndev->entropy));
+#endif /* CONFIG_IPV6_PRIVACY_MD5 */
init_timer(&ndev->regen_timer);
ndev->regen_timer.function = ipv6_regen_rndid;
ndev->regen_timer.data = (unsigned long) ndev;
@@ -391,14 +434,14 @@
ndev->tstamp = jiffies;
#ifdef CONFIG_SYSCTL
neigh_sysctl_register(dev, ndev->nd_parms, NET_IPV6,
- NET_IPV6_NEIGH, "ipv6", &ndisc_ifinfo_sysctl_change);
+ NET_IPV6_NEIGH, "ipv6", &ndisc_ifinfo_sysctl_change, NULL);
addrconf_sysctl_register(ndev, &ndev->cnf);
#endif
}
return ndev;
}
-static struct inet6_dev * ipv6_find_idev(struct net_device *dev)
+struct inet6_dev * ipv6_find_idev(struct net_device *dev)
{
struct inet6_dev *idev;
@@ -589,6 +632,10 @@
struct inet6_ifaddr *ifa, **ifap;
struct inet6_dev *idev = ifp->idev;
int hash;
+#ifdef CONFIG_IPV6_DELPREFIX
+ int deleted = 0, onlink = 0;
+ unsigned long expires = jiffies;
+#endif
hash = ipv6_addr_hash(&ifp->addr);
@@ -631,7 +678,32 @@
*ifap = ifa->if_next;
__in6_ifa_put(ifp);
ifa->if_next = NULL;
+#ifndef CONFIG_IPV6_DELPREFIX
break;
+#else
+ if (!(ifp->flags & IFA_F_PERMANENT) ||
+ onlink > 0)
+ break;
+ deleted = 1;
+ } else {
+ if (ipv6_prefix_equal(&ifa->addr, &ifp->addr,
+ ifp->prefix_len)) {
+ if (ifa->flags & IFA_F_PERMANENT) {
+ onlink = 1;
+ if (deleted)
+ break;
+ } else if (!onlink) {
+ unsigned long lifetime;
+ onlink = -1;
+
+ lifetime = ifp->valid_lft;
+ if (lifetime > 0x7fffffffUL/HZ)
+ lifetime = 0x7ffffffUL/HZ;
+ if (time_before(expires, ifp->tstamp + lifetime * HZ))
+ expires = ifp->tstamp + lifetime * HZ;
+ }
+ }
+#endif
}
}
write_unlock_bh(&idev->lock);
@@ -642,6 +714,52 @@
addrconf_del_timer(ifp);
+#ifdef CONFIG_IPV6_DELPREFIX
+ /*
+ * Clean-up on-link route.
+ * We need to respect prefix lifetime.
+ *
+ * 1) if the address was not permanent, don't delete it.
+ * - timer for fib entry will delete itself.
+ * 2) if there're other permanent addresses with same prefix, don't
+ * delete it.
+ * 3) if there're only dynamic addresses, change prefix route to
+ * dynamic.
+ * - lifetime will be set to the longest valid lifetime among the
+ * addresses with same prefix on the device
+ * - subsequent RA will update lifetime.
+ * 4) otherwise, delete it.
+ *
+ * --yoshfuji
+ */
+ if ((ifp->flags & IFA_F_PERMANENT) && onlink < 1) {
+ struct in6_addr prefix;
+ struct rt6_info *rt;
+
+ ipv6_addr_prefix(&prefix, &ifp->addr, ifp->prefix_len);
+ rt = rt6_lookup(&prefix, NULL, ifp->idev->dev->ifindex, 1);
+
+ if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) {
+ if (onlink == 0) {
+ ip6_del_rt(rt, NULL, NULL);
+ rt = NULL;
+ } else if (!(rt->rt6i_flags & RTF_EXPIRES)) {
+ /*
+ * prefix lifetime and valid lifetime are
+ * (almost) the same.
+ * subsequent RA will update appropriately.
+ * --yoshfuji
+ */
+ if (expires < jiffies)
+ expires = jiffies;
+ rt->rt6i_expires = expires;
+ rt->rt6i_flags |= RTF_EXPIRES;
+ }
+ }
+ dst_release(&rt->u.dst);
+ }
+#endif
+
in6_ifa_put(ifp);
}
@@ -743,147 +861,215 @@
/*
* Choose an appropriate source address
+ * draft-ietf-ipv6-default-addr-select-09.txt
* should do:
* i) get an address with an appropriate scope
* ii) see if there is a specific route for the destination and use
* an address of the attached interface
* iii) don't use deprecated addresses
*/
-static int inline ipv6_saddr_pref(const struct inet6_ifaddr *ifp, u8 invpref)
+#define IPV6_SADDRSELECT_SELF 0x01
+#define IPV6_SADDRSELECT_PREFERRED 0x02
+#define IPV6_SADDRSELECT_HOME 0x04
+#define IPV6_SADDRSELECT_PUBLIC 0x08
+#define IPV6_SADDRSELECT_INTERFACE 0x10
+#define IPV6_SADDRSELECT_LABEL 0x20
+
+struct addrselect_attrs {
+ struct inet6_ifaddr *ifp;
+ u16 flags;
+ s16 matchlen;
+ u8 scope;
+};
+
+static int __inline__ ipv6_addrselect_preferred(int type)
{
- int pref;
- pref = ifp->flags&IFA_F_DEPRECATED ? 0 : 2;
-#ifdef CONFIG_IPV6_PRIVACY
- pref |= (ifp->flags^invpref)&IFA_F_TEMPORARY ? 0 : 1;
-#endif
- return pref;
+ /* section 3.3, 3.4 */
+ if (type&(IPV6_ADDR_MAPPED|IPV6_ADDR_COMPATv4|
+ IPV6_ADDR_LOOPBACK|IPV6_ADDR_RESERVED))
+ return 1;
+ return 0;
}
-#ifdef CONFIG_IPV6_PRIVACY
-#define IPV6_GET_SADDR_MAXSCORE(score) ((score) == 3)
-#else
-#define IPV6_GET_SADDR_MAXSCORE(score) (score)
-#endif
-
-int ipv6_dev_get_saddr(struct net_device *dev,
+int ipv6_dev_get_saddr(struct net_device *daddr_dev,
struct in6_addr *daddr, struct in6_addr *saddr)
{
- struct inet6_ifaddr *ifp = NULL;
- struct inet6_ifaddr *match = NULL;
+ int daddr_type, daddr_scope;
+ u32 daddr_label;
+ struct inet6_ifaddr *ifp0, *ifp = NULL;
+ struct net_device *dev;
struct inet6_dev *idev;
- int scope;
+
int err;
- int hiscore = -1, score;
+ int update;
+ struct addrselect_attrs candidate = {NULL,0,0,0};
+#if defined(CONFIG_IPV6_PRIVACY)
+ u16 invpref = 0;
+#endif
- scope = ipv6_addr_scope(daddr);
+#ifdef CONFIG_IPV6_PRIVACY
+ if (ipv6_devconf.use_tempaddr > 1)
+ invpref |= IPV6_SADDRSELECT_PUBLIC;
+#endif
- /*
- * known dev
- * search dev and walk through dev addresses
- */
+ daddr_type = __ipv6_addr_type(daddr);
+ daddr_scope = __ipv6_addr_src_scope(daddr_type);
+ daddr_label = ipv6_addrselect_label_lookup(daddr,
+ daddr_dev?daddr_dev->ifindex:0);
- if (dev) {
- if (dev->flags & IFF_LOOPBACK)
- scope = IFA_HOST;
+ read_lock(&dev_base_lock);
+ read_lock(&addrconf_lock);
+ for (dev = dev_base; dev; dev=dev->next) {
+ /* Rule 0: Candidate Source Address (section 4)
+ * - multicast and link-local destination address,
+ * the set of candidate source address MUST only
+ * include addresses assigned to interfaces
+ * belonging to the same link as the outgoing
+ * interface.
+ * (- For site-local destination addresses, the
+ * set of candidate source addresses MUST only
+ * include addresses assigned to interfaces
+ * belonging to the same site as the outgoing
+ * interface.)
+ */
+ if ((daddr_type&IPV6_ADDR_MULTICAST ||
+ daddr_scope <= IPV6_ADDR_SCOPE_LINKLOCAL) &&
+ daddr_dev && dev != daddr_dev)
+ continue;
- read_lock(&addrconf_lock);
idev = __in6_dev_get(dev);
- if (idev) {
- read_lock_bh(&idev->lock);
- for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
- if (ifp->scope == scope) {
- if (ifp->flags&IFA_F_TENTATIVE)
- continue;
-#ifdef CONFIG_IPV6_PRIVACY
- score = ipv6_saddr_pref(ifp, idev->cnf.use_tempaddr > 1 ? IFA_F_TEMPORARY : 0);
-#else
- score = ipv6_saddr_pref(ifp, 0);
-#endif
- if (score <= hiscore)
- continue;
+ if (!idev)
+ continue;
- if (match)
- in6_ifa_put(match);
- match = ifp;
- hiscore = score;
- in6_ifa_hold(ifp);
+ read_lock_bh(&idev->lock);
+ ifp0 = idev->addr_list;
+ for (ifp=ifp0; ifp; ifp=ifp->if_next) {
+ struct addrselect_attrs temp = {NULL,0,0,0};
+ int addr_type;
+ update = 0;
+
+ /* Rule 0: Candidate Source Address (section 4)
+ * - In any case, anycast addresses, multicast
+ * addresses, and the unspecified address MUST
+ * NOT be included in a candidate set.
+ */
+ addr_type = __ipv6_addr_type(&ifp->addr);
+ if (addr_type == IPV6_ADDR_ANY ||
+ addr_type&IPV6_ADDR_MULTICAST)
+ continue;
- if (IPV6_GET_SADDR_MAXSCORE(score)) {
- read_unlock_bh(&idev->lock);
- read_unlock(&addrconf_lock);
- goto out;
- }
+ /* Rule 1: Prefer same address */
+ if (ipv6_addr_cmp(&ifp->addr, daddr) == 0)
+ temp.flags |= IPV6_SADDRSELECT_SELF;
+ if ((temp.flags^candidate.flags)&IPV6_SADDRSELECT_SELF) {
+ update = temp.flags&IPV6_SADDRSELECT_SELF;
+ if (!update) {
+ continue;
}
}
- read_unlock_bh(&idev->lock);
- }
- read_unlock(&addrconf_lock);
- }
- if (scope == IFA_LINK)
- goto out;
+ /* Rule 2: Prefer appropriate scope */
+ temp.scope = __ipv6_addr_src_scope(addr_type);
+ if (!update) {
+ update = temp.scope - candidate.scope;
+ if (update > 0) {
+ update = candidate.scope < daddr_scope ? 1 : -1;
+ } else if (update < 0) {
+ update = temp.scope < daddr_scope ? -1 : 1;
+ }
+ if (update < 0) {
+ continue;
+ }
+ }
- /*
- * dev == NULL or search failed for specified dev
- */
+ /* Rule 3: Avoid deprecated address */
+ if (ipv6_addrselect_preferred(addr_type) ||
+ !(ifp->flags & IFA_F_DEPRECATED))
+ temp.flags |= IPV6_SADDRSELECT_PREFERRED;
+ if (!update && (temp.flags^candidate.flags)&IPV6_SADDRSELECT_PREFERRED) {
+ update = temp.flags&IPV6_SADDRSELECT_PREFERRED;
+ if (!update) {
+ continue;
+ }
+ }
- read_lock(&dev_base_lock);
- read_lock(&addrconf_lock);
- for (dev = dev_base; dev; dev=dev->next) {
- idev = __in6_dev_get(dev);
- if (idev) {
- read_lock_bh(&idev->lock);
- for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
- if (ifp->scope == scope) {
- if (ifp->flags&IFA_F_TENTATIVE)
- continue;
+ /* XXX: Rule 4: Prefer home address */
+
+ /* Rule 5: Prefer outgoing interface */
+ if (daddr_dev == NULL || daddr_dev == dev)
+ temp.flags |= IPV6_SADDRSELECT_INTERFACE;
+ if (!update && (temp.flags^candidate.flags)&IPV6_SADDRSELECT_INTERFACE) {
+ update = temp.flags&IPV6_SADDRSELECT_INTERFACE;
+ if (!update) {
+ continue;
+ }
+ }
+
+ /* XXX: Rule 6: Prefer matching label */
+ if (ipv6_addrselect_label_lookup(&ifp->addr, dev->ifindex) == daddr_label)
+ temp.flags |= IPV6_SADDRSELECT_LABEL;
+ if (!update && (temp.flags^candidate.flags)&IPV6_SADDRSELECT_LABEL) {
+ update = temp.flags&IPV6_SADDRSELECT_LABEL;
+ if (!update) {
+ continue;
+ }
+ }
+
+ /* XXX: Rule 7: Prefer public address */
#ifdef CONFIG_IPV6_PRIVACY
- score = ipv6_saddr_pref(ifp, idev->cnf.use_tempaddr > 1 ? IFA_F_TEMPORARY : 0);
-#else
- score = ipv6_saddr_pref(ifp, 0);
+ if (!(ifp->flags & IFA_F_TEMPORARY))
+ temp.flags |= IPV6_SADDRSELECT_PUBLIC;
+ if (!update && (temp.flags^candidate.flags)&IPV6_SADDRSELECT_PUBLIC) {
+ update = (temp.flags^invpref)&IPV6_SADDRSELECT_PUBLIC;
+ if (!update) {
+ continue;
+ }
+ }
#endif
- if (score <= hiscore)
- continue;
-
- if (match)
- in6_ifa_put(match);
- match = ifp;
- hiscore = score;
- in6_ifa_hold(ifp);
- if (IPV6_GET_SADDR_MAXSCORE(score)) {
- read_unlock_bh(&idev->lock);
- goto out_unlock_base;
- }
+ /* Rule 8: Use longest matching prefix */
+ temp.matchlen = ipv6_addr_diff(&ifp->addr, daddr);
+ if (!update) {
+ update = temp.matchlen - candidate.matchlen;
+ if (update < 0) {
+ continue;
}
}
- read_unlock_bh(&idev->lock);
+
+ /* Final Rule */
+ if (!update && candidate.ifp) {
+ continue;
+ }
+
+ /* update candidate */
+ temp.ifp = ifp;
+ in6_ifa_hold(ifp);
+ if (candidate.ifp)
+ in6_ifa_put(candidate.ifp);
+ candidate = temp;
}
+ read_unlock_bh(&idev->lock);
}
-
-out_unlock_base:
read_unlock(&addrconf_lock);
read_unlock(&dev_base_lock);
-out:
- err = -EADDRNOTAVAIL;
- if (match) {
- ipv6_addr_copy(saddr, &match->addr);
+ if (candidate.ifp) {
+ ipv6_addr_copy(saddr, &candidate.ifp->addr);
+ in6_ifa_put(candidate.ifp);
err = 0;
- in6_ifa_put(match);
+ } else {
+ err = -EADDRNOTAVAIL;
}
-
return err;
}
-
int ipv6_get_saddr(struct dst_entry *dst,
struct in6_addr *daddr, struct in6_addr *saddr)
{
- return ipv6_dev_get_saddr(dst ? dst->dev : NULL, daddr, saddr);
+ return ipv6_dev_get_saddr(dst ? ((struct rt6_info *)dst)->rt6i_dev : NULL,
+ daddr, saddr);
}
-
int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr)
{
struct inet6_dev *idev;
@@ -972,6 +1158,70 @@
return ifp;
}
+/* address selection: default policy label */
+/* XXX: user level configuration */
+static struct ipv6_addrselect_label {
+ struct in6_addr addr;
+ u16 plen;
+ u32 ifindex;
+ u32 label;
+} ipv6_addrselect_label_table[] = {
+ /* ::1/128, label = 0 */
+ {
+ .addr = IN6ADDR_LOOPBACK_INIT,
+ .plen = 128,
+ .label = 0,
+ },
+ /* ::/0, label = 1 */
+ {
+ .addr = IN6ADDR_ANY_INIT,
+ .plen = 0,
+ .label = 1,
+ },
+ /* 2002::/16, label = 2 */
+ {
+ .addr = {{{ 0x20, 0x02 }}},
+ .plen = 16,
+ .label = 2,
+ },
+ /* ::/96, label = 3 */
+ {
+ .plen = 96,
+ .label = 3,
+ },
+ /* ::ffff:0:0/96, label = 4 */
+ {
+ .addr = {{{ [10] = 0xff, [11] = 0xff }}},
+ .plen = 96,
+ .label = 4,
+ },
+ /* sentinel */
+ {
+ .label = 0xffffffff,
+ }
+};
+
+static u32 ipv6_addrselect_label_lookup(const struct in6_addr *addr,
+ int ifindex)
+{
+ struct ipv6_addrselect_label *p;
+ int plen, matchlen = -1;
+ u32 label = 0xffffffff;
+
+ for (p = ipv6_addrselect_label_table;
+ p->label != 0xffffffff;
+ p++) {
+ if (ifindex && p->ifindex && ifindex != p->ifindex)
+ continue;
+ plen = ipv6_addr_diff(addr, &p->addr);
+ if (plen < p->plen || plen < matchlen)
+ continue;
+ matchlen = plen;
+ label = p->label;
+ }
+ return label;
+}
+
int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2)
{
const struct in6_addr *sk_rcv_saddr6 = &inet6_sk(sk)->rcv_saddr;
@@ -1151,15 +1401,19 @@
/* (re)generation of randomized interface identifier (RFC 3041 3.2, 3.5) */
static int __ipv6_regen_rndid(struct inet6_dev *idev)
{
+#ifdef CONFIG_IPV6_PRIVACY_MD5
struct net_device *dev;
- struct scatterlist sg[2];
-
- sg[0].page = virt_to_page(idev->entropy);
- sg[0].offset = offset_in_page(idev->entropy);
- sg[0].length = 8;
- sg[1].page = virt_to_page(idev->work_eui64);
- sg[1].offset = offset_in_page(idev->work_eui64);
- sg[1].length = 8;
+ struct scatterlist sg[] = {
+ {
+ .page = virt_to_page(idev->entropy),
+ .offset = offset_in_page(idev->entropy),
+ .length = 8,
+ },{
+ .page = virt_to_page(idev->work_eui64),
+ .offset = offset_in_page(idev->work_eui64),
+ .length = 8,
+ }
+ };
dev = idev->dev;
@@ -1169,7 +1423,11 @@
idev);
get_random_bytes(idev->work_eui64, sizeof(idev->work_eui64));
}
+#endif /* CONFIG_IPV6_PRIVACY_MD5 */
regen:
+#ifndef CONFIG_IPV6_PRIVACY_MD5
+ get_random_bytes(idev->rndid, sizeof(idev->rndid));
+#else /* CONFIG_IPV6_PRIVACY_MD5 */
spin_lock(&md5_tfm_lock);
if (unlikely(md5_tfm == NULL)) {
spin_unlock(&md5_tfm_lock);
@@ -1181,9 +1439,14 @@
spin_unlock(&md5_tfm_lock);
memcpy(idev->rndid, &idev->work_digest[0], 8);
+#endif /* CONFIG_IPV6_PRIVACY_MD5 */
idev->rndid[0] &= ~0x02;
+#ifndef CONFIG_IPV6_PRIVACY_MD5
+
+#else /* CONFIG_IPV6_PRIVACY_MD5 */
memcpy(idev->entropy, &idev->work_digest[8], 8);
+#endif /* CONFIG_IPV6_PRIVACY_MD5 */
/*
* <draft-ietf-ipngwg-temp-addresses-v2-00.txt>:
* check if generated address is not inappropriate
@@ -1982,7 +2245,10 @@
if (idev) {
addrconf_sysctl_unregister(&idev->cnf);
neigh_sysctl_unregister(idev->nd_parms);
- neigh_sysctl_register(dev, idev->nd_parms, NET_IPV6, NET_IPV6_NEIGH, "ipv6", &ndisc_ifinfo_sysctl_change);
+ neigh_sysctl_register(dev, idev->nd_parms,
+ NET_IPV6, NET_IPV6_NEIGH,
+ "ipv6",
+ &ndisc_ifinfo_sysctl_change, NULL);
addrconf_sysctl_register(idev, &idev->cnf);
}
#endif
@@ -2427,6 +2693,10 @@
unsigned long regen_advance;
#endif
+#ifdef CONFIG_IPV6_PRIVACY
+ regen_advance = ifp->idev->cnf.regen_max_retry * ifp->idev->cnf.dad_transmits * ifp->idev->nd_parms->retrans_time / HZ;
+#endif
+
if (ifp->flags & IFA_F_PERMANENT)
continue;
@@ -2469,28 +2739,33 @@
}
#ifdef CONFIG_IPV6_PRIVACY
} else if ((ifp->flags&IFA_F_TEMPORARY) &&
- !(ifp->flags&IFA_F_TENTATIVE)) {
- if (age >= ifp->prefered_lft - regen_advance) {
- struct inet6_ifaddr *ifpub = ifp->ifpub;
- if (time_before(ifp->tstamp + ifp->prefered_lft * HZ, next))
- next = ifp->tstamp + ifp->prefered_lft * HZ;
- if (!ifp->regen_count && ifpub) {
- ifp->regen_count++;
- in6_ifa_hold(ifp);
- in6_ifa_hold(ifpub);
- spin_unlock(&ifp->lock);
- write_unlock(&addrconf_hash_lock);
- ipv6_create_tempaddr(ifpub, ifp);
- in6_ifa_put(ifpub);
- in6_ifa_put(ifp);
- goto restart;
- }
- } else if (time_before(ifp->tstamp + ifp->prefered_lft * HZ - regen_advance * HZ, next))
- next = ifp->tstamp + ifp->prefered_lft * HZ - regen_advance * HZ;
- spin_unlock(&ifp->lock);
+ !(ifp->flags&IFA_F_TENTATIVE) &&
+ age >= ifp->prefered_lft - regen_advance) {
+ struct inet6_ifaddr *ifpub = ifp->ifpub;
+ if (time_before(ifp->tstamp + ifp->prefered_lft * HZ, next))
+ next = ifp->tstamp + ifp->prefered_lft * HZ;
+ if (!ifp->regen_count && ifpub) {
+ ifp->regen_count++;
+ in6_ifa_hold(ifp);
+ in6_ifa_hold(ifpub);
+ spin_unlock(&ifp->lock);
+ write_unlock(&addrconf_hash_lock);
+ ipv6_create_tempaddr(ifpub, ifp);
+ in6_ifa_put(ifpub);
+ in6_ifa_put(ifp);
+ goto restart;
+ } else {
+ spin_unlock(&ifp->lock);
+ }
#endif
} else {
/* ifp->prefered_lft <= ifp->valid_lft */
+#ifdef CONFIG_IPV6_PRIVACY
+ if (ifp->flags&IFA_F_TEMPORARY) {
+ if (time_before(ifp->tstamp + ifp->prefered_lft * HZ - regen_advance * HZ, next))
+ next = ifp->tstamp + ifp->prefered_lft * HZ - regen_advance * HZ;
+ } else
+#endif
if (time_before(ifp->tstamp + ifp->prefered_lft * HZ, next))
next = ifp->tstamp + ifp->prefered_lft * HZ;
spin_unlock(&ifp->lock);
@@ -2835,6 +3110,9 @@
array[DEVCONF_MAX_DESYNC_FACTOR] = cnf->max_desync_factor;
#endif
array[DEVCONF_MAX_ADDRESSES] = cnf->max_addresses;
+#ifdef CONFIG_IPV6_MROUTE
+ array[DEVCONF_MCFORWARDING] = cnf->mc_forwarding;
+#endif
}
static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev,
@@ -3147,7 +3425,7 @@
static struct addrconf_sysctl_table
{
struct ctl_table_header *sysctl_header;
- ctl_table addrconf_vars[18];
+ ctl_table addrconf_vars[19];
ctl_table addrconf_dev[2];
ctl_table addrconf_conf_dir[2];
ctl_table addrconf_proto_dir[2];
@@ -3296,6 +3574,16 @@
.mode = 0644,
.proc_handler = &proc_dointvec,
},
+#ifdef CONFIG_IPV6_MROUTE
+ {
+ .ctl_name = NET_IPV6_MC_FORWARDING,
+ .procname = "mc_forwarding",
+ .data = &ipv6_devconf.mc_forwarding,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+#endif
{
.ctl_name = 0, /* sentinel */
}
@@ -3440,6 +3728,9 @@
void __init addrconf_init(void)
{
+#ifdef CONFIG_IPV6_PRIVACY_MD5
+ struct crypto_tfm *tfm;
+#endif /* CONFIG_IPV6_PRIVACY_MD5 */
/* The addrconf netdev notifier requires that loopback_dev
* has it's ipv6 private information allocated and setup
* before it can bring up and give link-local addresses
@@ -3465,12 +3756,22 @@
register_netdevice_notifier(&ipv6_dev_notf);
-#ifdef CONFIG_IPV6_PRIVACY
- md5_tfm = crypto_alloc_tfm("md5", 0);
- if (unlikely(md5_tfm == NULL))
+#ifdef CONFIG_IPV6_PRIVACY_MD5
+ tfm = crypto_alloc_tfm("md5", 0);
+ if (likely(tfm != NULL)) {
+ spin_lock(&md5_tfm_lock);
+ if (likely(md5_tfm == NULL)) {
+ md5_tfm = tfm;
+ spin_unlock(&md5_tfm_lock);
+ } else {
+ spin_unlock(&md5_tfm_lock);
+ crypto_free_tfm(tfm);
+ }
+ } else {
printk(KERN_WARNING
"failed to load transform for md5\n");
-#endif
+ }
+#endif /* CONFIG_IPV6_PRIVACY_MD5 */
addrconf_verify(0);
rtnetlink_links[PF_INET6] = inet6_rtnetlink_table;
@@ -3487,6 +3788,9 @@
struct inet6_dev *idev;
struct inet6_ifaddr *ifa;
int i;
+#ifdef CONFIG_IPV6_PRIVACY_MD5
+ struct crypto_tfm *tfm;
+#endif /* CONFIG_IPV6_PRIVACY_MD5 */
unregister_netdevice_notifier(&ipv6_dev_notf);
@@ -3531,12 +3835,14 @@
rtnl_unlock();
-#ifdef CONFIG_IPV6_PRIVACY
- if (likely(md5_tfm != NULL)) {
- crypto_free_tfm(md5_tfm);
- md5_tfm = NULL;
- }
-#endif
+#ifdef CONFIG_IPV6_PRIVACY_MD5
+ spin_lock(&md5_tfm_lock);
+ tfm = md5_tfm;
+ md5_tfm = NULL;
+ spin_unlock(&md5_tfm_lock);
+ if (likely(tfm))
+ crypto_free_tfm(tfm);
+#endif /* CONFIG_IPV6_PRIVACY_MD5 */
#ifdef CONFIG_PROC_FS
proc_net_remove("if_inet6");
diff -urN linux-2.6.11/net/ipv6/af_inet6.c linux.sinabox/net/ipv6/af_inet6.c
--- linux-2.6.11/net/ipv6/af_inet6.c 2005-03-02 08:38:10.000000000 +0100
+++ linux.sinabox/net/ipv6/af_inet6.c 2005-03-26 19:02:06.000000000 +0100
@@ -13,6 +13,7 @@
* piggy, Karl Knutson : Socket protocol table
* Hideaki YOSHIFUJI : sin6_scope_id support
* Arnaldo Melo : check proc_net_create return, cleanups
+ * Hoerdt Mickael : Added Multicast routing support.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -62,6 +63,9 @@
#include <asm/uaccess.h>
#include <asm/system.h>
+#ifdef CONFIG_IPV6_MROUTE
+#include <linux/mroute6.h>
+#endif
MODULE_AUTHOR("Cast of dozens");
MODULE_DESCRIPTION("IPv6 protocol stack for Linux");
@@ -758,6 +762,9 @@
err = icmpv6_init(&inet6_family_ops);
if (err)
goto icmp_fail;
+#ifdef CONFIG_IPV6_MROUTE
+ ip6_mr_init();
+#endif
err = ndisc_init(&inet6_family_ops);
if (err)
goto ndisc_fail;
diff -urN linux-2.6.11/net/ipv6/ah6.c linux.sinabox/net/ipv6/ah6.c
--- linux-2.6.11/net/ipv6/ah6.c 2005-03-02 08:38:38.000000000 +0100
+++ linux.sinabox/net/ipv6/ah6.c 2005-03-26 19:02:06.000000000 +0100
@@ -264,6 +264,8 @@
hdr_len = skb->data - skb->nh.raw;
ah = (struct ipv6_auth_hdr*)skb->data;
+ if (x->props.replay_window && xfrm_replay_check(x, ah->seq_no))
+ goto out;
ahp = x->data;
nexthdr = ah->nexthdr;
ah_hlen = (ah->hdrlen + 2) << 2;
@@ -302,6 +304,8 @@
}
}
+ if (x->props.replay_window)
+ xfrm_replay_advance(x, ah->seq_no);
skb->nh.raw = skb_pull(skb, ah_hlen);
memcpy(skb->nh.raw, tmp_hdr, hdr_len);
skb->nh.ipv6h->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
diff -urN linux-2.6.11/net/ipv6/anycast.c linux.sinabox/net/ipv6/anycast.c
--- linux-2.6.11/net/ipv6/anycast.c 2005-03-02 08:38:34.000000000 +0100
+++ linux.sinabox/net/ipv6/anycast.c 2005-03-26 19:02:06.000000000 +0100
@@ -48,32 +48,6 @@
/* Big ac list lock for all the sockets */
static DEFINE_RWLOCK(ipv6_sk_ac_lock);
-/* XXX ip6_addr_match() and ip6_onlink() really belong in net/core.c */
-
-static int
-ip6_addr_match(struct in6_addr *addr1, struct in6_addr *addr2, int prefix)
-{
- __u32 mask;
- int i;
-
- if (prefix > 128 || prefix < 0)
- return 0;
- if (prefix == 0)
- return 1;
- for (i=0; i<4; ++i) {
- if (prefix >= 32)
- mask = ~0;
- else
- mask = htonl(~0 << (32 - prefix));
- if ((addr1->s6_addr32[i] ^ addr2->s6_addr32[i]) & mask)
- return 0;
- prefix -= 32;
- if (prefix <= 0)
- break;
- }
- return 1;
-}
-
static int
ip6_onlink(struct in6_addr *addr, struct net_device *dev)
{
@@ -87,8 +61,8 @@
if (idev) {
read_lock_bh(&idev->lock);
for (ifa=idev->addr_list; ifa; ifa=ifa->if_next) {
- onlink = ip6_addr_match(addr, &ifa->addr,
- ifa->prefix_len);
+ onlink = ipv6_prefix_equal(addr, &ifa->addr,
+ ifa->prefix_len);
if (onlink)
break;
}
diff -urN linux-2.6.11/net/ipv6/esp6.c linux.sinabox/net/ipv6/esp6.c
--- linux-2.6.11/net/ipv6/esp6.c 2005-03-02 08:38:12.000000000 +0100
+++ linux.sinabox/net/ipv6/esp6.c 2005-03-26 19:02:06.000000000 +0100
@@ -148,6 +148,7 @@
ret = -EINVAL;
goto out_nofree;
}
+ esph = (struct ipv6_esp_hdr*)skb->data;
if (elen <= 0 || (elen & (blksize-1))) {
ret = -EINVAL;
@@ -166,6 +167,11 @@
u8 sum[esp->auth.icv_full_len];
u8 sum1[alen];
+ if (x->props.replay_window && xfrm_replay_check(x, esph->seq_no)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
esp->auth.icv(esp, skb, 0, skb->len-alen, sum);
if (skb_copy_bits(skb, skb->len-alen, sum1, alen))
@@ -176,6 +182,10 @@
ret = -EINVAL;
goto out;
}
+
+ if (x->props.replay_window)
+ xfrm_replay_advance(x, esph->seq_no);
+
}
if ((nfrags = skb_cow_data(skb, 0, &trailer)) < 0) {
@@ -185,7 +195,6 @@
skb->ip_summed = CHECKSUM_NONE;
- esph = (struct ipv6_esp_hdr*)skb->data;
iph = skb->nh.ipv6h;
/* Get ivec. This can be wrong, check against another impls. */
@@ -307,7 +316,7 @@
if (x->aalg->alg_key_len > 512)
goto error;
}
- if (x->ealg == NULL)
+ if (x->ealg == NULL || (x->ealg->alg_key_len == 0 && x->props.ealgo != SADB_EALG_NULL))
goto error;
if (x->encap)
@@ -349,11 +358,13 @@
goto error;
}
esp->conf.key = x->ealg->alg_key;
- esp->conf.key_len = (x->ealg->alg_key_len+7)/8;
- if (x->props.ealgo == SADB_EALG_NULL)
+ if (x->props.ealgo == SADB_EALG_NULL) {
+ esp->conf.key_len = 0;
esp->conf.tfm = crypto_alloc_tfm(x->ealg->alg_name, CRYPTO_TFM_MODE_ECB);
- else
+ } else {
+ esp->conf.key_len = (x->ealg->alg_key_len+7)/8;
esp->conf.tfm = crypto_alloc_tfm(x->ealg->alg_name, CRYPTO_TFM_MODE_CBC);
+ }
if (esp->conf.tfm == NULL)
goto error;
esp->conf.ivlen = crypto_tfm_alg_ivsize(esp->conf.tfm);
diff -urN linux-2.6.11/net/ipv6/exthdrs.c linux.sinabox/net/ipv6/exthdrs.c
--- linux-2.6.11/net/ipv6/exthdrs.c 2005-03-02 08:37:47.000000000 +0100
+++ linux.sinabox/net/ipv6/exthdrs.c 2005-03-26 19:02:06.000000000 +0100
@@ -156,10 +156,18 @@
{
struct sk_buff *skb = *skbp;
struct inet6_skb_parm *opt = IP6CB(skb);
+#ifdef CONFIG_IPV6_STATISTICS
+ struct dst_entry *dst = skb->dst;
+ struct inet6_dev *idev = ((struct rt6_info *)dst)->rt6i_idev;
+#endif
if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||
!pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS);
+#else
IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
+#endif
kfree_skb(skb);
return -1;
}
@@ -172,7 +180,11 @@
return 1;
}
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS);
+#else
IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
+#endif
return -1;
}
@@ -220,6 +232,10 @@
struct inet6_skb_parm *opt = IP6CB(skb);
struct in6_addr *addr;
struct in6_addr daddr;
+#ifdef CONFIG_IPV6_STATISTICS
+ struct dst_entry *dst = skb->dst;
+ struct inet6_dev *idev = ((struct rt6_info *)dst)->rt6i_idev;
+#endif
int n, i;
struct ipv6_rt_hdr *hdr;
@@ -227,7 +243,11 @@
if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||
!pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS);
+#else
IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
+#endif
kfree_skb(skb);
return -1;
}
@@ -236,7 +256,11 @@
if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr) ||
skb->pkt_type != PACKET_HOST) {
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_INADDRERRORS);
+#else
IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
+#endif
kfree_skb(skb);
return -1;
}
@@ -252,13 +276,21 @@
}
if (hdr->type != IPV6_SRCRT_TYPE_0) {
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS);
+#else
IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
+#endif
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb->nh.raw);
return -1;
}
if (hdr->hdrlen & 0x01) {
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS);
+#else
IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
+#endif
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->hdrlen) - skb->nh.raw);
return -1;
}
@@ -271,7 +303,11 @@
n = hdr->hdrlen >> 1;
if (hdr->segments_left > n) {
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS);
+#else
IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
+#endif
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->segments_left) - skb->nh.raw);
return -1;
}
@@ -284,7 +320,11 @@
kfree_skb(skb);
/* the copy is a forwarded packet */
if (skb2 == NULL) {
- IP6_INC_STATS_BH(IPSTATS_MIB_OUTDISCARDS);
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_OUTDISCARDS);
+#else
+ IP6_INC_STATS_BH(IPSTATS_MIB_OUTDISCARDS);
+#endif
return -1;
}
*skbp = skb = skb2;
@@ -302,7 +342,11 @@
addr += i - 1;
if (ipv6_addr_is_multicast(addr)) {
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_INADDRERRORS);
+#else
IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
+#endif
kfree_skb(skb);
return -1;
}
@@ -321,7 +365,11 @@
if (skb->dst->dev->flags&IFF_LOOPBACK) {
if (skb->nh.ipv6h->hop_limit <= 1) {
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS);
+#else
IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
+#endif
icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
0, skb->dev);
kfree_skb(skb);
@@ -434,29 +482,49 @@
static int ipv6_hop_jumbo(struct sk_buff *skb, int optoff)
{
+#ifdef CONFIG_IPV6_STATISTICS
+ struct dst_entry *dst = skb->dst;
+ struct inet6_dev *idev = ((struct rt6_info *)dst)->rt6i_idev;
+#endif
u32 pkt_len;
if (skb->nh.raw[optoff+1] != 4 || (optoff&3) != 2) {
LIMIT_NETDEBUG(
printk(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n", skb->nh.raw[optoff+1]));
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS);
+#else
IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
+#endif
goto drop;
}
pkt_len = ntohl(*(u32*)(skb->nh.raw+optoff+2));
if (pkt_len <= IPV6_MAXPLEN) {
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS);
+#else
IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
+#endif
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2);
return 0;
}
if (skb->nh.ipv6h->payload_len) {
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS);
+#else
IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
+#endif
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff);
return 0;
}
if (pkt_len > skb->len - sizeof(struct ipv6hdr)) {
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_INTRUNCATEDPKTS);
+#else
IP6_INC_STATS_BH(IPSTATS_MIB_INTRUNCATEDPKTS);
+#endif
goto drop;
}
if (pkt_len + sizeof(struct ipv6hdr) < skb->len) {
@@ -483,11 +551,13 @@
{ -1, }
};
-int ipv6_parse_hopopts(struct sk_buff *skb, int nhoff)
+int ipv6_parse_hopopts(struct sk_buff **skbp, unsigned int *nhoffp)
{
- IP6CB(skb)->hop = sizeof(struct ipv6hdr);
- if (ip6_parse_tlv(tlvprochopopt_lst, skb))
- return sizeof(struct ipv6hdr);
+ IP6CB(*skbp)->hop = sizeof(struct ipv6hdr);
+ if (ip6_parse_tlv(tlvprochopopt_lst, *skbp)) {
+ *nhoffp = sizeof(struct ipv6hdr);
+ return 1;
+ }
return -1;
}
@@ -543,14 +613,34 @@
ipv6_push_rthdr(skb, proto, opt->srcrt, daddr);
if (opt->dst0opt)
ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst0opt);
- if (opt->hopopt)
+ if (skb->len > IPV6_MAXPLEN - (opt->hopopt ? (opt->hopopt->hdrlen+2)<<2 : 0)) {
+ /* data is jumbogram */
+ u8 *hopt = skb_push(skb, 8);
+ if (opt->hopopt) {
+ u8 *hlen;
+ ipv6_push_exthdr(skb, proto, NEXTHDR_HOP, opt->hopopt);
+ hlen = skb->data + 1;
+ (*hlen)++;
+ hopt[0] = IPV6_TLV_PADN;
+ hopt[1] = 0;
+ } else {
+ hopt[0] = *proto;
+ hopt[1] = 0;
+ }
+ hopt[2] = 0xC2;
+ hopt[3] = 4;
+ *(u32 *)&hopt[4] = htonl(skb->len);
+ *proto = NEXTHDR_HOP;
+ } else if (opt->hopopt)
ipv6_push_exthdr(skb, proto, NEXTHDR_HOP, opt->hopopt);
}
void ipv6_push_frag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, u8 *proto)
{
- if (opt->dst1opt)
+ if (opt->dst1opt) {
ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst1opt);
+ skb->h.raw = skb->data;
+ }
}
struct ipv6_txoptions *
diff -urN linux-2.6.11/net/ipv6/icmp.c linux.sinabox/net/ipv6/icmp.c
--- linux-2.6.11/net/ipv6/icmp.c 2005-03-02 08:37:52.000000000 +0100
+++ linux.sinabox/net/ipv6/icmp.c 2005-03-26 19:02:06.000000000 +0100
@@ -176,7 +176,11 @@
*/
dst = ip6_route_output(sk, fl);
if (dst->error) {
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS((((struct rt6_info *)dst)->rt6i_idev), IPSTATS_MIB_OUTNOROUTES);
+#else
IP6_INC_STATS(IPSTATS_MIB_OUTNOROUTES);
+#endif
} else if (dst->dev && (dst->dev->flags&IFF_LOOPBACK)) {
res = 1;
} else {
@@ -381,6 +385,8 @@
hlimit = np->hop_limit;
if (hlimit < 0)
hlimit = dst_metric(dst, RTAX_HOPLIMIT);
+ if (hlimit < 0)
+ hlimit = ipv6_get_hoplimit(dst->dev);
msg.skb = skb;
msg.offset = skb->nh.raw - skb->data;
@@ -467,6 +473,8 @@
hlimit = np->hop_limit;
if (hlimit < 0)
hlimit = dst_metric(dst, RTAX_HOPLIMIT);
+ if (hlimit < 0)
+ hlimit = ipv6_get_hoplimit(dst->dev);
idev = in6_dev_get(skb->dev);
diff -urN linux-2.6.11/net/ipv6/ip6_fib.c linux.sinabox/net/ipv6/ip6_fib.c
--- linux-2.6.11/net/ipv6/ip6_fib.c 2005-03-02 08:38:19.000000000 +0100
+++ linux.sinabox/net/ipv6/ip6_fib.c 2005-03-26 19:02:06.000000000 +0100
@@ -18,6 +18,7 @@
* Yuji SEKIYA @USAGI: Support default route on router node;
* remove ip6_null_entry from the top of
* routing table.
+ * Ville Nuorvala: Fixes to source address sub trees
*/
#include <linux/config.h>
#include <linux/errno.h>
@@ -49,6 +50,11 @@
struct rt6_statistics rt6_stats;
+#if !defined(CONFIG_IPV6_NEW_ROUNDROBIN)
+extern struct rt6_info *rt6_dflt_pointer;
+extern spinlock_t rt6_dflt_lock;
+#endif
+
static kmem_cache_t * fib6_node_kmem;
enum fib_walk_state_t
@@ -80,6 +86,7 @@
#define SUBTREE(fn) NULL
#endif
+static struct rt6_info * fib6_find_prefix(struct fib6_node *fn);
static void fib6_prune_clones(struct fib6_node *fn, struct rt6_info *rt);
static struct fib6_node * fib6_repair_tree(struct fib6_node *fn);
@@ -117,36 +124,6 @@
*/
/*
- * compare "prefix length" bits of an address
- */
-
-static __inline__ int addr_match(void *token1, void *token2, int prefixlen)
-{
- __u32 *a1 = token1;
- __u32 *a2 = token2;
- int pdw;
- int pbi;
-
- pdw = prefixlen >> 5; /* num of whole __u32 in prefix */
- pbi = prefixlen & 0x1f; /* num of bits in incomplete u32 in prefix */
-
- if (pdw)
- if (memcmp(a1, a2, pdw << 2))
- return 0;
-
- if (pbi) {
- __u32 mask;
-
- mask = htonl((0xffffffff) << (32 - pbi));
-
- if ((a1[pdw] ^ a2[pdw]) & mask)
- return 0;
- }
-
- return 1;
-}
-
-/*
* test bit
*/
@@ -261,7 +238,7 @@
* Prefix match
*/
if (plen < fn->fn_bit ||
- !addr_match(&key->addr, addr, fn->fn_bit))
+ !ipv6_prefix_equal(&key->addr, addr, fn->fn_bit))
goto insert_above;
/*
@@ -513,6 +490,9 @@
{
struct fib6_node *fn;
int err = -ENOMEM;
+#ifdef CONFIG_IPV6_SUBTREES
+ struct fib6_node *pn = NULL;
+#endif
fn = fib6_add_1(root, &rt->rt6i_dst.addr, sizeof(struct in6_addr),
rt->rt6i_dst.plen, offsetof(struct rt6_info, rt6i_dst));
@@ -565,10 +545,6 @@
/* Now link new subtree to main tree */
sfn->parent = fn;
fn->subtree = sfn;
- if (fn->leaf == NULL) {
- fn->leaf = rt;
- atomic_inc(&rt->rt6i_ref);
- }
} else {
sn = fib6_add_1(fn->subtree, &rt->rt6i_src.addr,
sizeof(struct in6_addr), rt->rt6i_src.plen,
@@ -578,6 +554,13 @@
goto st_failure;
}
+ /* fib6_add_1 might have cleared the old leaf pointer */
+ if (fn->leaf == NULL) {
+ fn->leaf = rt;
+ atomic_inc(&rt->rt6i_ref);
+ }
+
+ pn = fn;
fn = sn;
}
#endif
@@ -591,8 +574,29 @@
}
out:
- if (err)
+ if (err) {
+#ifdef CONFIG_IPV6_SUBTREES
+ /* If fib6_add_1 has cleared the old leaf pointer in the
+ * super-tree leaf node, we have to find a new one for it.
+ *
+ * This situation will never arise in the sub-tree since
+ * the node will at least have the duplicate route that
+ * caused fib6_add_rt2node to fail in the first place.
+ */
+
+ if (pn && !(pn->fn_flags & RTN_RTINFO)) {
+ pn->leaf = fib6_find_prefix(pn);
+#if RT6_DEBUG >= 2
+ if (!pn->leaf) {
+ BUG_TRAP(pn->leaf);
+ pn->leaf = &ip6_null_entry;
+ }
+#endif
+ atomic_inc(&pn->leaf->rt6i_ref);
+ }
+#endif
dst_free(&rt->u.dst);
+ }
return err;
#ifdef CONFIG_IPV6_SUBTREES
@@ -667,7 +671,7 @@
key = (struct rt6key *) ((u8 *) fn->leaf +
args->offset);
- if (addr_match(&key->addr, args->addr, key->plen))
+ if (ipv6_prefix_equal(&key->addr, args->addr, key->plen))
return fn;
}
@@ -680,16 +684,19 @@
struct fib6_node * fib6_lookup(struct fib6_node *root, struct in6_addr *daddr,
struct in6_addr *saddr)
{
- struct lookup_args args[2];
struct fib6_node *fn;
-
- args[0].offset = offsetof(struct rt6_info, rt6i_dst);
- args[0].addr = daddr;
-
+ struct lookup_args args[2] = {
+ {
+ .offset = offsetof(struct rt6_info, rt6i_dst),
+ .addr = daddr,
+ },
#ifdef CONFIG_IPV6_SUBTREES
- args[1].offset = offsetof(struct rt6_info, rt6i_src);
- args[1].addr = saddr;
+ {
+ .offset = offsetof(struct rt6_info, rt6i_src),
+ .addr = saddr,
+ },
#endif
+ };
fn = fib6_lookup_1(root, args);
@@ -718,7 +725,7 @@
* Prefix match
*/
if (plen < fn->fn_bit ||
- !addr_match(&key->addr, addr, fn->fn_bit))
+ !ipv6_prefix_equal(&key->addr, addr, fn->fn_bit))
return NULL;
if (plen == fn->fn_bit)
@@ -747,10 +754,8 @@
#ifdef CONFIG_IPV6_SUBTREES
if (src_len) {
BUG_TRAP(saddr!=NULL);
- if (fn == NULL)
- fn = fn->subtree;
if (fn)
- fn = fib6_locate_1(fn, saddr, src_len,
+ fn = fib6_locate_1(fn->subtree, saddr, src_len,
offsetof(struct rt6_info, rt6i_src));
}
#endif
@@ -1184,7 +1189,9 @@
if (rt->rt6i_flags&RTF_EXPIRES && rt->rt6i_expires) {
if (time_after(now, rt->rt6i_expires)) {
RT6_TRACE("expiring %p\n", rt);
+#if !defined(CONFIG_IPV6_NEW_ROUNDROBIN)
rt6_reset_dflt_pointer(rt);
+#endif
return -1;
}
gc_args.more++;
diff -urN linux-2.6.11/net/ipv6/ip6_input.c linux.sinabox/net/ipv6/ip6_input.c
--- linux-2.6.11/net/ipv6/ip6_input.c 2005-03-02 08:38:17.000000000 +0100
+++ linux.sinabox/net/ipv6/ip6_input.c 2005-03-26 19:02:06.000000000 +0100
@@ -19,6 +19,7 @@
*
* Mitsuru KANDA @USAGI and
* YOSHIFUJI Hideaki @USAGI: Remove ipv6_parse_exthdrs().
+ * Hoerdt Mickael : Added Multicast routing support.
*/
#include <linux/errno.h>
@@ -59,15 +60,27 @@
int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
{
struct ipv6hdr *hdr;
+#ifdef CONFIG_IPV6_STATISTICS
+ struct inet6_dev *idev = NULL;
+#endif
u32 pkt_len;
if (skb->pkt_type == PACKET_OTHERHOST)
goto drop;
+#ifdef CONFIG_IPV6_STATISTICS
+ idev = in6_dev_get(dev);
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_INRECEIVES);
+#else
IP6_INC_STATS_BH(IPSTATS_MIB_INRECEIVES);
+#endif
if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_INDISCARDS);
+#else
IP6_INC_STATS_BH(IPSTATS_MIB_INDISCARDS);
+#endif
goto out;
}
@@ -79,10 +92,8 @@
if (skb->len < sizeof(struct ipv6hdr))
goto err;
- if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) {
- IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
- goto drop;
- }
+ if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
+ goto err;
hdr = skb->nh.ipv6h;
@@ -96,10 +107,8 @@
if (pkt_len + sizeof(struct ipv6hdr) > skb->len)
goto truncated;
if (pkt_len + sizeof(struct ipv6hdr) < skb->len) {
- if (__pskb_trim(skb, pkt_len + sizeof(struct ipv6hdr))){
- IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
- goto drop;
- }
+ if (__pskb_trim(skb, pkt_len + sizeof(struct ipv6hdr)))
+ goto err;
hdr = skb->nh.ipv6h;
if (skb->ip_summed == CHECKSUM_HW)
skb->ip_summed = CHECKSUM_NONE;
@@ -107,22 +116,39 @@
}
if (hdr->nexthdr == NEXTHDR_HOP) {
+ unsigned int nhoff = offsetof(struct ipv6hdr, nexthdr);
skb->h.raw = (u8*)(hdr+1);
- if (ipv6_parse_hopopts(skb, offsetof(struct ipv6hdr, nexthdr)) < 0) {
- IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
- return 0;
+ if (ipv6_parse_hopopts(&skb, &nhoff) < 0) {
+ skb = NULL;
+ goto err;
}
- hdr = skb->nh.ipv6h;
}
+#ifdef CONFIG_IPV6_STATISTICS
+ if (idev)
+ in6_dev_put(idev);
+#endif
return NF_HOOK(PF_INET6,NF_IP6_PRE_ROUTING, skb, dev, NULL, ip6_rcv_finish);
truncated:
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_INTRUNCATEDPKTS);
+#else
IP6_INC_STATS_BH(IPSTATS_MIB_INTRUNCATEDPKTS);
+#endif
err:
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS);
+#else
IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
+#endif
drop:
- kfree_skb(skb);
+ if (skb)
+ kfree_skb(skb);
out:
+#ifdef CONFIG_IPV6_STATISTICS
+ if (idev)
+ in6_dev_put(idev);
+#endif
return 0;
}
@@ -135,17 +161,16 @@
{
struct inet6_protocol *ipprot;
struct sock *raw_sk;
+#ifdef CONFIG_IPV6_STATISTICS
+ struct dst_entry *dst = skb->dst;
+ struct inet6_dev *idev = ((struct rt6_info *)dst)->rt6i_idev;
+#endif
unsigned int nhoff;
int nexthdr;
u8 hash;
int cksum_sub = 0;
skb->h.raw = skb->nh.raw + sizeof(struct ipv6hdr);
-
- /*
- * Parse extension headers
- */
-
nexthdr = skb->nh.ipv6h->nexthdr;
nhoff = offsetof(struct ipv6hdr, nexthdr);
@@ -193,15 +218,27 @@
if (ret > 0)
goto resubmit;
else if (ret == 0)
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_INDELIVERS);
+#else
IP6_INC_STATS_BH(IPSTATS_MIB_INDELIVERS);
+#endif
} else {
if (!raw_sk) {
if (xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_INUNKNOWNPROTOS);
+#else
IP6_INC_STATS_BH(IPSTATS_MIB_INUNKNOWNPROTOS);
+#endif
icmpv6_param_prob(skb, ICMPV6_UNK_NEXTHDR, nhoff);
}
} else {
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_INDELIVERS);
+#else
IP6_INC_STATS_BH(IPSTATS_MIB_INDELIVERS);
+#endif
kfree_skb(skb);
}
}
@@ -209,7 +246,11 @@
return 0;
discard:
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_INDISCARDS);
+#else
IP6_INC_STATS_BH(IPSTATS_MIB_INDISCARDS);
+#endif
rcu_read_unlock();
kfree_skb(skb);
return 0;
@@ -224,18 +265,65 @@
int ip6_mc_input(struct sk_buff *skb)
{
struct ipv6hdr *hdr;
+#if defined(CONFIG_IPV6_STATISTICS) || defined(CONFIG_IPV6_MROUTE)
+ struct dst_entry *dst = skb->dst;
+#endif
+#ifdef CONFIG_IPV6_STATISTICS
+ struct inet6_dev *idev = ((struct rt6_info *)dst)->rt6i_idev;
+#endif
int deliver;
+ int discard = 1;
+#ifdef CONFIG_IPV6_MROUTE
+ skb->dev = dst->dev;
+#endif
+
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_INMCASTPKTS);
+#else
IP6_INC_STATS_BH(IPSTATS_MIB_INMCASTPKTS);
+#endif
hdr = skb->nh.ipv6h;
deliver = likely(!(skb->dev->flags & (IFF_PROMISC|IFF_ALLMULTI))) ||
ipv6_chk_mcast_addr(skb->dev, &hdr->daddr, NULL);
+#ifdef CONFIG_IPV6_MROUTE
/*
- * IPv6 multicast router mode isnt currently supported.
+ * IPv6 multicast router mode is now supported ;)
*/
+ if (ipv6_devconf.mc_forwarding == 1) {
+ int addr_typed;
+ int addr_types;
+
+ addr_typed = ipv6_addr_type(&hdr->daddr);
+ addr_types = ipv6_addr_type(&hdr->saddr);
+
+ if (!(addr_typed & (IPV6_ADDR_LOOPBACK | IPV6_ADDR_LINKLOCAL))) {
+ struct sk_buff *skb2;
+
+ /* check if this is a mld message */
+ if(hdr->nexthdr == NEXTHDR_HOP) {
+ if(skb->h.raw[0] == IPPROTO_ICMPV6 ){
+ ip6_input(skb);
+ return 0;
+ }
+ }
+
+ if (deliver) {
+ skb2 = skb_clone(skb,GFP_ATOMIC);
+ } else {
+ discard = 0;
+ skb2 = skb;
+ }
+ ip6_mr_input(skb2);
+ }
+ }
+#else
#if 0
+ /*
+ * IPv6 multicast router mode isnt currently supported.
+ */
if (ipv6_config.multicast_route) {
int addr_type;
@@ -257,13 +345,14 @@
}
}
#endif
+#endif
if (likely(deliver)) {
+ discard = 0;
ip6_input(skb);
- return 0;
}
/* discard */
- kfree_skb(skb);
-
+ if (discard)
+ kfree_skb(skb);
return 0;
}
diff -urN linux-2.6.11/net/ipv6/ip6mr.c linux.sinabox/net/ipv6/ip6mr.c
--- linux-2.6.11/net/ipv6/ip6mr.c 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/net/ipv6/ip6mr.c 2005-03-26 19:02:06.000000000 +0100
@@ -0,0 +1,1682 @@
+/*
+ * Linux IPv6 multicast routing support for BSD pim6sd
+ *
+ * (c) 2004 Mickael Hoerdt, <hoerdt@clarinet.u-strasbg.fr>
+ * LSIIT Laboratory, Strasbourg, France
+ * (c) 2004 Jean-Philippe Andriot, <jean-philippe.andriot@6WIND.com>
+ * 6WIND, Paris, France
+ *
+ * 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.
+ *
+ * Version: $Id: ip6mr.c,v 1.1 2004/12/27 17:54:01 hoerdt Exp $
+ *
+ * Fixes:
+ * Michael Chastain : Incorrect size of copying.
+ * Alan Cox : Added the cache manager code
+ * Alan Cox : Fixed the clone/copy bug and device race.
+ * Mike McLagan : Routing by source
+ * Malcolm Beattie : Buffer handling fixes.
+ * Alexey Kuznetsov : Double buffer free and other fixes.
+ * SVR Anand : Fixed several multicast bugs and problems.
+ * Alexey Kuznetsov : Status, optimisations and more.
+ * Brad Parker : Better behaviour on mrouted upcall
+ * overflow.
+ * Carlos Picoto : PIMv1 Support
+ * Pavlin Ivanov Radoslavov: PIMv2 Registers must checksum only PIM header
+ * Relax this requirement to work with older peers.
+ * Mickael Hoerdt and : IPv6 support based on linux/net/ipv4/ipmr.c [Linux 2.x]
+ * Jean-Philippe Andriot on netinet/ip6_mroute.c [*BSD]
+ *
+ */
+
+#include <linux/config.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/fcntl.h>
+#include <linux/stat.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/igmp.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/mroute.h>
+#include <linux/init.h>
+#include <net/ip.h>
+#include <net/protocol.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/icmp.h>
+#include <net/udp.h>
+#include <net/raw.h>
+#include <linux/notifier.h>
+#include <linux/if_arp.h>
+#include <linux/netfilter_ipv4.h>
+#include <net/ipip.h>
+#include <net/checksum.h>
+
+
+#include <net/ipv6.h>
+#include <net/ip6_route.h>
+#include <linux/mroute6.h>
+#include <net/addrconf.h>
+#include <linux/netfilter_ipv6.h>
+
+struct sock *mroute6_socket;
+
+
+/* Big lock, protecting vif table, mrt cache and mroute socket state.
+ Note that the changes are semaphored via rtnl_lock.
+ */
+
+static rwlock_t mrt_lock = RW_LOCK_UNLOCKED;
+
+/*
+ * Multicast router control variables
+ */
+
+static struct mif_device vif6_table[MAXMIFS]; /* Devices */
+static int maxvif;
+
+#define MIF_EXISTS(idx) (vif6_table[idx].dev != NULL)
+
+static int mroute_do_assert; /* Set in PIM assert */
+static int mroute_do_pim;
+
+static struct mfc6_cache *mfc6_cache_array[MFC_LINES]; /* Forwarding cache */
+
+static struct mfc6_cache *mfc_unres_queue; /* Queue of unresolved entries */
+static atomic_t cache_resolve_queue_len; /* Size of unresolved */
+
+/* Special spinlock for queue of unresolved entries */
+static spinlock_t mfc_unres_lock = SPIN_LOCK_UNLOCKED;
+
+/* We return to original Alan's scheme. Hash table of resolved
+ entries is changed only in process context and protected
+ with weak lock mrt_lock. Queue of unresolved entries is protected
+ with strong spinlock mfc_unres_lock.
+
+ In this case data path is free of exclusive locks at all.
+ */
+
+static kmem_cache_t *mrt_cachep;
+
+static int ip6_mr_forward(struct sk_buff *skb, struct mfc6_cache *cache, int local);
+static int ip6mr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert);
+static int ip6mr_fill_mroute(struct sk_buff *skb, struct mfc6_cache *c, struct rtmsg *rtm);
+
+static struct inet6_protocol pim6_protocol;
+
+static struct timer_list ipmr_expire_timer;
+
+
+#ifdef CONFIG_PROC_FS
+
+struct ipmr_mfc_iter {
+ struct mfc6_cache **cache;
+ int ct;
+};
+
+
+static struct mfc6_cache *ipmr_mfc_seq_idx(struct ipmr_mfc_iter *it, loff_t pos)
+{
+ struct mfc6_cache *mfc;
+
+ it->cache = mfc6_cache_array;
+ read_lock(&mrt_lock);
+ for (it->ct = 0; it->ct < MFC_LINES; it->ct++)
+ for(mfc = mfc6_cache_array[it->ct]; mfc; mfc = mfc->next)
+ if (pos-- == 0)
+ return mfc;
+ read_unlock(&mrt_lock);
+
+ it->cache = &mfc_unres_queue;
+ spin_lock_bh(&mfc_unres_lock);
+ for(mfc = mfc_unres_queue; mfc; mfc = mfc->next)
+ if (pos-- == 0)
+ return mfc;
+ spin_unlock_bh(&mfc_unres_lock);
+
+ it->cache = NULL;
+ return NULL;
+}
+
+
+
+
+/*
+ * The /proc interfaces to multicast routing /proc/ip6_mr_cache /proc/ip6_mr_vif
+ */
+
+struct ipmr_vif_iter {
+ int ct;
+};
+
+static struct mif_device *ip6mr_vif_seq_idx(struct ipmr_vif_iter *iter,
+ loff_t pos)
+{
+ for (iter->ct = 0; iter->ct < maxvif; ++iter->ct) {
+ if(!MIF_EXISTS(iter->ct))
+ continue;
+ if (pos-- == 0)
+ return &vif6_table[iter->ct];
+ }
+ return NULL;
+}
+
+static void *ip6mr_vif_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ read_lock(&mrt_lock);
+ return *pos ? ip6mr_vif_seq_idx(seq->private, *pos - 1)
+ : SEQ_START_TOKEN;
+}
+
+static void *ip6mr_vif_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ struct ipmr_vif_iter *iter = seq->private;
+
+ ++*pos;
+ if (v == SEQ_START_TOKEN)
+ return ip6mr_vif_seq_idx(iter, 0);
+
+ while (++iter->ct < maxvif) {
+ if(!MIF_EXISTS(iter->ct))
+ continue;
+ return &vif6_table[iter->ct];
+ }
+ return NULL;
+}
+
+static void ip6mr_vif_seq_stop(struct seq_file *seq, void *v)
+{
+ read_unlock(&mrt_lock);
+}
+
+static int ip6mr_vif_seq_show(struct seq_file *seq, void *v)
+{
+ if (v == SEQ_START_TOKEN) {
+ seq_puts(seq,
+ "Interface BytesIn PktsIn BytesOut PktsOut Flags\n");
+ } else {
+ const struct mif_device *vif = v;
+ const char *name = vif->dev ? vif->dev->name : "none";
+
+ seq_printf(seq,
+ "%2Zd %-10s %8ld %7ld %8ld %7ld %05X\n",
+ vif - vif6_table,
+ name, vif->bytes_in, vif->pkt_in,
+ vif->bytes_out, vif->pkt_out,
+ vif->flags);
+ }
+ return 0;
+}
+
+static struct seq_operations ip6mr_vif_seq_ops = {
+ .start = ip6mr_vif_seq_start,
+ .next = ip6mr_vif_seq_next,
+ .stop = ip6mr_vif_seq_stop,
+ .show = ip6mr_vif_seq_show,
+};
+
+static int ip6mr_vif_open(struct inode *inode, struct file *file)
+{
+ struct seq_file *seq;
+ int rc = -ENOMEM;
+ struct ipmr_vif_iter *s = kmalloc(sizeof(*s), GFP_KERNEL);
+
+ if (!s)
+ goto out;
+
+ rc = seq_open(file, &ip6mr_vif_seq_ops);
+ if (rc)
+ goto out_kfree;
+
+ s->ct = 0;
+ seq = file->private_data;
+ seq->private = s;
+out:
+ return rc;
+out_kfree:
+ kfree(s);
+ goto out;
+
+}
+
+static struct file_operations ip6mr_vif_fops = {
+ .owner = THIS_MODULE,
+ .open = ip6mr_vif_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ return *pos ? ipmr_mfc_seq_idx(seq->private, *pos - 1)
+ : SEQ_START_TOKEN;
+}
+
+static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ struct mfc6_cache *mfc = v;
+ struct ipmr_mfc_iter *it = seq->private;
+
+ ++*pos;
+
+ if (v == SEQ_START_TOKEN)
+ return ipmr_mfc_seq_idx(seq->private, 0);
+
+ if (mfc->next)
+ return mfc->next;
+
+ if (it->cache == &mfc_unres_queue)
+ goto end_of_list;
+
+ BUG_ON(it->cache != mfc6_cache_array);
+
+ while (++it->ct < MFC_LINES) {
+ mfc = mfc6_cache_array[it->ct];
+ if (mfc)
+ return mfc;
+ }
+
+ /* exhausted cache_array, show unresolved */
+ read_unlock(&mrt_lock);
+ it->cache = &mfc_unres_queue;
+ it->ct = 0;
+
+ spin_lock_bh(&mfc_unres_lock);
+ mfc = mfc_unres_queue;
+ if (mfc)
+ return mfc;
+
+ end_of_list:
+ spin_unlock_bh(&mfc_unres_lock);
+ it->cache = NULL;
+
+ return NULL;
+}
+
+static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v)
+{
+ struct ipmr_mfc_iter *it = seq->private;
+
+ if (it->cache == &mfc_unres_queue)
+ spin_unlock_bh(&mfc_unres_lock);
+ else if (it->cache == mfc6_cache_array)
+ read_unlock(&mrt_lock);
+}
+
+static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
+{
+ int n;
+
+ if (v == SEQ_START_TOKEN) {
+ seq_puts(seq,
+ "Group Origin Iif Pkts Bytes Wrong Oifs\n");
+ } else {
+ const struct mfc6_cache *mfc = v;
+ const struct ipmr_mfc_iter *it = seq->private;
+ int i;
+
+ for(i=0;i<16;i++) {
+ seq_printf(seq,"%02x",mfc->mf6c_mcastgrp.s6_addr[i]);
+ }
+ seq_printf(seq," ");
+ for(i=0;i<16;i++) {
+ seq_printf(seq,"%02x",mfc->mf6c_origin.s6_addr[i]);
+ }
+ seq_printf(seq," ");
+
+ seq_printf(seq, "%-3d %8ld %8ld %8ld",
+ mfc->mf6c_parent,
+ mfc->mfc_un.res.pkt,
+ mfc->mfc_un.res.bytes,
+ mfc->mfc_un.res.wrong_if);
+
+ if (it->cache != &mfc_unres_queue) {
+ for(n = mfc->mfc_un.res.minvif;
+ n < mfc->mfc_un.res.maxvif; n++ ) {
+ if(MIF_EXISTS(n)
+ && mfc->mfc_un.res.ttls[n] < 255)
+ seq_printf(seq,
+ " %2d:%-3d",
+ n, mfc->mfc_un.res.ttls[n]);
+ }
+ }
+ seq_putc(seq, '\n');
+ }
+ return 0;
+}
+
+static struct seq_operations ipmr_mfc_seq_ops = {
+ .start = ipmr_mfc_seq_start,
+ .next = ipmr_mfc_seq_next,
+ .stop = ipmr_mfc_seq_stop,
+ .show = ipmr_mfc_seq_show,
+};
+
+static int ipmr_mfc_open(struct inode *inode, struct file *file)
+{
+ struct seq_file *seq;
+ int rc = -ENOMEM;
+ struct ipmr_mfc_iter *s = kmalloc(sizeof(*s), GFP_KERNEL);
+
+ if (!s)
+ goto out;
+
+ rc = seq_open(file, &ipmr_mfc_seq_ops);
+ if (rc)
+ goto out_kfree;
+
+ memset(s, 0, sizeof(*s));
+ seq = file->private_data;
+ seq->private = s;
+out:
+ return rc;
+out_kfree:
+ kfree(s);
+ goto out;
+
+}
+
+static struct file_operations ip6mr_mfc_fops = {
+ .owner = THIS_MODULE,
+ .open = ipmr_mfc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+#endif
+
+#ifdef CONFIG_IPV6_PIMSM_V2
+static int reg_vif_num = -1;
+
+static int pim6_rcv(struct sk_buff **pskb,unsigned int *nhoffp)
+{
+ struct pimreghdr *pim;
+ struct ipv6hdr *encap;
+ struct sk_buff *skb = *pskb;
+ struct net_device *reg_dev = NULL;
+
+ if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(*encap)))
+ goto drop;
+
+ pim = (struct pimreghdr*)skb->h.raw;
+ if (pim->type != ((PIM_VERSION<<4)|(PIM_REGISTER)) ||
+ (pim->flags&PIM_NULL_REGISTER) ||
+ (ip_compute_csum((void *)pim, sizeof(*pim)) != 0 &&
+ (u16)csum_fold(skb_checksum(skb, 0, skb->len, 0))))
+ goto drop;
+
+ /* check if the inner packet is destined to mcast group */
+ encap = (struct ipv6hdr*)(skb->h.raw + sizeof(struct pimreghdr));
+
+ if(!(ipv6_addr_type(&encap->daddr)&IPV6_ADDR_MULTICAST) ||
+ encap->payload_len == 0 ||
+ ntohs(encap->payload_len) + sizeof(*pim) > skb->len)
+ goto drop;
+
+ read_lock(&mrt_lock);
+ if (reg_vif_num >= 0)
+ reg_dev = vif6_table[reg_vif_num].dev;
+ if (reg_dev)
+ dev_hold(reg_dev);
+ read_unlock(&mrt_lock);
+
+ if (reg_dev == NULL)
+ goto drop;
+
+ skb->mac.raw = skb->nh.raw;
+ skb_pull(skb, (u8*)encap - skb->data);
+ skb->nh.ipv6h = (struct ipv6hdr *)skb->data;
+ skb->dev = reg_dev;
+ skb->protocol = htons(ETH_P_IP);
+ skb->ip_summed = 0;
+ skb->pkt_type = PACKET_HOST;
+ dst_release(skb->dst);
+ ((struct net_device_stats*)reg_dev->priv)->rx_bytes += skb->len;
+ ((struct net_device_stats*)reg_dev->priv)->rx_packets++;
+ skb->dst = NULL;
+#ifdef CONFIG_NETFILTER
+ nf_conntrack_put(skb->nfct);
+ skb->nfct = NULL;
+#endif
+ netif_rx(skb);
+ dev_put(reg_dev);
+ return 0;
+ drop:
+ kfree_skb(skb);
+ return 0;
+}
+
+static struct inet6_protocol pim6_protocol = {
+ .handler = pim6_rcv,
+};
+#endif
+
+/* Service routines creating virtual interfaces: PIMREG */
+#ifdef CONFIG_IPV6_PIMSM_V2
+
+
+static int reg_vif_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ read_lock(&mrt_lock);
+ ((struct net_device_stats*)dev->priv)->tx_bytes += skb->len;
+ ((struct net_device_stats*)dev->priv)->tx_packets++;
+ ip6mr_cache_report(skb, reg_vif_num, MRT6MSG_WHOLEPKT);
+ read_unlock(&mrt_lock);
+ kfree_skb(skb);
+ return 0;
+}
+
+static struct net_device_stats *reg_vif_get_stats(struct net_device *dev)
+{
+ return (struct net_device_stats*)dev->priv;
+}
+
+static void reg_vif_setup(struct net_device *dev)
+{
+ dev->type = ARPHRD_PIMREG;
+ dev->mtu = 1500 - sizeof(struct ipv6hdr) - 8;
+ dev->flags = IFF_NOARP;
+ dev->hard_start_xmit = reg_vif_xmit;
+ dev->get_stats = reg_vif_get_stats;
+ dev->destructor = free_netdev;
+}
+
+static struct net_device *ip6mr_reg_vif(void)
+{
+ struct net_device *dev;
+ struct inet6_dev *in_dev;
+
+ dev = alloc_netdev(sizeof(struct net_device_stats), "pim6reg",
+ reg_vif_setup);
+
+ if (dev == NULL)
+ return NULL;
+
+ if (register_netdevice(dev)) {
+ free_netdev(dev);
+ return NULL;
+ }
+ dev->iflink = 0;
+
+ if ((in_dev = ipv6_find_idev(dev)) == NULL) {
+ goto failure;
+ }
+
+/*
+ * if ((in_dev = __in6_dev_get(dev)) == NULL)
+ goto failure;
+*/
+#if 0
+ in_dev->cnf.rp_filter = 0;
+#endif
+
+ if (dev_open(dev))
+ goto failure;
+
+ return dev;
+
+failure:
+ /* allow the register to be completed before unregistering. */
+ rtnl_unlock();
+ rtnl_lock();
+
+ unregister_netdevice(dev);
+ return NULL;
+}
+#endif
+
+/*
+ * Delete a VIF entry
+ */
+
+static int mif6_delete(int vifi)
+{
+ struct mif_device *v;
+ struct net_device *dev;
+ struct inet6_dev *in_dev;
+
+ if (vifi < 0 || vifi >= maxvif)
+ return -EADDRNOTAVAIL;
+
+ v = &vif6_table[vifi];
+
+ write_lock_bh(&mrt_lock);
+ dev = v->dev;
+ v->dev = NULL;
+
+ if (!dev) {
+ write_unlock_bh(&mrt_lock);
+ return -EADDRNOTAVAIL;
+ }
+
+#ifdef CONFIG_IPV6_PIMSM_V2
+ if (vifi == reg_vif_num)
+ reg_vif_num = -1;
+#endif
+
+ if (vifi+1 == maxvif) {
+ int tmp;
+ for (tmp=vifi-1; tmp>=0; tmp--) {
+ if (MIF_EXISTS(tmp))
+ break;
+ }
+ maxvif = tmp+1;
+ }
+
+ write_unlock_bh(&mrt_lock);
+
+ dev_set_allmulti(dev, -1);
+
+ if ((in_dev = __in6_dev_get(dev)) != NULL) {
+ in_dev->cnf.mc_forwarding--;
+ }
+
+ if (v->flags&(MIFF_REGISTER))
+ unregister_netdevice(dev);
+
+ dev_put(dev);
+ return 0;
+}
+
+/* Destroy an unresolved cache entry, killing queued skbs
+ and reporting error to netlink readers.
+ */
+
+static void ip6mr_destroy_unres(struct mfc6_cache *c)
+{
+ struct sk_buff *skb;
+
+ atomic_dec(&cache_resolve_queue_len);
+
+ while((skb=skb_dequeue(&c->mfc_un.unres.unresolved))) {
+ if (skb->nh.ipv6h->version == 0) {
+ struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct ipv6hdr));
+ nlh->nlmsg_type = NLMSG_ERROR;
+ nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
+ skb_trim(skb, nlh->nlmsg_len);
+ ((struct nlmsgerr*)NLMSG_DATA(nlh))->error = -ETIMEDOUT;
+ netlink_unicast(rtnl, skb, NETLINK_CB(skb).dst_pid, MSG_DONTWAIT);
+ } else
+ kfree_skb(skb);
+ }
+
+ kmem_cache_free(mrt_cachep, c);
+}
+
+
+/* Single timer process for all the unresolved queue. */
+
+static void ipmr_expire_process(unsigned long dummy)
+{
+ unsigned long now;
+ unsigned long expires;
+ struct mfc6_cache *c, **cp;
+
+ if (!spin_trylock(&mfc_unres_lock)) {
+ mod_timer(&ipmr_expire_timer, jiffies+HZ/10);
+ return;
+ }
+
+ if (atomic_read(&cache_resolve_queue_len) == 0)
+ goto out;
+
+ now = jiffies;
+ expires = 10*HZ;
+ cp = &mfc_unres_queue;
+
+ while ((c=*cp) != NULL) {
+ if (time_after(c->mfc_un.unres.expires, now)) {
+ unsigned long interval = c->mfc_un.unres.expires - now;
+ if (interval < expires)
+ expires = interval;
+ cp = &c->next;
+ continue;
+ }
+
+ *cp = c->next;
+
+ ip6mr_destroy_unres(c);
+ }
+
+ if (atomic_read(&cache_resolve_queue_len))
+ mod_timer(&ipmr_expire_timer, jiffies + expires);
+
+out:
+ spin_unlock(&mfc_unres_lock);
+}
+
+/* Fill oifs list. It is called under write locked mrt_lock. */
+
+static void ip6mr_update_threshoulds(struct mfc6_cache *cache, unsigned char *ttls)
+{
+ int vifi;
+
+ cache->mfc_un.res.minvif = MAXVIFS;
+ cache->mfc_un.res.maxvif = 0;
+ memset(cache->mfc_un.res.ttls, 255, MAXVIFS);
+
+ for (vifi=0; vifi<maxvif; vifi++) {
+ if (MIF_EXISTS(vifi) && ttls[vifi] && ttls[vifi] < 255) {
+ cache->mfc_un.res.ttls[vifi] = ttls[vifi];
+ if (cache->mfc_un.res.minvif > vifi)
+ cache->mfc_un.res.minvif = vifi;
+ if (cache->mfc_un.res.maxvif <= vifi)
+ cache->mfc_un.res.maxvif = vifi + 1;
+ }
+ }
+}
+
+static int mif6_add(struct mif6ctl *vifc, int mrtsock)
+{
+ int vifi = vifc->mif6c_mifi;
+ struct mif_device *v = &vif6_table[vifi];
+ struct net_device *dev;
+ struct inet6_dev *in_dev;
+
+ /* Is vif busy ? */
+ if (MIF_EXISTS(vifi))
+ return -EADDRINUSE;
+
+ switch (vifc->mif6c_flags) {
+#ifdef CONFIG_IPV6_PIMSM_V2
+ case MIFF_REGISTER:
+ /*
+ * Special Purpose VIF in PIM
+ * All the packets will be sent to the daemon
+ */
+ if (reg_vif_num >= 0)
+ return -EADDRINUSE;
+ dev = ip6mr_reg_vif();
+ if (!dev)
+ return -ENOBUFS;
+ break;
+#endif
+ case 0:
+ dev=dev_get_by_index(vifc->mif6c_pifi);
+ if (!dev)
+ return -EADDRNOTAVAIL;
+ __dev_put(dev);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if ((in_dev = __in6_dev_get(dev)) == NULL)
+ return -EADDRNOTAVAIL;
+ in_dev->cnf.mc_forwarding++;
+ dev_set_allmulti(dev, +1);
+
+ /*
+ * Fill in the VIF structures
+ */
+ v->rate_limit=vifc->vifc_rate_limit;
+ v->flags=vifc->mif6c_flags;
+ if(!mrtsock)
+ v->flags |= VIFF_STATIC;
+ v->threshold=vifc->vifc_threshold;
+ v->bytes_in = 0;
+ v->bytes_out = 0;
+ v->pkt_in = 0;
+ v->pkt_out = 0;
+ v->link = dev->ifindex;
+ if (v->flags&(MIFF_REGISTER))
+ v->link = dev->iflink;
+
+ /* And finish update writing critical data */
+ write_lock_bh(&mrt_lock);
+ dev_hold(dev);
+ v->dev=dev;
+#ifdef CONFIG_IPV6_PIMSM_V2
+ if (v->flags&MIFF_REGISTER)
+ reg_vif_num = vifi;
+#endif
+ if (vifi+1 > maxvif)
+ maxvif = vifi+1;
+ write_unlock_bh(&mrt_lock);
+ return 0;
+}
+
+static struct mfc6_cache *ip6mr_cache_find(struct in6_addr origin,struct in6_addr mcastgrp)
+{
+ int line=MFC6_HASH(mcastgrp,origin);
+ struct mfc6_cache *c;
+
+ for (c=mfc6_cache_array[line]; c; c = c->next) {
+ if (IN6_ARE_ADDR_EQUAL(&c->mf6c_origin,&origin) &&
+ IN6_ARE_ADDR_EQUAL(&c->mf6c_mcastgrp,&mcastgrp))
+ break;
+ }
+ return c;
+}
+
+/*
+ * Allocate a multicast cache entry
+ */
+static struct mfc6_cache *ip6mr_cache_alloc(void)
+{
+ struct mfc6_cache *c=kmem_cache_alloc(mrt_cachep, GFP_KERNEL);
+ if(c==NULL)
+ return NULL;
+ memset(c, 0, sizeof(*c));
+ c->mfc_un.res.minvif = MAXVIFS;
+ return c;
+}
+
+static struct mfc6_cache *ip6mr_cache_alloc_unres(void)
+{
+ struct mfc6_cache *c=kmem_cache_alloc(mrt_cachep, GFP_ATOMIC);
+ if(c==NULL)
+ return NULL;
+ memset(c, 0, sizeof(*c));
+ skb_queue_head_init(&c->mfc_un.unres.unresolved);
+ c->mfc_un.unres.expires = jiffies + 10*HZ;
+ return c;
+}
+
+/*
+ * A cache entry has gone into a resolved state from queued
+ */
+
+static void ip6mr_cache_resolve(struct mfc6_cache *uc, struct mfc6_cache *c)
+{
+ struct sk_buff *skb;
+
+ /*
+ * Play the pending entries through our router
+ */
+
+ while((skb=__skb_dequeue(&uc->mfc_un.unres.unresolved))) {
+ if (skb->nh.ipv6h->version == 0) {
+ int err;
+ struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct ipv6hdr));
+
+ if (ip6mr_fill_mroute(skb, c, NLMSG_DATA(nlh)) > 0) {
+ nlh->nlmsg_len = skb->tail - (u8*)nlh;
+ } else {
+ nlh->nlmsg_type = NLMSG_ERROR;
+ nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
+ skb_trim(skb, nlh->nlmsg_len);
+ ((struct nlmsgerr*)NLMSG_DATA(nlh))->error = -EMSGSIZE;
+ }
+ err = netlink_unicast(rtnl, skb, NETLINK_CB(skb).dst_pid, MSG_DONTWAIT);
+ } else
+ ip6_mr_forward(skb, c, 0);
+ }
+}
+
+/*
+ * Bounce a cache query up to pim6sd. We could use netlink for this but pim6sd
+ * expects the following bizarre scheme.
+ *
+ * Called under mrt_lock.
+ */
+
+static int ip6mr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert)
+{
+ struct sk_buff *skb;
+ struct mrt6msg *msg;
+ int ret;
+
+#ifdef CONFIG_IPV6_PIMSM_V2
+ if (assert == MRT6MSG_WHOLEPKT)
+ skb = skb_realloc_headroom(pkt, sizeof(struct ipv6hdr));
+ else
+#endif
+ skb = alloc_skb(128, GFP_ATOMIC);
+
+ if(!skb)
+ return -ENOBUFS;
+
+ /* I suppose that internal messages
+ * do not require checksums */
+
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+#ifdef CONFIG_IPV6_PIMSM_V2
+ if (assert == MRT6MSG_WHOLEPKT) {
+ /* Ugly, but we have no choice with this interface.
+ Duplicate old header, fix length etc.
+ And all this only to mangle msg->im6_msgtype and
+ to set msg->im6_mbz to "mbz" :-)
+ */
+ msg = (struct mrt6msg*)skb_push(skb, sizeof(struct ipv6hdr));
+ skb->nh.raw = skb->h.raw = (u8*)msg;
+ memcpy(msg, pkt->nh.raw, sizeof(struct ipv6hdr));
+ msg->im6_msgtype = MRT6MSG_WHOLEPKT;
+ msg->im6_mbz = 0;
+ msg->im6_mif = reg_vif_num;
+ } else
+#endif
+ {
+
+ /*
+ * Copy the IP header
+ */
+
+ skb->nh.ipv6h = (struct ipv6hdr *)skb_put(skb, sizeof(struct ipv6hdr));
+ memcpy(skb->data,pkt->data,sizeof(struct ipv6hdr));
+
+ msg = (struct mrt6msg*)skb->nh.ipv6h;
+ skb->dst = dst_clone(pkt->dst);
+
+ /*
+ * Add our header
+ */
+
+ msg->im6_msgtype = assert;
+ msg->im6_mbz = 0;
+ msg->im6_mif = vifi;
+ skb->h.raw = skb->nh.raw;
+ }
+
+ if (mroute6_socket == NULL) {
+ kfree_skb(skb);
+ return -EINVAL;
+ }
+
+ /*
+ * Deliver to user space multicast routing algorithms
+ */
+ if ((ret=sock_queue_rcv_skb(mroute6_socket,skb))<0) {
+ if (net_ratelimit())
+ printk(KERN_WARNING "mroute6: pending queue full, dropping entries.\n");
+ kfree_skb(skb);
+ }
+
+ return ret;
+}
+
+/*
+ * Queue a packet for resolution. It gets locked cache entry!
+ */
+
+static int
+ip6mr_cache_unresolved(vifi_t vifi, struct sk_buff *skb)
+{
+ int err;
+ struct mfc6_cache *c;
+
+ spin_lock_bh(&mfc_unres_lock);
+ for (c=mfc_unres_queue; c; c=c->next) {
+ if (IN6_ARE_ADDR_EQUAL(&c->mf6c_mcastgrp,&skb->nh.ipv6h->daddr) &&
+ IN6_ARE_ADDR_EQUAL(&c->mf6c_origin,&skb->nh.ipv6h->saddr))
+ break;
+ }
+
+ if (c == NULL) {
+ /*
+ * Create a new entry if allowable
+ */
+
+ if (atomic_read(&cache_resolve_queue_len)>=10 ||
+ (c=ip6mr_cache_alloc_unres())==NULL) {
+ spin_unlock_bh(&mfc_unres_lock);
+
+ kfree_skb(skb);
+ return -ENOBUFS;
+ }
+
+ /*
+ * Fill in the new cache entry
+ */
+ c->mf6c_parent=-1;
+ c->mf6c_origin=skb->nh.ipv6h->saddr;
+ c->mf6c_mcastgrp=skb->nh.ipv6h->daddr;
+
+ /*
+ * Reflect first query at pim6sd
+ */
+ if ((err = ip6mr_cache_report(skb, vifi, MRT6MSG_NOCACHE))<0) {
+ /* If the report failed throw the cache entry
+ out - Brad Parker
+ */
+ spin_unlock_bh(&mfc_unres_lock);
+
+ kmem_cache_free(mrt_cachep, c);
+ kfree_skb(skb);
+ return err;
+ }
+
+ atomic_inc(&cache_resolve_queue_len);
+ c->next = mfc_unres_queue;
+ mfc_unres_queue = c;
+
+ mod_timer(&ipmr_expire_timer, c->mfc_un.unres.expires);
+ }
+
+ /*
+ * See if we can append the packet
+ */
+ if (c->mfc_un.unres.unresolved.qlen>3) {
+ kfree_skb(skb);
+ err = -ENOBUFS;
+ } else {
+ skb_queue_tail(&c->mfc_un.unres.unresolved,skb);
+ err = 0;
+ }
+
+ spin_unlock_bh(&mfc_unres_lock);
+ return err;
+}
+
+/*
+ * MFC6 cache manipulation by user space
+ */
+
+static int ip6mr_mfc_delete(struct mf6cctl *mfc)
+{
+ int line;
+ struct mfc6_cache *c, **cp;
+
+ line=MFC6_HASH(mfc->mf6cc_mcastgrp.sin6_addr, mfc->mf6cc_origin.sin6_addr);
+
+ for (cp=&mfc6_cache_array[line]; (c=*cp) != NULL; cp = &c->next) {
+ if (IN6_ARE_ADDR_EQUAL(&c->mf6c_origin,&mfc->mf6cc_origin.sin6_addr) &&
+ IN6_ARE_ADDR_EQUAL(&c->mf6c_mcastgrp,&mfc->mf6cc_mcastgrp.sin6_addr)) {
+ write_lock_bh(&mrt_lock);
+ *cp = c->next;
+ write_unlock_bh(&mrt_lock);
+
+ kmem_cache_free(mrt_cachep, c);
+ return 0;
+ }
+ }
+ return -ENOENT;
+}
+
+static int ip6mr_device_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+ struct mif_device *v;
+ int ct;
+ if (event != NETDEV_UNREGISTER)
+ return NOTIFY_DONE;
+ v=&vif6_table[0];
+ for(ct=0;ct<maxvif;ct++,v++) {
+ if (v->dev==ptr)
+ mif6_delete(ct);
+ }
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block ip6_mr_notifier = {
+ .notifier_call = ip6mr_device_event
+};
+
+/*
+ * Setup for IP multicast routing
+ */
+
+void __init ip6_mr_init(void)
+{
+ printk(KERN_INFO "6WIND/LSIIT IPv6 multicast forwarding 0.1 plus PIM-SM/SSM with *BSD API\n");
+
+ mrt_cachep = kmem_cache_create("ip6_mrt_cache",
+ sizeof(struct mfc6_cache),
+ 0, SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (!mrt_cachep)
+ panic("cannot allocate ip_mrt_cache");
+
+ init_timer(&ipmr_expire_timer);
+ ipmr_expire_timer.function=ipmr_expire_process;
+ register_netdevice_notifier(&ip6_mr_notifier);
+#ifdef CONFIG_PROC_FS
+ proc_net_fops_create("ip6_mr_vif", 0, &ip6mr_vif_fops);
+ proc_net_fops_create("ip6_mr_cache", 0, &ip6mr_mfc_fops);
+#endif
+}
+
+
+static int ip6mr_mfc_add(struct mf6cctl *mfc, int mrtsock)
+{
+ int line;
+ struct mfc6_cache *uc, *c, **cp;
+ unsigned char ttls[MAXVIFS];
+ int i;
+
+ memset(ttls, 255, MAXVIFS);
+ for(i=0;i<MAXVIFS;i++) {
+ if(IF_ISSET(i,&mfc->mf6cc_ifset))
+ ttls[i]=1;
+
+ }
+
+ line=MFC6_HASH(mfc->mf6cc_mcastgrp.sin6_addr, mfc->mf6cc_origin.sin6_addr);
+
+ for (cp=&mfc6_cache_array[line]; (c=*cp) != NULL; cp = &c->next) {
+ if (IN6_ARE_ADDR_EQUAL(&c->mf6c_origin,&mfc->mf6cc_origin.sin6_addr) &&
+ IN6_ARE_ADDR_EQUAL(&c->mf6c_mcastgrp,&mfc->mf6cc_mcastgrp.sin6_addr))
+ break;
+ }
+
+ if (c != NULL) {
+ write_lock_bh(&mrt_lock);
+ c->mf6c_parent = mfc->mf6cc_parent;
+ ip6mr_update_threshoulds(c, ttls);
+ if (!mrtsock)
+ c->mfc_flags |= MFC_STATIC;
+ write_unlock_bh(&mrt_lock);
+ return 0;
+ }
+
+ if(!(ipv6_addr_type(&mfc->mf6cc_mcastgrp.sin6_addr)&IPV6_ADDR_MULTICAST))
+ return -EINVAL;
+
+ c=ip6mr_cache_alloc();
+ if (c==NULL)
+ return -ENOMEM;
+
+ c->mf6c_origin=mfc->mf6cc_origin.sin6_addr;
+ c->mf6c_mcastgrp=mfc->mf6cc_mcastgrp.sin6_addr;
+ c->mf6c_parent=mfc->mf6cc_parent;
+ ip6mr_update_threshoulds(c, ttls);
+ if (!mrtsock)
+ c->mfc_flags |= MFC_STATIC;
+
+ write_lock_bh(&mrt_lock);
+ c->next = mfc6_cache_array[line];
+ mfc6_cache_array[line] = c;
+ write_unlock_bh(&mrt_lock);
+
+ /*
+ * Check to see if we resolved a queued list. If so we
+ * need to send on the frames and tidy up.
+ */
+ spin_lock_bh(&mfc_unres_lock);
+ for (cp = &mfc_unres_queue; (uc=*cp) != NULL;
+ cp = &uc->next) {
+ if (IN6_ARE_ADDR_EQUAL(&uc->mf6c_origin,&c->mf6c_origin) &&
+ IN6_ARE_ADDR_EQUAL(&uc->mf6c_mcastgrp,&c->mf6c_mcastgrp)) {
+ *cp = uc->next;
+ if (atomic_dec_and_test(&cache_resolve_queue_len))
+ del_timer(&ipmr_expire_timer);
+ break;
+ }
+ }
+ spin_unlock_bh(&mfc_unres_lock);
+
+ if (uc) {
+ ip6mr_cache_resolve(uc, c);
+ kmem_cache_free(mrt_cachep, uc);
+ }
+ return 0;
+}
+
+/*
+ * Close the multicast socket, and clear the vif tables etc
+ */
+
+static void mroute_clean_tables(struct sock *sk)
+{
+ int i;
+
+ /*
+ * Shut down all active vif entries
+ */
+ for(i=0; i<maxvif; i++) {
+ if (!(vif6_table[i].flags&VIFF_STATIC))
+ mif6_delete(i);
+ }
+
+ /*
+ * Wipe the cache
+ */
+ for (i=0;i<MFC_LINES;i++) {
+ struct mfc6_cache *c, **cp;
+
+ cp = &mfc6_cache_array[i];
+ while ((c = *cp) != NULL) {
+ if (c->mfc_flags&MFC_STATIC) {
+ cp = &c->next;
+ continue;
+ }
+ write_lock_bh(&mrt_lock);
+ *cp = c->next;
+ write_unlock_bh(&mrt_lock);
+
+ kmem_cache_free(mrt_cachep, c);
+ }
+ }
+
+ if (atomic_read(&cache_resolve_queue_len) != 0) {
+ struct mfc6_cache *c;
+
+ spin_lock_bh(&mfc_unres_lock);
+ while (mfc_unres_queue != NULL) {
+ c = mfc_unres_queue;
+ mfc_unres_queue = c->next;
+ spin_unlock_bh(&mfc_unres_lock);
+
+ ip6mr_destroy_unres(c);
+
+ spin_lock_bh(&mfc_unres_lock);
+ }
+ spin_unlock_bh(&mfc_unres_lock);
+ }
+}
+
+static void mrtsock_destruct(struct sock *sk)
+{
+ rtnl_lock();
+ if (sk == mroute6_socket) {
+ ipv6_devconf.mc_forwarding--;
+
+ write_lock_bh(&mrt_lock);
+ mroute6_socket=NULL;
+ write_unlock_bh(&mrt_lock);
+
+ mroute_clean_tables(sk);
+ }
+ rtnl_unlock();
+}
+
+/*
+ * Socket options and virtual interface manipulation. The whole
+ * virtual interface system is a complete heap, but unfortunately
+ * that's how BSD mrouted happens to think. Maybe one day with a proper
+ * MOSPF/PIM router set up we can clean this up.
+ */
+
+int ip6_mroute_setsockopt(struct sock *sk,int optname,char __user *optval,int optlen)
+{
+ int ret;
+ struct mif6ctl vif;
+ struct mf6cctl mfc;
+ mifi_t mifi;
+
+ if(optname!=MRT6_INIT)
+ {
+ if(sk!=mroute6_socket && !capable(CAP_NET_ADMIN))
+ return -EACCES;
+ }
+
+ switch(optname)
+ {
+ case MRT6_INIT:
+ if (sk->sk_type != SOCK_RAW ||
+ inet_sk(sk)->num != IPPROTO_ICMPV6)
+ return -EOPNOTSUPP;
+ if(optlen!=sizeof(int))
+ return -ENOPROTOOPT;
+
+ rtnl_lock();
+ if (mroute6_socket) {
+ rtnl_unlock();
+ return -EADDRINUSE;
+ }
+
+ ret = ip6_ra_control(sk, 1, mrtsock_destruct);
+ if (ret == 0) {
+ write_lock_bh(&mrt_lock);
+ mroute6_socket=sk;
+ write_unlock_bh(&mrt_lock);
+
+ ipv6_devconf.mc_forwarding++;
+ }
+ rtnl_unlock();
+ return ret;
+ case MRT6_DONE:
+ if (sk!=mroute6_socket)
+ return -EACCES;
+ return ip6_ra_control(sk, -1, NULL);
+ case MRT6_ADD_MIF:
+ if(optlen!=sizeof(vif))
+ return -EINVAL;
+ if (copy_from_user(&vif,optval,sizeof(vif)))
+ return -EFAULT;
+ if(vif.mif6c_mifi >= MAXVIFS)
+ return -ENFILE;
+ rtnl_lock();
+ ret = mif6_add(&vif, sk==mroute6_socket);
+ rtnl_unlock();
+ return ret;
+ case MRT6_DEL_MIF:
+ if(optlen!=sizeof(mifi_t))
+ return -EINVAL;
+ if (copy_from_user(&mifi,optval,sizeof(mifi_t)))
+ return -EFAULT;
+ rtnl_lock();
+ ret = mif6_delete(mifi);
+ rtnl_unlock();
+ return ret;
+
+ /*
+ * Manipulate the forwarding caches. These live
+ * in a sort of kernel/user symbiosis.
+ */
+ case MRT6_ADD_MFC:
+ case MRT6_DEL_MFC:
+ if(optlen!=sizeof(mfc))
+ return -EINVAL;
+ if (copy_from_user(&mfc,optval, sizeof(mfc)))
+ return -EFAULT;
+ rtnl_lock();
+ if (optname==MRT6_DEL_MFC)
+ ret = ip6mr_mfc_delete(&mfc);
+ else
+ ret = ip6mr_mfc_add(&mfc, sk==mroute6_socket);
+ rtnl_unlock();
+ return ret;
+ /*
+ * Control PIM assert (to activate pim will activate assert)
+ */
+ case MRT6_ASSERT:
+ {
+ int v;
+ if(get_user(v,(int __user *)optval))
+ return -EFAULT;
+ mroute_do_assert=(v)?1:0;
+ return 0;
+ }
+#ifdef CONFIG_IPV6_PIMSM_V2
+ case MRT6_PIM:
+ {
+ int v, ret;
+ if(get_user(v,(int __user *)optval))
+ return -EFAULT;
+ v = (v)?1:0;
+ rtnl_lock();
+ ret = 0;
+ if (v != mroute_do_pim) {
+ mroute_do_pim = v;
+ mroute_do_assert = v;
+ if (mroute_do_pim)
+ ret = inet6_add_protocol(&pim6_protocol,
+ IPPROTO_PIM);
+ else
+ ret = inet6_del_protocol(&pim6_protocol,
+ IPPROTO_PIM);
+ if (ret < 0)
+ ret = -EAGAIN;
+ }
+ rtnl_unlock();
+ return ret;
+ }
+#endif
+ /*
+ * Spurious command, or MRT_VERSION which you cannot
+ * set.
+ */
+ default:
+ return -ENOPROTOOPT;
+ }
+}
+
+/*
+ * Getsock opt support for the multicast routing system.
+ */
+
+int ip6_mroute_getsockopt(struct sock *sk,int optname,char __user *optval,int __user *optlen)
+{
+ int olr;
+ int val;
+
+ if(optname!=MRT6_VERSION &&
+#ifdef CONFIG_IPV6_PIMSM_V2
+ optname!=MRT6_PIM &&
+#endif
+ optname!=MRT6_ASSERT)
+ return -ENOPROTOOPT;
+
+ if (get_user(olr, optlen))
+ return -EFAULT;
+
+ olr = min_t(unsigned int, olr, sizeof(int));
+ if (olr < 0)
+ return -EINVAL;
+
+ if(put_user(olr,optlen))
+ return -EFAULT;
+ if(optname==MRT6_VERSION)
+ val=0x0305;
+#ifdef CONFIG_IPV6_PIMSM_V2
+ else if(optname==MRT6_PIM)
+ val=mroute_do_pim;
+#endif
+ else
+ val=mroute_do_assert;
+ if(copy_to_user(optval,&val,olr))
+ return -EFAULT;
+ return 0;
+}
+
+/*
+ * The IP multicast ioctl support routines.
+ */
+
+int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg)
+{
+ struct sioc_sg_req6 sr;
+ struct sioc_mif_req6 vr;
+ struct mif_device *vif;
+ struct mfc6_cache *c;
+
+ switch(cmd)
+ {
+ case SIOCGETMIFCNT_IN6:
+ if (copy_from_user(&vr,arg,sizeof(vr)))
+ return -EFAULT;
+ if(vr.mifi>=maxvif)
+ return -EINVAL;
+ read_lock(&mrt_lock);
+ vif=&vif6_table[vr.mifi];
+ if(MIF_EXISTS(vr.mifi)) {
+ vr.icount=vif->pkt_in;
+ vr.ocount=vif->pkt_out;
+ vr.ibytes=vif->bytes_in;
+ vr.obytes=vif->bytes_out;
+ read_unlock(&mrt_lock);
+
+ if (copy_to_user(arg,&vr,sizeof(vr)))
+ return -EFAULT;
+ return 0;
+ }
+ read_unlock(&mrt_lock);
+ return -EADDRNOTAVAIL;
+ case SIOCGETSGCNT_IN6:
+ if (copy_from_user(&sr,arg,sizeof(sr)))
+ return -EFAULT;
+
+ read_lock(&mrt_lock);
+ c = ip6mr_cache_find(sr.src.sin6_addr, sr.grp.sin6_addr);
+ if (c) {
+ sr.pktcnt = c->mfc_un.res.pkt;
+ sr.bytecnt = c->mfc_un.res.bytes;
+ sr.wrong_if = c->mfc_un.res.wrong_if;
+ read_unlock(&mrt_lock);
+
+ if (copy_to_user(arg,&sr,sizeof(sr)))
+ return -EFAULT;
+ return 0;
+ }
+ read_unlock(&mrt_lock);
+ return -EADDRNOTAVAIL;
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+
+static inline int ip6mr_forward_finish(struct sk_buff *skb)
+{
+#ifdef notyet
+ struct ip_options * opt = &(IP6CB(skb)->opt);
+
+ IP_INC_STATS_BH(OutForwDatagrams);
+
+ if (unlikely(opt->optlen))
+ ip_forward_options(skb);
+#endif
+
+ return dst_output(skb);
+}
+
+/*
+ * Processing handlers for ip6mr_forward
+ */
+
+static void ip6mr_queue_xmit(struct sk_buff *skb, struct mfc6_cache *c, int vifi)
+{
+ struct ipv6hdr *ipv6h = skb->nh.ipv6h;
+ struct mif_device *vif = &vif6_table[vifi];
+ struct net_device *dev;
+#if 0
+ struct rtable *rt;
+ int encap = 0;
+#endif
+ struct in6_addr *snd_addr=&ipv6h->daddr;
+ int full_len = skb->len;
+
+ if (vif->dev == NULL)
+ goto out_free;
+
+#ifdef CONFIG_IPV6_PIMSM_V2
+ if (vif->flags & MIFF_REGISTER) {
+ vif->pkt_out++;
+ vif->bytes_out+=skb->len;
+ ((struct net_device_stats*)vif->dev->priv)->tx_bytes += skb->len;
+ ((struct net_device_stats*)vif->dev->priv)->tx_packets++;
+ ip6mr_cache_report(skb, vifi, MRT6MSG_WHOLEPKT);
+ kfree_skb(skb);
+ return;
+ }
+#endif
+ /*
+ * RFC1584 teaches, that DVMRP/PIM router must deliver packets locally
+ * not only before forwarding, but after forwarding on all output
+ * interfaces. It is clear, if mrouter runs a multicasting
+ * program, it should receive packets not depending to what interface
+ * program is joined.
+ * If we will not make it, the program will have to join on all
+ * interfaces. On the other hand, multihoming host (or router, but
+ * not mrouter) cannot join to more than one interface - it will
+ * result in receiving multiple packets.
+ */
+ dev = vif->dev;
+ skb->dev=dev;
+ vif->pkt_out++;
+ vif->bytes_out+=skb->len;
+
+ ipv6h = skb->nh.ipv6h;
+
+ ipv6h->hop_limit--;
+
+ if(dev->hard_header) {
+ unsigned char ha[MAX_ADDR_LEN];
+ ndisc_mc_map(snd_addr,ha,dev,1);
+ if(dev->hard_header(skb,dev, ETH_P_IPV6,ha,NULL,full_len) < 0)
+ goto out_free;
+ }
+
+ NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, skb->dev, dev,
+ dev_queue_xmit);
+/* NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, skb, skb->dev, dev,
+ ip6mr_forward_finish);
+*/
+
+
+ /* NF_HOOK(PF_INET6, NF_IP6_FORWARD, skb, skb->dev, dev,
+ ip6mr_forward_finish);
+ */
+ return;
+ /* XXX */
+
+out_free:
+ kfree_skb(skb);
+ return;
+}
+
+static int ip6mr_find_vif(struct net_device *dev)
+{
+ int ct;
+ for (ct=maxvif-1; ct>=0; ct--) {
+ if (vif6_table[ct].dev == dev)
+ break;
+ }
+ return ct;
+}
+
+static int ip6_mr_forward(struct sk_buff *skb, struct mfc6_cache *cache, int local)
+{
+ int psend = -1;
+ int vif, ct;
+
+ vif = cache->mf6c_parent;
+ cache->mfc_un.res.pkt++;
+ cache->mfc_un.res.bytes += skb->len;
+
+ /*
+ * Wrong interface: drop packet and (maybe) send PIM assert.
+ */
+ if (vif6_table[vif].dev != skb->dev) {
+ int true_vifi;
+
+ if (((struct rtable*)skb->dst)->fl.iif == 0) {
+ /* It is our own packet, looped back.
+ Very complicated situation...
+
+ The best workaround until routing daemons will be
+ fixed is not to redistribute packet, if it was
+ send through wrong interface. It means, that
+ multicast applications WILL NOT work for
+ (S,G), which have default multicast route pointing
+ to wrong oif. In any case, it is not a good
+ idea to use multicasting applications on router.
+ */
+ goto dont_forward;
+ }
+
+ cache->mfc_un.res.wrong_if++;
+ true_vifi = ip6mr_find_vif(skb->dev);
+
+ if (true_vifi >= 0 && mroute_do_assert &&
+ /* pimsm uses asserts, when switching from RPT to SPT,
+ so that we cannot check that packet arrived on an oif.
+ It is bad, but otherwise we would need to move pretty
+ large chunk of pimd to kernel. Ough... --ANK
+ */
+ (mroute_do_pim || cache->mfc_un.res.ttls[true_vifi] < 255) &&
+ time_after(jiffies,
+ cache->mfc_un.res.last_assert + MFC_ASSERT_THRESH)) {
+ cache->mfc_un.res.last_assert = jiffies;
+ ip6mr_cache_report(skb, true_vifi, MRT6MSG_WRONGMIF);
+ }
+ goto dont_forward;
+ }
+
+ vif6_table[vif].pkt_in++;
+ vif6_table[vif].bytes_in+=skb->len;
+
+ /*
+ * Forward the frame
+ */
+ for (ct = cache->mfc_un.res.maxvif-1; ct >= cache->mfc_un.res.minvif; ct--) {
+ if (skb->nh.ipv6h->hop_limit > cache->mfc_un.res.ttls[ct]) {
+ struct ipv6hdr *ipv6h = skb->nh.ipv6h;
+ if (psend != -1) {
+ struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
+ if (skb2) {
+ ip6mr_queue_xmit(skb2, cache, psend);
+ ipv6h->hop_limit++;
+ }
+ }
+ psend=ct;
+ }
+ }
+ if (psend != -1) {
+ struct ipv6hdr *ipv6h = skb->nh.ipv6h;
+ if (local) {
+ struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
+ if (skb2) {
+ ip6mr_queue_xmit(skb2, cache, psend);
+ ipv6h->hop_limit++;
+ }
+ } else {
+ ip6mr_queue_xmit(skb, cache, psend);
+ ipv6h->hop_limit++;
+ return 0;
+ }
+ }
+
+dont_forward:
+ if (!local)
+ kfree_skb(skb);
+ return 0;
+}
+
+
+/*
+ * Multicast packets for forwarding arrive here
+ */
+
+int ip6_mr_input(struct sk_buff *skb)
+{
+ struct mfc6_cache *cache;
+ int local = ((struct rt6_info*)skb->dst)->rt6i_flags&RTCF_LOCAL;
+#if 0
+ IP6CB(skb)->flags = 0;
+#endif
+
+ read_lock(&mrt_lock);
+ cache = ip6mr_cache_find(skb->nh.ipv6h->saddr, skb->nh.ipv6h->daddr);
+
+ /*
+ * No usable cache entry
+ */
+ if (cache==NULL) {
+ int vif;
+
+ vif = ip6mr_find_vif(skb->dev);
+ if (vif >= 0) {
+ int err = ip6mr_cache_unresolved(vif, skb);
+ read_unlock(&mrt_lock);
+
+ return err;
+ }
+ read_unlock(&mrt_lock);
+ kfree_skb(skb);
+ return -ENODEV;
+ }
+
+ ip6_mr_forward(skb, cache, local);
+
+ read_unlock(&mrt_lock);
+
+ return 0;
+#if 0
+dont_forward:
+ kfree_skb(skb);
+ return 0;
+#endif
+}
+
+
+static int
+ip6mr_fill_mroute(struct sk_buff *skb, struct mfc6_cache *c, struct rtmsg *rtm)
+{
+ int ct;
+ struct rtnexthop *nhp;
+ struct net_device *dev = vif6_table[c->mf6c_parent].dev;
+ u8 *b = skb->tail;
+ struct rtattr *mp_head;
+
+ if (dev)
+ RTA_PUT(skb, RTA_IIF, 4, &dev->ifindex);
+
+ mp_head = (struct rtattr*)skb_put(skb, RTA_LENGTH(0));
+
+ for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) {
+ if (c->mfc_un.res.ttls[ct] < 255) {
+ if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4))
+ goto rtattr_failure;
+ nhp = (struct rtnexthop*)skb_put(skb, RTA_ALIGN(sizeof(*nhp)));
+ nhp->rtnh_flags = 0;
+ nhp->rtnh_hops = c->mfc_un.res.ttls[ct];
+ nhp->rtnh_ifindex = vif6_table[ct].dev->ifindex;
+ nhp->rtnh_len = sizeof(*nhp);
+ }
+ }
+ mp_head->rta_type = RTA_MULTIPATH;
+ mp_head->rta_len = skb->tail - (u8*)mp_head;
+ rtm->rtm_type = RTN_MULTICAST;
+ return 1;
+
+rtattr_failure:
+ skb_trim(skb, b - skb->data);
+ return -EMSGSIZE;
+}
diff -urN linux-2.6.11/net/ipv6/ip6_output.c linux.sinabox/net/ipv6/ip6_output.c
--- linux-2.6.11/net/ipv6/ip6_output.c 2005-03-02 08:37:47.000000000 +0100
+++ linux.sinabox/net/ipv6/ip6_output.c 2005-03-26 19:02:06.000000000 +0100
@@ -75,6 +75,9 @@
struct dst_entry *dst = skb->dst;
struct hh_cache *hh = dst->hh;
+#ifdef CONFIG_IPV6_STATISTICS
+ struct inet6_dev *idev = ((struct rt6_info *)dst)->rt6i_idev;
+#endif
if (hh) {
int hh_alen;
@@ -88,14 +91,18 @@
} else if (dst->neighbour)
return dst->neighbour->output(skb);
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_OUTNOROUTES);
+#else
IP6_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES);
+#endif
kfree_skb(skb);
return -EINVAL;
}
/* dev_loopback_xmit for use with netfilter. */
-static int ip6_dev_loopback_xmit(struct sk_buff *newskb)
+int ip6_dev_loopback_xmit(struct sk_buff *newskb)
{
newskb->mac.raw = newskb->data;
__skb_pull(newskb, newskb->nh.raw - newskb->data);
@@ -112,6 +119,9 @@
{
struct dst_entry *dst = skb->dst;
struct net_device *dev = dst->dev;
+#ifdef CONFIG_IPV6_STATISTICS
+ struct inet6_dev *idev = ((struct rt6_info *)dst)->rt6i_idev;
+#endif
skb->protocol = htons(ETH_P_IPV6);
skb->dev = dev;
@@ -133,13 +143,21 @@
ip6_dev_loopback_xmit);
if (skb->nh.ipv6h->hop_limit == 0) {
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS(idev, IPSTATS_MIB_OUTDISCARDS);
+#else
IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS);
+#endif
kfree_skb(skb);
return 0;
}
}
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS(idev, IPSTATS_MIB_OUTMCASTPKTS);
+#else
IP6_INC_STATS(IPSTATS_MIB_OUTMCASTPKTS);
+#endif
}
return NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, skb,NULL, skb->dev,ip6_output_finish);
@@ -147,7 +165,7 @@
int ip6_output(struct sk_buff *skb)
{
- if (skb->len > dst_pmtu(skb->dst))
+ if (skb->len > dst_pmtu(skb->dst) || ip6_dst_allfrag(skb->dst))
return ip6_fragment(skb, ip6_output2);
else
return ip6_output2(skb);
@@ -166,11 +184,21 @@
.saddr = iph->saddr, } },
.proto = iph->nexthdr,
};
+#ifdef CONFIG_IPV6_STATISTICS
+ struct inet6_dev *idev = NULL;
+#endif
dst = ip6_route_output(skb->sk, &fl);
+#ifdef CONFIG_IPV6_STATISTICS
+ idev = ((struct rt6_info *)dst)->rt6i_idev;
+#endif
if (dst->error) {
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS(idev, IPSTATS_MIB_OUTNOROUTES);
+#else
IP6_INC_STATS(IPSTATS_MIB_OUTNOROUTES);
+#endif
LIMIT_NETDEBUG(
printk(KERN_DEBUG "ip6_route_me_harder: No more route.\n"));
dst_release(dst);
@@ -209,11 +237,16 @@
struct in6_addr *first_hop = &fl->fl6_dst;
struct dst_entry *dst = skb->dst;
struct ipv6hdr *hdr;
+#ifdef CONFIG_IPV6_STATISTICS
+ struct inet6_dev *idev = ((struct rt6_info *)dst)->rt6i_idev;
+#endif
u8 proto = fl->proto;
int seg_len = skb->len;
int hlimit;
u32 mtu;
+ skb->h.raw = skb->data;
+
if (opt) {
int head_room;
@@ -229,7 +262,11 @@
kfree_skb(skb);
skb = skb2;
if (skb == NULL) {
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS(idev, IPSTATS_MIB_OUTDISCARDS);
+#else
IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS);
+#endif
return -ENOBUFS;
}
if (sk)
@@ -253,6 +290,8 @@
hlimit = np->hop_limit;
if (hlimit < 0)
hlimit = dst_metric(dst, RTAX_HOPLIMIT);
+ if (hlimit < 0)
+ hlimit = ipv6_get_hoplimit(dst->dev);
hdr->payload_len = htons(seg_len);
hdr->nexthdr = proto;
@@ -263,15 +302,28 @@
mtu = dst_pmtu(dst);
if ((skb->len <= mtu) || ipfragok) {
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS);
+#else
IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS);
+#endif
return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, ip6_maybe_reroute);
}
if (net_ratelimit())
- printk(KERN_DEBUG "IPv6: sending pkt_too_big to self\n");
+ printk(KERN_DEBUG "IPv6: sending pkt_too_big to self; "
+ "saddr=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x, "
+ "daddr=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x, "
+ "skb->len(%d) > mtu(%d)\n",
+ NIP6(hdr->saddr), NIP6(hdr->daddr),
+ skb->len, mtu);
skb->dev = dst->dev;
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS(idev, IPSTATS_MIB_FRAGFAILS);
+#else
IP6_INC_STATS(IPSTATS_MIB_FRAGFAILS);
+#endif
kfree_skb(skb);
return -EMSGSIZE;
}
@@ -348,14 +400,32 @@
struct dst_entry *dst = skb->dst;
struct ipv6hdr *hdr = skb->nh.ipv6h;
struct inet6_skb_parm *opt = IP6CB(skb);
+#ifdef CONFIG_IPV6_STATISTICS
+ struct inet6_dev *idev = ((struct rt6_info *)dst)->rt6i_idev;
+#endif
if (ipv6_devconf.forwarding == 0)
goto error;
+#ifdef CONFIG_USE_POLICY_FWD
if (!xfrm6_policy_check(NULL, XFRM_POLICY_FWD, skb)) {
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS(idev, IPSTATS_MIB_INDISCARDS);
+#else
IP6_INC_STATS(IPSTATS_MIB_INDISCARDS);
+#endif
goto drop;
}
+#else
+ if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS(idev, IPSTATS_MIB_INDISCARDS);
+#else
+ IP6_INC_STATS(IPSTATS_MIB_INDISCARDS);
+#endif
+ goto drop;
+ }
+#endif
skb->ip_summed = CHECKSUM_NONE;
@@ -392,7 +462,11 @@
}
if (!xfrm6_route_forward(skb)) {
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS(idev, IPSTATS_MIB_INDISCARDS);
+#else
IP6_INC_STATS(IPSTATS_MIB_INDISCARDS);
+#endif
goto drop;
}
@@ -430,14 +504,23 @@
/* Again, force OUTPUT device used as source address */
skb->dev = dst->dev;
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst_pmtu(dst), skb->dev);
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_INTOOBIGERRORS);
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_FRAGFAILS);
+#else
IP6_INC_STATS_BH(IPSTATS_MIB_INTOOBIGERRORS);
IP6_INC_STATS_BH(IPSTATS_MIB_FRAGFAILS);
+#endif
kfree_skb(skb);
return -EMSGSIZE;
}
if (skb_cow(skb, dst->dev->hard_header_len)) {
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS(idev, IPSTATS_MIB_OUTDISCARDS);
+#else
IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS);
+#endif
goto drop;
}
@@ -447,11 +530,19 @@
hdr->hop_limit--;
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_OUTFORWDATAGRAMS);
+#else
IP6_INC_STATS_BH(IPSTATS_MIB_OUTFORWDATAGRAMS);
+#endif
return NF_HOOK(PF_INET6,NF_IP6_FORWARD, skb, skb->dev, dst->dev, ip6_forward_finish);
error:
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_INADDRERRORS);
+#else
IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
+#endif
drop:
kfree_skb(skb);
return -EINVAL;
@@ -500,17 +591,21 @@
switch (**nexthdr) {
case NEXTHDR_HOP:
+ break;
case NEXTHDR_ROUTING:
+ found_rhdr = 1;
+ break;
case NEXTHDR_DEST:
- if (**nexthdr == NEXTHDR_ROUTING) found_rhdr = 1;
- if (**nexthdr == NEXTHDR_DEST && found_rhdr) return offset;
- offset += ipv6_optlen(exthdr);
- *nexthdr = &exthdr->nexthdr;
- exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
+ if (found_rhdr)
+ return offset;
break;
- default :
+ default:
return offset;
}
+
+ offset += ipv6_optlen(exthdr);
+ *nexthdr = &exthdr->nexthdr;
+ exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
}
return offset;
@@ -523,6 +618,9 @@
struct rt6_info *rt = (struct rt6_info*)skb->dst;
struct ipv6hdr *tmp_hdr;
struct frag_hdr *fh;
+#ifdef CONFIG_IPV6_STATISTICS
+ struct inet6_dev *idev = rt->rt6i_idev;
+#endif
unsigned int mtu, hlen, left, len;
u32 frag_id = 0;
int ptr, offset = 0, err=0;
@@ -566,7 +664,11 @@
tmp_hdr = kmalloc(hlen, GFP_ATOMIC);
if (!tmp_hdr) {
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS(idev, IPSTATS_MIB_FRAGFAILS);
+#else
IP6_INC_STATS(IPSTATS_MIB_FRAGFAILS);
+#endif
return -ENOMEM;
}
@@ -622,7 +724,11 @@
kfree(tmp_hdr);
if (err == 0) {
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS(idev, IPSTATS_MIB_FRAGOKS);
+#else
IP6_INC_STATS(IPSTATS_MIB_FRAGOKS);
+#endif
return 0;
}
@@ -632,7 +738,11 @@
frag = skb;
}
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS(idev, IPSTATS_MIB_FRAGFAILS);
+#else
IP6_INC_STATS(IPSTATS_MIB_FRAGFAILS);
+#endif
return err;
}
@@ -665,7 +775,11 @@
if ((frag = alloc_skb(len+hlen+sizeof(struct frag_hdr)+LL_RESERVED_SPACE(rt->u.dst.dev), GFP_ATOMIC)) == NULL) {
NETDEBUG(printk(KERN_INFO "IPv6: frag: no memory for new fragment!\n"));
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS(idev, IPSTATS_MIB_FRAGFAILS);
+#else
IP6_INC_STATS(IPSTATS_MIB_FRAGFAILS);
+#endif
err = -ENOMEM;
goto fail;
}
@@ -723,19 +837,31 @@
* Put this fragment into the sending queue.
*/
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS(idev, IPSTATS_MIB_FRAGCREATES);
+#else
IP6_INC_STATS(IPSTATS_MIB_FRAGCREATES);
+#endif
err = output(frag);
if (err)
goto fail;
}
kfree_skb(skb);
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS(idev, IPSTATS_MIB_FRAGOKS);
+#else
IP6_INC_STATS(IPSTATS_MIB_FRAGOKS);
+#endif
return err;
fail:
kfree_skb(skb);
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS(idev, IPSTATS_MIB_FRAGFAILS);
+#else
IP6_INC_STATS(IPSTATS_MIB_FRAGFAILS);
+#endif
return err;
}
@@ -814,6 +940,9 @@
struct inet_sock *inet = inet_sk(sk);
struct ipv6_pinfo *np = inet6_sk(sk);
struct sk_buff *skb;
+#ifdef CONFIG_IPV6_STATISTICS
+ struct inet6_dev *idev = rt->rt6i_idev;
+#endif
unsigned int maxfraglen, fragheaderlen;
int exthdrlen;
int hh_len;
@@ -848,6 +977,7 @@
inet->cork.fl = *fl;
np->cork.hop_limit = hlimit;
inet->cork.fragsize = mtu = dst_pmtu(&rt->u.dst);
+ inet->cork.flags |= ip6_dst_allfrag(&rt->u.dst) ? IPCORK_ALLFRAG : 0;
inet->cork.length = 0;
sk->sk_sndmsg_page = NULL;
sk->sk_sndmsg_off = 0;
@@ -899,7 +1029,7 @@
while (length > 0) {
/* Check if the remaining data fits into current packet. */
- copy = mtu - skb->len;
+ copy = (inet->cork.length <= mtu && !(inet->cork.flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - skb->len;
if (copy < length)
copy = maxfraglen - skb->len;
@@ -924,7 +1054,7 @@
* we know we need more fragment(s).
*/
datalen = length + fraggap;
- if (datalen > mtu - fragheaderlen)
+ if (datalen > (inet->cork.length <= mtu && !(inet->cork.flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - fragheaderlen)
datalen = maxfraglen - fragheaderlen;
fraglen = datalen + fragheaderlen;
@@ -1080,7 +1210,11 @@
return 0;
error:
inet->cork.length -= length;
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS(idev, IPSTATS_MIB_OUTDISCARDS);
+#else
IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS);
+#endif
return err;
}
@@ -1095,6 +1229,9 @@
struct ipv6_txoptions *opt = np->cork.opt;
struct rt6_info *rt = np->cork.rt;
struct flowi *fl = &inet->cork.fl;
+#ifdef CONFIG_IPV6_STATISTICS
+ struct inet6_dev *idev = rt->rt6i_idev;
+#endif
unsigned char proto = fl->proto;
int err = 0;
@@ -1140,7 +1277,11 @@
ipv6_addr_copy(&hdr->daddr, final_dst);
skb->dst = dst_clone(&rt->u.dst);
- IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS);
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS);
+#else
+ IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS);
+#endif
err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, skb->dst->dev, dst_output);
if (err) {
if (err > 0)
@@ -1158,6 +1299,7 @@
if (np->cork.rt) {
dst_release(&np->cork.rt->u.dst);
np->cork.rt = NULL;
+ inet->cork.flags &= ~IPCORK_ALLFRAG;
}
memset(&inet->cork.fl, 0, sizeof(inet->cork.fl));
return err;
@@ -1170,9 +1312,19 @@
struct inet_sock *inet = inet_sk(sk);
struct ipv6_pinfo *np = inet6_sk(sk);
struct sk_buff *skb;
+#ifdef CONFIG_IPV6_STATISTICS
+ struct dst_entry *dst;
+ struct inet6_dev *idev = NULL;
+#endif
while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL) {
+#ifdef CONFIG_IPV6_STATISTICS
+ dst = skb->dst;
+ idev = ((struct rt6_info *)dst)->rt6i_idev;
+ IP6_INC_STATS(idev, IPSTATS_MIB_OUTDISCARDS);
+#else
IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS);
+#endif
kfree_skb(skb);
}
@@ -1185,6 +1337,7 @@
if (np->cork.rt) {
dst_release(&np->cork.rt->u.dst);
np->cork.rt = NULL;
+ inet->cork.flags &= ~IPCORK_ALLFRAG;
}
memset(&inet->cork.fl, 0, sizeof(inet->cork.fl));
}
diff -urN linux-2.6.11/net/ipv6/ip6_tunnel.c linux.sinabox/net/ipv6/ip6_tunnel.c
--- linux-2.6.11/net/ipv6/ip6_tunnel.c 2005-03-02 08:37:48.000000000 +0100
+++ linux.sinabox/net/ipv6/ip6_tunnel.c 2005-03-26 19:02:06.000000000 +0100
@@ -736,7 +736,7 @@
dsfield = INET_ECN_encapsulate(0, dsfield);
ipv6_change_dsfield(ipv6h, ~INET_ECN_MASK, dsfield);
ipv6h->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
- ipv6h->hop_limit = t->parms.hop_limit;
+ ipv6h->hop_limit = t->parms.hop_limit; /*XXX use physical link's mtu */
ipv6h->nexthdr = proto;
ipv6_addr_copy(&ipv6h->saddr, &fl.fl6_src);
ipv6_addr_copy(&ipv6h->daddr, &fl.fl6_dst);
diff -urN linux-2.6.11/net/ipv6/ipv6_sockglue.c linux.sinabox/net/ipv6/ipv6_sockglue.c
--- linux-2.6.11/net/ipv6/ipv6_sockglue.c 2005-03-02 08:37:48.000000000 +0100
+++ linux.sinabox/net/ipv6/ipv6_sockglue.c 2005-03-26 19:02:06.000000000 +0100
@@ -23,6 +23,8 @@
* Changes:
* David L Stevens <dlstevens@us.ibm.com>:
* - added multicast source filtering API for MLDv2
+ * Hoerdt Mickael <hoerdt@clarinet.u-strasbg.fr>:
+ * - added multicat routing support for IPv6
*/
#include <linux/module.h>
@@ -55,6 +57,10 @@
#include <asm/uaccess.h>
+#ifdef CONFIG_IPV6_MROUTE
+#include <linux/mroute6.h>
+#endif
+
DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics);
static struct packet_type ipv6_packet_type = {
@@ -69,9 +75,14 @@
{
struct ip6_ra_chain *ra, *new_ra, **rap;
+#ifndef CONFIG_IPV6_MROUTE
/* RA packet may be delivered ONLY to IPPROTO_RAW socket */
if (sk->sk_type != SOCK_RAW || inet_sk(sk)->num != IPPROTO_RAW)
return -EINVAL;
+#else
+ if (sk->sk_type != SOCK_RAW || inet_sk(sk)->num == IPPROTO_RAW)
+ return -EINVAL;
+#endif
new_ra = (sel>=0) ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
@@ -136,6 +147,11 @@
valbool = (val!=0);
+#ifdef CONFIG_IPV6_MROUTE
+ if(optname >= MRT6_BASE && optname <= (MRT6_BASE + 10))
+ return ip6_mroute_setsockopt(sk,optname,optval,optlen);
+#endif
+
lock_sock(sk);
switch (optname) {
@@ -535,6 +551,11 @@
return udp_prot.getsockopt(sk, level, optname, optval, optlen);
if(level!=SOL_IPV6)
return -ENOPROTOOPT;
+
+#ifdef CONFIG_IPV6_MROUTE
+ if(optname >= MRT6_BASE && optname <= (MRT6_BASE + 10))
+ return ip6_mroute_getsockopt(sk,optname,optval,optlen);
+#endif
if (get_user(len, optlen))
return -EFAULT;
switch (optname) {
diff -urN linux-2.6.11/net/ipv6/ipv6_syms.c linux.sinabox/net/ipv6/ipv6_syms.c
--- linux-2.6.11/net/ipv6/ipv6_syms.c 2005-03-02 08:38:13.000000000 +0100
+++ linux.sinabox/net/ipv6/ipv6_syms.c 2005-03-26 19:02:06.000000000 +0100
@@ -7,7 +7,7 @@
#include <net/ip6_route.h>
#include <net/xfrm.h>
-EXPORT_SYMBOL(ipv6_addr_type);
+EXPORT_SYMBOL(__ipv6_addr_type);
EXPORT_SYMBOL(icmpv6_send);
EXPORT_SYMBOL(icmpv6_statistics);
EXPORT_SYMBOL(icmpv6_err_convert);
@@ -38,4 +38,8 @@
#endif
EXPORT_SYMBOL(rt6_lookup);
EXPORT_SYMBOL(fl6_sock_lookup);
+EXPORT_SYMBOL(ip6_append_data);
+EXPORT_SYMBOL(ip6_flush_pending_frames);
+EXPORT_SYMBOL(ip6_push_pending_frames);
+EXPORT_SYMBOL(ip6_dst_lookup);
EXPORT_SYMBOL(ipv6_push_nfrag_opts);
diff -urN linux-2.6.11/net/ipv6/Kconfig linux.sinabox/net/ipv6/Kconfig
--- linux-2.6.11/net/ipv6/Kconfig 2005-03-02 08:38:09.000000000 +0100
+++ linux.sinabox/net/ipv6/Kconfig 2005-03-26 19:02:06.000000000 +0100
@@ -2,7 +2,7 @@
# IPv6 configuration
#
config IPV6_PRIVACY
- bool "IPv6: Privacy Extensions (RFC 3041) support"
+ bool "IPv6: Privacy Extensions support"
depends on IPV6
---help---
Privacy Extensions for Stateless Address Autoconfiguration in IPv6
@@ -17,6 +17,22 @@
See <file:Documentation/networking/ip-sysctl.txt> for details.
+config IPV6_PRIVACY_MD5
+ bool "IPv6: Use RFC 3041 randomized interface identifiers"
+ depends on IPV6_PRIVACY
+ ---help---
+ Instead of standard pseudo random generator, use
+ traditional algorithm described in the original RFC 3041.
+
+config IPV6_ROUTER_PREF
+ bool "IPv6: default router preference"
+ depends on IPV6
+
+config IPV6_NEW_ROUNDROBIN
+ bool
+ depends on IPV6_ROUTER_PREF
+ default y
+
config INET6_AH
tristate "IPv6: AH transformation"
depends on IPV6
@@ -77,3 +93,51 @@
If unsure, say N.
+config IPV6_MROUTE
+ bool "IPv6: multicast routing (EXPERIMENTAL)"
+ depends on IPV6 && EXPERIMENTAL
+ ---help---
+ Experimental support for IPv6 multicast forwarding.
+ If unsure, say N.
+
+config IPV6_PIMSM_V2
+ bool "IPv6: PIM-SM version 2 support (EXPERIMENTAL)"
+ depends on IPV6_MROUTE
+ ---help---
+ Support for IPv6 PIM multicast routing protocol PIM-SMv2.
+ If unsure, say N.
+
+config IPV6_STATISTICS
+ bool "IPv6: per-interface statistics for SNMP"
+ depends on IPV6
+
+config IPV6_DELPREFIX
+ bool "IPv6: delete prefix route on manual address deletion"
+ depends on IPV6
+ ---help---
+ When an address is being configured manually, kernel
+ automatically append a prefix route for the address.
+ On the other hand, kernel won't delete it when the address
+ is being deleted.
+
+ It is not a problem on prefix for auto-configured address,
+ but this probably is confusing on prefix for manual addresses.
+ (Note: prefix route for auto-configured address is managed
+ by its timer.)
+
+ With this option, delete prefix route if there's no address
+ on the device. In addition, if all the other address are
+ auto-configured address, we change it to dynamic
+ prefix route.
+
+ This is experimental.
+
+config IPV6_ALLFRAG
+ bool "IPv6: fragment < 1280"
+ depends on IPV6
+ ---help---
+ According to RFC2460, always append fragment header after
+ receiving TooBig w/ mtu < 1280.
+
+ This is experimental.
+
diff -urN linux-2.6.11/net/ipv6/Makefile linux.sinabox/net/ipv6/Makefile
--- linux-2.6.11/net/ipv6/Makefile 2005-03-02 08:38:17.000000000 +0100
+++ linux.sinabox/net/ipv6/Makefile 2005-03-26 19:02:06.000000000 +0100
@@ -10,6 +10,8 @@
exthdrs.o sysctl_net_ipv6.o datagram.o proc.o \
ip6_flowlabel.o ipv6_syms.o
+ipv6-$(CONFIG_IPV6_MROUTE) += ip6mr.o
+
ipv6-$(CONFIG_XFRM) += xfrm6_policy.o xfrm6_state.o xfrm6_input.o \
xfrm6_output.o
ipv6-objs += $(ipv6-y)
diff -urN linux-2.6.11/net/ipv6/mcast.c linux.sinabox/net/ipv6/mcast.c
--- linux-2.6.11/net/ipv6/mcast.c 2005-03-02 08:38:25.000000000 +0100
+++ linux.sinabox/net/ipv6/mcast.c 2005-03-26 19:02:06.000000000 +0100
@@ -62,6 +62,11 @@
#include <net/ip6_checksum.h>
+#ifdef CONFIG_IPV6_MROUTE
+#include <linux/mroute6.h>
+int ip6_dev_loopback_xmit(struct sk_buff *newskb);
+#endif
+
/* Set to 3 to get tracing... */
#define MCAST_DEBUG 2
@@ -1320,7 +1325,11 @@
struct inet6_dev *idev = in6_dev_get(skb->dev);
int err;
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS);
+#else
IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS);
+#endif
payload_len = skb->tail - (unsigned char *)skb->nh.ipv6h -
sizeof(struct ipv6hdr);
mldlen = skb->tail - skb->h.raw;
@@ -1330,11 +1339,33 @@
IPPROTO_ICMPV6, csum_partial(skb->h.raw, mldlen, 0));
err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, skb->dev,
dev_queue_xmit);
+
+#ifdef CONFIG_IPV6_MROUTE
+ /*
+ * if we are acting as a multicast router, loopback a copy to the
+ * process level multicast routing daemon
+ */
+ if (mroute6_socket != NULL) {
+ struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC);
+ if (newskb)
+ NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, newskb, NULL,
+ newskb->dev, ip6_dev_loopback_xmit);
+ }
+#endif
+
if (!err) {
ICMP6_INC_STATS(idev,ICMP6_MIB_OUTMSGS);
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS(idev, IPSTATS_MIB_OUTMCASTPKTS);
+#else
IP6_INC_STATS(IPSTATS_MIB_OUTMCASTPKTS);
+#endif
} else
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS(idev, IPSTATS_MIB_OUTDISCARDS);
+#else
IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS);
+#endif
if (likely(idev != NULL))
in6_dev_put(idev);
@@ -1604,7 +1635,11 @@
static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
{
struct sock *sk = igmp6_socket->sk;
+#ifdef CONFIG_IPV6_STATISTICS
+ struct inet6_dev *idev = __in6_dev_get(dev);
+#else
struct inet6_dev *idev;
+#endif
struct sk_buff *skb;
struct icmp6hdr *hdr;
struct in6_addr *snd_addr;
@@ -1616,7 +1651,11 @@
IPV6_TLV_ROUTERALERT, 2, 0, 0,
IPV6_TLV_PADN, 0 };
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS);
+#else
IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS);
+#endif
snd_addr = addr;
if (type == ICMPV6_MGM_REDUCTION) {
snd_addr = &all_routers;
@@ -1630,7 +1669,11 @@
skb = sock_alloc_send_skb(sk, LL_RESERVED_SPACE(dev) + full_len, 1, &err);
if (skb == NULL) {
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS(idev, IPSTATS_MIB_OUTDISCARDS);
+#else
IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS);
+#endif
return;
}
@@ -1669,22 +1712,47 @@
err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, skb->dev,
dev_queue_xmit);
+
+#ifdef CONFIG_IPV6_MROUTE
+ /*
+ * if we are acting as a multicast router, loopback a copy to the
+ * process level multicast routing daemon
+ */
+ if (mroute6_socket != NULL) {
+ struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC);
+ if (newskb)
+ NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, newskb, NULL,
+ newskb->dev, ip6_dev_loopback_xmit);
+ }
+#endif
if (!err) {
if (type == ICMPV6_MGM_REDUCTION)
ICMP6_INC_STATS(idev, ICMP6_MIB_OUTGROUPMEMBREDUCTIONS);
else
ICMP6_INC_STATS(idev, ICMP6_MIB_OUTGROUPMEMBRESPONSES);
ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS);
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS(idev, IPSTATS_MIB_OUTMCASTPKTS);
+#else
IP6_INC_STATS(IPSTATS_MIB_OUTMCASTPKTS);
+#endif
} else
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS(idev, IPSTATS_MIB_OUTDISCARDS);
+#else
IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS);
+#endif
if (likely(idev != NULL))
in6_dev_put(idev);
return;
out:
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS(idev, IPSTATS_MIB_OUTDISCARDS);
+#else
IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS);
+#endif
kfree_skb(skb);
}
diff -urN linux-2.6.11/net/ipv6/ndisc.c linux.sinabox/net/ipv6/ndisc.c
--- linux-2.6.11/net/ipv6/ndisc.c 2005-03-02 08:38:10.000000000 +0100
+++ linux.sinabox/net/ipv6/ndisc.c 2005-03-26 19:02:06.000000000 +0100
@@ -437,6 +437,7 @@
return;
}
+ ND_PRINTK2("%s:dst=%p\n", __FUNCTION__, dst);
if (inc_opt) {
if (dev->addr_len)
len += NDISC_OPT_SPACE(dev->addr_len);
@@ -444,7 +445,7 @@
inc_opt = 0;
}
- skb = sock_alloc_send_skb(sk, MAX_HEADER + len + LL_RESERVED_SPACE(dev),
+ skb = sock_alloc_send_skb(sk, MAX_HEADER + len + LL_RESERVED_SPACE(dev) + dst->header_len + 64,
1, &err);
if (skb == NULL) {
@@ -485,7 +486,11 @@
skb->dst = dst;
idev = in6_dev_get(dst->dev);
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS);
+#else
IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS);
+#endif
err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, dst_output);
if (!err) {
ICMP6_INC_STATS(idev, ICMP6_MIB_OUTNEIGHBORADVERTISEMENTS);
@@ -534,7 +539,7 @@
if (send_llinfo)
len += NDISC_OPT_SPACE(dev->addr_len);
- skb = sock_alloc_send_skb(sk, MAX_HEADER + len + LL_RESERVED_SPACE(dev),
+ skb = sock_alloc_send_skb(sk, MAX_HEADER + len + LL_RESERVED_SPACE(dev) + dst->header_len + 64,
1, &err);
if (skb == NULL) {
ND_PRINTK0(KERN_ERR
@@ -570,7 +575,11 @@
/* send it! */
skb->dst = dst;
idev = in6_dev_get(dst->dev);
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS);
+#else
IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS);
+#endif
err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, dst_output);
if (!err) {
ICMP6_INC_STATS(idev, ICMP6_MIB_OUTNEIGHBORSOLICITS);
@@ -610,7 +619,7 @@
if (dev->addr_len)
len += NDISC_OPT_SPACE(dev->addr_len);
- skb = sock_alloc_send_skb(sk, MAX_HEADER + len + LL_RESERVED_SPACE(dev),
+ skb = sock_alloc_send_skb(sk, MAX_HEADER + len + LL_RESERVED_SPACE(dev) + dst->header_len + 64,
1, &err);
if (skb == NULL) {
ND_PRINTK0(KERN_ERR
@@ -644,7 +653,11 @@
/* send it! */
skb->dst = dst;
idev = in6_dev_get(dst->dev);
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS);
+#else
IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS);
+#endif
err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, dst_output);
if (!err) {
ICMP6_INC_STATS(idev, ICMP6_MIB_OUTROUTERSOLICITS);
@@ -809,7 +822,6 @@
* sender should delay its response
* by a random time between 0 and
* MAX_ANYCAST_DELAY_TIME seconds.
- * (RFC2461) -- yoshfuji
*/
struct sk_buff *n = skb_clone(skb, GFP_ATOMIC);
if (n)
@@ -825,7 +837,7 @@
ipv6_addr_all_nodes(&maddr);
ndisc_send_na(dev, NULL, &maddr, &msg->target,
- idev->cnf.forwarding, 0, (ifp != NULL), 1);
+ idev->cnf.forwarding, 0, (ifp != NULL) && inc, inc);
goto out;
}
@@ -846,7 +858,7 @@
NEIGH_UPDATE_F_OVERRIDE);
if (neigh || !dev->hard_header) {
ndisc_send_na(dev, neigh, saddr, &msg->target,
- idev->cnf.forwarding,
+ idev->cnf.forwarding,
1, (ifp != NULL && inc), inc);
if (neigh)
neigh_release(neigh);
@@ -1021,6 +1033,7 @@
struct rt6_info *rt;
int lifetime;
struct ndisc_options ndopts;
+ int pref = 0;
int optlen;
__u8 * opt = (__u8 *)(ra_msg + 1);
@@ -1082,7 +1095,18 @@
lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime);
+#ifdef CONFIG_IPV6_ROUTER_PREF
+ pref = IPV6_SIGNEDPREF(ra_msg->icmph.icmp6_router_pref);
+ if (pref < -1) {
+ if (net_ratelimit())
+ ND_PRINTK2("ICMP6 RA: invalid RA preference; zero lifetime\n");
+ lifetime = 0;
+ }
+#endif
+
rt = rt6_get_dflt_router(&skb->nh.ipv6h->saddr, skb->dev);
+ if (rt)
+ neigh = rt->rt6i_nexthop;
if (rt)
neigh = rt->rt6i_nexthop;
@@ -1097,7 +1121,7 @@
ND_PRINTK3(KERN_DEBUG
"ICMPv6 RA: adding default router.\n");
- rt = rt6_add_dflt_router(&skb->nh.ipv6h->saddr, skb->dev);
+ rt = rt6_add_dflt_router(&skb->nh.ipv6h->saddr, skb->dev, pref);
if (rt == NULL) {
ND_PRINTK0(KERN_ERR
"ICMPv6 RA: %s() failed to add default route.\n",
@@ -1121,8 +1145,11 @@
if (rt)
rt->rt6i_expires = jiffies + (HZ * lifetime);
- if (ra_msg->icmph.icmp6_hop_limit)
+ if (ra_msg->icmph.icmp6_hop_limit) {
in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
+ if (rt)
+ rt->u.dst.metrics[RTAX_HOPLIMIT-1] = ra_msg->icmph.icmp6_hop_limit;
+ }
/*
* Update Reachable Time and Retrans Timer
@@ -1329,6 +1356,7 @@
int rd_len;
int err;
int hlen;
+ u8 ha_buf[MAX_ADDR_LEN], *ha = NULL;
dev = skb->dev;
@@ -1341,10 +1369,14 @@
ndisc_flow_init(&fl, NDISC_REDIRECT, &saddr_buf, &skb->nh.ipv6h->saddr);
- rt = rt6_lookup(&skb->nh.ipv6h->saddr, NULL, dev->ifindex, 1);
- if (rt == NULL)
+ /*
+ * we use ip6_route_output() here so that we do not try to
+ * send redirect to off-link.
+ * cf) ndisc_dst_alloc() assumes that destination is on-link.
+ */
+ dst = ip6_route_output(NULL, &fl);
+ if (dst == NULL)
return;
- dst = &rt->u.dst;
err = xfrm_lookup(&dst, &fl, NULL, 0);
if (err) {
@@ -1366,16 +1398,14 @@
}
if (dev->addr_len) {
+ read_lock_bh(&neigh->lock);
if (neigh->nud_state&NUD_VALID) {
- len += NDISC_OPT_SPACE(dev->addr_len);
- } else {
- /* If nexthop is not valid, do not redirect!
- We will make it later, when will be sure,
- that it is alive.
- */
- dst_release(dst);
- return;
- }
+ memcpy(ha_buf, neigh->ha, dev->addr_len);
+ read_unlock_bh(&neigh->lock);
+ ha = ha_buf;
+ len += NDISC_OPT_SPACE(dev->addr_len);
+ } else
+ read_unlock_bh(&neigh->lock);
}
rd_len = min_t(unsigned int,
@@ -1383,7 +1413,7 @@
rd_len &= ~0x7;
len += rd_len;
- buff = sock_alloc_send_skb(sk, MAX_HEADER + len + LL_RESERVED_SPACE(dev),
+ buff = sock_alloc_send_skb(sk, MAX_HEADER + len + LL_RESERVED_SPACE(dev) + dst->header_len + 64,
1, &err);
if (buff == NULL) {
ND_PRINTK0(KERN_ERR
@@ -1420,8 +1450,8 @@
* include target_address option
*/
- if (dev->addr_len)
- opt = ndisc_fill_addr_option(opt, ND_OPT_TARGET_LL_ADDR, neigh->ha,
+ if (ha)
+ opt = ndisc_fill_addr_option(opt, ND_OPT_TARGET_LL_ADDR, ha,
dev->addr_len, dev->type);
/*
@@ -1441,7 +1471,11 @@
buff->dst = dst;
idev = in6_dev_get(dst->dev);
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS);
+#else
IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS);
+#endif
err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, buff, NULL, dst->dev, dst_output);
if (!err) {
ICMP6_INC_STATS(idev, ICMP6_MIB_OUTREDIRECTS);
@@ -1533,10 +1567,46 @@
};
#ifdef CONFIG_SYSCTL
+static void __ndisc_ifinfo_notifier(struct inet6_dev *idev)
+{
+ idev->tstamp = jiffies;
+ inet6_ifinfo_notify(RTM_NEWLINK, idev);
+}
+
+static void ndisc_ifinfo_notifier(void *data)
+{
+ struct net_device *dev = data;
+ if (dev) {
+ struct inet6_dev *idev = in6_dev_get(dev);
+ if (idev) {
+ __ndisc_ifinfo_notifier(idev);
+ in6_dev_put(idev);
+ }
+ }
+}
+
int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl, int write, struct file * filp, void __user *buffer, size_t *lenp, loff_t *ppos)
{
struct net_device *dev = ctl->extra1;
struct inet6_dev *idev;
+#if 1
+ static char warncomm[TASK_COMM_LEN];
+ static int warned;
+ const char *dev_name = dev ? dev->name : "default";
+
+ if (strcmp(warncomm, current->comm) && warned < 5) {
+ strcpy(warncomm, current->comm);
+ printk(KERN_WARNING
+ "process `%s' is using old sysctl "
+ "net.ipv6.neigh.%s.%s; "
+ "Use net.ipv6.neigh.%s.%s_ms "
+ "instead.\n",
+ warncomm,
+ dev_name, ctl->procname,
+ dev_name, ctl->procname);
+ warned++;
+ }
+#endif
if (write && dev && (idev = in6_dev_get(dev)) != NULL) {
idev->tstamp = jiffies;
@@ -1578,7 +1648,8 @@
#ifdef CONFIG_SYSCTL
neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6, NET_IPV6_NEIGH,
- "ipv6", &ndisc_ifinfo_sysctl_change);
+ "ipv6", &ndisc_ifinfo_sysctl_change,
+ ndisc_ifinfo_notifier);
#endif
register_netdevice_notifier(&ndisc_netdev_notifier);
diff -urN linux-2.6.11/net/ipv6/netfilter/ip6_conntrack_core.c linux.sinabox/net/ipv6/netfilter/ip6_conntrack_core.c
--- linux-2.6.11/net/ipv6/netfilter/ip6_conntrack_core.c 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/net/ipv6/netfilter/ip6_conntrack_core.c 2005-03-26 19:02:06.000000000 +0100
@@ -0,0 +1,1593 @@
+/*
+ * IPv6 Connection Tracking
+ * Linux INET6 implementation
+ *
+ * Copyright (C)2003 USAGI/WIDE Project
+ *
+ * Authors:
+ * Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
+ *
+ * Based on: net/ipv4/netfilter/ip_conntrack_core.c
+ *
+ * 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.
+ */
+
+/* (c) 1999 Paul `Rusty' Russell. Licenced under the GNU General
+ * Public Licence.
+ *
+ * 23 Apr 2001: Harald Welte <laforge@gnumonks.org>
+ * - new API and handling of conntrack/nat helpers
+ * - now capable of multiple expectations for one master
+ * 16 Jul 2002: Harald Welte <laforge@gnumonks.org>
+ * - add usage/reference counts to ip_conntrack_expect
+ * - export ip_conntrack[_expect]_{find_get,put} functions
+ * */
+
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/icmpv6.h>
+#include <linux/ipv6.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv6.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/proc_fs.h>
+#include <linux/vmalloc.h>
+#include <net/checksum.h>
+#include <linux/stddef.h>
+#include <linux/sysctl.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/jhash.h>
+#include <net/ipv6.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+
+/* This rwlock protects the main hash table, protocol/helper/expected
+ registrations, conntrack timers*/
+#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip6_conntrack_lock)
+#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip6_conntrack_lock)
+
+#include <linux/netfilter_ipv6/ip6_conntrack.h>
+#include <linux/netfilter_ipv6/ip6_conntrack_protocol.h>
+#include <linux/netfilter_ipv6/ip6_conntrack_helper.h>
+#include <linux/netfilter_ipv6/ip6_conntrack_core.h>
+#include <linux/netfilter_ipv4/listhelp.h>
+
+#define IP6_CONNTRACK_VERSION "0.1"
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+DECLARE_RWLOCK(ip6_conntrack_lock);
+DECLARE_RWLOCK(ip6_conntrack_expect_tuple_lock);
+
+void (*ip6_conntrack_destroyed)(struct ip6_conntrack *conntrack) = NULL;
+LIST_HEAD(ip6_conntrack_expect_list);
+LIST_HEAD(ip6_protocol_list);
+static LIST_HEAD(helpers);
+unsigned int ip6_conntrack_htable_size = 0;
+static int ip6_conntrack_max = 0;
+static atomic_t ip6_conntrack_count = ATOMIC_INIT(0);
+struct list_head *ip6_conntrack_hash;
+static kmem_cache_t *ip6_conntrack_cachep;
+
+extern struct ip6_conntrack_protocol ip6_conntrack_generic_protocol;
+
+/*
+ * Based on ipv6_skip_exthdr() in net/ipv6/exthdr.c
+ *
+ * This function parses (probably truncated) exthdr set "hdr"
+ * of length "len". "nexthdrp" initially points to some place,
+ * where type of the first header can be found.
+ *
+ * It skips all well-known exthdrs, and returns pointer to the start
+ * of unparsable area i.e. the first header with unknown type.
+ * if success, *nexthdr is updated by type/protocol of this header.
+ *
+ * NOTES: - it may return pointer pointing beyond end of packet,
+ * if the last recognized header is truncated in the middle.
+ * - if packet is truncated, so that all parsed headers are skipped,
+ * it returns -1.
+ * - First fragment header is skipped, not-first ones
+ * are considered as unparsable.
+ * - ESP is unparsable for now and considered like
+ * normal payload protocol.
+ * - Note also special handling of AUTH header. Thanks to IPsec wizards.
+ */
+
+static int ip6_ct_skip_exthdr(struct sk_buff *skb, int start, u8 *nexthdrp,
+ int len)
+{
+ u8 nexthdr = *nexthdrp;
+
+ while (ipv6_ext_hdr(nexthdr)) {
+ struct ipv6_opt_hdr hdr;
+ int hdrlen;
+
+ if (len < (int)sizeof(struct ipv6_opt_hdr))
+ return -1;
+ if (nexthdr == NEXTHDR_NONE)
+ break;
+ if (skb_copy_bits(skb, start, &hdr, sizeof(hdr)))
+ BUG();
+ if (nexthdr == NEXTHDR_FRAGMENT) {
+ struct frag_hdr fhdr;
+
+ if (len < (int)sizeof(struct frag_hdr))
+ return -1;
+ if (skb_copy_bits(skb, start, &fhdr, sizeof(fhdr)))
+ BUG();
+ if (ntohs(fhdr.frag_off) & ~0x7)
+ return -1;
+ hdrlen = 8;
+ } else if (nexthdr == NEXTHDR_AUTH)
+ hdrlen = (hdr.hdrlen+2)<<2;
+ else
+ hdrlen = ipv6_optlen(&hdr);
+
+ nexthdr = hdr.nexthdr;
+ len -= hdrlen;
+ start += hdrlen;
+ }
+
+ *nexthdrp = nexthdr;
+ return start;
+}
+
+int ip6_ct_tuple_src_equal(const struct ip6_conntrack_tuple *t1,
+ const struct ip6_conntrack_tuple *t2)
+{
+ if (ipv6_addr_cmp(&t1->src.ip, &t2->src.ip))
+ return 0;
+
+ if (t1->src.u.all != t2->src.u.all)
+ return 0;
+
+ if (t1->dst.protonum != t2->dst.protonum)
+ return 0;
+
+ return 1;
+
+}
+
+int ip6_ct_tuple_dst_equal(const struct ip6_conntrack_tuple *t1,
+ const struct ip6_conntrack_tuple *t2)
+{
+ if (ipv6_addr_cmp(&t1->dst.ip, &t2->dst.ip))
+ return 0;
+
+ if (t1->dst.u.all != t2->dst.u.all)
+ return 0;
+
+ if (t1->dst.protonum != t2->dst.protonum)
+ return 0;
+
+ return 1;
+}
+
+int ip6_ct_tuple_equal(const struct ip6_conntrack_tuple *t1,
+ const struct ip6_conntrack_tuple *t2)
+{
+ return ip6_ct_tuple_src_equal(t1, t2) && ip6_ct_tuple_dst_equal(t1, t2);
+}
+
+int ip6_ct_tuple_mask_cmp(const struct ip6_conntrack_tuple *t,
+ const struct ip6_conntrack_tuple *tuple,
+ const struct ip6_conntrack_tuple *mask)
+{
+ int count = 0;
+
+ for (count = 0; count < 8; count++){
+ if ((ntohs(t->src.ip.s6_addr16[count]) ^
+ ntohs(tuple->src.ip.s6_addr16[count])) &
+ ntohs(mask->src.ip.s6_addr16[count]))
+ return 0;
+
+ if ((ntohs(t->dst.ip.s6_addr16[count]) ^
+ ntohs(tuple->dst.ip.s6_addr16[count])) &
+ ntohs(mask->dst.ip.s6_addr16[count]))
+ return 0;
+ }
+
+ if ((t->src.u.all ^ tuple->src.u.all) & mask->src.u.all)
+ return 0;
+
+ if ((t->dst.u.all ^ tuple->dst.u.all) & mask->dst.u.all)
+ return 0;
+
+ if ((t->dst.protonum ^ tuple->dst.protonum) & mask->dst.protonum)
+ return 0;
+
+ return 1;
+}
+
+static inline int proto_cmpfn(const struct ip6_conntrack_protocol *curr,
+ u_int8_t protocol)
+{
+ return protocol == curr->proto;
+}
+
+struct ip6_conntrack_protocol *__ip6_ct_find_proto(u_int8_t protocol)
+{
+ struct ip6_conntrack_protocol *p;
+
+ MUST_BE_READ_LOCKED(&ip6_conntrack_lock);
+ p = LIST_FIND(&ip6_protocol_list, proto_cmpfn,
+ struct ip6_conntrack_protocol *, protocol);
+ if (!p)
+ p = &ip6_conntrack_generic_protocol;
+
+ return p;
+}
+
+struct ip6_conntrack_protocol *ip6_ct_find_proto(u_int8_t protocol)
+{
+ struct ip6_conntrack_protocol *p;
+
+ READ_LOCK(&ip6_conntrack_lock);
+ p = __ip6_ct_find_proto(protocol);
+ READ_UNLOCK(&ip6_conntrack_lock);
+ return p;
+}
+
+inline void
+ip6_conntrack_put(struct ip6_conntrack *ct)
+{
+ IP6_NF_ASSERT(ct);
+ nf_conntrack_put(&ct->ct_general);
+}
+
+static int ip6_conntrack_hash_rnd_initted;
+static unsigned int ip6_conntrack_hash_rnd;
+static u_int32_t
+hash_conntrack(const struct ip6_conntrack_tuple *tuple)
+{
+ u32 a, b, c;
+
+ a = tuple->src.ip.s6_addr32[0];
+ b = tuple->src.ip.s6_addr32[1];
+ c = tuple->src.ip.s6_addr32[2];
+
+ a += JHASH_GOLDEN_RATIO;
+ b += JHASH_GOLDEN_RATIO;
+ c += ip6_conntrack_hash_rnd;
+ __jhash_mix(a, b, c);
+
+ a += tuple->src.ip.s6_addr32[3];
+ b += tuple->dst.ip.s6_addr32[0];
+ c += tuple->dst.ip.s6_addr32[1];
+ __jhash_mix(a, b, c);
+
+ a += tuple->dst.ip.s6_addr32[2];
+ b += tuple->dst.ip.s6_addr32[3];
+ c += tuple->src.u.all | (tuple->dst.u.all << 16);
+ __jhash_mix(a, b, c);
+
+ a += tuple->dst.protonum;
+ __jhash_mix(a, b, c);
+
+ return c % ip6_conntrack_htable_size;
+}
+
+int
+ip6_get_tuple(const struct ipv6hdr *ipv6h,
+ const struct sk_buff *skb,
+ unsigned int dataoff,
+ u_int8_t protonum,
+ struct ip6_conntrack_tuple *tuple,
+ const struct ip6_conntrack_protocol *protocol)
+{
+ /* Should I check that this packet is'nt fragmented
+ like IPv4 conntrack? - kozakai */
+
+ ipv6_addr_copy(&tuple->src.ip, &ipv6h->saddr);
+ ipv6_addr_copy(&tuple->dst.ip, &ipv6h->daddr);
+
+ tuple->dst.protonum = protonum;
+
+ return protocol->pkt_to_tuple(skb, dataoff, tuple);
+}
+
+static int
+invert_tuple(struct ip6_conntrack_tuple *inverse,
+ const struct ip6_conntrack_tuple *orig,
+ const struct ip6_conntrack_protocol *protocol)
+{
+ ipv6_addr_copy(&inverse->src.ip, &orig->dst.ip);
+ ipv6_addr_copy(&inverse->dst.ip, &orig->src.ip);
+ inverse->dst.protonum = orig->dst.protonum;
+
+ return protocol->invert_tuple(inverse, orig);
+}
+
+
+/* ip6_conntrack_expect helper functions */
+
+/* Compare tuple parts depending on mask. */
+static inline int expect_cmp(const struct ip6_conntrack_expect *i,
+ const struct ip6_conntrack_tuple *tuple)
+{
+ MUST_BE_READ_LOCKED(&ip6_conntrack_expect_tuple_lock);
+ return ip6_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask);
+}
+
+static void
+destroy_expect(struct ip6_conntrack_expect *exp)
+{
+ DEBUGP("destroy_expect(%p) use=%d\n", exp, atomic_read(&exp->use));
+ IP6_NF_ASSERT(atomic_read(&exp->use));
+ IP6_NF_ASSERT(!timer_pending(&exp->timeout));
+
+ kfree(exp);
+}
+
+
+inline void ip6_conntrack_expect_put(struct ip6_conntrack_expect *exp)
+{
+ IP6_NF_ASSERT(exp);
+
+ if (atomic_dec_and_test(&exp->use)) {
+ /* usage count dropped to zero */
+ destroy_expect(exp);
+ }
+}
+
+static inline struct ip6_conntrack_expect *
+__ip6_ct_expect_find(const struct ip6_conntrack_tuple *tuple)
+{
+ MUST_BE_READ_LOCKED(&ip6_conntrack_lock);
+ MUST_BE_READ_LOCKED(&ip6_conntrack_expect_tuple_lock);
+ return LIST_FIND(&ip6_conntrack_expect_list, expect_cmp,
+ struct ip6_conntrack_expect *, tuple);
+}
+
+/* Find a expectation corresponding to a tuple. */
+struct ip6_conntrack_expect *
+ip6_conntrack_expect_find_get(const struct ip6_conntrack_tuple *tuple)
+{
+ struct ip6_conntrack_expect *exp;
+
+ READ_LOCK(&ip6_conntrack_lock);
+ READ_LOCK(&ip6_conntrack_expect_tuple_lock);
+ exp = __ip6_ct_expect_find(tuple);
+ if (exp)
+ atomic_inc(&exp->use);
+ READ_UNLOCK(&ip6_conntrack_expect_tuple_lock);
+ READ_UNLOCK(&ip6_conntrack_lock);
+
+ return exp;
+}
+
+/* remove one specific expectation from all lists and drop refcount,
+ * does _NOT_ delete the timer. */
+static void __unexpect_related(struct ip6_conntrack_expect *expect)
+{
+ DEBUGP("unexpect_related(%p)\n", expect);
+ MUST_BE_WRITE_LOCKED(&ip6_conntrack_lock);
+
+ /* we're not allowed to unexpect a confirmed expectation! */
+ IP6_NF_ASSERT(!expect->sibling);
+
+ /* delete from global and local lists */
+ list_del(&expect->list);
+ list_del(&expect->expected_list);
+
+ /* decrement expect-count of master conntrack */
+ if (expect->expectant)
+ expect->expectant->expecting--;
+
+ ip6_conntrack_expect_put(expect);
+}
+
+/* remove one specific expecatation from all lists, drop refcount
+ * and expire timer.
+ * This function can _NOT_ be called for confirmed expects! */
+static void unexpect_related(struct ip6_conntrack_expect *expect)
+{
+ IP6_NF_ASSERT(expect->expectant);
+ IP6_NF_ASSERT(expect->expectant->helper);
+ /* if we are supposed to have a timer, but we can't delete
+ * it: race condition. __unexpect_related will
+ * be calledd by timeout function */
+ if (expect->expectant->helper->timeout
+ && !del_timer(&expect->timeout))
+ return;
+
+ __unexpect_related(expect);
+}
+
+/* delete all unconfirmed expectations for this conntrack */
+static void remove_expectations(struct ip6_conntrack *ct, int drop_refcount)
+{
+ struct list_head *exp_entry, *next;
+ struct ip6_conntrack_expect *exp;
+
+ DEBUGP("remove_expectations(%p)\n", ct);
+
+ list_for_each_safe(exp_entry, next, &ct->sibling_list) {
+ exp = list_entry(exp_entry, struct ip6_conntrack_expect,
+ expected_list);
+
+ /* we skip established expectations, as we want to delete
+ * the un-established ones only */
+ if (exp->sibling) {
+ DEBUGP("remove_expectations: skipping established %p of %p\n", exp->sibling, ct);
+ if (drop_refcount) {
+ /* Indicate that this expectations parent is dead */
+ ip6_conntrack_put(exp->expectant);
+ exp->expectant = NULL;
+ }
+ continue;
+ }
+
+ IP6_NF_ASSERT(list_inlist(&ip6_conntrack_expect_list, exp));
+ IP6_NF_ASSERT(exp->expectant == ct);
+
+ /* delete expectation from global and private lists */
+ unexpect_related(exp);
+ }
+}
+
+static void
+clean_from_lists(struct ip6_conntrack *ct)
+{
+ unsigned int ho, hr;
+
+ DEBUGP("clean_from_lists(%p)\n", ct);
+ MUST_BE_WRITE_LOCKED(&ip6_conntrack_lock);
+
+ ho = hash_conntrack(&ct->tuplehash[IP6_CT_DIR_ORIGINAL].tuple);
+ hr = hash_conntrack(&ct->tuplehash[IP6_CT_DIR_REPLY].tuple);
+
+ LIST_DELETE(&ip6_conntrack_hash[ho],
+ &ct->tuplehash[IP6_CT_DIR_ORIGINAL]);
+ LIST_DELETE(&ip6_conntrack_hash[hr],
+ &ct->tuplehash[IP6_CT_DIR_REPLY]);
+
+ /* Destroy all un-established, pending expectations */
+ remove_expectations(ct, 1);
+}
+
+static void
+destroy_conntrack(struct nf_conntrack *nfct)
+{
+ struct ip6_conntrack *ct = (struct ip6_conntrack *)nfct, *master = NULL;
+ struct ip6_conntrack_protocol *proto;
+
+ DEBUGP("destroy_conntrack(%p)\n", ct);
+ IP6_NF_ASSERT(atomic_read(&nfct->use) == 0);
+ IP6_NF_ASSERT(!timer_pending(&ct->timeout));
+
+ /* To make sure we don't get any weird locking issues here:
+ * destroy_conntrack() MUST NOT be called with a write lock
+ * to ip6_conntrack_lock!!! -HW */
+ proto = ip6_ct_find_proto(ct->tuplehash[IP6_CT_DIR_REPLY].tuple.dst.protonum);
+ if (proto && proto->destroy)
+ proto->destroy(ct);
+
+ if (ip6_conntrack_destroyed)
+ ip6_conntrack_destroyed(ct);
+
+ WRITE_LOCK(&ip6_conntrack_lock);
+ /* Delete us from our own list to prevent corruption later */
+ list_del(&ct->sibling_list);
+
+ /* Delete our master expectation */
+ if (ct->master) {
+ if (ct->master->expectant) {
+ /* can't call __unexpect_related here,
+ * since it would screw up expect_list */
+ list_del(&ct->master->expected_list);
+ master = ct->master->expectant;
+ }
+ kfree(ct->master);
+ }
+ WRITE_UNLOCK(&ip6_conntrack_lock);
+
+ if (master)
+ ip6_conntrack_put(master);
+
+ DEBUGP("destroy_conntrack: returning ct=%p to slab\n", ct);
+ kmem_cache_free(ip6_conntrack_cachep, ct);
+ atomic_dec(&ip6_conntrack_count);
+}
+
+static void death_by_timeout(unsigned long ul_conntrack)
+{
+ struct ip6_conntrack *ct = (void *)ul_conntrack;
+
+ WRITE_LOCK(&ip6_conntrack_lock);
+ clean_from_lists(ct);
+ WRITE_UNLOCK(&ip6_conntrack_lock);
+ ip6_conntrack_put(ct);
+}
+
+static inline int
+conntrack_tuple_cmp(const struct ip6_conntrack_tuple_hash *i,
+ const struct ip6_conntrack_tuple *tuple,
+ const struct ip6_conntrack *ignored_conntrack)
+{
+ MUST_BE_READ_LOCKED(&ip6_conntrack_lock);
+ return i->ctrack != ignored_conntrack
+ && ip6_ct_tuple_equal(tuple, &i->tuple);
+}
+
+static struct ip6_conntrack_tuple_hash *
+__ip6_conntrack_find(const struct ip6_conntrack_tuple *tuple,
+ const struct ip6_conntrack *ignored_conntrack)
+{
+ struct ip6_conntrack_tuple_hash *h;
+ unsigned int hash = hash_conntrack(tuple);
+
+ MUST_BE_READ_LOCKED(&ip6_conntrack_lock);
+ h = LIST_FIND(&ip6_conntrack_hash[hash],
+ conntrack_tuple_cmp,
+ struct ip6_conntrack_tuple_hash *,
+ tuple, ignored_conntrack);
+ return h;
+}
+
+/* Find a connection corresponding to a tuple. */
+struct ip6_conntrack_tuple_hash *
+ip6_conntrack_find_get(const struct ip6_conntrack_tuple *tuple,
+ const struct ip6_conntrack *ignored_conntrack)
+{
+ struct ip6_conntrack_tuple_hash *h;
+
+ READ_LOCK(&ip6_conntrack_lock);
+ h = __ip6_conntrack_find(tuple, ignored_conntrack);
+ if (h)
+ atomic_inc(&h->ctrack->ct_general.use);
+ READ_UNLOCK(&ip6_conntrack_lock);
+
+ return h;
+}
+
+/* Confirm a connection given skb; places it in hash table */
+int __ip6_conntrack_confirm(struct sk_buff *skb)
+{
+ unsigned int hash, repl_hash;
+ struct ip6_conntrack *ct;
+ enum ip6_conntrack_info ctinfo;
+
+ ct = ip6_conntrack_get(skb, &ctinfo);
+
+ /* ip6t_REJECT uses ip6_conntrack_attach to attach related
+ ICMP/TCP RST packets in other direction. Actual packet
+ which created connection will be IP6_CT_NEW or for an
+ expected connection, IP6_CT_RELATED. */
+ if (CTINFO2DIR(ctinfo) != IP6_CT_DIR_ORIGINAL)
+ return NF_ACCEPT;
+
+ hash = hash_conntrack(&ct->tuplehash[IP6_CT_DIR_ORIGINAL].tuple);
+ repl_hash = hash_conntrack(&ct->tuplehash[IP6_CT_DIR_REPLY].tuple);
+
+ /* We're not in hash table, and we refuse to set up related
+ connections for unconfirmed conns. But packet copies and
+ REJECT will give spurious warnings here. */
+ /* IP6_NF_ASSERT(atomic_read(&ct->ct_general.use) == 1); */
+
+ /* No external references means noone else could have
+ confirmed us. */
+ IP6_NF_ASSERT(!is_confirmed(ct));
+ DEBUGP("Confirming conntrack %p\n", ct);
+
+ WRITE_LOCK(&ip6_conntrack_lock);
+ /* See if there's one in the list already, including reverse:
+ NAT could have grabbed it without realizing, since we're
+ not in the hash. If there is, we lost race. */
+ if (!LIST_FIND(&ip6_conntrack_hash[hash],
+ conntrack_tuple_cmp,
+ struct ip6_conntrack_tuple_hash *,
+ &ct->tuplehash[IP6_CT_DIR_ORIGINAL].tuple, NULL)
+ && !LIST_FIND(&ip6_conntrack_hash[repl_hash],
+ conntrack_tuple_cmp,
+ struct ip6_conntrack_tuple_hash *,
+ &ct->tuplehash[IP6_CT_DIR_REPLY].tuple, NULL)) {
+ list_prepend(&ip6_conntrack_hash[hash],
+ &ct->tuplehash[IP6_CT_DIR_ORIGINAL]);
+ list_prepend(&ip6_conntrack_hash[repl_hash],
+ &ct->tuplehash[IP6_CT_DIR_REPLY]);
+ /* Timer relative to confirmation time, not original
+ setting time, otherwise we'd get timer wrap in
+ wierd delay cases. */
+ ct->timeout.expires += jiffies;
+ add_timer(&ct->timeout);
+ atomic_inc(&ct->ct_general.use);
+ set_bit(IP6S_CONFIRMED_BIT, &ct->status);
+ WRITE_UNLOCK(&ip6_conntrack_lock);
+ return NF_ACCEPT;
+ }
+
+ WRITE_UNLOCK(&ip6_conntrack_lock);
+ return NF_DROP;
+}
+
+/* Is this needed ? this code is for NAT. - kozakai */
+/* Returns true if a connection correspondings to the tuple (required
+ for NAT). */
+int
+ip6_conntrack_tuple_taken(const struct ip6_conntrack_tuple *tuple,
+ const struct ip6_conntrack *ignored_conntrack)
+{
+ struct ip6_conntrack_tuple_hash *h;
+
+ READ_LOCK(&ip6_conntrack_lock);
+ h = __ip6_conntrack_find(tuple, ignored_conntrack);
+ READ_UNLOCK(&ip6_conntrack_lock);
+
+ return h != NULL;
+}
+
+/* Returns conntrack if it dealt with ICMP, and filled in skb fields */
+struct ip6_conntrack *
+icmp6_error_track(struct sk_buff *skb,
+ unsigned int icmp6off,
+ enum ip6_conntrack_info *ctinfo,
+ unsigned int hooknum)
+{
+ struct ip6_conntrack_tuple intuple, origtuple;
+ struct ip6_conntrack_tuple_hash *h;
+ struct ipv6hdr *ip6h;
+ struct icmp6hdr hdr;
+ struct ipv6hdr inip6h;
+ unsigned int inip6off;
+ struct ip6_conntrack_protocol *inproto;
+ u_int8_t inprotonum;
+ unsigned int inprotoff;
+
+ IP6_NF_ASSERT(skb->nfct == NULL);
+
+ ip6h = skb->nh.ipv6h;
+ if (skb_copy_bits(skb, icmp6off, &hdr, sizeof(hdr)) != 0) {
+ DEBUGP("icmp_error_track: Can't copy ICMPv6 hdr.\n");
+ return NULL;
+ }
+
+ if (hdr.icmp6_type >= 128)
+ return NULL;
+
+ /*
+ * Should I ignore invalid ICMPv6 error here ?
+ * ex) ICMPv6 error in ICMPv6 error, Fragmented packet, and so on.
+ * - kozakai
+ */
+
+ /* Why not check checksum in IPv4 conntrack ? - kozakai */
+ /* Ignore it if the checksum's bogus. */
+
+ if (csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, skb->len - icmp6off,
+ IPPROTO_ICMPV6,
+ skb_checksum(skb, icmp6off,
+ skb->len - icmp6off, 0))) {
+ DEBUGP("ICMPv6 checksum failed\n");
+ return NULL;
+ }
+
+ inip6off = icmp6off + sizeof(hdr);
+ if (skb_copy_bits(skb, inip6off, &inip6h, sizeof(inip6h)) != 0) {
+ DEBUGP("Can't copy inner IPv6 hdr.\n");
+ return NULL;
+ }
+
+ inprotonum = inip6h.nexthdr;
+ inprotoff = ip6_ct_skip_exthdr(skb, inip6off + sizeof(inip6h),
+ &inprotonum,
+ skb->len - inip6off - sizeof(inip6h));
+
+ if (inprotoff < 0 || inprotoff > skb->len
+ || inprotonum == NEXTHDR_FRAGMENT) {
+ DEBUGP("icmp6_error: Can't find protocol header in ICMPv6 payload.\n");
+ return NULL;
+ }
+
+ inproto = ip6_ct_find_proto(inprotonum);
+
+ /* Are they talking about one of our connections? */
+ if (!ip6_get_tuple(&inip6h, skb, inprotoff, inprotonum,
+ &origtuple, inproto)) {
+ DEBUGP("icmp6_error: ! get_tuple p=%u\n", inprotonum);
+ return NULL;
+ }
+
+ /* Ordinarily, we'd expect the inverted tupleproto, but it's
+ been preserved inside the ICMP. */
+ if (!invert_tuple(&intuple, &origtuple, inproto)) {
+ DEBUGP("icmp6_error_track: Can't invert tuple\n");
+ return NULL;
+ }
+
+ *ctinfo = IP6_CT_RELATED;
+
+ h = ip6_conntrack_find_get(&intuple, NULL);
+ if (!h) {
+ DEBUGP("icmp6_error_track: no match\n");
+ return NULL;
+ } else {
+ if (DIRECTION(h) == IP6_CT_DIR_REPLY)
+ *ctinfo += IP6_CT_IS_REPLY;
+ }
+
+ /* Update skb to refer to this connection */
+ skb->nfct = &h->ctrack->ct_general;
+ return h->ctrack;
+}
+
+/* There's a small race here where we may free a just-assured
+ connection. Too bad: we're in trouble anyway. */
+static inline int unreplied(const struct ip6_conntrack_tuple_hash *i)
+{
+ return !(test_bit(IP6S_ASSURED_BIT, &i->ctrack->status));
+}
+
+static int early_drop(struct list_head *chain)
+{
+ /* Traverse backwards: gives us oldest, which is roughly LRU */
+ struct ip6_conntrack_tuple_hash *h;
+ int dropped = 0;
+
+ READ_LOCK(&ip6_conntrack_lock);
+ h = LIST_FIND_B(chain, unreplied, struct ip6_conntrack_tuple_hash *);
+ if (h)
+ atomic_inc(&h->ctrack->ct_general.use);
+ READ_UNLOCK(&ip6_conntrack_lock);
+
+ if (!h)
+ return dropped;
+
+ if (del_timer(&h->ctrack->timeout)) {
+ death_by_timeout((unsigned long)h->ctrack);
+ dropped = 1;
+ }
+ ip6_conntrack_put(h->ctrack);
+ return dropped;
+}
+
+static inline int helper_cmp(const struct ip6_conntrack_helper *i,
+ const struct ip6_conntrack_tuple *rtuple)
+{
+ return ip6_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask);
+}
+
+struct ip6_conntrack_helper *
+ip6_ct_find_helper(const struct ip6_conntrack_tuple *tuple){
+
+ MUST_BE_READ_LOCKED(&ip6_conntrack_lock);
+ return LIST_FIND(&helpers, helper_cmp,
+ struct ip6_conntrack_helper *,
+ tuple);
+}
+
+/* Allocate a new conntrack: we return -ENOMEM if classification
+ failed due to stress. Otherwise it really is unclassifiable. */
+static struct ip6_conntrack_tuple_hash *
+init_conntrack(const struct ip6_conntrack_tuple *tuple,
+ struct ip6_conntrack_protocol *protocol,
+ struct sk_buff *skb,
+ unsigned int protoff)
+{
+ struct ip6_conntrack *conntrack;
+ struct ip6_conntrack_tuple repl_tuple;
+ size_t hash;
+ struct ip6_conntrack_expect *expected;
+ static unsigned int drop_next = 0;
+
+ if (!ip6_conntrack_hash_rnd_initted) {
+ get_random_bytes(&ip6_conntrack_hash_rnd, 4);
+ ip6_conntrack_hash_rnd_initted = 1;
+ }
+
+ hash = hash_conntrack(tuple);
+
+ if (ip6_conntrack_max &&
+ atomic_read(&ip6_conntrack_count) >= ip6_conntrack_max) {
+ /* Try dropping from random chain, or else from the
+ chain about to put into (in case they're trying to
+ bomb one hash chain). */
+ unsigned int next = (drop_next++)%ip6_conntrack_htable_size;
+
+ if (!early_drop(&ip6_conntrack_hash[next])
+ && !early_drop(&ip6_conntrack_hash[hash])) {
+ if (net_ratelimit())
+ printk(KERN_WARNING
+ "ip6_conntrack: table full, dropping"
+ " packet.\n");
+ return ERR_PTR(-ENOMEM);
+ }
+ }
+
+ if (!invert_tuple(&repl_tuple, tuple, protocol)) {
+ DEBUGP("Can't invert tuple.\n");
+ return NULL;
+ }
+
+ conntrack = kmem_cache_alloc(ip6_conntrack_cachep, GFP_ATOMIC);
+ if (!conntrack) {
+ DEBUGP("Can't allocate conntrack.\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ memset(conntrack, 0, sizeof(*conntrack));
+ atomic_set(&conntrack->ct_general.use, 1);
+ conntrack->ct_general.destroy = destroy_conntrack;
+ conntrack->tuplehash[IP6_CT_DIR_ORIGINAL].tuple = *tuple;
+ conntrack->tuplehash[IP6_CT_DIR_ORIGINAL].ctrack = conntrack;
+ conntrack->tuplehash[IP6_CT_DIR_REPLY].tuple = repl_tuple;
+ conntrack->tuplehash[IP6_CT_DIR_REPLY].ctrack = conntrack;
+
+ if (!protocol->new(conntrack, skb, protoff)) {
+ kmem_cache_free(ip6_conntrack_cachep, conntrack);
+ return NULL;
+ }
+ /* Don't set timer yet: wait for confirmation */
+ init_timer(&conntrack->timeout);
+ conntrack->timeout.data = (unsigned long)conntrack;
+ conntrack->timeout.function = death_by_timeout;
+
+ INIT_LIST_HEAD(&conntrack->sibling_list);
+
+ WRITE_LOCK(&ip6_conntrack_lock);
+ /* Need finding and deleting of expected ONLY if we win race */
+ READ_LOCK(&ip6_conntrack_expect_tuple_lock);
+ expected = LIST_FIND(&ip6_conntrack_expect_list, expect_cmp,
+ struct ip6_conntrack_expect *, tuple);
+ READ_UNLOCK(&ip6_conntrack_expect_tuple_lock);
+
+ /* If master is not in hash table yet (ie. packet hasn't left
+ this machine yet), how can other end know about expected?
+ Hence these are not the droids you are looking for (if
+ master ct never got confirmed, we'd hold a reference to it
+ and weird things would happen to future packets). */
+ if (expected && !is_confirmed(expected->expectant))
+ expected = NULL;
+
+ /* Look up the conntrack helper for master connections only */
+ if (!expected)
+ conntrack->helper = ip6_ct_find_helper(&repl_tuple);
+
+ /* If the expectation is dying, then this is a loser. */
+ if (expected
+ && expected->expectant->helper->timeout
+ && ! del_timer(&expected->timeout))
+ expected = NULL;
+
+ if (expected) {
+ DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n",
+ conntrack, expected);
+ /* Welcome, Mr. Bond. We've been expecting you... */
+ IP6_NF_ASSERT(master_ct6(conntrack));
+ __set_bit(IP6S_EXPECTED_BIT, &conntrack->status);
+ conntrack->master = expected;
+ expected->sibling = conntrack;
+ LIST_DELETE(&ip6_conntrack_expect_list, expected);
+ expected->expectant->expecting--;
+ nf_conntrack_get(&master_ct6(conntrack)->ct_general);
+ }
+ atomic_inc(&ip6_conntrack_count);
+ WRITE_UNLOCK(&ip6_conntrack_lock);
+
+ if (expected && expected->expectfn)
+ expected->expectfn(conntrack);
+ return &conntrack->tuplehash[IP6_CT_DIR_ORIGINAL];
+}
+
+/* On success, returns conntrack ptr, sets skb->nfct and ctinfo */
+static inline struct ip6_conntrack *
+resolve_normal_ct(struct sk_buff *skb,
+ unsigned int protoff,
+ u_int16_t protonum,
+ struct ip6_conntrack_protocol *proto,
+ int *set_reply,
+ unsigned int hooknum,
+ enum ip6_conntrack_info *ctinfo)
+{
+ struct ip6_conntrack_tuple tuple;
+ struct ip6_conntrack_tuple_hash *h;
+
+ if (!ip6_get_tuple(skb->nh.ipv6h, skb, protoff, protonum, &tuple, proto))
+ return NULL;
+
+ /* look for tuple match */
+ h = ip6_conntrack_find_get(&tuple, NULL);
+ if (!h) {
+ h = init_conntrack(&tuple, proto, skb, protoff);
+ if (!h)
+ return NULL;
+ if (IS_ERR(h))
+ return (void *)h;
+ }
+
+ /* It exists; we have (non-exclusive) reference. */
+ if (DIRECTION(h) == IP6_CT_DIR_REPLY) {
+ *ctinfo = IP6_CT_ESTABLISHED + IP6_CT_IS_REPLY;
+ /* Please set reply bit if this packet OK */
+ *set_reply = 1;
+ } else {
+ /* Once we've had two way comms, always ESTABLISHED. */
+ if (test_bit(IP6S_SEEN_REPLY_BIT, &h->ctrack->status)) {
+ DEBUGP("ip6_conntrack_in: normal packet for %p\n",
+ h->ctrack);
+ *ctinfo = IP6_CT_ESTABLISHED;
+ } else if (test_bit(IP6S_EXPECTED_BIT, &h->ctrack->status)) {
+ DEBUGP("ip6_conntrack_in: related packet for %p\n",
+ h->ctrack);
+ *ctinfo = IP6_CT_RELATED;
+ } else {
+ DEBUGP("ip6_conntrack_in: new packet for %p\n",
+ h->ctrack);
+ *ctinfo = IP6_CT_NEW;
+ }
+ *set_reply = 0;
+ }
+ skb->nfct = &h->ctrack->ct_general;
+ skb->nfctinfo = *ctinfo;
+ return h->ctrack;
+}
+
+/* Netfilter hook itself. */
+unsigned int ip6_conntrack_in(unsigned int hooknum,
+ struct sk_buff **pskb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ struct ip6_conntrack *ct;
+ enum ip6_conntrack_info ctinfo;
+ struct ip6_conntrack_protocol *proto;
+ int set_reply;
+ int ret;
+ u_int8_t protonum;
+ int len;
+ int daddr_type;
+ int protoff, extoff;
+
+ /* FIXME: Do this right please. --RR */
+ (*pskb)->nfcache |= NFC_UNKNOWN;
+
+ /* Ignore multicast - kozakai */
+ daddr_type = ipv6_addr_type(&(*pskb)->nh.ipv6h->daddr);
+ if (daddr_type & IPV6_ADDR_MULTICAST)
+ return NF_ACCEPT;
+
+ /* Previously seen (loopback)? Ignore. Do this before
+ fragment check. */
+ if ((*pskb)->nfct)
+ return NF_ACCEPT;
+
+ extoff = (u8*)((*pskb)->nh.ipv6h+1) - (*pskb)->data;
+ len = (*pskb)->len - extoff;
+
+ /* Verify that a protocol is present and get the protocol handler
+ we need */
+ protonum = (*pskb)->nh.ipv6h->nexthdr;
+ protoff = ip6_ct_skip_exthdr(*pskb, extoff, &protonum, len);
+
+ /*
+ * Notice! (protoff == (*pskb)->len) mean that this packet doesn't
+ * have no data except of IPv6 & ext headers. but tracked anyway.
+ * - kozakai
+ */
+ if (protoff < 0 || protoff > (*pskb)->len
+ || protonum == NEXTHDR_FRAGMENT) {
+ DEBUGP("ip6_conntrack_core: can't find proto in pkt\n");
+ return NF_ACCEPT;
+ }
+
+ /* It may be an icmp error... */
+ if (protonum == IPPROTO_ICMPV6
+ && icmp6_error_track(*pskb, protoff, &ctinfo, hooknum))
+ return NF_ACCEPT;
+
+ proto = ip6_ct_find_proto(protonum);
+
+ if (!(ct = resolve_normal_ct(*pskb, protoff, protonum, proto,
+ &set_reply, hooknum,&ctinfo)))
+ /* Not valid part of a connection */
+ return NF_ACCEPT;
+
+ if (IS_ERR(ct))
+ /* Too stressed to deal. */
+ return NF_DROP;
+
+ IP6_NF_ASSERT((*pskb)->nfct);
+
+ ret = proto->packet(ct, *pskb, protoff, ctinfo);
+ if (ret == -1) {
+ /* Invalid */
+ nf_conntrack_put((*pskb)->nfct);
+ (*pskb)->nfct = NULL;
+ return NF_ACCEPT;
+ }
+
+ if (ret != NF_DROP && ct->helper) {
+ ret = ct->helper->help(*pskb, protoff, ct, ctinfo);
+ if (ret == -1) {
+ /* Invalid */
+ nf_conntrack_put((*pskb)->nfct);
+ (*pskb)->nfct = NULL;
+ return NF_ACCEPT;
+ }
+ }
+ if (set_reply)
+ set_bit(IP6S_SEEN_REPLY_BIT, &ct->status);
+
+ return ret;
+}
+
+int ip6_invert_tuplepr(struct ip6_conntrack_tuple *inverse,
+ const struct ip6_conntrack_tuple *orig)
+{
+ return invert_tuple(inverse, orig, ip6_ct_find_proto(orig->dst.protonum));
+}
+
+static inline int resent_expect(const struct ip6_conntrack_expect *i,
+ const struct ip6_conntrack_tuple *tuple,
+ const struct ip6_conntrack_tuple *mask)
+{
+ DEBUGP("resent_expect\n");
+ DEBUGP(" tuple: "); DUMP_TUPLE(&i->tuple);
+ DEBUGP("test tuple: "); DUMP_TUPLE(tuple);
+ return (ip6_ct_tuple_equal(&i->tuple, tuple)
+ && ip6_ct_tuple_equal(&i->mask, mask));
+}
+
+static struct in6_addr *
+or_addr6_bits(struct in6_addr *result, const struct in6_addr *one,
+ const struct in6_addr *two)
+{
+
+ int count = 0;
+
+ for (count = 0; count < 8; count++)
+ result->s6_addr16[count] = ntohs(one->s6_addr16[count])
+ & ntohs(two->s6_addr16[count]);
+
+ return result;
+}
+
+/* Would two expected things clash? */
+static inline int expect_clash(const struct ip6_conntrack_expect *i,
+ const struct ip6_conntrack_tuple *tuple,
+ const struct ip6_conntrack_tuple *mask)
+{
+ /* Part covered by intersection of masks must be unequal,
+ otherwise they clash */
+ struct ip6_conntrack_tuple intersect_mask;
+
+ intersect_mask.src.u.all = i->mask.src.u.all & mask->src.u.all;
+ intersect_mask.dst.u.all = i->mask.dst.u.all & mask->dst.u.all;
+ intersect_mask.dst.protonum = i->mask.dst.protonum
+ & mask->dst.protonum;
+
+ or_addr6_bits(&intersect_mask.src.ip, &i->mask.src.ip,
+ &mask->src.ip);
+ or_addr6_bits(&intersect_mask.dst.ip, &i->mask.dst.ip,
+ &mask->dst.ip);
+
+ return ip6_ct_tuple_mask_cmp(&i->tuple, tuple, &intersect_mask);
+}
+
+inline void ip6_conntrack_unexpect_related(struct ip6_conntrack_expect *expect)
+{
+ WRITE_LOCK(&ip6_conntrack_lock);
+ unexpect_related(expect);
+ WRITE_UNLOCK(&ip6_conntrack_lock);
+}
+
+static void expectation_timed_out(unsigned long ul_expect)
+{
+ struct ip6_conntrack_expect *expect = (void *) ul_expect;
+
+ DEBUGP("expectation %p timed out\n", expect);
+ WRITE_LOCK(&ip6_conntrack_lock);
+ __unexpect_related(expect);
+ WRITE_UNLOCK(&ip6_conntrack_lock);
+}
+
+/* Add a related connection. */
+int ip6_conntrack_expect_related(struct ip6_conntrack *related_to,
+ struct ip6_conntrack_expect *expect)
+{
+ struct ip6_conntrack_expect *old, *new;
+ int ret = 0;
+
+ WRITE_LOCK(&ip6_conntrack_lock);
+ /* Because of the write lock, no reader can walk the lists,
+ * so there is no need to use the tuple lock too */
+
+ DEBUGP("ip6_conntrack_expect_related %p\n", related_to);
+ DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple);
+ DEBUGP("mask: "); DUMP_TUPLE(&expect->mask);
+
+ old = LIST_FIND(&ip6_conntrack_expect_list, resent_expect,
+ struct ip6_conntrack_expect *, &expect->tuple,
+ &expect->mask);
+ if (old) {
+ /* Helper private data may contain offsets but no pointers
+ pointing into the payload - otherwise we should have to copy
+ the data filled out by the helper over the old one */
+ DEBUGP("expect_related: resent packet\n");
+ if (related_to->helper->timeout) {
+ if (!del_timer(&old->timeout)) {
+ /* expectation is dying. Fall through */
+ old = NULL;
+ } else {
+ old->timeout.expires = jiffies +
+ related_to->helper->timeout * HZ;
+ add_timer(&old->timeout);
+ }
+ }
+
+ if (old) {
+ WRITE_UNLOCK(&ip6_conntrack_lock);
+ return -EEXIST;
+ }
+ } else if (related_to->helper->max_expected &&
+ related_to->expecting >= related_to->helper->max_expected) {
+ struct list_head *cur_item;
+ /* old == NULL */
+ if (!(related_to->helper->flags &
+ IP6_CT_HELPER_F_REUSE_EXPECT)) {
+ WRITE_UNLOCK(&ip6_conntrack_lock);
+ if (net_ratelimit())
+ printk(KERN_WARNING
+ "ip6_conntrack: max number of expected "
+ "connections %i of %s for "
+ "%x:%x:%x:%x:%x:%x:%x:%x->%x:%x:%x:%x:%x:%x:%x:%x\n",
+ related_to->helper->max_expected,
+ related_to->helper->name,
+ NIP6(related_to->tuplehash[IP6_CT_DIR_ORIGINAL].tuple.src.ip),
+ NIP6(related_to->tuplehash[IP6_CT_DIR_ORIGINAL].tuple.dst.ip));
+ return -EPERM;
+ }
+ DEBUGP("ip6_conntrack: max number of expected "
+ "connections %i of %s reached for "
+ "%x:%x:%x:%x:%x:%x:%x:%x->%x:%x:%x:%x:%x:%x:%x:%x, reusing\n",
+ related_to->helper->max_expected,
+ related_to->helper->name,
+ NIP6(related_to->tuplehash[IP6_CT_DIR_ORIGINAL].tuple.src.ip),
+ NIP6(related_to->tuplehash[IP6_CT_DIR_ORIGINAL].tuple.dst.ip));
+
+ /* choose the the oldest expectation to evict */
+ list_for_each(cur_item, &related_to->sibling_list) {
+ struct ip6_conntrack_expect *cur;
+
+ cur = list_entry(cur_item,
+ struct ip6_conntrack_expect,
+ expected_list);
+ if (cur->sibling == NULL) {
+ old = cur;
+ break;
+ }
+ }
+
+ /* (!old) cannot happen, since related_to->expecting is the
+ * number of unconfirmed expects */
+ IP6_NF_ASSERT(old);
+
+ /* newnat14 does not reuse the real allocated memory
+ * structures but rather unexpects the old and
+ * allocates a new. unexpect_related will decrement
+ * related_to->expecting.
+ */
+ unexpect_related(old);
+ ret = -EPERM;
+ } else if (LIST_FIND(&ip6_conntrack_expect_list, expect_clash,
+ struct ip6_conntrack_expect *, &expect->tuple,
+ &expect->mask)) {
+ WRITE_UNLOCK(&ip6_conntrack_lock);
+ DEBUGP("expect_related: busy!\n");
+ return -EBUSY;
+ }
+
+ new = (struct ip6_conntrack_expect *)
+ kmalloc(sizeof(struct ip6_conntrack_expect), GFP_ATOMIC);
+ if (!new) {
+ WRITE_UNLOCK(&ip6_conntrack_lock);
+ DEBUGP("expect_relaed: OOM allocating expect\n");
+ return -ENOMEM;
+ }
+
+ DEBUGP("new expectation %p of conntrack %p\n", new, related_to);
+ memcpy(new, expect, sizeof(*expect));
+ new->expectant = related_to;
+ new->sibling = NULL;
+ atomic_set(&new->use, 1);
+
+ /* add to expected list for this connection */
+ list_add(&new->expected_list, &related_to->sibling_list);
+ /* add to global list of expectations */
+ list_prepend(&ip6_conntrack_expect_list, &new->list);
+ /* add and start timer if required */
+ if (related_to->helper->timeout) {
+ init_timer(&new->timeout);
+ new->timeout.data = (unsigned long)new;
+ new->timeout.function = expectation_timed_out;
+ new->timeout.expires = jiffies +
+ related_to->helper->timeout * HZ;
+ add_timer(&new->timeout);
+ }
+ related_to->expecting++;
+
+ WRITE_UNLOCK(&ip6_conntrack_lock);
+
+ return ret;
+}
+
+
+/* Is this code needed ? this is for NAT. - kozakai */
+/* Alter reply tuple (maybe alter helper). If it's already taken,
+ return 0 and don't do alteration. */
+int ip6_conntrack_alter_reply(struct ip6_conntrack *conntrack,
+ const struct ip6_conntrack_tuple *newreply)
+{
+ WRITE_LOCK(&ip6_conntrack_lock);
+ if (__ip6_conntrack_find(newreply, conntrack)) {
+ WRITE_UNLOCK(&ip6_conntrack_lock);
+ return 0;
+ }
+ /* Should be unconfirmed, so not in hash table yet */
+ IP6_NF_ASSERT(!is_confirmed(conntrack));
+
+ DEBUGP("Altering reply tuple of %p to ", conntrack);
+ DUMP_TUPLE(newreply);
+
+ conntrack->tuplehash[IP6_CT_DIR_REPLY].tuple = *newreply;
+ if (!conntrack->master)
+ conntrack->helper = ip6_ct_find_helper(newreply);
+ WRITE_UNLOCK(&ip6_conntrack_lock);
+
+ return 1;
+}
+
+int ip6_conntrack_helper_register(struct ip6_conntrack_helper *me)
+{
+ WRITE_LOCK(&ip6_conntrack_lock);
+ list_prepend(&helpers, me);
+ WRITE_UNLOCK(&ip6_conntrack_lock);
+
+ return 0;
+}
+
+static inline int unhelp(struct ip6_conntrack_tuple_hash *i,
+ const struct ip6_conntrack_helper *me)
+{
+ if (i->ctrack->helper == me) {
+ /* Get rid of any expected. */
+ remove_expectations(i->ctrack, 0);
+ /* And *then* set helper to NULL */
+ i->ctrack->helper = NULL;
+ }
+ return 0;
+}
+
+void ip6_conntrack_helper_unregister(struct ip6_conntrack_helper *me)
+{
+ unsigned int i;
+
+ /* Need write lock here, to delete helper. */
+ WRITE_LOCK(&ip6_conntrack_lock);
+ LIST_DELETE(&helpers, me);
+
+ /* Get rid of expecteds, set helpers to NULL. */
+ for (i = 0; i < ip6_conntrack_htable_size; i++)
+ LIST_FIND_W(&ip6_conntrack_hash[i], unhelp,
+ struct ip6_conntrack_tuple_hash *, me);
+ WRITE_UNLOCK(&ip6_conntrack_lock);
+
+ /* Someone could be still looking at the helper in a bh. */
+ synchronize_net();
+}
+
+/* Refresh conntrack for this many jiffies. */
+void ip6_ct_refresh(struct ip6_conntrack *ct, unsigned long extra_jiffies)
+{
+ IP6_NF_ASSERT(ct->timeout.data == (unsigned long)ct);
+
+ WRITE_LOCK(&ip6_conntrack_lock);
+ /* If not in hash table, timer will not be active yet */
+ if (!is_confirmed(ct))
+ ct->timeout.expires = extra_jiffies;
+ else {
+ /* Need del_timer for race avoidance (may already be dying). */
+ if (del_timer(&ct->timeout)) {
+ ct->timeout.expires = jiffies + extra_jiffies;
+ add_timer(&ct->timeout);
+ }
+ }
+ WRITE_UNLOCK(&ip6_conntrack_lock);
+}
+
+/* Used by ip6t_REJECT. */
+static void ip6_conntrack_attach(struct sk_buff *nskb, struct sk_buff *skb)
+{
+ struct ip6_conntrack *ct;
+ enum ip6_conntrack_info ctinfo;
+
+ ct = ip6_conntrack_get(skb, &ctinfo);
+
+ /* This ICMP is in reverse direction to the packet which
+ caused it */
+ if (CTINFO2DIR(ctinfo) == IP6_CT_DIR_ORIGINAL)
+ ctinfo = IP6_CT_RELATED + IP6_CT_IS_REPLY;
+ else
+ ctinfo = IP6_CT_RELATED;
+
+ /* Attach new skbuff, and increment count */
+ nskb->nfct = &ct->ct_general;
+ nskb->nfctinfo = ctinfo;
+ nf_conntrack_get(nskb->nfct);
+}
+
+static inline int
+do_kill(const struct ip6_conntrack_tuple_hash *i,
+ int (*kill)(const struct ip6_conntrack *i, void *data),
+ void *data)
+{
+ return kill(i->ctrack, data);
+}
+
+/* Bring out ya dead! */
+static struct ip6_conntrack_tuple_hash *
+get_next_corpse(int (*kill)(const struct ip6_conntrack *i, void *data),
+ void *data)
+{
+ struct ip6_conntrack_tuple_hash *h = NULL;
+ unsigned int i;
+
+ READ_LOCK(&ip6_conntrack_lock);
+ for (i = 0; !h && i < ip6_conntrack_htable_size; i++) {
+ h = LIST_FIND(&ip6_conntrack_hash[i], do_kill,
+ struct ip6_conntrack_tuple_hash *, kill, data);
+ }
+ if (h)
+ atomic_inc(&h->ctrack->ct_general.use);
+ READ_UNLOCK(&ip6_conntrack_lock);
+
+ return h;
+}
+
+void
+ip6_ct_selective_cleanup(int (*kill)(const struct ip6_conntrack *i, void *data),
+ void *data)
+{
+ struct ip6_conntrack_tuple_hash *h;
+
+ /* This is order n^2, by the way. */
+ while ((h = get_next_corpse(kill, data)) != NULL) {
+ /* Time to push up daises... */
+ if (del_timer(&h->ctrack->timeout))
+ death_by_timeout((unsigned long)h->ctrack);
+ /* ... else the timer will get him soon. */
+
+ ip6_conntrack_put(h->ctrack);
+ }
+}
+
+/* Fast function for those who don't want to parse /proc (and I don't
+ blame them). */
+/* Reversing the socket's dst/src point of view gives us the reply
+ mapping. */
+static int
+getorigdst(struct sock *sk, int optval, void __user *user, int *len)
+{
+ struct inet_sock *inet = inet_sk(sk);
+ struct ipv6_pinfo *np = inet6_sk(sk);
+ struct ip6_conntrack_tuple_hash *h;
+ struct ip6_conntrack_tuple tuple;
+
+ memset(&tuple, 0, sizeof(tuple));
+ ipv6_addr_copy(&tuple.src.ip, &np->rcv_saddr);
+ ipv6_addr_copy(&tuple.dst.ip, &np->daddr);
+ tuple.src.u.tcp.port = inet->sport;
+ tuple.dst.u.tcp.port = inet->dport;
+ tuple.dst.protonum = IPPROTO_TCP;
+
+ /* We only do TCP at the moment: is there a better way? */
+ if (strcmp(sk->sk_prot->name, "TCP")) {
+ DEBUGP("IPV6_NF_ORIGINAL_DST: Not a TCP socket\n");
+ return -ENOPROTOOPT;
+ }
+
+ if ((unsigned int) *len < sizeof(struct sockaddr_in6)) {
+ DEBUGP("IPV6_NF_ORIGINAL_DST: len %u not %u\n",
+ *len, sizeof(struct sockaddr_in6));
+ return -EINVAL;
+ }
+
+ h = ip6_conntrack_find_get(&tuple, NULL);
+ if (h) {
+ struct sockaddr_in6 sin;
+ memset(&sin, 0, sizeof(sin));
+
+ sin.sin6_family = AF_INET6;
+ sin.sin6_port = h->ctrack->tuplehash[IP6_CT_DIR_ORIGINAL]
+ .tuple.dst.u.tcp.port;
+ ipv6_addr_copy(&sin.sin6_addr,
+ &h->ctrack->tuplehash[IP6_CT_DIR_ORIGINAL]
+ .tuple.dst.ip);
+ /* FIXME: sin6_scope_id */
+
+ DEBUGP("IPV6_NF_ORIGINAL_DST: %x:%x:%x:%x:%x:%x:%x:%x %u\n",
+ NIP6(sin.sin6_addr), ntohs(sin.sin6_port));
+ ip6_conntrack_put(h->ctrack);
+ if (copy_to_user(user, &sin, sizeof(sin)) != 0)
+ return -EFAULT;
+ else
+ return 0;
+ }
+ DEBUGP("IPV6_NF_ORIGINAL_DST: Can't find %x:%x:%x:%x:%x:%x:%x:%x/%u-%x:%x:%x:%x:%x:%x:%x:%x/%u.\n",
+ NIP6(tuple.src.ip), ntohs(tuple.src.u.tcp.port),
+ NIP6(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port));
+ return -ENOENT;
+}
+
+static struct nf_sockopt_ops so_getorigdst = {
+ .pf = PF_INET6,
+ .get_optmin = IPV6_NF_ORIGINAL_DST,
+ .get_optmax = IPV6_NF_ORIGINAL_DST+1,
+ .get = &getorigdst,
+};
+
+#define NET_IP6_CONNTRACK_MAX 2089
+#define NET_IP6_CONNTRACK_MAX_NAME "ip6_conntrack_max"
+
+#ifdef CONFIG_SYSCTL
+static struct ctl_table_header *ip6_conntrack_sysctl_header;
+
+static ctl_table ip6_conntrack_table[] = {
+ {
+ .ctl_name = NET_IP6_CONNTRACK_MAX,
+ .procname = NET_IP6_CONNTRACK_MAX_NAME,
+ .data = &ip6_conntrack_max,
+ .maxlen = sizeof(ip6_conntrack_max),
+ .mode = 0644,
+ .proc_handler = proc_dointvec
+ },
+ { .ctl_name = 0 }
+};
+
+static ctl_table ip6_conntrack_dir_table[] = {
+ {
+ .ctl_name = NET_IPV6,
+ .procname = "ipv6", NULL,
+ .mode = 0555,
+ .child = ip6_conntrack_table
+ },
+ { .ctl_name = 0 }
+};
+
+static ctl_table ip6_conntrack_root_table[] = {
+ {
+ .ctl_name = CTL_NET,
+ .procname = "net",
+ .mode = 0555,
+ .child = ip6_conntrack_dir_table
+ },
+ { .ctl_name = 0 }
+};
+#endif /*CONFIG_SYSCTL*/
+
+static int kill_all(const struct ip6_conntrack *i, void *data)
+{
+ return 1;
+}
+
+/* Mishearing the voices in his head, our hero wonders how he's
+ supposed to kill the mall. */
+void ip6_conntrack_cleanup(void)
+{
+#ifdef CONFIG_SYSCTL
+ unregister_sysctl_table(ip6_conntrack_sysctl_header);
+#endif
+ ip6_ct_attach = NULL;
+ /* This makes sure all current packets have passed through
+ netfilter framework. Roll on, two-stage module
+ delete... */
+ synchronize_net();
+
+ i_see_dead_people:
+ ip6_ct_selective_cleanup(kill_all, NULL);
+ if (atomic_read(&ip6_conntrack_count) != 0) {
+ schedule();
+ goto i_see_dead_people;
+ }
+
+ kmem_cache_destroy(ip6_conntrack_cachep);
+ vfree(ip6_conntrack_hash);
+ nf_unregister_sockopt(&so_getorigdst);
+}
+
+static int hashsize = 0;
+MODULE_PARM(hashsize, "i");
+
+int __init ip6_conntrack_init(void)
+{
+ unsigned int i;
+ int ret;
+
+ /* Idea from tcp.c: use 1/16384 of memory. On i386: 32MB
+ * machine has 256 buckets. >= 1GB machines have 8192 buckets. */
+ if (hashsize) {
+ ip6_conntrack_htable_size = hashsize;
+ } else {
+ ip6_conntrack_htable_size
+ = (((num_physpages << PAGE_SHIFT) / 16384)
+ / sizeof(struct list_head));
+ if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE))
+ ip6_conntrack_htable_size = 8192;
+ if (ip6_conntrack_htable_size < 16)
+ ip6_conntrack_htable_size = 16;
+ }
+ ip6_conntrack_max = 8 * ip6_conntrack_htable_size;
+
+ printk("ip6_conntrack version %s (%u buckets, %d max)"
+ " - %Zd bytes per conntrack\n", IP6_CONNTRACK_VERSION,
+ ip6_conntrack_htable_size, ip6_conntrack_max,
+ sizeof(struct ip6_conntrack));
+
+ ret = nf_register_sockopt(&so_getorigdst);
+ if (ret != 0) {
+ printk(KERN_ERR "Unable to register netfilter socket option\n");
+ return ret;
+ }
+
+ ip6_conntrack_hash = vmalloc(sizeof(struct list_head)
+ * ip6_conntrack_htable_size);
+ if (!ip6_conntrack_hash) {
+ printk(KERN_ERR "Unable to create ip6_conntrack_hash\n");
+ goto err_unreg_sockopt;
+ }
+
+ ip6_conntrack_cachep = kmem_cache_create("ip6_conntrack",
+ sizeof(struct ip6_conntrack), 0,
+ SLAB_HWCACHE_ALIGN, NULL, NULL);
+ if (!ip6_conntrack_cachep) {
+ printk(KERN_ERR "Unable to create ip6_conntrack slab cache\n");
+ goto err_free_hash;
+ }
+ /* Don't NEED lock here, but good form anyway. */
+ WRITE_LOCK(&ip6_conntrack_lock);
+ /* Sew in builtin protocols. */
+ list_append(&ip6_protocol_list, &ip6_conntrack_protocol_tcp);
+ list_append(&ip6_protocol_list, &ip6_conntrack_protocol_udp);
+ list_append(&ip6_protocol_list, &ip6_conntrack_protocol_icmpv6);
+ WRITE_UNLOCK(&ip6_conntrack_lock);
+
+ for (i = 0; i < ip6_conntrack_htable_size; i++)
+ INIT_LIST_HEAD(&ip6_conntrack_hash[i]);
+
+/* This is fucking braindead. There is NO WAY of doing this without
+ the CONFIG_SYSCTL unless you don't want to detect errors.
+ Grrr... --RR */
+#ifdef CONFIG_SYSCTL
+ ip6_conntrack_sysctl_header
+ = register_sysctl_table(ip6_conntrack_root_table, 0);
+ if (ip6_conntrack_sysctl_header == NULL) {
+ goto err_free_ct_cachep;
+ }
+#endif /*CONFIG_SYSCTL*/
+
+ /* For use by ip6t_REJECT */
+ ip6_ct_attach = ip6_conntrack_attach;
+ return ret;
+
+#ifdef CONFIG_SYSCTL
+err_free_ct_cachep:
+ kmem_cache_destroy(ip6_conntrack_cachep);
+#endif /*CONFIG_SYSCTL*/
+err_free_hash:
+ vfree(ip6_conntrack_hash);
+err_unreg_sockopt:
+ nf_unregister_sockopt(&so_getorigdst);
+
+ return -ENOMEM;
+}
diff -urN linux-2.6.11/net/ipv6/netfilter/ip6_conntrack_ftp.c linux.sinabox/net/ipv6/netfilter/ip6_conntrack_ftp.c
--- linux-2.6.11/net/ipv6/netfilter/ip6_conntrack_ftp.c 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/net/ipv6/netfilter/ip6_conntrack_ftp.c 2005-03-26 19:02:06.000000000 +0100
@@ -0,0 +1,554 @@
+/*
+ * FTP extension for IPv6 connection tracking.
+ * Linux INET6 implementation
+ *
+ * Copyright (C)2003 USAGI/WIDE Project
+ *
+ * Authors:
+ * Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
+ *
+ * Based on: net/ipv4/netfilter/ip_conntrack_ftp.c
+ *
+ * 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.
+ */
+
+/* FTP extension for IP6 connection tracking. */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/netfilter.h>
+#include <linux/ipv6.h>
+#include <linux/ctype.h>
+#include <net/checksum.h>
+#include <net/tcp.h>
+#include <net/ipv6.h>
+#include <linux/kernel.h>
+
+#include <linux/netfilter_ipv6/ip6_conntrack.h>
+#include <linux/netfilter_ipv4/lockhelp.h>
+#include <linux/netfilter_ipv6/ip6_conntrack_helper.h>
+#include <linux/netfilter_ipv6/ip6_conntrack_ftp.h>
+
+/* This is slow, but it's simple. --RR */
+static char ftp_buffer[65536];
+
+DECLARE_LOCK(ip6_ftp_lock);
+struct module *ip6_conntrack_ftp = THIS_MODULE;
+
+#define MAX_PORTS 8
+static int ports[MAX_PORTS];
+static int ports_c = 0;
+#ifdef MODULE_PARM
+MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
+#endif
+
+static int loose = 0;
+MODULE_PARM(loose, "i");
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+struct cmd_info {
+ struct in6_addr ip;
+ u_int16_t port;
+};
+
+static int try_eprt(const char *, size_t, struct cmd_info *, char);
+static int try_espv_response(const char *, size_t, struct cmd_info *, char);
+
+static struct ftp_search {
+ enum ip6_conntrack_dir dir;
+ const char *pattern;
+ size_t plen;
+ char skip;
+ char term;
+ enum ip6_ct_ftp_type ftptype;
+ int (*getnum)(const char *, size_t, struct cmd_info *, char);
+} search[] = {
+ {
+ IP6_CT_DIR_ORIGINAL,
+ "EPRT", sizeof("EPRT") - 1, ' ', '\r',
+ IP6_CT_FTP_EPRT,
+ try_eprt,
+ },
+ {
+ IP6_CT_DIR_REPLY,
+ "229 ", sizeof("229 ") - 1, '(', ')',
+ IP6_CT_FTP_EPSV,
+ try_espv_response,
+ },
+};
+
+/* This code is based on inet_pton() in glibc-2.2.4 */
+
+#define NS_IN6ADDRSZ 16
+#define NS_INADDRSZ 4
+#define NS_INT16SZ 2
+
+/*
+ * return the length of string of address parse untill error,
+ * dlen or reaching terminal char - kozakai
+ */
+static int
+get_ipv6_addr(const char *src, u_int8_t *dst, size_t dlen, u_int8_t term)
+{
+ static const char xdigits[] = "0123456789abcdef";
+ u_int8_t tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
+ const char *curtok;
+ int ch, saw_xdigit;
+ u_int32_t val;
+ size_t clen = 0;
+
+ tp = memset(tmp, '\0', NS_IN6ADDRSZ);
+ endp = tp + NS_IN6ADDRSZ;
+ colonp = NULL;
+
+ /* Leading :: requires some special handling. */
+ if (*src == ':'){
+ if (*++src != ':')
+ return (0);
+ clen++;
+ }
+
+ curtok = src;
+ saw_xdigit = 0;
+ val = 0;
+ while ((clen < dlen) && (*src != term)) {
+ const char *pch;
+
+ ch = tolower (*src++);
+ clen++;
+
+ pch = strchr(xdigits, ch);
+ if (pch != NULL) {
+ val <<= 4;
+ val |= (pch - xdigits);
+ if (val > 0xffff)
+ return (0);
+
+ saw_xdigit = 1;
+ continue;
+ }
+ if (ch == ':') {
+ curtok = src;
+ if (!saw_xdigit) {
+ if (colonp)
+ return (0);
+ colonp = tp;
+ continue;
+ } else if (*src == term) {
+ return (0);
+ }
+ if (tp + NS_INT16SZ > endp)
+ return (0);
+ *tp++ = (u_int8_t) (val >> 8) & 0xff;
+ *tp++ = (u_int8_t) val & 0xff;
+ saw_xdigit = 0;
+ val = 0;
+ continue;
+ }
+ return (0);
+ }
+ if (saw_xdigit) {
+ if (tp + NS_INT16SZ > endp)
+ return (0);
+
+ *tp++ = (u_int8_t) (val >> 8) & 0xff;
+ *tp++ = (u_int8_t) val & 0xff;
+ }
+ if (colonp != NULL) {
+ /*
+ * Since some memmove()'s erroneously fail to handle
+ * overlapping regions, we'll do the shift by hand.
+ */
+ const int n = tp - colonp;
+ int i;
+
+ if (tp == endp)
+ return (0);
+
+ for (i = 1; i <= n; i++) {
+ endp[- i] = colonp[n - i];
+ colonp[n - i] = 0;
+ }
+ tp = endp;
+ }
+ if (tp != endp || (*src != term))
+ return (0);
+
+ memcpy(dst, tmp, NS_IN6ADDRSZ);
+ return clen;
+}
+
+/* return length of port if succeed. */
+static int get_port(const char *data, u_int16_t *port, size_t dlen, char term)
+{
+ int i;
+ u_int16_t tmp_port = 0;
+
+ for(i = 0; i < dlen; i++) {
+ /* Finished? */
+ if(data[i] == term){
+ *port = htons(tmp_port);
+ return i;
+ }
+
+ if(data[i] < '0' || data[i] > '9')
+ return 0;
+
+ tmp_port = tmp_port*10 + (data[i] - '0');
+ }
+ return 0;
+}
+
+/* Returns 0, or length of numbers: |1|132.235.1.2|6275| */
+static int try_eprt(const char *data, size_t dlen, struct cmd_info *cmd,
+ char term)
+{
+ char delim;
+ int len;
+ int addr_len;
+
+ /* First character is delimiter, then "1" for IPv4, then
+ delimiter again. */
+
+ if (dlen <= 3)
+ return 0;
+
+ delim = data[0];
+
+ if (isdigit(delim) || delim < 33 || delim > 126
+ || data[1] != '2' || data[2] != delim){
+ return 0;
+ }
+ DEBUGP("Got %c2%c\n", delim, delim);
+
+ len = 3;
+
+ /* Now we have IP address. */
+ addr_len = get_ipv6_addr(&data[len], cmd->ip.s6_addr,
+ dlen - len, delim);
+
+ if (addr_len == 0)
+ return 0;
+
+ len += addr_len + 1;
+
+ DEBUGP("Got IPv6 address!\n");
+
+ addr_len = get_port(&data[len], &cmd->port, dlen, delim);
+
+ if(addr_len == 0)
+ return 0;
+
+ len += addr_len + 1;
+
+ return len;
+}
+
+/* Returns 0, or length of numbers: |||6446| */
+static int try_espv_response(const char *data, size_t dlen,
+ struct cmd_info *cmd, char term)
+{
+ char delim;
+ size_t len;
+
+ /* Three delimiters. */
+ if (dlen <= 3)
+ return 0;
+
+ delim = data[0];
+
+ if (isdigit(delim) || delim < 33 || delim > 126
+ || data[1] != delim || data[2] != delim)
+ return 0;
+
+ len = get_port(&data[3], &cmd->port, dlen, delim);
+
+ if(len == 0)
+ return 0;
+
+ return 3 + len + 1;
+}
+
+/* Return 1 for match, 0 for accept, -1 for partial. */
+static int find_pattern(const char *data, size_t dlen,
+ const char *pattern, size_t plen,
+ char skip, char term,
+ unsigned int *numoff,
+ unsigned int *numlen,
+ struct cmd_info *cmd,
+ int (*getnum)(const char *, size_t, struct cmd_info *,
+ char))
+{
+ size_t i;
+
+ DEBUGP("find_pattern `%s': dlen = %u\n", pattern, dlen);
+ if (dlen == 0)
+ return 0;
+
+ if (dlen <= plen) {
+ /* Short packet: try for partial? */
+ if (strnicmp(data, pattern, dlen) == 0)
+ return -1;
+ else return 0;
+ }
+
+ if (strnicmp(data, pattern, plen) != 0) {
+#if 0
+ size_t i;
+
+ DEBUGP("ftp: string mismatch\n");
+ for (i = 0; i < plen; i++) {
+ DEBUGP("ftp:char %u `%c'(%u) vs `%c'(%u)\n",
+ i, data[i], data[i],
+ pattern[i], pattern[i]);
+ }
+#endif
+ return 0;
+ }
+
+ DEBUGP("Pattern matches!\n");
+ /* Now we've found the constant string, try to skip
+ to the 'skip' character */
+ for (i = plen; data[i] != skip; i++)
+ if (i == dlen - 1) return -1;
+
+ /* Skip over the last character */
+ i++;
+
+ DEBUGP("Skipped up to `%c'!\n", skip);
+
+ *numoff = i;
+ *numlen = getnum(data + i, dlen - i, cmd, term);
+ if (!*numlen)
+ return -1;
+
+ DEBUGP("Match succeeded!\n");
+ return 1;
+}
+
+static int help(const struct sk_buff *skb,
+ unsigned int protoff,
+ struct ip6_conntrack *ct,
+ enum ip6_conntrack_info ctinfo)
+{
+ unsigned int dataoff, datalen;
+ struct tcphdr tcph;
+ u_int32_t old_seq_aft_nl;
+ int old_seq_aft_nl_set, ret;
+ int dir = CTINFO2DIR(ctinfo);
+ unsigned int matchlen, matchoff;
+ struct ip6_ct_ftp_master *ct_ftp_info = &ct->help.ct_ftp_info;
+ struct ip6_conntrack_expect expect, *exp = &expect;
+ struct ip6_ct_ftp_expect *exp_ftp_info = &exp->help.exp_ftp_info;
+
+ unsigned int i;
+ int found = 0;
+
+ struct ipv6hdr *ipv6h = skb->nh.ipv6h;
+ struct ip6_conntrack_tuple *t = &exp->tuple, *mask = &exp->mask;
+ struct cmd_info cmd;
+ unsigned int csum;
+
+ /* Until there's been traffic both ways, don't look in packets. */
+ if (ctinfo != IP6_CT_ESTABLISHED
+ && ctinfo != IP6_CT_ESTABLISHED+IP6_CT_IS_REPLY) {
+ DEBUGP("ftp: Conntrackinfo = %u\n", ctinfo);
+ return NF_ACCEPT;
+ }
+
+ if (skb_copy_bits(skb, protoff, &tcph, sizeof(tcph)) != 0)
+ return NF_ACCEPT;
+
+ dataoff = protoff + tcph.doff * 4;
+ /* No data? */
+ if (dataoff >= skb->len) {
+ DEBUGP("ftp: dataoff(%u) >= skblen(%u)\n", dataoff, skb->len);
+ return NF_ACCEPT;
+ }
+ datalen = skb->len - dataoff;
+
+ LOCK_BH(&ip6_ftp_lock);
+
+ csum = skb_copy_and_csum_bits(skb, dataoff, ftp_buffer,
+ skb->len - dataoff, 0);
+ csum = skb_checksum(skb, protoff, tcph.doff * 4, csum);
+
+ /* Checksum invalid? Ignore. */
+ /* FIXME: Source route IP option packets --RR */
+ if (csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len - protoff,
+ IPPROTO_TCP, csum)) {
+ DEBUGP("ftp_help: bad csum: %p %u\n"
+ "%x:%x:%x:%x:%x:%x:%x:%x -> %x:%x:%x:%x:%x:%x:%x:%x\n",
+ &tcph, skb->len - protoff, NIP6(ipv6h->saddr),
+ NIP6(ipv6h->daddr));
+ ret = NF_ACCEPT;
+ goto out;
+ }
+
+ old_seq_aft_nl_set = ct_ftp_info->seq_aft_nl_set[dir];
+ old_seq_aft_nl = ct_ftp_info->seq_aft_nl[dir];
+
+ DEBUGP("conntrack_ftp: datalen %u\n", datalen);
+ if (ftp_buffer[datalen - 1] == '\n') {
+ DEBUGP("conntrack_ftp: datalen %u ends in \\n\n", datalen);
+ if (!old_seq_aft_nl_set
+ || after(ntohl(tcph.seq) + datalen, old_seq_aft_nl)) {
+ DEBUGP("conntrack_ftp: updating nl to %u\n",
+ ntohl(tcph.seq) + datalen);
+ ct_ftp_info->seq_aft_nl[dir] =
+ ntohl(tcph.seq) + datalen;
+ ct_ftp_info->seq_aft_nl_set[dir] = 1;
+ }
+ }
+
+ if(!old_seq_aft_nl_set ||
+ (ntohl(tcph.seq) != old_seq_aft_nl)) {
+ DEBUGP("ip6_conntrack_ftp_help: wrong seq pos %s(%u)\n",
+ old_seq_aft_nl_set ? "":"(UNSET) ", old_seq_aft_nl);
+ ret = NF_ACCEPT;
+ goto out;
+ }
+
+ /* Initialize IP array to expected address (it's not mentioned
+ in EPSV responses) */
+ ipv6_addr_copy(&cmd.ip, &ct->tuplehash[dir].tuple.src.ip);
+
+ for (i = 0; i < ARRAY_SIZE(search); i++) {
+ if (search[i].dir != dir) continue;
+
+ found = find_pattern(ftp_buffer, datalen,
+ search[i].pattern,
+ search[i].plen,
+ search[i].skip,
+ search[i].term,
+ &matchoff, &matchlen,
+ &cmd,
+ search[i].getnum);
+ if (found) break;
+ }
+ if (found == -1) {
+ /* We don't usually drop packets. After all, this is
+ connection tracking, not packet filtering.
+ However, it is neccessary for accurate tracking in
+ this case. */
+ if (net_ratelimit())
+ printk("conntrack_ftp: partial %s %u+%u\n",
+ search[i].pattern,
+ ntohl(tcph.seq), datalen);
+ ret = NF_DROP;
+ goto out;
+ } else if (found == 0) { /* No match */
+ ret = NF_ACCEPT;
+ goto out;
+ }
+
+ DEBUGP("conntrack_ftp: match `%.*s' (%u bytes at %u)\n",
+ (int)matchlen, ftp_buffer + matchoff,
+ matchlen, ntohl(tcph.seq) + matchoff);
+
+ memset(&expect, 0, sizeof(expect));
+
+ /* Update the ftp info */
+ if (!ipv6_addr_cmp(&cmd.ip, &ct->tuplehash[dir].tuple.src.ip)) {
+ exp->seq = ntohl(tcph.seq) + matchoff;
+ exp_ftp_info->len = matchlen;
+ exp_ftp_info->ftptype = search[i].ftptype;
+ exp_ftp_info->port = cmd.port;
+ } else {
+ /*
+ This situation is occurred with NAT.
+ */
+ if (!loose) {
+ ret = NF_ACCEPT;
+ goto out;
+ }
+ }
+
+ ipv6_addr_copy(&t->src.ip, &ct->tuplehash[!dir].tuple.src.ip);
+ ipv6_addr_copy(&t->dst.ip, &cmd.ip);
+ t->src.u.tcp.port = 0;
+ t->dst.u.tcp.port = cmd.port;
+ t->dst.protonum = IPPROTO_TCP;
+
+ ipv6_addr_set(&mask->src.ip, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF);
+ mask->src.u.tcp.port = 0;
+ mask->dst.u.tcp.port = 0xFFFF;
+ mask->dst.protonum = 0xFFFF;
+
+ exp->expectfn = NULL;
+
+ /* Ignore failure; should only happen with NAT */
+ ip6_conntrack_expect_related(ct, &expect);
+ ret = NF_ACCEPT;
+ out:
+ UNLOCK_BH(&ip6_ftp_lock);
+ return ret;
+}
+
+static struct ip6_conntrack_helper ftp[MAX_PORTS];
+static char ftp_names[MAX_PORTS][10];
+
+/* Not __exit: called from init() */
+static void fini(void)
+{
+ int i;
+ for (i = 0; i < ports_c; i++) {
+ DEBUGP("ip6_ct_ftp: unregistering helper for port %d\n",
+ ports[i]);
+ ip6_conntrack_helper_unregister(&ftp[i]);
+ }
+}
+
+static int __init init(void)
+{
+ int i, ret;
+ char *tmpname;
+
+ if (ports[0] == 0)
+ ports[0] = FTP_PORT;
+
+ for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
+ memset(&ftp[i], 0, sizeof(struct ip6_conntrack_helper));
+ ftp[i].tuple.src.u.tcp.port = htons(ports[i]);
+ ftp[i].tuple.dst.protonum = IPPROTO_TCP;
+ ftp[i].mask.src.u.tcp.port = 0xFFFF;
+ ftp[i].mask.dst.protonum = 0xFFFF;
+ ftp[i].max_expected = 1;
+ ftp[i].timeout = 0;
+ ftp[i].flags = IP6_CT_HELPER_F_REUSE_EXPECT;
+ ftp[i].me = ip6_conntrack_ftp;
+ ftp[i].help = help;
+
+ tmpname = &ftp_names[i][0];
+ if (ports[i] == FTP_PORT)
+ sprintf(tmpname, "ftp");
+ else
+ sprintf(tmpname, "ftp-%d", ports[i]);
+ ftp[i].name = tmpname;
+
+ DEBUGP("ip6_ct_ftp: registering helper for port %d\n",
+ ports[i]);
+ ret = ip6_conntrack_helper_register(&ftp[i]);
+
+ if (ret) {
+ fini();
+ return ret;
+ }
+ ports_c++;
+ }
+ return 0;
+}
+
+
+PROVIDES_CONNTRACK6(ftp);
+EXPORT_SYMBOL(ip6_ftp_lock);
+MODULE_LICENSE("GPL");
+module_init(init);
+module_exit(fini);
diff -urN linux-2.6.11/net/ipv6/netfilter/ip6_conntrack_proto_generic.c linux.sinabox/net/ipv6/netfilter/ip6_conntrack_proto_generic.c
--- linux-2.6.11/net/ipv6/netfilter/ip6_conntrack_proto_generic.c 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/net/ipv6/netfilter/ip6_conntrack_proto_generic.c 2005-03-26 19:02:06.000000000 +0100
@@ -0,0 +1,82 @@
+/*
+ * IPv6 generic protocol extension for IPv6 connection tracking
+ * Linux INET6 implementation
+ *
+ * Copyright (C)2003 USAGI/WIDE Project
+ *
+ * Authors:
+ * Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
+ *
+ * Based on: net/ipv4/netfilter/ip_conntrack_proto_generic.c
+ *
+ * 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.
+ */
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv6/ip6_conntrack_protocol.h>
+
+#define GENERIC_TIMEOUT (600*HZ)
+
+static int generic_pkt_to_tuple(const struct sk_buff *skb,
+ unsigned int dataoff,
+ struct ip6_conntrack_tuple *tuple)
+{
+ tuple->src.u.all = 0;
+ tuple->dst.u.all = 0;
+
+ return 1;
+}
+
+static int generic_invert_tuple(struct ip6_conntrack_tuple *tuple,
+ const struct ip6_conntrack_tuple *orig)
+{
+ tuple->src.u.all = 0;
+ tuple->dst.u.all = 0;
+
+ return 1;
+}
+
+/* Print out the per-protocol part of the tuple. */
+static unsigned int generic_print_tuple(char *buffer,
+ const struct ip6_conntrack_tuple *tuple)
+{
+ return 0;
+}
+
+/* Print out the private part of the conntrack. */
+static unsigned int generic_print_conntrack(char *buffer,
+ const struct ip6_conntrack *state)
+{
+ return 0;
+}
+
+/* Returns verdict for packet, or -1 for invalid. */
+static int established(struct ip6_conntrack *conntrack,
+ const struct sk_buff *skb,
+ unsigned int dataoff,
+ enum ip6_conntrack_info conntrackinfo)
+{
+ ip6_ct_refresh(conntrack, GENERIC_TIMEOUT);
+ return NF_ACCEPT;
+}
+
+/* Called when a new connection for this protocol found. */
+static int
+new(struct ip6_conntrack *conntrack,
+ const struct sk_buff *skb,
+ unsigned int dataoff)
+{
+ return 1;
+}
+
+struct ip6_conntrack_protocol ip6_conntrack_generic_protocol
+= { { NULL, NULL }, 0, "unknown",
+ generic_pkt_to_tuple, generic_invert_tuple, generic_print_tuple,
+ generic_print_conntrack, established, new, NULL, NULL, NULL };
+
diff -urN linux-2.6.11/net/ipv6/netfilter/ip6_conntrack_proto_icmpv6.c linux.sinabox/net/ipv6/netfilter/ip6_conntrack_proto_icmpv6.c
--- linux-2.6.11/net/ipv6/netfilter/ip6_conntrack_proto_icmpv6.c 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/net/ipv6/netfilter/ip6_conntrack_proto_icmpv6.c 2005-03-26 19:02:06.000000000 +0100
@@ -0,0 +1,135 @@
+/*
+ * ICMPv6 extension for IPv6 connection tracking
+ * Linux INET6 implementation
+ *
+ * Copyright (C)2003 USAGI/WIDE Project
+ *
+ * Authors:
+ * Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
+ *
+ * Based on: net/ipv4/netfilter/ip_conntrack_proto_icmp.c
+ *
+ * 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.
+ */
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/netfilter.h>
+#include <linux/in.h>
+#include <linux/icmpv6.h>
+#include <linux/netfilter_ipv6/ip6_conntrack_protocol.h>
+
+#define ICMPV6_TIMEOUT (30*HZ)
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+static int icmpv6_pkt_to_tuple(const struct sk_buff *skb,
+ unsigned int dataoff,
+ struct ip6_conntrack_tuple *tuple)
+{
+ struct icmp6hdr hdr;
+
+ if (skb_copy_bits(skb, dataoff, &hdr, sizeof(hdr)) != 0)
+ return 0;
+ tuple->dst.u.icmpv6.type = hdr.icmp6_type;
+ tuple->src.u.icmpv6.id = hdr.icmp6_identifier;
+ tuple->dst.u.icmpv6.code = hdr.icmp6_code;
+
+ return 1;
+}
+
+static int icmpv6_invert_tuple(struct ip6_conntrack_tuple *tuple,
+ const struct ip6_conntrack_tuple *orig)
+{
+ /* Add 1; spaces filled with 0. */
+ static u_int8_t invmap[] = {
+ [ICMPV6_ECHO_REQUEST] = ICMPV6_ECHO_REPLY + 1,
+ [ICMPV6_ECHO_REPLY] = ICMPV6_ECHO_REQUEST + 1,
+ [ICMPV6_NI_QUERY] = ICMPV6_NI_QUERY + 1,
+ [ICMPV6_NI_REPLY] = ICMPV6_NI_REPLY +1
+ };
+
+ if (orig->dst.u.icmpv6.type >= sizeof(invmap)
+ || !invmap[orig->dst.u.icmpv6.type])
+ return 0;
+
+ tuple->src.u.icmpv6.id = orig->src.u.icmpv6.id;
+ tuple->dst.u.icmpv6.type = invmap[orig->dst.u.icmpv6.type] - 1;
+ tuple->dst.u.icmpv6.code = orig->dst.u.icmpv6.code;
+ return 1;
+}
+
+/* Print out the per-protocol part of the tuple. */
+static unsigned int icmpv6_print_tuple(char *buffer,
+ const struct ip6_conntrack_tuple *tuple)
+{
+ return sprintf(buffer, "type=%u code=%u id=%u ",
+ tuple->dst.u.icmpv6.type,
+ tuple->dst.u.icmpv6.code,
+ ntohs(tuple->src.u.icmpv6.id));
+}
+
+/* Print out the private part of the conntrack. */
+static unsigned int icmpv6_print_conntrack(char *buffer,
+ const struct ip6_conntrack *conntrack)
+{
+ return sprintf(buffer, "count=%u ",
+ atomic_read(&conntrack->proto.icmpv6.count));
+}
+
+/* Returns verdict for packet, or -1 for invalid. */
+static int icmpv6_packet(struct ip6_conntrack *ct,
+ const struct sk_buff *skb,
+ unsigned int dataoff,
+ enum ip6_conntrack_info ctinfo)
+{
+ /* Try to delete connection immediately after all replies:
+ won't actually vanish as we still have skb, and del_timer
+ means this will only run once even if count hits zero twice
+ (theoretically possible with SMP) */
+ if (CTINFO2DIR(ctinfo) == IP6_CT_DIR_REPLY) {
+ if (atomic_dec_and_test(&ct->proto.icmpv6.count)
+ && del_timer(&ct->timeout))
+ ct->timeout.function((unsigned long)ct);
+ } else {
+ atomic_inc(&ct->proto.icmpv6.count);
+ ip6_ct_refresh(ct, ICMPV6_TIMEOUT);
+ }
+
+ return NF_ACCEPT;
+}
+
+/* Called when a new connection for this protocol found. */
+static int icmpv6_new(struct ip6_conntrack *conntrack,
+ const struct sk_buff *skb,
+ unsigned int dataoff)
+{
+ static u_int8_t valid_new[] = {
+ [ICMPV6_ECHO_REQUEST] = 1,
+ [ICMPV6_NI_QUERY] = 1
+ };
+
+ if (conntrack->tuplehash[0].tuple.dst.u.icmpv6.type >= sizeof(valid_new)
+ || !valid_new[conntrack->tuplehash[0].tuple.dst.u.icmpv6.type]) {
+ /* Can't create a new ICMPV6 `conn' with this. */
+ DEBUGP("icmpv6: can't create new conn with type %u\n",
+ conntrack->tuplehash[0].tuple.dst.u.icmpv6.type);
+ DUMP_TUPLE(&conntrack->tuplehash[0].tuple);
+ return 0;
+ }
+ atomic_set(&conntrack->proto.icmpv6.count, 0);
+ return 1;
+}
+
+struct ip6_conntrack_protocol ip6_conntrack_protocol_icmpv6
+= { { NULL, NULL }, IPPROTO_ICMPV6, "icmpv6",
+ icmpv6_pkt_to_tuple, icmpv6_invert_tuple, icmpv6_print_tuple,
+ icmpv6_print_conntrack, icmpv6_packet, icmpv6_new, NULL, NULL, NULL };
diff -urN linux-2.6.11/net/ipv6/netfilter/ip6_conntrack_proto_tcp.c linux.sinabox/net/ipv6/netfilter/ip6_conntrack_proto_tcp.c
--- linux-2.6.11/net/ipv6/netfilter/ip6_conntrack_proto_tcp.c 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/net/ipv6/netfilter/ip6_conntrack_proto_tcp.c 2005-03-26 19:02:06.000000000 +0100
@@ -0,0 +1,273 @@
+/*
+ * TCP extension for IPv6 Connection Tracking
+ * Linux INET6 implementation
+ *
+ * Copyright (C)2003 USAGI/WIDE Project
+ *
+ * Authors:
+ * Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
+ *
+ * Based on: net/ipv4/netfilter/ip_conntrack_proto_tcp.c
+ *
+ * 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.
+ */
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/netfilter.h>
+#include <linux/module.h>
+#include <linux/in.h>
+#include <linux/ipv6.h>
+#include <linux/tcp.h>
+#include <linux/string.h>
+
+#include <net/tcp.h>
+
+#include <linux/netfilter_ipv6/ip6_conntrack.h>
+#include <linux/netfilter_ipv6/ip6_conntrack_protocol.h>
+#include <linux/netfilter_ipv4/lockhelp.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+/* Protects conntrack->proto.tcp */
+static DECLARE_RWLOCK(tcp_lock);
+
+/* FIXME: Examine ipfilter's timeouts and conntrack transitions more
+ closely. They're more complex. --RR */
+
+/* Actually, I believe that neither ipmasq (where this code is stolen
+ from) nor ipfilter do it exactly right. A new conntrack machine taking
+ into account packet loss (which creates uncertainty as to exactly
+ the conntrack of the connection) is required. RSN. --RR */
+
+static const char *tcp_conntrack_names[] = {
+ "NONE",
+ "ESTABLISHED",
+ "SYN_SENT",
+ "SYN_RECV",
+ "FIN_WAIT",
+ "TIME_WAIT",
+ "CLOSE",
+ "CLOSE_WAIT",
+ "LAST_ACK",
+ "LISTEN"
+};
+
+#define SECS *HZ
+#define MINS * 60 SECS
+#define HOURS * 60 MINS
+#define DAYS * 24 HOURS
+
+
+static unsigned long tcp_timeouts[]
+= { 30 MINS, /* TCP_CONNTRACK_NONE, */
+ 5 DAYS, /* TCP_CONNTRACK_ESTABLISHED, */
+ 2 MINS, /* TCP_CONNTRACK_SYN_SENT, */
+ 60 SECS, /* TCP_CONNTRACK_SYN_RECV, */
+ 2 MINS, /* TCP_CONNTRACK_FIN_WAIT, */
+ 2 MINS, /* TCP_CONNTRACK_TIME_WAIT, */
+ 10 SECS, /* TCP_CONNTRACK_CLOSE, */
+ 60 SECS, /* TCP_CONNTRACK_CLOSE_WAIT, */
+ 30 SECS, /* TCP_CONNTRACK_LAST_ACK, */
+ 2 MINS, /* TCP_CONNTRACK_LISTEN, */
+};
+
+#define sNO TCP_CONNTRACK_NONE
+#define sES TCP_CONNTRACK_ESTABLISHED
+#define sSS TCP_CONNTRACK_SYN_SENT
+#define sSR TCP_CONNTRACK_SYN_RECV
+#define sFW TCP_CONNTRACK_FIN_WAIT
+#define sTW TCP_CONNTRACK_TIME_WAIT
+#define sCL TCP_CONNTRACK_CLOSE
+#define sCW TCP_CONNTRACK_CLOSE_WAIT
+#define sLA TCP_CONNTRACK_LAST_ACK
+#define sLI TCP_CONNTRACK_LISTEN
+#define sIV TCP_CONNTRACK_MAX
+
+static enum tcp_conntrack tcp_conntracks[2][5][TCP_CONNTRACK_MAX] = {
+ {
+/* ORIGINAL */
+/* sNO, sES, sSS, sSR, sFW, sTW, sCL, sCW, sLA, sLI */
+/*syn*/ {sSS, sES, sSS, sSR, sSS, sSS, sSS, sSS, sSS, sLI },
+/*fin*/ {sTW, sFW, sSS, sTW, sFW, sTW, sCL, sTW, sLA, sLI },
+/*ack*/ {sES, sES, sSS, sES, sFW, sTW, sCL, sCW, sLA, sES },
+/*rst*/ {sCL, sCL, sSS, sCL, sCL, sTW, sCL, sCL, sCL, sCL },
+/*none*/{sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV }
+ },
+ {
+/* REPLY */
+/* sNO, sES, sSS, sSR, sFW, sTW, sCL, sCW, sLA, sLI */
+/*syn*/ {sSR, sES, sSR, sSR, sSR, sSR, sSR, sSR, sSR, sSR },
+/*fin*/ {sCL, sCW, sSS, sTW, sTW, sTW, sCL, sCW, sLA, sLI },
+/*ack*/ {sCL, sES, sSS, sSR, sFW, sTW, sCL, sCW, sCL, sLI },
+/*rst*/ {sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sLA, sLI },
+/*none*/{sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV }
+ }
+};
+
+static int tcp_pkt_to_tuple(const struct sk_buff *skb,
+ unsigned int dataoff,
+ struct ip6_conntrack_tuple *tuple)
+{
+ struct tcphdr hdr;
+
+ /* Actually only need first 8 bytes. */
+ if (skb_copy_bits(skb, dataoff, &hdr, 8) != 0)
+ return 0;
+
+ tuple->src.u.tcp.port = hdr.source;
+ tuple->dst.u.tcp.port = hdr.dest;
+
+ return 1;
+}
+
+static int tcp_invert_tuple(struct ip6_conntrack_tuple *tuple,
+ const struct ip6_conntrack_tuple *orig)
+{
+ tuple->src.u.tcp.port = orig->dst.u.tcp.port;
+ tuple->dst.u.tcp.port = orig->src.u.tcp.port;
+ return 1;
+}
+
+/* Print out the per-protocol part of the tuple. */
+static unsigned int tcp_print_tuple(char *buffer,
+ const struct ip6_conntrack_tuple *tuple)
+{
+ return sprintf(buffer, "sport=%hu dport=%hu ",
+ ntohs(tuple->src.u.tcp.port),
+ ntohs(tuple->dst.u.tcp.port));
+}
+
+/* Print out the private part of the conntrack. */
+static unsigned int tcp_print_conntrack(char *buffer,
+ const struct ip6_conntrack *conntrack)
+{
+ enum tcp_conntrack state;
+
+ READ_LOCK(&tcp_lock);
+ state = conntrack->proto.tcp.state;
+ READ_UNLOCK(&tcp_lock);
+
+ return sprintf(buffer, "%s ", tcp_conntrack_names[state]);
+}
+
+static unsigned int get_conntrack_index(const struct tcphdr *tcph)
+{
+ if (tcph->rst) return 3;
+ else if (tcph->syn) return 0;
+ else if (tcph->fin) return 1;
+ else if (tcph->ack) return 2;
+ else return 4;
+}
+
+/* Returns verdict for packet, or -1 for invalid. */
+static int tcp_packet(struct ip6_conntrack *conntrack,
+ const struct sk_buff *skb,
+ unsigned int dataoff,
+ enum ip6_conntrack_info ctinfo)
+{
+ enum tcp_conntrack newconntrack, oldtcpstate;
+ struct tcphdr tcph;
+
+ if (skb_copy_bits(skb, dataoff, &tcph, sizeof(tcph)) != 0)
+ return -1;
+
+ WRITE_LOCK(&tcp_lock);
+ oldtcpstate = conntrack->proto.tcp.state;
+ newconntrack
+ = tcp_conntracks
+ [CTINFO2DIR(ctinfo)]
+ [get_conntrack_index(&tcph)][oldtcpstate];
+
+ /* Invalid */
+ if (newconntrack == TCP_CONNTRACK_MAX) {
+ DEBUGP("ip6_conntrack_tcp: Invalid dir=%i index=%u conntrack=%u\n",
+ CTINFO2DIR(ctinfo), get_conntrack_index(&tcph),
+ conntrack->proto.tcp.state);
+ WRITE_UNLOCK(&tcp_lock);
+ return -1;
+ }
+
+ conntrack->proto.tcp.state = newconntrack;
+
+ /* Poor man's window tracking: record SYN/ACK for handshake check */
+ if (oldtcpstate == TCP_CONNTRACK_SYN_SENT
+ && CTINFO2DIR(ctinfo) == IP6_CT_DIR_REPLY
+ && tcph.syn && tcph.ack)
+ conntrack->proto.tcp.handshake_ack
+ = htonl(ntohl(tcph.seq) + 1);
+
+ /* If only reply is a RST, we can consider ourselves not to
+ have an established connection: this is a fairly common
+ problem case, so we can delete the conntrack
+ immediately. --RR */
+ if (!test_bit(IP6S_SEEN_REPLY_BIT, &conntrack->status) && tcph.rst) {
+ WRITE_UNLOCK(&tcp_lock);
+ if (del_timer(&conntrack->timeout))
+ conntrack->timeout.function((unsigned long)conntrack);
+ } else {
+ /* Set ASSURED if we see see valid ack in ESTABLISHED after SYN_RECV */
+ if (oldtcpstate == TCP_CONNTRACK_SYN_RECV
+ && CTINFO2DIR(ctinfo) == IP6_CT_DIR_ORIGINAL
+ && tcph.ack && !tcph.syn
+ && tcph.ack_seq == conntrack->proto.tcp.handshake_ack)
+ set_bit(IP6S_ASSURED_BIT, &conntrack->status);
+
+ WRITE_UNLOCK(&tcp_lock);
+ ip6_ct_refresh(conntrack, tcp_timeouts[newconntrack]);
+ }
+
+ return NF_ACCEPT;
+}
+
+/* Called when a new connection for this protocol found. */
+static int tcp_new(struct ip6_conntrack *conntrack, const struct sk_buff *skb,
+ unsigned int dataoff)
+{
+ enum tcp_conntrack newconntrack;
+ struct tcphdr tcph;
+
+ if (skb_copy_bits(skb, dataoff, &tcph, sizeof(tcph)) != 0)
+ return -1;
+
+ /* Don't need lock here: this conntrack not in circulation yet */
+ newconntrack
+ = tcp_conntracks[0][get_conntrack_index(&tcph)]
+ [TCP_CONNTRACK_NONE];
+
+ /* Invalid: delete conntrack */
+ if (newconntrack == TCP_CONNTRACK_MAX) {
+ DEBUGP("ip6_conntrack_tcp: invalid new deleting.\n");
+ return 0;
+ }
+
+ conntrack->proto.tcp.state = newconntrack;
+ return 1;
+}
+
+static int tcp_exp_matches_pkt(struct ip6_conntrack_expect *exp,
+ const struct sk_buff *skb,
+ unsigned int dataoff)
+{
+ struct tcphdr tcph;
+ unsigned int datalen;
+
+ if (skb_copy_bits(skb, dataoff, &tcph, sizeof(tcph)) != 0)
+ return 0;
+ datalen = skb->len - dataoff;
+
+ return between(exp->seq, ntohl(tcph.seq), ntohl(tcph.seq) + datalen);
+}
+
+struct ip6_conntrack_protocol ip6_conntrack_protocol_tcp
+= { { NULL, NULL }, IPPROTO_TCP, "tcp",
+ tcp_pkt_to_tuple, tcp_invert_tuple, tcp_print_tuple, tcp_print_conntrack,
+ tcp_packet, tcp_new, NULL, tcp_exp_matches_pkt, NULL };
diff -urN linux-2.6.11/net/ipv6/netfilter/ip6_conntrack_proto_udp.c linux.sinabox/net/ipv6/netfilter/ip6_conntrack_proto_udp.c
--- linux-2.6.11/net/ipv6/netfilter/ip6_conntrack_proto_udp.c 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/net/ipv6/netfilter/ip6_conntrack_proto_udp.c 2005-03-26 19:02:06.000000000 +0100
@@ -0,0 +1,95 @@
+/*
+ * UDP extension for IPv6 Connection Tracking
+ * Linux INET6 implementation
+ *
+ * Copyright (C)2003 USAGI/WIDE Project
+ *
+ * Authors:
+ * Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
+ *
+ * Based on: net/ipv4/netfilter/ip_conntrack_proto_udp.c
+ *
+ * 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.
+ */
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/netfilter.h>
+#include <linux/udp.h>
+#include <linux/netfilter_ipv6/ip6_conntrack_protocol.h>
+
+#define UDP_TIMEOUT (30*HZ)
+#define UDP_STREAM_TIMEOUT (180*HZ)
+
+static int udp_pkt_to_tuple(const struct sk_buff *skb,
+ unsigned int dataoff,
+ struct ip6_conntrack_tuple *tuple)
+{
+ struct udphdr hdr;
+
+ /* Actually only need first 8 bytes. */
+ if (skb_copy_bits(skb, dataoff, &hdr, 8) != 0)
+ return 0;
+
+ tuple->src.u.udp.port = hdr.source;
+ tuple->dst.u.udp.port = hdr.dest;
+
+ return 1;
+}
+
+static int udp_invert_tuple(struct ip6_conntrack_tuple *tuple,
+ const struct ip6_conntrack_tuple *orig)
+{
+ tuple->src.u.udp.port = orig->dst.u.udp.port;
+ tuple->dst.u.udp.port = orig->src.u.udp.port;
+ return 1;
+}
+
+/* Print out the per-protocol part of the tuple. */
+static unsigned int udp_print_tuple(char *buffer,
+ const struct ip6_conntrack_tuple *tuple)
+{
+ return sprintf(buffer, "sport=%hu dport=%hu ",
+ ntohs(tuple->src.u.udp.port),
+ ntohs(tuple->dst.u.udp.port));
+}
+
+/* Print out the private part of the conntrack. */
+static unsigned int udp_print_conntrack(char *buffer,
+ const struct ip6_conntrack *conntrack)
+{
+ return 0;
+}
+
+/* Returns verdict for packet, and may modify conntracktype */
+static int udp_packet(struct ip6_conntrack *conntrack,
+ const struct sk_buff *skb,
+ unsigned int dataoff,
+ enum ip6_conntrack_info conntrackinfo)
+{
+ /* If we've seen traffic both ways, this is some kind of UDP
+ stream. Extend timeout. */
+ if (test_bit(IP6S_SEEN_REPLY_BIT, &conntrack->status)) {
+ ip6_ct_refresh(conntrack, UDP_STREAM_TIMEOUT);
+ /* Also, more likely to be important, and not a probe */
+ set_bit(IP6S_ASSURED_BIT, &conntrack->status);
+ } else
+ ip6_ct_refresh(conntrack, UDP_TIMEOUT);
+
+ return NF_ACCEPT;
+}
+
+/* Called when a new connection for this protocol found. */
+static int udp_new(struct ip6_conntrack *conntrack, const struct sk_buff *skb,
+ unsigned int dataoff)
+{
+ return 1;
+}
+
+struct ip6_conntrack_protocol ip6_conntrack_protocol_udp
+= { { NULL, NULL }, IPPROTO_UDP, "udp",
+ udp_pkt_to_tuple, udp_invert_tuple, udp_print_tuple, udp_print_conntrack,
+ udp_packet, udp_new, NULL, NULL, NULL };
diff -urN linux-2.6.11/net/ipv6/netfilter/ip6_conntrack_reasm.c linux.sinabox/net/ipv6/netfilter/ip6_conntrack_reasm.c
--- linux-2.6.11/net/ipv6/netfilter/ip6_conntrack_reasm.c 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/net/ipv6/netfilter/ip6_conntrack_reasm.c 2005-03-26 19:02:06.000000000 +0100
@@ -0,0 +1,990 @@
+/*
+ * IPv6 fragment reassembly for connection tracking
+ * Linux INET6 implementation
+ *
+ * Copyright (C)2003 USAGI/WIDE Project
+ *
+ * Authors:
+ * Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
+ *
+ * Based on: net/ipv6/reassembly.c
+ *
+ * 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.
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/jiffies.h>
+#include <linux/net.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/in6.h>
+#include <linux/ipv6.h>
+#include <linux/icmpv6.h>
+#include <linux/random.h>
+#include <linux/jhash.h>
+
+#include <net/sock.h>
+#include <net/snmp.h>
+
+#include <net/ipv6.h>
+#include <net/protocol.h>
+#include <net/transp_v6.h>
+#include <net/rawv6.h>
+#include <net/ndisc.h>
+#include <net/addrconf.h>
+#include <linux/sysctl.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv6.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+#define IP6CT_FRAGS_HIGH_THRESH 262144 /* == 256*1024 */
+#define IP6CT_FRAGS_LOW_THRESH 196608 /* == 192*1024 */
+#define IP6CT_FRAGS_TIMEOUT IPV6_FRAG_TIMEOUT
+
+static int sysctl_ip6_ct_frag_high_thresh = 256*1024;
+static int sysctl_ip6_ct_frag_low_thresh = 192*1024;
+static int sysctl_ip6_ct_frag_time = IPV6_FRAG_TIMEOUT;
+
+struct ip6ct_frag_skb_cb
+{
+ struct inet6_skb_parm h;
+ int offset;
+ struct sk_buff *orig;
+};
+
+#define IP6CT_FRAG6_CB(skb) ((struct ip6ct_frag_skb_cb*)((skb)->cb))
+
+
+/*
+ * Equivalent of ipv4 struct ipq
+ */
+
+struct ip6ct_frag_queue
+{
+ struct ip6ct_frag_queue *next;
+ struct list_head lru_list; /* lru list member */
+
+ __u32 id; /* fragment id */
+ struct in6_addr saddr;
+ struct in6_addr daddr;
+
+ spinlock_t lock;
+ atomic_t refcnt;
+ struct timer_list timer; /* expire timer */
+ struct sk_buff *fragments;
+ int len;
+ int meat;
+ struct timeval stamp;
+ unsigned int csum;
+ __u8 last_in; /* has first/last segment arrived? */
+#define COMPLETE 4
+#define FIRST_IN 2
+#define LAST_IN 1
+ __u16 nhoffset;
+ struct ip6ct_frag_queue **pprev;
+};
+
+/* Hash table. */
+
+#define IP6CT_Q_HASHSZ 64
+
+static struct ip6ct_frag_queue *ip6_ct_frag_hash[IP6CT_Q_HASHSZ];
+static rwlock_t ip6_ct_frag_lock = RW_LOCK_UNLOCKED;
+static u32 ip6_ct_frag_hash_rnd;
+static LIST_HEAD(ip6_ct_frag_lru_list);
+int ip6_ct_frag_nqueues = 0;
+
+static __inline__ void __fq_unlink(struct ip6ct_frag_queue *fq)
+{
+ if(fq->next)
+ fq->next->pprev = fq->pprev;
+ *fq->pprev = fq->next;
+ list_del(&fq->lru_list);
+ ip6_ct_frag_nqueues--;
+}
+
+static __inline__ void fq_unlink(struct ip6ct_frag_queue *fq)
+{
+ write_lock(&ip6_ct_frag_lock);
+ __fq_unlink(fq);
+ write_unlock(&ip6_ct_frag_lock);
+}
+
+static unsigned int ip6qhashfn(u32 id, struct in6_addr *saddr,
+ struct in6_addr *daddr)
+{
+ u32 a, b, c;
+
+ a = saddr->s6_addr32[0];
+ b = saddr->s6_addr32[1];
+ c = saddr->s6_addr32[2];
+
+ a += JHASH_GOLDEN_RATIO;
+ b += JHASH_GOLDEN_RATIO;
+ c += ip6_ct_frag_hash_rnd;
+ __jhash_mix(a, b, c);
+
+ a += saddr->s6_addr32[3];
+ b += daddr->s6_addr32[0];
+ c += daddr->s6_addr32[1];
+ __jhash_mix(a, b, c);
+
+ a += daddr->s6_addr32[2];
+ b += daddr->s6_addr32[3];
+ c += id;
+ __jhash_mix(a, b, c);
+
+ return c & (IP6CT_Q_HASHSZ - 1);
+}
+
+static struct timer_list ip6_ct_frag_secret_timer;
+int sysctl_ip6_ct_frag_secret_interval = 10 * 60 * HZ;
+
+static void ip6_ct_frag_secret_rebuild(unsigned long dummy)
+{
+ unsigned long now = jiffies;
+ int i;
+
+ write_lock(&ip6_ct_frag_lock);
+ get_random_bytes(&ip6_ct_frag_hash_rnd, sizeof(u32));
+ for (i = 0; i < IP6CT_Q_HASHSZ; i++) {
+ struct ip6ct_frag_queue *q;
+
+ q = ip6_ct_frag_hash[i];
+ while (q) {
+ struct ip6ct_frag_queue *next = q->next;
+ unsigned int hval = ip6qhashfn(q->id,
+ &q->saddr,
+ &q->daddr);
+
+ if (hval != i) {
+ /* Unlink. */
+ if (q->next)
+ q->next->pprev = q->pprev;
+ *q->pprev = q->next;
+
+ /* Relink to new hash chain. */
+ if ((q->next = ip6_ct_frag_hash[hval]) != NULL)
+ q->next->pprev = &q->next;
+ ip6_ct_frag_hash[hval] = q;
+ q->pprev = &ip6_ct_frag_hash[hval];
+ }
+
+ q = next;
+ }
+ }
+ write_unlock(&ip6_ct_frag_lock);
+
+ mod_timer(&ip6_ct_frag_secret_timer, now + sysctl_ip6_ct_frag_secret_interval);
+}
+
+atomic_t ip6_ct_frag_mem = ATOMIC_INIT(0);
+
+/* Memory Tracking Functions. */
+static inline void frag_kfree_skb(struct sk_buff *skb)
+{
+ atomic_sub(skb->truesize, &ip6_ct_frag_mem);
+ if (IP6CT_FRAG6_CB(skb)->orig)
+ kfree_skb(IP6CT_FRAG6_CB(skb)->orig);
+
+ kfree_skb(skb);
+}
+
+static inline void frag_free_queue(struct ip6ct_frag_queue *fq)
+{
+ atomic_sub(sizeof(struct ip6ct_frag_queue), &ip6_ct_frag_mem);
+ kfree(fq);
+}
+
+static inline struct ip6ct_frag_queue *frag_alloc_queue(void)
+{
+ struct ip6ct_frag_queue *fq = kmalloc(sizeof(struct ip6ct_frag_queue), GFP_ATOMIC);
+
+ if(!fq)
+ return NULL;
+ atomic_add(sizeof(struct ip6ct_frag_queue), &ip6_ct_frag_mem);
+ return fq;
+}
+
+/* Destruction primitives. */
+
+/* Complete destruction of fq. */
+static void ip6_ct_frag_destroy(struct ip6ct_frag_queue *fq)
+{
+ struct sk_buff *fp;
+
+ BUG_TRAP(fq->last_in&COMPLETE);
+ BUG_TRAP(del_timer(&fq->timer) == 0);
+
+ /* Release all fragment data. */
+ fp = fq->fragments;
+ while (fp) {
+ struct sk_buff *xp = fp->next;
+
+ frag_kfree_skb(fp);
+ fp = xp;
+ }
+
+ frag_free_queue(fq);
+}
+
+static __inline__ void fq_put(struct ip6ct_frag_queue *fq)
+{
+ if (atomic_dec_and_test(&fq->refcnt))
+ ip6_ct_frag_destroy(fq);
+}
+
+/* Kill fq entry. It is not destroyed immediately,
+ * because caller (and someone more) holds reference count.
+ */
+static __inline__ void fq_kill(struct ip6ct_frag_queue *fq)
+{
+ if (del_timer(&fq->timer))
+ atomic_dec(&fq->refcnt);
+
+ if (!(fq->last_in & COMPLETE)) {
+ fq_unlink(fq);
+ atomic_dec(&fq->refcnt);
+ fq->last_in |= COMPLETE;
+ }
+}
+
+static void ip6_ct_frag_evictor(void)
+{
+ struct ip6ct_frag_queue *fq;
+ struct list_head *tmp;
+
+ for(;;) {
+ if (atomic_read(&ip6_ct_frag_mem) <= sysctl_ip6_ct_frag_low_thresh)
+ return;
+ read_lock(&ip6_ct_frag_lock);
+ if (list_empty(&ip6_ct_frag_lru_list)) {
+ read_unlock(&ip6_ct_frag_lock);
+ return;
+ }
+ tmp = ip6_ct_frag_lru_list.next;
+ fq = list_entry(tmp, struct ip6ct_frag_queue, lru_list);
+ atomic_inc(&fq->refcnt);
+ read_unlock(&ip6_ct_frag_lock);
+
+ spin_lock(&fq->lock);
+ if (!(fq->last_in&COMPLETE))
+ fq_kill(fq);
+ spin_unlock(&fq->lock);
+
+ fq_put(fq);
+ }
+}
+
+static void ip6_ct_frag_expire(unsigned long data)
+{
+ struct ip6ct_frag_queue *fq = (struct ip6ct_frag_queue *) data;
+
+ spin_lock(&fq->lock);
+
+ if (fq->last_in & COMPLETE)
+ goto out;
+
+ fq_kill(fq);
+
+out:
+ spin_unlock(&fq->lock);
+ fq_put(fq);
+}
+
+/* Creation primitives. */
+
+
+static struct ip6ct_frag_queue *ip6_ct_frag_intern(unsigned int hash,
+ struct ip6ct_frag_queue *fq_in)
+{
+ struct ip6ct_frag_queue *fq;
+
+ write_lock(&ip6_ct_frag_lock);
+#ifdef CONFIG_SMP
+ for (fq = ip6_ct_frag_hash[hash]; fq; fq = fq->next) {
+ if (fq->id == fq_in->id &&
+ !ipv6_addr_cmp(&fq_in->saddr, &fq->saddr) &&
+ !ipv6_addr_cmp(&fq_in->daddr, &fq->daddr)) {
+ atomic_inc(&fq->refcnt);
+ write_unlock(&ip6_ct_frag_lock);
+ fq_in->last_in |= COMPLETE;
+ fq_put(fq_in);
+ return fq;
+ }
+ }
+#endif
+ fq = fq_in;
+
+ if (!mod_timer(&fq->timer, jiffies + sysctl_ip6_ct_frag_time))
+ atomic_inc(&fq->refcnt);
+
+ atomic_inc(&fq->refcnt);
+ if((fq->next = ip6_ct_frag_hash[hash]) != NULL)
+ fq->next->pprev = &fq->next;
+ ip6_ct_frag_hash[hash] = fq;
+ fq->pprev = &ip6_ct_frag_hash[hash];
+ INIT_LIST_HEAD(&fq->lru_list);
+ list_add_tail(&fq->lru_list, &ip6_ct_frag_lru_list);
+ ip6_ct_frag_nqueues++;
+ write_unlock(&ip6_ct_frag_lock);
+ return fq;
+}
+
+
+static struct ip6ct_frag_queue *
+ip6_ct_frag_create(unsigned int hash, u32 id, struct in6_addr *src, struct in6_addr *dst)
+{
+ struct ip6ct_frag_queue *fq;
+
+ if ((fq = frag_alloc_queue()) == NULL) {
+ DEBUGP("Can't alloc new queue\n");
+ goto oom;
+ }
+
+ memset(fq, 0, sizeof(struct ip6ct_frag_queue));
+
+ fq->id = id;
+ ipv6_addr_copy(&fq->saddr, src);
+ ipv6_addr_copy(&fq->daddr, dst);
+
+ init_timer(&fq->timer);
+ fq->timer.function = ip6_ct_frag_expire;
+ fq->timer.data = (long) fq;
+ fq->lock = SPIN_LOCK_UNLOCKED;
+ atomic_set(&fq->refcnt, 1);
+
+ return ip6_ct_frag_intern(hash, fq);
+
+oom:
+ return NULL;
+}
+
+static __inline__ struct ip6ct_frag_queue *
+fq_find(u32 id, struct in6_addr *src, struct in6_addr *dst)
+{
+ struct ip6ct_frag_queue *fq;
+ unsigned int hash = ip6qhashfn(id, src, dst);
+
+ read_lock(&ip6_ct_frag_lock);
+ for(fq = ip6_ct_frag_hash[hash]; fq; fq = fq->next) {
+ if (fq->id == id &&
+ !ipv6_addr_cmp(src, &fq->saddr) &&
+ !ipv6_addr_cmp(dst, &fq->daddr)) {
+ atomic_inc(&fq->refcnt);
+ read_unlock(&ip6_ct_frag_lock);
+ return fq;
+ }
+ }
+ read_unlock(&ip6_ct_frag_lock);
+
+ return ip6_ct_frag_create(hash, id, src, dst);
+}
+
+
+static int ip6_ct_frag_queue(struct ip6ct_frag_queue *fq, struct sk_buff *skb,
+ struct frag_hdr *fhdr, int nhoff)
+{
+ struct sk_buff *prev, *next;
+ int offset, end;
+
+ if (fq->last_in & COMPLETE) {
+ DEBUGP("Allready completed\n");
+ goto err;
+ }
+
+ offset = ntohs(fhdr->frag_off) & ~0x7;
+ end = offset + (ntohs(skb->nh.ipv6h->payload_len) -
+ ((u8 *) (fhdr + 1) - (u8 *) (skb->nh.ipv6h + 1)));
+
+ if ((unsigned int)end > IPV6_MAXPLEN) {
+ DEBUGP("offset is too large.\n");
+ return -1;
+ }
+
+ if (skb->ip_summed == CHECKSUM_HW)
+ skb->csum = csum_sub(skb->csum,
+ csum_partial(skb->nh.raw, (u8*)(fhdr+1)-skb->nh.raw, 0));
+
+ /* Is this the final fragment? */
+ if (!(fhdr->frag_off & htons(IP6_MF))) {
+ /* If we already have some bits beyond end
+ * or have different end, the segment is corrupted.
+ */
+ if (end < fq->len ||
+ ((fq->last_in & LAST_IN) && end != fq->len)) {
+ DEBUGP("already received last fragment\n");
+ goto err;
+ }
+ fq->last_in |= LAST_IN;
+ fq->len = end;
+ } else {
+ /* Check if the fragment is rounded to 8 bytes.
+ * Required by the RFC.
+ */
+ if (end & 0x7) {
+ /* RFC2460 says always send parameter problem in
+ * this case. -DaveM
+ */
+ DEBUGP("the end of this message is not rounded to 8 bytes.\n");
+ return -1;
+ }
+ if (end > fq->len) {
+ /* Some bits beyond end -> corruption. */
+ if (fq->last_in & LAST_IN) {
+ DEBUGP("last packet already reached.\n");
+ goto err;
+ }
+ fq->len = end;
+ }
+ }
+
+ if (end == offset)
+ goto err;
+
+ /* Point into the IP datagram 'data' part. */
+ if (!pskb_pull(skb, (u8 *) (fhdr + 1) - skb->data)) {
+ DEBUGP("queue: message is too short.\n");
+ goto err;
+ }
+ if (end-offset < skb->len) {
+ if (pskb_trim(skb, end - offset)) {
+ DEBUGP("Can't trim\n");
+ goto err;
+ }
+ if (skb->ip_summed != CHECKSUM_UNNECESSARY)
+ skb->ip_summed = CHECKSUM_NONE;
+ }
+
+ /* Find out which fragments are in front and at the back of us
+ * in the chain of fragments so far. We must know where to put
+ * this fragment, right?
+ */
+ prev = NULL;
+ for(next = fq->fragments; next != NULL; next = next->next) {
+ if (IP6CT_FRAG6_CB(next)->offset >= offset)
+ break; /* bingo! */
+ prev = next;
+ }
+
+ /* We found where to put this one. Check for overlap with
+ * preceding fragment, and, if needed, align things so that
+ * any overlaps are eliminated.
+ */
+ if (prev) {
+ int i = (IP6CT_FRAG6_CB(prev)->offset + prev->len) - offset;
+
+ if (i > 0) {
+ offset += i;
+ if (end <= offset) {
+ DEBUGP("overlap\n");
+ goto err;
+ }
+ if (!pskb_pull(skb, i)) {
+ DEBUGP("Can't pull\n");
+ goto err;
+ }
+ if (skb->ip_summed != CHECKSUM_UNNECESSARY)
+ skb->ip_summed = CHECKSUM_NONE;
+ }
+ }
+
+ /* Look for overlap with succeeding segments.
+ * If we can merge fragments, do it.
+ */
+ while (next && IP6CT_FRAG6_CB(next)->offset < end) {
+ int i = end - IP6CT_FRAG6_CB(next)->offset; /* overlap is 'i' bytes */
+
+ if (i < next->len) {
+ /* Eat head of the next overlapped fragment
+ * and leave the loop. The next ones cannot overlap.
+ */
+ DEBUGP("Eat head of the overlapped parts.: %d", i);
+ if (!pskb_pull(next, i))
+ goto err;
+ IP6CT_FRAG6_CB(next)->offset += i; /* next fragment */
+ fq->meat -= i;
+ if (next->ip_summed != CHECKSUM_UNNECESSARY)
+ next->ip_summed = CHECKSUM_NONE;
+ break;
+ } else {
+ struct sk_buff *free_it = next;
+
+ /* Old fragmnet is completely overridden with
+ * new one drop it.
+ */
+ next = next->next;
+
+ if (prev)
+ prev->next = next;
+ else
+ fq->fragments = next;
+
+ fq->meat -= free_it->len;
+ frag_kfree_skb(free_it);
+ }
+ }
+
+ IP6CT_FRAG6_CB(skb)->offset = offset;
+
+ /* Insert this fragment in the chain of fragments. */
+ skb->next = next;
+ if (prev)
+ prev->next = skb;
+ else
+ fq->fragments = skb;
+
+ skb->dev = NULL;
+ fq->stamp = skb->stamp;
+ fq->meat += skb->len;
+ atomic_add(skb->truesize, &ip6_ct_frag_mem);
+
+ /* The first fragment.
+ * nhoffset is obtained from the first fragment, of course.
+ */
+ if (offset == 0) {
+ fq->nhoffset = nhoff;
+ fq->last_in |= FIRST_IN;
+ }
+ write_lock(&ip6_ct_frag_lock);
+ list_move_tail(&fq->lru_list, &ip6_ct_frag_lru_list);
+ write_unlock(&ip6_ct_frag_lock);
+ return 0;
+
+err:
+ return -1;
+}
+
+/*
+ * Check if this packet is complete.
+ * Returns NULL on failure by any reason, and pointer
+ * to current nexthdr field in reassembled frame.
+ *
+ * It is called with locked fq, and caller must check that
+ * queue is eligible for reassembly i.e. it is not COMPLETE,
+ * the last and the first frames arrived and all the bits are here.
+ */
+static struct sk_buff *
+ip6_ct_frag_reasm(struct ip6ct_frag_queue *fq, struct net_device *dev)
+{
+ struct sk_buff *fp, *op, *head = fq->fragments;
+ int payload_len;
+
+ fq_kill(fq);
+
+ BUG_TRAP(head != NULL);
+ BUG_TRAP(IP6CT_FRAG6_CB(head)->offset == 0);
+
+ /* Unfragmented part is taken from the first segment. */
+ payload_len = (head->data - head->nh.raw) - sizeof(struct ipv6hdr) + fq->len - sizeof(struct frag_hdr);
+ if (payload_len > IPV6_MAXPLEN) {
+ DEBUGP("payload len is too large.\n");
+ goto out_oversize;
+ }
+
+ /* Head of list must not be cloned. */
+ if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC)) {
+ DEBUGP("skb is cloned but can't expand head");
+ goto out_oom;
+ }
+
+ /* If the first fragment is fragmented itself, we split
+ * it to two chunks: the first with data and paged part
+ * and the second, holding only fragments. */
+ if (skb_shinfo(head)->frag_list) {
+ struct sk_buff *clone;
+ int i, plen = 0;
+
+ if ((clone = alloc_skb(0, GFP_ATOMIC)) == NULL) {
+ DEBUGP("Can't alloc skb\n");
+ goto out_oom;
+ }
+ clone->next = head->next;
+ head->next = clone;
+ skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list;
+ skb_shinfo(head)->frag_list = NULL;
+ for (i=0; i<skb_shinfo(head)->nr_frags; i++)
+ plen += skb_shinfo(head)->frags[i].size;
+ clone->len = clone->data_len = head->data_len - plen;
+ head->data_len -= clone->len;
+ head->len -= clone->len;
+ clone->csum = 0;
+ clone->ip_summed = head->ip_summed;
+
+ IP6CT_FRAG6_CB(clone)->orig = NULL;
+ atomic_add(clone->truesize, &ip6_ct_frag_mem);
+ }
+
+ /* We have to remove fragment header from datagram and to relocate
+ * header in order to calculate ICV correctly. */
+ head->nh.raw[fq->nhoffset] = head->h.raw[0];
+ memmove(head->head + sizeof(struct frag_hdr), head->head,
+ (head->data - head->head) - sizeof(struct frag_hdr));
+ head->mac.raw += sizeof(struct frag_hdr);
+ head->nh.raw += sizeof(struct frag_hdr);
+
+ skb_shinfo(head)->frag_list = head->next;
+ head->h.raw = head->data;
+ skb_push(head, head->data - head->nh.raw);
+ atomic_sub(head->truesize, &ip6_ct_frag_mem);
+
+ for (fp=head->next; fp; fp = fp->next) {
+ head->data_len += fp->len;
+ head->len += fp->len;
+ if (head->ip_summed != fp->ip_summed)
+ head->ip_summed = CHECKSUM_NONE;
+ else if (head->ip_summed == CHECKSUM_HW)
+ head->csum = csum_add(head->csum, fp->csum);
+ head->truesize += fp->truesize;
+ atomic_sub(fp->truesize, &ip6_ct_frag_mem);
+ }
+
+ head->next = NULL;
+ head->dev = dev;
+ head->stamp = fq->stamp;
+ head->nh.ipv6h->payload_len = ntohs(payload_len);
+
+ /* Yes, and fold redundant checksum back. 8) */
+ if (head->ip_summed == CHECKSUM_HW)
+ head->csum = csum_partial(head->nh.raw, head->h.raw-head->nh.raw, head->csum);
+
+ fq->fragments = NULL;
+
+ /* all original skbs are linked into the IP6CT_FRAG6_CB(head).orig */
+ fp = skb_shinfo(head)->frag_list;
+ if (IP6CT_FRAG6_CB(fp)->orig == NULL)
+ /* at above code, head skb is divided into two skbs. */
+ fp = fp->next;
+
+ op = IP6CT_FRAG6_CB(head)->orig;
+ for (; fp; fp = fp->next) {
+ struct sk_buff *orig = IP6CT_FRAG6_CB(fp)->orig;
+
+ op->next = orig;
+ op = orig;
+ IP6CT_FRAG6_CB(fp)->orig = NULL;
+ }
+
+ return head;
+
+out_oversize:
+ if (net_ratelimit())
+ printk(KERN_DEBUG "ip6_ct_frag_reasm: payload len = %d\n", payload_len);
+ goto out_fail;
+out_oom:
+ if (net_ratelimit())
+ printk(KERN_DEBUG "ip6_ct_frag_reasm: no memory for reassembly\n");
+out_fail:
+ return NULL;
+}
+
+/*
+ * find the header just before Fragment Header.
+ *
+ * if success return 0 and set ...
+ * (*prevhdrp): the value of "Next Header Field" in the header
+ * just before Fragment Header.
+ * (*prevhoff): the offset of "Next Header Field" in the header
+ * just before Fragment Header.
+ * (*fhoff) : the offset of Fragment Header.
+ *
+ * Based on ipv6_skip_hdr() in net/ipv6/exthdr.c
+ *
+ */
+static int
+find_prev_fhdr(struct sk_buff *skb, u8 *prevhdrp, int *prevhoff, int *fhoff)
+{
+ u8 nexthdr = skb->nh.ipv6h->nexthdr;
+ u8 prev_nhoff = (u8 *)&skb->nh.ipv6h->nexthdr - skb->data;
+ int start = (u8 *)(skb->nh.ipv6h+1) - skb->data;
+ int len = skb->len - start;
+ u8 prevhdr = NEXTHDR_IPV6;
+
+ while (nexthdr != NEXTHDR_FRAGMENT) {
+ struct ipv6_opt_hdr hdr;
+ int hdrlen;
+
+ if (!ipv6_ext_hdr(nexthdr)) {
+ return -1;
+ }
+ if (len < (int)sizeof(struct ipv6_opt_hdr)) {
+ DEBUGP("too short\n");
+ return -1;
+ }
+ if (nexthdr == NEXTHDR_NONE) {
+ DEBUGP("next header is none\n");
+ return -1;
+ }
+ if (skb_copy_bits(skb, start, &hdr, sizeof(hdr)))
+ BUG();
+ if (nexthdr == NEXTHDR_AUTH)
+ hdrlen = (hdr.hdrlen+2)<<2;
+ else
+ hdrlen = ipv6_optlen(&hdr);
+
+ prevhdr = nexthdr;
+ prev_nhoff = start;
+
+ nexthdr = hdr.nexthdr;
+ len -= hdrlen;
+ start += hdrlen;
+ }
+
+ if (len < 0)
+ return -1;
+
+ *prevhdrp = prevhdr;
+ *prevhoff = prev_nhoff;
+ *fhoff = start;
+
+ return 0;
+}
+
+struct sk_buff *ip6_ct_gather_frags(struct sk_buff *skb)
+{
+ struct sk_buff *clone;
+ struct net_device *dev = skb->dev;
+ struct frag_hdr *fhdr;
+ struct ip6ct_frag_queue *fq;
+ struct ipv6hdr *hdr;
+ int fhoff, nhoff;
+ u8 prevhdr;
+ struct sk_buff *ret_skb = NULL;
+
+ /* Jumbo payload inhibits frag. header */
+ if (skb->nh.ipv6h->payload_len == 0) {
+ DEBUGP("payload len = 0\n");
+ return skb;
+ }
+
+ if (find_prev_fhdr(skb, &prevhdr, &nhoff, &fhoff) < 0)
+ return skb;
+
+ clone = skb_clone(skb, GFP_ATOMIC);
+ if (clone == NULL) {
+ DEBUGP("Can't clone skb\n");
+ return skb;
+ }
+
+ IP6CT_FRAG6_CB(clone)->orig = skb;
+
+ if (!pskb_may_pull(clone, fhoff + sizeof(*fhdr))) {
+ DEBUGP("message is too short.\n");
+ goto ret_orig;
+ }
+
+ clone->h.raw = clone->data + fhoff;
+ hdr = clone->nh.ipv6h;
+ fhdr = (struct frag_hdr *)clone->h.raw;
+
+ if (!(fhdr->frag_off & htons(0xFFF9))) {
+ DEBUGP("Invalid fragment offset\n");
+ /* It is not a fragmented frame */
+ goto ret_orig;
+ }
+
+ if (atomic_read(&ip6_ct_frag_mem) > sysctl_ip6_ct_frag_high_thresh)
+ ip6_ct_frag_evictor();
+
+ if ((fq = fq_find(fhdr->identification, &hdr->saddr, &hdr->daddr)) == NULL) {
+ DEBUGP("Can't find and can't create new queue\n");
+ goto ret_orig;
+ }
+
+ spin_lock(&fq->lock);
+
+ if (ip6_ct_frag_queue(fq, clone, fhdr, nhoff) < 0) {
+ spin_unlock(&fq->lock);
+ DEBUGP("Can't insert skb to queue\n");
+ fq_put(fq);
+ goto ret_orig;
+ }
+
+ if (fq->last_in == (FIRST_IN|LAST_IN) &&
+ fq->meat == fq->len) {
+ ret_skb = ip6_ct_frag_reasm(fq, dev);
+
+ if (ret_skb == NULL)
+ DEBUGP("Can't reassemble fragmented packets\n");
+ }
+ spin_unlock(&fq->lock);
+
+ fq_put(fq);
+ return ret_skb;
+
+ret_orig:
+ kfree_skb(clone);
+ return skb;
+}
+
+int ip6_ct_output_frags(struct sk_buff *skb, struct nf_info *info)
+{
+ struct sk_buff *s, *s2;
+ struct nf_info *copy_info;
+
+ for (s = IP6CT_FRAG6_CB(skb)->orig; s;) {
+ if (skb->nfct)
+ nf_conntrack_get(skb->nfct);
+ s->nfct = skb->nfct;
+ s->nfcache = skb->nfcache;
+
+ /*
+ * nf_reinject() frees copy_info,
+ * so I have to copy it every time. (T-T
+ */
+ copy_info = kmalloc(sizeof(*copy_info), GFP_ATOMIC);
+ if (copy_info == NULL) {
+ DEBUGP("Can't kmalloc() for nf_info\n");
+ return -1;
+ }
+
+ copy_info->pf = info->pf;
+ copy_info->hook = info->hook;
+ copy_info->indev = info->indev;
+ copy_info->outdev = info->outdev;
+ copy_info->okfn = info->okfn;
+ copy_info->elem = info->elem;
+
+ /*
+ * nf_reinject() put the module "ip6_conntrack".
+ */
+ if (!try_module_get(info->elem->owner)) {
+ DEBUGP("Can't get module.\n");
+ kfree_skb(s);
+ continue;
+ }
+
+ if (copy_info->indev)
+ dev_hold(copy_info->indev);
+ if (copy_info->outdev)
+ dev_hold(copy_info->outdev);
+
+ s2 = s->next;
+ nf_reinject(s, copy_info, NF_ACCEPT);
+ s = s2;
+ }
+
+ kfree_skb(skb);
+
+ return 0;
+}
+
+int ip6_ct_kfree_frags(struct sk_buff *skb)
+{
+ struct sk_buff *s, *s2;
+
+ for (s = IP6CT_FRAG6_CB(skb)->orig; s; s = s2) {
+
+ s2 = s->next;
+ kfree_skb(s);
+ }
+
+ kfree_skb(skb);
+
+ return 0;
+}
+
+#ifdef CONFIG_SYSCTL
+
+#define IP6CT_HIGH_THRESH_NAME "ip6ct_frags_high_thresh"
+#define IP6CT_LOW_THRESH_NAME "ip6ct_frags_low_thresh"
+#define IP6CT_TIMEOUT_NAME "ip6ct_frags_timeout"
+
+static struct ctl_table_header *ip6_ct_frags_sysctl_header;
+
+static ctl_table ip6_ct_frags_table[] = {
+ {
+ .ctl_name = IP6CT_FRAGS_HIGH_THRESH,
+ .procname = IP6CT_HIGH_THRESH_NAME,
+ .data = &sysctl_ip6_ct_frag_high_thresh,
+ .maxlen = sizeof(sysctl_ip6_ct_frag_high_thresh),
+ .mode = 0644,
+ .proc_handler = proc_dointvec
+ },
+ {
+ .ctl_name = IP6CT_FRAGS_LOW_THRESH,
+ .procname = IP6CT_LOW_THRESH_NAME,
+ .data = &sysctl_ip6_ct_frag_low_thresh,
+ .maxlen = sizeof(sysctl_ip6_ct_frag_high_thresh),
+ .mode = 0644,
+ .proc_handler = proc_dointvec
+ },
+ {
+ .ctl_name = IP6CT_FRAGS_TIMEOUT,
+ .procname = IP6CT_TIMEOUT_NAME,
+ .data = &sysctl_ip6_ct_frag_time,
+ .maxlen = sizeof(sysctl_ip6_ct_frag_time),
+ .mode = 0644,
+ .proc_handler = proc_dointvec
+ },
+ { .ctl_name = 0 }
+};
+
+static ctl_table ip6_ct_frags_dir_table[] = {
+ {
+ .ctl_name = NET_IPV6,
+ .procname = "ipv6", NULL,
+ .mode = 0555,
+ .child = ip6_ct_frags_table
+ },
+ { .ctl_name = 0 }
+};
+
+static ctl_table ip6_ct_frags_root_table[] = {
+ {
+ .ctl_name = CTL_NET,
+ .procname = "net",
+ .mode = 0555,
+ .child = ip6_ct_frags_dir_table
+ },
+ { .ctl_name = 0 }
+};
+
+#endif /*CONFIG_SYSCTL*/
+
+int __init ip6_ct_frags_init(void)
+{
+#ifdef CONFIG_SYSCTL
+ ip6_ct_frags_sysctl_header = register_sysctl_table(ip6_ct_frags_root_table, 0);
+
+ if (ip6_ct_frags_sysctl_header == NULL) {
+ printk("ip6_ct_frags_init: Can't register sysctl tables.\n");
+ return -ENOMEM;
+ }
+#endif
+
+ ip6_ct_frag_hash_rnd = (u32) ((num_physpages ^ (num_physpages>>7)) ^
+ (jiffies ^ (jiffies >> 6)));
+
+ init_timer(&ip6_ct_frag_secret_timer);
+ ip6_ct_frag_secret_timer.function = ip6_ct_frag_secret_rebuild;
+ ip6_ct_frag_secret_timer.expires = jiffies + sysctl_ip6_ct_frag_secret_interval;
+ add_timer(&ip6_ct_frag_secret_timer);
+
+ return 0;
+}
+
+void ip6_ct_frags_cleanup(void)
+{
+ del_timer(&ip6_ct_frag_secret_timer);
+#ifdef CONFIG_SYSCTL
+ unregister_sysctl_table(ip6_ct_frags_sysctl_header);
+#endif
+ sysctl_ip6_ct_frag_low_thresh = 0;
+ ip6_ct_frag_evictor();
+}
diff -urN linux-2.6.11/net/ipv6/netfilter/ip6_conntrack_standalone.c linux.sinabox/net/ipv6/netfilter/ip6_conntrack_standalone.c
--- linux-2.6.11/net/ipv6/netfilter/ip6_conntrack_standalone.c 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/net/ipv6/netfilter/ip6_conntrack_standalone.c 2005-03-26 19:02:06.000000000 +0100
@@ -0,0 +1,502 @@
+/*
+ * IPv6 Connection Tracking
+ * Linux INET6 implementation
+ *
+ * Copyright (C)2003 USAGI/WIDE Project
+ *
+ * Authors:
+ * Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
+ *
+ * Based on: net/ipv4/netfilter/ip_conntrack_standalone.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/* This file contains all the functions required for the standalone
+ ip6_conntrack module.
+
+ These are not required by the compatibility layer.
+*/
+
+/* (c) 1999 Paul `Rusty' Russell. Licenced under the GNU General
+ Public Licence. */
+
+#include <linux/types.h>
+#include <linux/ipv6.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv6.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/proc_fs.h>
+#include <linux/version.h>
+#include <net/checksum.h>
+
+#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip6_conntrack_lock)
+#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip6_conntrack_lock)
+
+#include <linux/netfilter_ipv6/ip6_conntrack.h>
+#include <linux/netfilter_ipv6/ip6_conntrack_protocol.h>
+#include <linux/netfilter_ipv6/ip6_conntrack_core.h>
+#include <linux/netfilter_ipv6/ip6_conntrack_helper.h>
+#include <linux/netfilter_ipv6/ip6_conntrack_reasm.h>
+#include <linux/netfilter_ipv4/listhelp.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+MODULE_LICENSE("GPL");
+
+static int kill_proto(const struct ip6_conntrack *i, void *data)
+{
+ return (i->tuplehash[IP6_CT_DIR_ORIGINAL].tuple.dst.protonum ==
+ *((u_int8_t *) data));
+}
+
+static unsigned int
+print_tuple(char *buffer, const struct ip6_conntrack_tuple *tuple,
+ struct ip6_conntrack_protocol *proto)
+{
+ int len;
+
+ len = sprintf(buffer, "src=%x:%x:%x:%x:%x:%x:%x:%x dst=%x:%x:%x:%x:%x:%x:%x:%x ",
+ NIP6(tuple->src.ip), NIP6(tuple->dst.ip));
+
+ len += proto->print_tuple(buffer + len, tuple);
+
+ return len;
+}
+
+/* FIXME: Don't print source proto part. --RR */
+static unsigned int
+print_expect(char *buffer, const struct ip6_conntrack_expect *expect)
+{
+ unsigned int len;
+
+ if (expect->expectant->helper->timeout)
+ len = sprintf(buffer, "EXPECTING: %lu ",
+ timer_pending(&expect->timeout)
+ ? (expect->timeout.expires - jiffies)/HZ : 0);
+ else
+ len = sprintf(buffer, "EXPECTING: - ");
+ len += sprintf(buffer + len, "use=%u proto=%u ",
+ atomic_read(&expect->use), expect->tuple.dst.protonum);
+ len += print_tuple(buffer + len, &expect->tuple,
+ __ip6_ct_find_proto(expect->tuple.dst.protonum));
+ len += sprintf(buffer + len, "\n");
+ return len;
+}
+
+static unsigned int
+print_conntrack(char *buffer, struct ip6_conntrack *conntrack)
+{
+ unsigned int len;
+ struct ip6_conntrack_protocol *proto
+ = __ip6_ct_find_proto(conntrack->tuplehash[IP6_CT_DIR_ORIGINAL]
+ .tuple.dst.protonum);
+
+ len = sprintf(buffer, "%-8s %u %lu ",
+ proto->name,
+ conntrack->tuplehash[IP6_CT_DIR_ORIGINAL]
+ .tuple.dst.protonum,
+ timer_pending(&conntrack->timeout)
+ ? (conntrack->timeout.expires - jiffies)/HZ : 0);
+
+ len += proto->print_conntrack(buffer + len, conntrack);
+ len += print_tuple(buffer + len,
+ &conntrack->tuplehash[IP6_CT_DIR_ORIGINAL].tuple,
+ proto);
+ if (!(test_bit(IP6S_SEEN_REPLY_BIT, &conntrack->status)))
+ len += sprintf(buffer + len, "[UNREPLIED] ");
+ len += print_tuple(buffer + len,
+ &conntrack->tuplehash[IP6_CT_DIR_REPLY].tuple,
+ proto);
+ if (test_bit(IP6S_ASSURED_BIT, &conntrack->status))
+ len += sprintf(buffer + len, "[ASSURED] ");
+ len += sprintf(buffer + len, "use=%u ",
+ atomic_read(&conntrack->ct_general.use));
+ len += sprintf(buffer + len, "\n");
+
+ return len;
+}
+
+/* Returns true when finished. */
+static inline int
+conntrack_iterate(const struct ip6_conntrack_tuple_hash *hash,
+ char *buffer, off_t offset, off_t *upto,
+ unsigned int *len, unsigned int maxlen)
+{
+ unsigned int newlen;
+ IP6_NF_ASSERT(hash->ctrack);
+
+ MUST_BE_READ_LOCKED(&ip6_conntrack_lock);
+
+ /* Only count originals */
+ if (DIRECTION(hash))
+ return 0;
+
+ if ((*upto)++ < offset)
+ return 0;
+
+ newlen = print_conntrack(buffer + *len, hash->ctrack);
+ if (*len + newlen > maxlen)
+ return 1;
+ else *len += newlen;
+
+ return 0;
+}
+
+static int
+list_conntracks(char *buffer, char **start, off_t offset, int length)
+{
+ unsigned int i;
+ unsigned int len = 0;
+ off_t upto = 0;
+ struct list_head *e;
+
+ READ_LOCK(&ip6_conntrack_lock);
+ /* Traverse hash; print originals then reply. */
+ for (i = 0; i < ip6_conntrack_htable_size; i++) {
+ if (LIST_FIND(&ip6_conntrack_hash[i], conntrack_iterate,
+ struct ip6_conntrack_tuple_hash *,
+ buffer, offset, &upto, &len, length))
+ goto finished;
+ }
+
+ /* Now iterate through expecteds. */
+ for (e = ip6_conntrack_expect_list.next;
+ e != &ip6_conntrack_expect_list; e = e->next) {
+ unsigned int last_len;
+ struct ip6_conntrack_expect *expect
+ = (struct ip6_conntrack_expect *)e;
+ if (upto++ < offset) continue;
+
+ last_len = len;
+ len += print_expect(buffer + len, expect);
+ if (len > length) {
+ len = last_len;
+ goto finished;
+ }
+ }
+
+ finished:
+ READ_UNLOCK(&ip6_conntrack_lock);
+
+ /* `start' hack - see fs/proc/generic.c line ~165 */
+ *start = (char *)((unsigned int)upto - offset);
+ return len;
+}
+
+static unsigned int ip6_confirm(unsigned int hooknum,
+ struct sk_buff **pskb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *));
+static unsigned int ip6_conntrack_out(unsigned int hooknum,
+ struct sk_buff **pskb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *));
+static unsigned int ip6_conntrack_reasm(unsigned int hooknum,
+ struct sk_buff **pskb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *));
+static unsigned int ip6_conntrack_local(unsigned int hooknum,
+ struct sk_buff **pskb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *));
+
+/* Connection tracking may drop packets, but never alters them, so
+ make it the first hook. */
+static struct nf_hook_ops ip6_conntrack_in_ops = {
+ /* Don't forget to change .hook to "ip6_conntrack_input". - zak */
+ .hook = ip6_conntrack_reasm,
+ .owner = THIS_MODULE,
+ .pf = PF_INET6,
+ .hooknum = NF_IP6_PRE_ROUTING,
+ .priority = NF_IP6_PRI_CONNTRACK,
+};
+
+static struct nf_hook_ops ip6_conntrack_local_out_ops = {
+ .hook = ip6_conntrack_local,
+ .owner = THIS_MODULE,
+ .pf = PF_INET6,
+ .hooknum = NF_IP6_LOCAL_OUT,
+ .priority = NF_IP6_PRI_CONNTRACK,
+};
+
+/* Refragmenter; last chance. */
+static struct nf_hook_ops ip6_conntrack_out_ops = {
+ .hook = ip6_conntrack_out,
+ .owner = THIS_MODULE,
+ .pf = PF_INET6,
+ .hooknum = NF_IP6_POST_ROUTING,
+ .priority = NF_IP6_PRI_LAST,
+};
+
+static struct nf_hook_ops ip6_conntrack_local_in_ops = {
+ .hook = ip6_confirm,
+ .owner = THIS_MODULE,
+ .pf = PF_INET6,
+ .hooknum = NF_IP6_LOCAL_IN,
+ .priority = NF_IP6_PRI_LAST-1,
+};
+
+static unsigned int ip6_confirm(unsigned int hooknum,
+ struct sk_buff **pskb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ int ret;
+
+ ret = ip6_conntrack_confirm(*pskb);
+
+ return ret;
+}
+
+static unsigned int ip6_conntrack_out(unsigned int hooknum,
+ struct sk_buff **pskb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+
+ if (ip6_conntrack_confirm(*pskb) != NF_ACCEPT)
+ return NF_DROP;
+
+ return NF_ACCEPT;
+}
+
+static unsigned int ip6_conntrack_reasm(unsigned int hooknum,
+ struct sk_buff **pskb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ struct sk_buff *skb = *pskb;
+ struct sk_buff **rsmd_pskb = &skb;
+ int fragd = 0;
+ int ret;
+
+ skb->nfcache |= NFC_UNKNOWN;
+
+ /*
+ * Previously seen (loopback)? Ignore. Do this before
+ * fragment check.
+ */
+ if (skb->nfct) {
+ DEBUGP("previously seen\n");
+ return NF_ACCEPT;
+ }
+
+ skb = ip6_ct_gather_frags(skb);
+
+ /* queued */
+ if (skb == NULL)
+ return NF_STOLEN;
+
+ if (skb != (*pskb))
+ fragd = 1;
+
+ ret = ip6_conntrack_in(hooknum, rsmd_pskb, in, out, okfn);
+
+ if (!fragd)
+ return ret;
+
+ if (ret == NF_DROP) {
+ ip6_ct_kfree_frags(skb);
+ }else{
+ struct nf_info info;
+
+ info.pf = PF_INET6;
+ info.hook = hooknum;
+ info.indev = in;
+ info.outdev = out;
+ info.okfn = okfn;
+ switch (hooknum) {
+ case NF_IP6_PRE_ROUTING:
+ info.elem = &ip6_conntrack_in_ops;
+ break;
+ case NF_IP6_LOCAL_OUT:
+ info.elem = &ip6_conntrack_local_out_ops;
+ break;
+ }
+
+ if (ip6_ct_output_frags(skb, &info) <0)
+ DEBUGP("Can't output fragments\n");
+
+ }
+
+ return NF_STOLEN;
+}
+
+static unsigned int ip6_conntrack_local(unsigned int hooknum,
+ struct sk_buff **pskb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ unsigned int ret;
+
+ /* root is playing with raw sockets. */
+ if ((*pskb)->len < sizeof(struct ipv6hdr)) {
+ if (net_ratelimit())
+ printk("ip6t_hook: IPv6 header is too short.\n");
+ return NF_ACCEPT;
+ }
+
+ ret = ip6_conntrack_reasm(hooknum, pskb, in, out, okfn);
+
+ return ret;
+}
+
+static int init_or_cleanup(int init)
+{
+ struct proc_dir_entry *proc;
+ int ret = 0;
+
+ if (!init) goto cleanup;
+
+ ret = ip6_ct_frags_init();
+ if (ret < 0)
+ goto cleanup_reasm;
+
+ ret = ip6_conntrack_init();
+ if (ret < 0)
+ goto cleanup_nothing;
+
+ proc = proc_net_create("ip6_conntrack",0,list_conntracks);
+ if (!proc) goto cleanup_init;
+ proc->owner = THIS_MODULE;
+
+ ret = nf_register_hook(&ip6_conntrack_in_ops);
+ if (ret < 0) {
+ printk("ip6_conntrack: can't register pre-routing hook.\n");
+ goto cleanup_proc;
+ }
+ ret = nf_register_hook(&ip6_conntrack_local_out_ops);
+ if (ret < 0) {
+ printk("ip6_conntrack: can't register local out hook.\n");
+ goto cleanup_inops;
+ }
+ ret = nf_register_hook(&ip6_conntrack_out_ops);
+ if (ret < 0) {
+ printk("ip6_conntrack: can't register post-routing hook.\n");
+ goto cleanup_inandlocalops;
+ }
+ ret = nf_register_hook(&ip6_conntrack_local_in_ops);
+ if (ret < 0) {
+ printk("ip6_conntrack: can't register local in hook.\n");
+ goto cleanup_inoutandlocalops;
+ }
+
+ return ret;
+
+ cleanup:
+ nf_unregister_hook(&ip6_conntrack_local_in_ops);
+ cleanup_inoutandlocalops:
+ nf_unregister_hook(&ip6_conntrack_out_ops);
+ cleanup_inandlocalops:
+ nf_unregister_hook(&ip6_conntrack_local_out_ops);
+ cleanup_inops:
+ nf_unregister_hook(&ip6_conntrack_in_ops);
+ cleanup_proc:
+ proc_net_remove("ip6_conntrack");
+ cleanup_init:
+ ip6_conntrack_cleanup();
+ cleanup_reasm:
+ ip6_ct_frags_cleanup();
+ cleanup_nothing:
+ return ret;
+}
+
+/* FIXME: Allow NULL functions and sub in pointers to generic for
+ them. --RR */
+int ip6_conntrack_protocol_register(struct ip6_conntrack_protocol *proto)
+{
+ int ret = 0;
+ struct list_head *i;
+
+ WRITE_LOCK(&ip6_conntrack_lock);
+ for (i = ip6_protocol_list.next; i != &ip6_protocol_list; i = i->next) {
+ if (((struct ip6_conntrack_protocol *)i)->proto
+ == proto->proto) {
+ ret = -EBUSY;
+ goto out;
+ }
+ }
+
+ list_prepend(&ip6_protocol_list, proto);
+
+ out:
+ WRITE_UNLOCK(&ip6_conntrack_lock);
+ return ret;
+}
+
+void ip6_conntrack_protocol_unregister(struct ip6_conntrack_protocol *proto)
+{
+ WRITE_LOCK(&ip6_conntrack_lock);
+
+ /* ip_ct_find_proto() returns proto_generic in case there is no protocol
+ * helper. So this should be enough - HW */
+ LIST_DELETE(&ip6_protocol_list, proto);
+ WRITE_UNLOCK(&ip6_conntrack_lock);
+
+ /* Somebody could be still looking at the proto in bh. */
+ synchronize_net();
+
+ /* Remove all contrack entries for this protocol */
+ ip6_ct_selective_cleanup(kill_proto, &proto->proto);
+}
+
+static int __init init(void)
+{
+ return init_or_cleanup(1);
+}
+
+static void __exit fini(void)
+{
+ init_or_cleanup(0);
+}
+
+module_init(init);
+module_exit(fini);
+
+/* Some modules need us, but don't depend directly on any symbol.
+ They should call this. */
+void need_ip6_conntrack(void)
+{
+}
+
+EXPORT_SYMBOL(ip6_conntrack_protocol_register);
+EXPORT_SYMBOL(ip6_conntrack_protocol_unregister);
+EXPORT_SYMBOL(ip6_invert_tuplepr);
+EXPORT_SYMBOL(ip6_conntrack_alter_reply);
+EXPORT_SYMBOL(ip6_conntrack_destroyed);
+EXPORT_SYMBOL(ip6_conntrack_get);
+EXPORT_SYMBOL(need_ip6_conntrack);
+EXPORT_SYMBOL(ip6_conntrack_helper_register);
+EXPORT_SYMBOL(ip6_conntrack_helper_unregister);
+EXPORT_SYMBOL(ip6_ct_selective_cleanup);
+EXPORT_SYMBOL(ip6_ct_refresh);
+EXPORT_SYMBOL(ip6_ct_find_proto);
+EXPORT_SYMBOL(__ip6_ct_find_proto);
+EXPORT_SYMBOL(ip6_ct_find_helper);
+EXPORT_SYMBOL(ip6_conntrack_expect_related);
+EXPORT_SYMBOL(ip6_conntrack_unexpect_related);
+EXPORT_SYMBOL_GPL(ip6_conntrack_expect_find_get);
+EXPORT_SYMBOL_GPL(ip6_conntrack_expect_put);
+EXPORT_SYMBOL(ip6_conntrack_tuple_taken);
+EXPORT_SYMBOL(ip6_conntrack_htable_size);
+EXPORT_SYMBOL(ip6_conntrack_expect_list);
+EXPORT_SYMBOL(ip6_conntrack_lock);
+EXPORT_SYMBOL_GPL(ip6_conntrack_find_get);
+EXPORT_SYMBOL_GPL(ip6_conntrack_put);
diff -urN linux-2.6.11/net/ipv6/netfilter/ip6t_IMQ.c linux.sinabox/net/ipv6/netfilter/ip6t_IMQ.c
--- linux-2.6.11/net/ipv6/netfilter/ip6t_IMQ.c 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/net/ipv6/netfilter/ip6t_IMQ.c 2005-03-26 00:49:04.000000000 +0100
@@ -0,0 +1,78 @@
+/*
+ * This target marks packets to be enqueued to an imq device
+ */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter_ipv6/ip6t_IMQ.h>
+#include <linux/imq.h>
+
+static unsigned int imq_target(struct sk_buff **pskb,
+ unsigned int hooknum,
+ const struct net_device *in,
+ const struct net_device *out,
+ const void *targinfo,
+ void *userdata)
+{
+ struct ip6t_imq_info *mr = (struct ip6t_imq_info*)targinfo;
+
+ (*pskb)->imq_flags = mr->todev | IMQ_F_ENQUEUE;
+ (*pskb)->nfcache |= NFC_ALTERED;
+
+ return IP6T_CONTINUE;
+}
+
+static int imq_checkentry(const char *tablename,
+ const struct ip6t_entry *e,
+ void *targinfo,
+ unsigned int targinfosize,
+ unsigned int hook_mask)
+{
+ struct ip6t_imq_info *mr;
+
+ if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_imq_info))) {
+ printk(KERN_WARNING "IMQ: invalid targinfosize\n");
+ return 0;
+ }
+ mr = (struct ip6t_imq_info*)targinfo;
+
+ if (strcmp(tablename, "mangle") != 0) {
+ printk(KERN_WARNING
+ "IMQ: IMQ can only be called from \"mangle\" table, not \"%s\"\n",
+ tablename);
+ return 0;
+ }
+
+ if (mr->todev > IMQ_MAX_DEVS) {
+ printk(KERN_WARNING
+ "IMQ: invalid device specified, highest is %u\n",
+ IMQ_MAX_DEVS);
+ return 0;
+ }
+
+ return 1;
+}
+
+static struct ip6t_target ip6t_imq_reg = {
+ .name = "IMQ",
+ .target = imq_target,
+ .checkentry = imq_checkentry,
+ .me = THIS_MODULE
+};
+
+static int __init init(void)
+{
+ if (ip6t_register_target(&ip6t_imq_reg))
+ return -EINVAL;
+
+ return 0;
+}
+
+static void __exit fini(void)
+{
+ ip6t_unregister_target(&ip6t_imq_reg);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
diff -urN linux-2.6.11/net/ipv6/netfilter/ip6t_REJECT.c linux.sinabox/net/ipv6/netfilter/ip6t_REJECT.c
--- linux-2.6.11/net/ipv6/netfilter/ip6t_REJECT.c 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/net/ipv6/netfilter/ip6t_REJECT.c 2005-03-26 19:02:06.000000000 +0100
@@ -0,0 +1,453 @@
+/*
+ * IP6 tables REJECT target module
+ * Linux INET6 implementation
+ *
+ * Copyright (C)2003 USAGI/WIDE Project
+ *
+ * Authors:
+ * Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
+ *
+ * Based on net/ipv4/netfilter/ipt_REJECT.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/* This module works well with IPv6 Connection Tracking. - kozakai */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/icmpv6.h>
+#include <net/ipv6.h>
+#include <net/tcp.h>
+#include <net/icmp.h>
+#include <net/ip6_fib.h>
+#include <net/ip6_route.h>
+#include <net/flow.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter_ipv6/ip6t_REJECT.h>
+
+MODULE_AUTHOR("Yasuyuki KOZAKAI <yasuyuki.kozakai@toshiba.co.jp>");
+MODULE_DESCRIPTION("IP6 tables REJECT target module");
+MODULE_LICENSE("GPL");
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+static void connection_attach(struct sk_buff *new_skb, struct sk_buff *skb)
+{
+ void (*attach)(struct sk_buff *, struct sk_buff *);
+ if (skb->nfct && (attach = ip6_ct_attach) != NULL) {
+ mb();
+ attach(new_skb, skb);
+ }
+}
+
+static int maybe_reroute(struct sk_buff *skb)
+{
+ if (skb->nfcache & NFC_ALTERED){
+ if (ip6_route_me_harder(skb) != 0){
+ kfree_skb(skb);
+ return -EINVAL;
+ }
+ }
+
+ return dst_output(skb);
+}
+
+/* Send RST reply */
+static void send_reset(struct sk_buff *oldskb)
+{
+ struct sk_buff *nskb;
+ struct tcphdr otcph, *tcph;
+ unsigned int otcplen, tcphoff, hh_len;
+ int needs_ack;
+ struct ipv6hdr *oip6h = oldskb->nh.ipv6h, *ip6h;
+ struct dst_entry *dst = NULL;
+ u8 proto = oip6h->nexthdr;
+ struct flowi fl;
+ int err;
+
+ if ((!(ipv6_addr_type(&oip6h->saddr) & IPV6_ADDR_UNICAST)) ||
+ (!(ipv6_addr_type(&oip6h->daddr) & IPV6_ADDR_UNICAST))) {
+ DEBUGP("ip6t_REJECT: addr is not unicast.\n");
+ return;
+ }
+
+ tcphoff = ipv6_skip_exthdr(oldskb, ((u8*)(oip6h+1) - oldskb->data),
+ &proto, oldskb->len - ((u8*)(oip6h+1)
+ - oldskb->data));
+
+ if ((tcphoff < 0) || (tcphoff > oldskb->len)) {
+ DEBUGP("ip6t_REJECT: Can't get TCP header.\n");
+ return;
+ }
+
+ otcplen = oldskb->len - tcphoff;
+
+ /* IP header checks: fragment, too short. */
+ if ((proto != IPPROTO_TCP) || (otcplen < sizeof(struct tcphdr))) {
+ DEBUGP("ip6t_REJECT: proto(%d) != IPPROTO_TCP, or too short. otcplen = %d\n",
+ proto, otcplen);
+ return;
+ }
+
+ if (skb_copy_bits(oldskb, tcphoff, &otcph, sizeof(struct tcphdr))) {
+ if (net_ratelimit())
+ printk("ip6t_REJECT: Can't copy tcp header\n");
+ return;
+ }
+
+ /* No RST for RST. */
+ if (otcph.rst) {
+ DEBUGP("ip6t_REJECT: RST is set\n");
+ return;
+ }
+
+ /* Check checksum. */
+ if (csum_ipv6_magic(&oip6h->saddr, &oip6h->daddr, otcplen, IPPROTO_TCP,
+ skb_checksum(oldskb, tcphoff, otcplen, 0))) {
+ DEBUGP("ip6t_REJECT: TCP checksum is invalid\n");
+ return;
+ }
+
+ memset(&fl, 0, sizeof(fl));
+ fl.proto = IPPROTO_TCP;
+ ipv6_addr_copy(&fl.fl6_src, &oip6h->daddr);
+ ipv6_addr_copy(&fl.fl6_dst, &oip6h->saddr);
+ fl.fl_ip_sport = otcph.dest;
+ fl.fl_ip_dport = otcph.source;
+ err = ip6_dst_lookup(NULL, &dst, &fl);
+ if (err) {
+ if (net_ratelimit())
+ printk("ip6t_REJECT: can't find dst. err = %d\n", err);
+ return;
+ }
+
+ hh_len = (dst->dev->hard_header_len + 15)&~15;
+ nskb = alloc_skb(hh_len + 15 + dst->header_len + sizeof(struct ipv6hdr)
+ + sizeof(struct tcphdr) + dst->trailer_len,
+ GFP_ATOMIC);
+
+ if (!nskb) {
+ if (net_ratelimit())
+ printk("ip6t_REJECT: Can't alloc skb\n");
+ dst_release(dst);
+ return;
+ }
+
+ nskb->dst = dst;
+ dst_hold(dst);
+
+ skb_reserve(nskb, hh_len + dst->header_len);
+
+ ip6h = nskb->nh.ipv6h = (struct ipv6hdr *)
+ skb_put(nskb, sizeof(struct ipv6hdr));
+ ip6h->version = 6;
+ ip6h->hop_limit = dst_metric(dst, RTAX_HOPLIMIT);
+ ip6h->nexthdr = IPPROTO_TCP;
+ ip6h->payload_len = htons(sizeof(struct tcphdr));
+ ipv6_addr_copy(&ip6h->saddr, &oip6h->daddr);
+ ipv6_addr_copy(&ip6h->daddr, &oip6h->saddr);
+
+ tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr));
+ /* Truncate to length (no data) */
+ tcph->doff = sizeof(struct tcphdr)/4;
+ tcph->source = otcph.dest;
+ tcph->dest = otcph.source;
+
+ if (otcph.ack) {
+ needs_ack = 0;
+ tcph->seq = otcph.ack_seq;
+ tcph->ack_seq = 0;
+ } else {
+ needs_ack = 1;
+ tcph->ack_seq = htonl(ntohl(otcph.seq) + otcph.syn + otcph.fin
+ + otcplen - (otcph.doff<<2));
+ tcph->seq = 0;
+ }
+
+ /* Reset flags */
+ ((u_int8_t *)tcph)[13] = 0;
+ tcph->rst = 1;
+ tcph->ack = needs_ack;
+ tcph->window = 0;
+ tcph->urg_ptr = 0;
+ tcph->check = 0;
+
+ /* Adjust TCP checksum */
+ tcph->check = csum_ipv6_magic(&nskb->nh.ipv6h->saddr,
+ &nskb->nh.ipv6h->daddr,
+ sizeof(struct tcphdr), IPPROTO_TCP,
+ csum_partial((char *)tcph,
+ sizeof(struct tcphdr), 0));
+
+ connection_attach(nskb, oldskb);
+
+ NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
+ maybe_reroute);
+
+ dst_release(dst);
+}
+
+static void send_unreach(struct sk_buff *skb_in, unsigned char code)
+{
+ struct ipv6hdr *ip6h, *hdr = skb_in->nh.ipv6h;
+ struct icmp6hdr *icmp6h;
+ struct dst_entry *dst = NULL;
+ struct rt6_info *rt;
+ int tmo;
+ __u32 csum;
+ unsigned int len, datalen, hh_len;
+ int saddr_type, daddr_type;
+ unsigned int ptr, ip6off;
+ u8 proto;
+ struct flowi fl;
+ struct sk_buff *nskb;
+ char *data;
+
+ saddr_type = ipv6_addr_type(&hdr->saddr);
+ daddr_type = ipv6_addr_type(&hdr->daddr);
+
+ if ((!(saddr_type & IPV6_ADDR_UNICAST)) ||
+ (!(daddr_type & IPV6_ADDR_UNICAST))) {
+ DEBUGP("ip6t_REJECT: addr is not unicast.\n");
+ return;
+ }
+
+ ip6off = skb_in->nh.raw - skb_in->data;
+ proto = hdr->nexthdr;
+ ptr = ipv6_skip_exthdr(skb_in, ip6off + sizeof(struct ipv6hdr), &proto,
+ skb_in->len - ip6off);
+
+ if ((ptr < 0) || (ptr > skb_in->len)) {
+ ptr = ip6off + sizeof(struct ipv6hdr);
+ proto = hdr->nexthdr;
+ } else if (proto == IPPROTO_ICMPV6) {
+ u8 type;
+
+ if (skb_copy_bits(skb_in, ptr + offsetof(struct icmp6hdr,
+ icmp6_type), &type, 1)) {
+ DEBUGP("ip6t_REJECT: Can't get ICMPv6 type\n");
+ return;
+ }
+
+ if (!(type & ICMPV6_INFOMSG_MASK)) {
+ DEBUGP("ip6t_REJECT: no reply to icmp error\n");
+ return;
+ }
+ } else if (proto == IPPROTO_UDP) {
+ int plen = skb_in->len - (ptr - ip6off);
+ uint16_t check;
+
+ if (plen < sizeof(struct udphdr)) {
+ DEBUGP("ip6t_REJECT: too short\n");
+ return;
+ }
+
+ if (skb_copy_bits(skb_in, ptr + offsetof(struct udphdr, check),
+ &check, 2)) {
+ if (net_ratelimit())
+ printk("ip6t_REJECT: can't get copy from skb");
+ return;
+ }
+
+ if (check &&
+ csum_ipv6_magic(&hdr->saddr, &hdr->daddr, plen,
+ IPPROTO_UDP,
+ skb_checksum(skb_in, ptr, plen, 0))) {
+ DEBUGP("ip6t_REJECT: UDP checksum is invalid.\n");
+ return;
+ }
+ }
+
+ memset(&fl, 0, sizeof(fl));
+ fl.proto = IPPROTO_ICMPV6;
+ ipv6_addr_copy(&fl.fl6_src, &hdr->daddr);
+ ipv6_addr_copy(&fl.fl6_dst, &hdr->saddr);
+ fl.fl_icmp_type = ICMPV6_DEST_UNREACH;
+ fl.fl_icmp_code = code;
+
+ if (ip6_dst_lookup(NULL, &dst, &fl)) {
+ return;
+ }
+
+ rt = (struct rt6_info *)dst;
+ tmo = 1*HZ;
+
+ if (rt->rt6i_dst.plen < 128)
+ tmo >>= ((128 - rt->rt6i_dst.plen)>>5);
+
+ if (!xrlim_allow(dst, tmo)) {
+ if (net_ratelimit())
+ printk("ip6t_REJECT: rate limitted\n");
+ goto dst_release_out;
+ }
+
+ len = skb_in->len + sizeof(struct ipv6hdr) + sizeof(struct icmp6hdr);
+
+ if (len > dst_pmtu(dst))
+ len = dst_pmtu(dst);
+ if (len > IPV6_MIN_MTU)
+ len = IPV6_MIN_MTU;
+
+ datalen = len - sizeof(struct ipv6hdr) - sizeof(struct icmp6hdr);
+ hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15;
+
+ nskb = alloc_skb(hh_len + 15 + dst->header_len + dst->trailer_len + len,
+ GFP_ATOMIC);
+
+ if (!nskb) {
+ if (net_ratelimit())
+ printk("ip6t_REJECT: can't alloc skb\n");
+ goto dst_release_out;
+ }
+
+ nskb->priority = 0;
+ nskb->dst = dst;
+ dst_hold(dst);
+
+ skb_reserve(nskb, hh_len + dst->header_len);
+
+ ip6h = nskb->nh.ipv6h = (struct ipv6hdr *)
+ skb_put(nskb, sizeof(struct ipv6hdr));
+ ip6h->version = 6;
+ ip6h->hop_limit = dst_metric(dst, RTAX_HOPLIMIT);
+ ip6h->nexthdr = IPPROTO_ICMPV6;
+ ip6h->payload_len = htons(datalen + sizeof(struct icmp6hdr));
+ ipv6_addr_copy(&ip6h->saddr, &hdr->daddr);
+ ipv6_addr_copy(&ip6h->daddr, &hdr->saddr);
+
+ icmp6h = (struct icmp6hdr *) skb_put(nskb, sizeof(struct icmp6hdr));
+ icmp6h->icmp6_type = ICMPV6_DEST_UNREACH;
+ icmp6h->icmp6_code = code;
+ icmp6h->icmp6_cksum = 0;
+
+ data = skb_put(nskb, datalen);
+
+ csum = csum_partial((unsigned char *)icmp6h, sizeof(struct icmp6hdr), 0);
+ csum = skb_copy_and_csum_bits(skb_in, ip6off, data, datalen, csum);
+ icmp6h->icmp6_cksum = csum_ipv6_magic(&hdr->saddr, &hdr->daddr,
+ datalen + sizeof(struct icmp6hdr),
+ IPPROTO_ICMPV6, csum);
+
+ connection_attach(nskb, skb_in);
+ NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
+ maybe_reroute);
+
+dst_release_out:
+ dst_release(dst);
+}
+
+static unsigned int reject6_target(struct sk_buff **pskb,
+ const struct net_device *in,
+ const struct net_device *out,
+ unsigned int hooknum,
+ const void *targinfo,
+ void *userinfo)
+{
+ const struct ip6t_reject_info *reject = targinfo;
+
+ DEBUGP(KERN_DEBUG "%s: medium point\n", __FUNCTION__);
+ /* WARNING: This code causes reentry within ip6tables.
+ This means that the ip6tables jump stack is now crap. We
+ must return an absolute verdict. --RR */
+ switch (reject->with) {
+ case IP6T_ICMP6_NO_ROUTE:
+ send_unreach(*pskb, ICMPV6_NOROUTE);
+ break;
+ case IP6T_ICMP6_ADM_PROHIBITED:
+ send_unreach(*pskb, ICMPV6_ADM_PROHIBITED);
+ break;
+ case IP6T_ICMP6_NOT_NEIGHBOUR:
+ send_unreach(*pskb, ICMPV6_NOT_NEIGHBOUR);
+ break;
+ case IP6T_ICMP6_ADDR_UNREACH:
+ send_unreach(*pskb, ICMPV6_ADDR_UNREACH);
+ break;
+ case IP6T_ICMP6_PORT_UNREACH:
+ send_unreach(*pskb, ICMPV6_PORT_UNREACH);
+ break;
+ case IP6T_ICMP6_ECHOREPLY:
+ /* Do nothing */
+ break;
+ case IP6T_TCP_RESET:
+ send_reset(*pskb);
+ break;
+ default:
+ if (net_ratelimit())
+ printk(KERN_WARNING "ip6t_REJECT: case %u not handled yet\n", reject->with);
+ break;
+ }
+
+ return NF_DROP;
+}
+
+static int check(const char *tablename,
+ const struct ip6t_entry *e,
+ void *targinfo,
+ unsigned int targinfosize,
+ unsigned int hook_mask)
+{
+ const struct ip6t_reject_info *rejinfo = targinfo;
+
+ if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_reject_info))) {
+ DEBUGP("ip6t_REJECT: targinfosize %u != 0\n", targinfosize);
+ return 0;
+ }
+
+ /* Only allow these for packet filtering. */
+ if (strcmp(tablename, "filter") != 0) {
+ DEBUGP("ip6t_REJECT: bad table `%s'.\n", tablename);
+ return 0;
+ }
+
+ if ((hook_mask & ~((1 << NF_IP6_LOCAL_IN)
+ | (1 << NF_IP6_FORWARD)
+ | (1 << NF_IP6_LOCAL_OUT))) != 0) {
+ DEBUGP("ip6t_REJECT: bad hook mask %X\n", hook_mask);
+ return 0;
+ }
+
+ if (rejinfo->with == IP6T_ICMP6_ECHOREPLY) {
+ printk("ip6t_REJECT: ECHOREPLY is not supported.\n");
+ return 0;
+ } else if (rejinfo->with == IP6T_TCP_RESET) {
+ /* Must specify that it's a TCP packet */
+ if (e->ipv6.proto != IPPROTO_TCP
+ || (e->ipv6.invflags & IP6T_INV_PROTO)) {
+ DEBUGP("ip6t_REJECT: TCP_RESET illegal for non-tcp\n");
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static struct ip6t_target ip6t_reject_reg = {
+ .name = "REJECT",
+ .target = reject6_target,
+ .checkentry = check,
+ .me = THIS_MODULE
+};
+
+static int __init init(void)
+{
+ if (ip6t_register_target(&ip6t_reject_reg))
+ return -EINVAL;
+ return 0;
+}
+
+static void __exit fini(void)
+{
+ ip6t_unregister_target(&ip6t_reject_reg);
+}
+
+module_init(init);
+module_exit(fini);
diff -urN linux-2.6.11/net/ipv6/netfilter/ip6t_state.c linux.sinabox/net/ipv6/netfilter/ip6t_state.c
--- linux-2.6.11/net/ipv6/netfilter/ip6t_state.c 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/net/ipv6/netfilter/ip6t_state.c 2005-03-26 19:02:06.000000000 +0100
@@ -0,0 +1,79 @@
+/*
+ * Matching connection tracking information
+ * Linux INET6 implementation
+ *
+ * Copyright (C)2003 USAGI/WIDE Project
+ *
+ * Authors:
+ * Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
+ *
+ * Based on: net/ipv4/netfilter/ip6t_state.c
+ *
+ * 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.
+ */
+/* Kernel module to match connection tracking information.
+ * GPL (C) 1999 Rusty Russell (rusty@rustcorp.com.au).
+ */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter_ipv6/ip6_conntrack.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter_ipv6/ip6t_state.h>
+
+static int
+match(const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ const void *matchinfo,
+ int offset,
+ unsigned int protoff,
+ int *hotdrop)
+{
+ const struct ip6t_state_info *sinfo = matchinfo;
+ enum ip6_conntrack_info ctinfo;
+ unsigned int statebit;
+
+ if (!ip6_conntrack_get(skb, &ctinfo))
+ statebit = IP6T_STATE_INVALID;
+ else
+ statebit = IP6T_STATE_BIT(ctinfo);
+
+ return (sinfo->statemask & statebit);
+}
+
+static int check(const char *tablename,
+ const struct ip6t_ip6 *ip,
+ void *matchinfo,
+ unsigned int matchsize,
+ unsigned int hook_mask)
+{
+ if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_state_info)))
+ return 0;
+
+ return 1;
+}
+
+static struct ip6t_match state_match = {
+ .name = "state",
+ .match = &match,
+ .checkentry = &check,
+ .me = THIS_MODULE,
+};
+
+static int __init init(void)
+{
+ need_ip6_conntrack();
+ return ip6t_register_match(&state_match);
+}
+
+static void __exit fini(void)
+{
+ ip6t_unregister_match(&state_match);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
diff -urN linux-2.6.11/net/ipv6/netfilter/ip6t_ULOG.c linux.sinabox/net/ipv6/netfilter/ip6t_ULOG.c
--- linux-2.6.11/net/ipv6/netfilter/ip6t_ULOG.c 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/net/ipv6/netfilter/ip6t_ULOG.c 2005-03-24 19:24:16.000000000 +0100
@@ -0,0 +1,142 @@
+/*
+ * netfilter module for userspace packet logging daemons
+ *
+ * (C) 2000-2004 by Harald Welte <laforge@netfilter.org>
+ *
+ * 2000/09/22 ulog-cprange feature added
+ * 2001/01/04 in-kernel queue as proposed by Sebastian Zander
+ * <zander@fokus.gmd.de>
+ * 2001/01/30 per-rule nlgroup conflicts with global queue.
+ * nlgroup now global (sysctl)
+ * 2001/04/19 ulog-queue reworked, now fixed buffer size specified at
+ * module loadtime -HW
+ * 2002/07/07 remove broken nflog_rcv() function -HW
+ * 2002/08/29 fix shifted/unshifted nlgroup bug -HW
+ * 2002/10/30 fix uninitialized mac_len field - <Anders K. Pedersen>
+ * 2004/10/25 fix erroneous calculation of 'len' parameter to NLMSG_PUT
+ * resulting in bogus 'error during NLMSG_PUT' messages.
+ * 2005/02/10 ported to ipv6
+ *
+ * (C) 1999-2001 Paul `Rusty' Russell
+ * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter_ipv4/ipt_ULOG.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jonas Berlin <xkr47@outerspace.dyndns.org>");
+MODULE_DESCRIPTION("ip6tables userspace logging module");
+
+#if 0
+#define DEBUGP(format, args...) printk("%s:%s:" format, \
+ __FILE__, __FUNCTION__ , ## args)
+#else
+#define DEBUGP(format, args...)
+#endif
+
+static unsigned int nflog = 1;
+module_param(nflog, int, 0400);
+MODULE_PARM_DESC(nflog, "register as internal netfilter logging module");
+
+// from ipt_ULOG.c
+void ipt_ulog_packet(unsigned int hooknum,
+ const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ const struct ipt_ulog_info *loginfo,
+ const char *prefix);
+
+static unsigned int ip6t_ulog_target(struct sk_buff **pskb,
+ const struct net_device *in,
+ const struct net_device *out,
+ unsigned int hooknum,
+ const void *targinfo, void *userinfo)
+{
+ const struct ipt_ulog_info *loginfo = (const struct ipt_ulog_info *) targinfo;
+
+ ipt_ulog_packet(hooknum, *pskb, in, out, loginfo, NULL);
+
+ return IP6T_CONTINUE;
+}
+
+static void ip6t_logfn(unsigned int hooknum,
+ const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ const char *prefix)
+{
+ struct ipt_ulog_info loginfo = {
+ .nl_group = ULOG_DEFAULT_NLGROUP,
+ .copy_range = 0,
+ .qthreshold = ULOG_DEFAULT_QTHRESHOLD,
+ .prefix = ""
+ };
+
+ ipt_ulog_packet(hooknum, skb, in, out, &loginfo, prefix);
+}
+
+static int ip6t_ulog_checkentry(const char *tablename,
+ const struct ip6t_entry *e,
+ void *targinfo,
+ unsigned int targinfosize,
+ unsigned int hookmask)
+{
+ struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
+
+ if (targinfosize != IP6T_ALIGN(sizeof(struct ipt_ulog_info))) {
+ DEBUGP("ip6t_ULOG: targinfosize %u != 0\n", targinfosize);
+ return 0;
+ }
+
+ if (loginfo->prefix[sizeof(loginfo->prefix) - 1] != '\0') {
+ DEBUGP("ip6t_ULOG: prefix term %i\n",
+ loginfo->prefix[sizeof(loginfo->prefix) - 1]);
+ return 0;
+ }
+
+ if (loginfo->qthreshold > ULOG_MAX_QLEN) {
+ DEBUGP("ip6t_ULOG: queue threshold %i > MAX_QLEN\n",
+ loginfo->qthreshold);
+ return 0;
+ }
+
+ return 1;
+}
+
+static struct ip6t_target ip6t_ulog_reg = {
+ .name = "ULOG",
+ .target = ip6t_ulog_target,
+ .checkentry = ip6t_ulog_checkentry,
+ .me = THIS_MODULE,
+};
+
+static int __init init(void)
+{
+ DEBUGP("ip6t_ULOG: init module\n");
+
+ if (ip6t_register_target(&ip6t_ulog_reg) != 0) {
+ return -EINVAL;
+ }
+ if (nflog)
+ nf_log_register(PF_INET6, &ip6t_logfn);
+
+ return 0;
+}
+
+static void __exit fini(void)
+{
+ DEBUGP("ip6t_ULOG: cleanup_module\n");
+
+ if (nflog)
+ nf_log_unregister(PF_INET6, &ip6t_logfn);
+ ip6t_unregister_target(&ip6t_ulog_reg);
+}
+
+module_init(init);
+module_exit(fini);
diff -urN linux-2.6.11/net/ipv6/netfilter/Kconfig linux.sinabox/net/ipv6/netfilter/Kconfig
--- linux-2.6.11/net/ipv6/netfilter/Kconfig 2005-03-02 08:38:25.000000000 +0100
+++ linux.sinabox/net/ipv6/netfilter/Kconfig 2005-03-26 19:02:06.000000000 +0100
@@ -5,6 +5,16 @@
menu "IPv6: Netfilter Configuration"
depends on INET && IPV6 && NETFILTER
+config IP6_NF_FTP
+ tristate "FTP protocol support"
+ depends on IP6_NF_CONNTRACK
+ help
+ Tracking FTP connections is problematic: special helpers are
+ required for tracking them.
+
+ If you want to compile it as a module, say M here and read
+ <file:Documentation/modules.txt>. If unsure, say `Y'.
+
#tristate 'Connection tracking (required for masq/NAT)' CONFIG_IP6_NF_CONNTRACK
#if [ "$CONFIG_IP6_NF_CONNTRACK" != "n" ]; then
# dep_tristate ' FTP protocol support' CONFIG_IP6_NF_FTP $CONFIG_IP6_NF_CONNTRACK
@@ -167,6 +177,32 @@
To compile it as a module, choose M here. If unsure, say N.
+config IP6_NF_CONNTRACK
+ tristate "Connection tracking (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ ---help---
+ Connection tracking keeps a record of what packets have passed
+ through your machine, in order to figure out how they are related
+ into connections.
+
+ It can also be used to enhance packet filtering
+ (see `Connection state match support'
+ below).
+
+ If you want to compile it as a module, say M here and read
+ <file:Documentation/modules.txt>. If unsure, say `N'.
+
+config IP6_NF_MATCH_STATE
+ tristate "Connection state match support"
+ depends on IP6_NF_CONNTRACK && IP6_NF_IPTABLES
+ help
+ Connection state matching allows you to match packets based on their
+ relationship to a tracked connection (ie. previous packets). This
+ is a powerful tool for packet classification.
+
+ If you want to compile it as a module, say M here and read
+ <file:Documentation/modules.txt>. If unsure, say `N'.
+
# dep_tristate ' Multiple port match support' CONFIG_IP6_NF_MATCH_MULTIPORT $CONFIG_IP6_NF_IPTABLES
# dep_tristate ' TOS match support' CONFIG_IP6_NF_MATCH_TOS $CONFIG_IP6_NF_IPTABLES
# if [ "$CONFIG_IP6_NF_CONNTRACK" != "n" ]; then
@@ -187,6 +223,15 @@
To compile it as a module, choose M here. If unsure, say N.
+config IP6_NF_TARGET_IMQ
+ tristate "IMQ target support"
+ depends on IP6_NF_MANGLE
+ help
+ This option adds a `IMQ' target which is used to specify if and
+ to which imq device packets should get enqueued/dequeued.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
config IP6_NF_TARGET_LOG
tristate "LOG target support"
depends on IP6_NF_FILTER
@@ -196,8 +241,17 @@
To compile it as a module, choose M here. If unsure, say N.
+config IP6_NF_TARGET_REJECT
+ tristate "REJECT target support"
+ depends on IP6_NF_FILTER
+ help
+ The REJECT target allows a filtering rule to specify that an ICMP
+ error should be issued in response to an incoming packet, rather
+ than silently being dropped.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
# if [ "$CONFIG_IP6_NF_FILTER" != "n" ]; then
-# dep_tristate ' REJECT target support' CONFIG_IP6_NF_TARGET_REJECT $CONFIG_IP6_NF_FILTER
# if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
# dep_tristate ' MIRROR target support (EXPERIMENTAL)' CONFIG_IP6_NF_TARGET_MIRROR $CONFIG_IP6_NF_FILTER
# fi
@@ -238,5 +292,22 @@
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
+config IP6_NF_TARGET_ULOG
+ tristate "ULOG target support"
+ depends on IP6_NF_IPTABLES && IP_NF_TARGET_ULOG
+ ---help---
+ This option adds a `ULOG' target, which allows you to create rules in
+ any ip6tables table. The packet is passed to a userspace logging
+ daemon using netlink multicast sockets; unlike the LOG target
+ which can only be viewed through syslog.
+
+ NOTE: This target requires the ipv4 version of ULOG to be compiled as
+ well.
+
+ The apropriate userspace logging daemon (ulogd) may be obtained from
+ <http://www.gnumonks.org/projects/ulogd/>
+
+ To compile it as a module, choose M here. If unsure, say N.
+
endmenu
diff -urN linux-2.6.11/net/ipv6/netfilter/Kconfig.orig linux.sinabox/net/ipv6/netfilter/Kconfig.orig
--- linux-2.6.11/net/ipv6/netfilter/Kconfig.orig 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/net/ipv6/netfilter/Kconfig.orig 2005-03-26 00:49:04.000000000 +0100
@@ -0,0 +1,268 @@
+#
+# IP netfilter configuration
+#
+
+menu "IPv6: Netfilter Configuration"
+ depends on INET && IPV6 && NETFILTER
+
+#tristate 'Connection tracking (required for masq/NAT)' CONFIG_IP6_NF_CONNTRACK
+#if [ "$CONFIG_IP6_NF_CONNTRACK" != "n" ]; then
+# dep_tristate ' FTP protocol support' CONFIG_IP6_NF_FTP $CONFIG_IP6_NF_CONNTRACK
+#fi
+config IP6_NF_QUEUE
+ tristate "Userspace queueing via NETLINK"
+ ---help---
+
+ This option adds a queue handler to the kernel for IPv6
+ packets which lets us to receive the filtered packets
+ with QUEUE target using libiptc as we can do with
+ the IPv4 now.
+
+ (C) Fernando Anton 2001
+ IPv64 Project - Work based in IPv64 draft by Arturo Azcorra.
+ Universidad Carlos III de Madrid
+ Universidad Politecnica de Alcala de Henares
+ email: <fanton@it.uc3m.es>.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP6_NF_IPTABLES
+ tristate "IP6 tables support (required for filtering/masq/NAT)"
+ help
+ ip6tables is a general, extensible packet identification framework.
+ Currently only the packet filtering and packet mangling subsystem
+ for IPv6 use this, but connection tracking is going to follow.
+ Say 'Y' or 'M' here if you want to use either of those.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+# The simple matches.
+config IP6_NF_MATCH_LIMIT
+ tristate "limit match support"
+ depends on IP6_NF_IPTABLES
+ help
+ limit matching allows you to control the rate at which a rule can be
+ matched: mainly useful in combination with the LOG target ("LOG
+ target support", below) and to avoid some Denial of Service attacks.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP6_NF_MATCH_MAC
+ tristate "MAC address match support"
+ depends on IP6_NF_IPTABLES
+ help
+ mac matching allows you to match packets based on the source
+ Ethernet address of the packet.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP6_NF_MATCH_RT
+ tristate "Routing header match support"
+ depends on IP6_NF_IPTABLES
+ help
+ rt matching allows you to match packets based on the routing
+ header of the packet.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP6_NF_MATCH_OPTS
+ tristate "Hop-by-hop and Dst opts header match support"
+ depends on IP6_NF_IPTABLES
+ help
+ This allows one to match packets based on the hop-by-hop
+ and destination options headers of a packet.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP6_NF_MATCH_FRAG
+ tristate "Fragmentation header match support"
+ depends on IP6_NF_IPTABLES
+ help
+ frag matching allows you to match packets based on the fragmentation
+ header of the packet.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP6_NF_MATCH_HL
+ tristate "HL match support"
+ depends on IP6_NF_IPTABLES
+ help
+ HL matching allows you to match packets based on the hop
+ limit of the packet.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP6_NF_MATCH_MULTIPORT
+ tristate "Multiple port match support"
+ depends on IP6_NF_IPTABLES
+ help
+ Multiport matching allows you to match TCP or UDP packets based on
+ a series of source or destination ports: normally a rule can only
+ match a single range of ports.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP6_NF_MATCH_OWNER
+ tristate "Owner match support"
+ depends on IP6_NF_IPTABLES
+ help
+ Packet owner matching allows you to match locally-generated packets
+ based on who created them: the user, group, process or session.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+# dep_tristate ' MAC address match support' CONFIG_IP6_NF_MATCH_MAC $CONFIG_IP6_NF_IPTABLES
+config IP6_NF_MATCH_MARK
+ tristate "netfilter MARK match support"
+ depends on IP6_NF_IPTABLES
+ help
+ Netfilter mark matching allows you to match packets based on the
+ `nfmark' value in the packet. This can be set by the MARK target
+ (see below).
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP6_NF_MATCH_IPV6HEADER
+ tristate "IPv6 Extension Headers Match"
+ depends on IP6_NF_IPTABLES
+ help
+ This module allows one to match packets based upon
+ the ipv6 extension headers.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP6_NF_MATCH_AHESP
+ tristate "AH/ESP match support"
+ depends on IP6_NF_IPTABLES
+ help
+ This module allows one to match AH and ESP packets.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP6_NF_MATCH_LENGTH
+ tristate "Packet Length match support"
+ depends on IP6_NF_IPTABLES
+ help
+ This option allows you to match the length of a packet against a
+ specific value or range of values.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP6_NF_MATCH_EUI64
+ tristate "EUI64 address check"
+ depends on IP6_NF_IPTABLES
+ help
+ This module performs checking on the IPv6 source address
+ Compares the last 64 bits with the EUI64 (delivered
+ from the MAC address) address
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP6_NF_MATCH_PHYSDEV
+ tristate "Physdev match support"
+ depends on IP6_NF_IPTABLES && BRIDGE_NETFILTER
+ help
+ Physdev packet matching matches against the physical bridge ports
+ the IP packet arrived on or will leave by.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+# dep_tristate ' Multiple port match support' CONFIG_IP6_NF_MATCH_MULTIPORT $CONFIG_IP6_NF_IPTABLES
+# dep_tristate ' TOS match support' CONFIG_IP6_NF_MATCH_TOS $CONFIG_IP6_NF_IPTABLES
+# if [ "$CONFIG_IP6_NF_CONNTRACK" != "n" ]; then
+# dep_tristate ' Connection state match support' CONFIG_IP6_NF_MATCH_STATE $CONFIG_IP6_NF_CONNTRACK $CONFIG_IP6_NF_IPTABLES
+# fi
+# if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+# dep_tristate ' Unclean match support (EXPERIMENTAL)' CONFIG_IP6_NF_MATCH_UNCLEAN $CONFIG_IP6_NF_IPTABLES
+# dep_tristate ' Owner match support (EXPERIMENTAL)' CONFIG_IP6_NF_MATCH_OWNER $CONFIG_IP6_NF_IPTABLES
+# fi
+# The targets
+config IP6_NF_FILTER
+ tristate "Packet filtering"
+ depends on IP6_NF_IPTABLES
+ help
+ Packet filtering defines a table `filter', which has a series of
+ rules for simple packet filtering at local input, forwarding and
+ local output. See the man page for iptables(8).
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP6_NF_TARGET_IMQ
+ tristate "IMQ target support"
+ depends on IP6_NF_MANGLE
+ help
+ This option adds a `IMQ' target which is used to specify if and
+ to which imq device packets should get enqueued/dequeued.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config IP6_NF_TARGET_LOG
+ tristate "LOG target support"
+ depends on IP6_NF_FILTER
+ help
+ This option adds a `LOG' target, which allows you to create rules in
+ any iptables table which records the packet header to the syslog.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+# if [ "$CONFIG_IP6_NF_FILTER" != "n" ]; then
+# dep_tristate ' REJECT target support' CONFIG_IP6_NF_TARGET_REJECT $CONFIG_IP6_NF_FILTER
+# if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+# dep_tristate ' MIRROR target support (EXPERIMENTAL)' CONFIG_IP6_NF_TARGET_MIRROR $CONFIG_IP6_NF_FILTER
+# fi
+# fi
+config IP6_NF_MANGLE
+ tristate "Packet mangling"
+ depends on IP6_NF_IPTABLES
+ help
+ This option adds a `mangle' table to iptables: see the man page for
+ iptables(8). This table is used for various packet alterations
+ which can effect how the packet is routed.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+# dep_tristate ' TOS target support' CONFIG_IP6_NF_TARGET_TOS $CONFIG_IP_NF_MANGLE
+config IP6_NF_TARGET_MARK
+ tristate "MARK target support"
+ depends on IP6_NF_MANGLE
+ help
+ This option adds a `MARK' target, which allows you to create rules
+ in the `mangle' table which alter the netfilter mark (nfmark) field
+ associated with the packet packet prior to routing. This can change
+ the routing method (see `Use netfilter MARK value as routing
+ key') and can also be used by other subsystems to change their
+ behavior.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+#dep_tristate ' LOG target support' CONFIG_IP6_NF_TARGET_LOG $CONFIG_IP6_NF_IPTABLES
+config IP6_NF_RAW
+ tristate 'raw table support (required for TRACE)'
+ depends on IP6_NF_IPTABLES
+ help
+ This option adds a `raw' table to ip6tables. This table is the very
+ first in the netfilter framework and hooks in at the PREROUTING
+ and OUTPUT chains.
+
+ If you want to compile it as a module, say M here and read
+ <file:Documentation/modules.txt>. If unsure, say `N'.
+
+config IP6_NF_TARGET_ULOG
+ tristate "ULOG target support"
+ depends on IP6_NF_IPTABLES && IP_NF_TARGET_ULOG
+ ---help---
+ This option adds a `ULOG' target, which allows you to create rules in
+ any ip6tables table. The packet is passed to a userspace logging
+ daemon using netlink multicast sockets; unlike the LOG target
+ which can only be viewed through syslog.
+
+ NOTE: This target requires the ipv4 version of ULOG to be compiled as
+ well.
+
+ The apropriate userspace logging daemon (ulogd) may be obtained from
+ <http://www.gnumonks.org/projects/ulogd/>
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+endmenu
+
diff -urN linux-2.6.11/net/ipv6/netfilter/Makefile linux.sinabox/net/ipv6/netfilter/Makefile
--- linux-2.6.11/net/ipv6/netfilter/Makefile 2005-03-02 08:38:10.000000000 +0100
+++ linux.sinabox/net/ipv6/netfilter/Makefile 2005-03-26 19:02:06.000000000 +0100
@@ -2,6 +2,18 @@
# Makefile for the netfilter modules on top of IPv6.
#
+# objects for the conntrack
+ip6_nf_conntrack-objs := ip6_conntrack_core.o ip6_conntrack_proto_generic.o ip6_conntrack_proto_tcp.o ip6_conntrack_proto_udp.o ip6_conntrack_proto_icmpv6.o ip6_conntrack_reasm.o
+
+# objects for the standalone - connection tracking
+ip6_conntrack-objs := ip6_conntrack_standalone.o $(ip6_nf_conntrack-objs)
+
+# connection tracking
+obj-$(CONFIG_IP6_NF_CONNTRACK) += ip6_conntrack.o
+
+# connection tracking helpers
+obj-$(CONFIG_IP6_NF_FTP) += ip6_conntrack_ftp.o
+
# Link order matters here.
obj-$(CONFIG_IP6_NF_IPTABLES) += ip6_tables.o
obj-$(CONFIG_IP6_NF_MATCH_LIMIT) += ip6t_limit.o
@@ -20,7 +32,11 @@
obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o
obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o
obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o
+obj-$(CONFIG_IP6_NF_TARGET_IMQ) += ip6t_IMQ.o
obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o
obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
+obj-$(CONFIG_IP6_NF_TARGET_ULOG) += ip6t_ULOG.o
obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o
+obj-$(CONFIG_IP6_NF_MATCH_STATE) += ip6t_state.o
+obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o
diff -urN linux-2.6.11/net/ipv6/netfilter/Makefile.orig linux.sinabox/net/ipv6/netfilter/Makefile.orig
--- linux-2.6.11/net/ipv6/netfilter/Makefile.orig 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/net/ipv6/netfilter/Makefile.orig 2005-03-26 00:49:04.000000000 +0100
@@ -0,0 +1,28 @@
+#
+# Makefile for the netfilter modules on top of IPv6.
+#
+
+# Link order matters here.
+obj-$(CONFIG_IP6_NF_IPTABLES) += ip6_tables.o
+obj-$(CONFIG_IP6_NF_MATCH_LIMIT) += ip6t_limit.o
+obj-$(CONFIG_IP6_NF_MATCH_MARK) += ip6t_mark.o
+obj-$(CONFIG_IP6_NF_MATCH_LENGTH) += ip6t_length.o
+obj-$(CONFIG_IP6_NF_MATCH_MAC) += ip6t_mac.o
+obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
+obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o ip6t_dst.o
+obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o
+obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o
+obj-$(CONFIG_IP6_NF_MATCH_AHESP) += ip6t_esp.o ip6t_ah.o
+obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o
+obj-$(CONFIG_IP6_NF_MATCH_MULTIPORT) += ip6t_multiport.o
+obj-$(CONFIG_IP6_NF_MATCH_OWNER) += ip6t_owner.o
+obj-$(CONFIG_IP6_NF_MATCH_PHYSDEV) += ip6t_physdev.o
+obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o
+obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o
+obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o
+obj-$(CONFIG_IP6_NF_TARGET_IMQ) += ip6t_IMQ.o
+obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o
+obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
+obj-$(CONFIG_IP6_NF_TARGET_ULOG) += ip6t_ULOG.o
+obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
+obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o
diff -urN linux-2.6.11/net/ipv6/proc.c linux.sinabox/net/ipv6/proc.c
--- linux-2.6.11/net/ipv6/proc.c 2005-03-02 08:38:07.000000000 +0100
+++ linux.sinabox/net/ipv6/proc.c 2005-03-26 19:02:06.000000000 +0100
@@ -164,7 +164,13 @@
if (idev) {
seq_printf(seq, "%-32s\t%u\n", "ifIndex", idev->dev->ifindex);
+#ifdef CONFIG_IPV6_STATISTICS
+ snmp6_seq_show_item(seq, (void **)idev->stats.ipv6_statistics, snmp6_ipstats_list);
+#endif
snmp6_seq_show_item(seq, (void **)idev->stats.icmpv6, snmp6_icmp6_list);
+#if 0
+ snmp6_seq_show_item(seq, (void **)idev->stats.udp_stats_in6, snmp6_udp6_list);
+#endif
} else {
snmp6_seq_show_item(seq, (void **)ipv6_statistics, snmp6_ipstats_list);
snmp6_seq_show_item(seq, (void **)icmpv6_statistics, snmp6_icmp6_list);
@@ -284,19 +290,45 @@
if (!idev || !idev->dev)
return -EINVAL;
+#ifdef CONFIG_IPV6_STATISTICS
+ if (snmp6_mib_init((void **)idev->stats.ipv6_statistics, sizeof(struct ipstats_mib),
+ __alignof__(struct ipstats_mib)) < 0)
+ goto err_ip;
+#endif
+
if (snmp6_mib_init((void **)idev->stats.icmpv6, sizeof(struct icmpv6_mib),
__alignof__(struct icmpv6_mib)) < 0)
goto err_icmp;
+#if 0
+ if (snmp6_mib_init((void **)idev->stats.udp_stats_in6, sizeof(struct udp_mib),
+ __alignof__(struct udp_mib)) < 0)
+ goto err_udp;
+#endif
+
return 0;
+#if 0
+err_udp:
+ snmp6_mib_free((void **)idev->stats.icmpv6);
+#endif
err_icmp:
+#ifdef CONFIG_IPV6_STATISTICS
+ snmp6_mib_free((void **)idev->stats.ipv6_statistics);
+err_ip:
+#endif
return err;
}
int snmp6_free_dev(struct inet6_dev *idev)
{
+#ifdef CONFIG_IPV6_STATISTICS
+ snmp6_mib_free((void **)idev->stats.ipv6_statistics);
+#endif
snmp6_mib_free((void **)idev->stats.icmpv6);
+#if 0
+ snmp6_mib_free((void **)idev->stats.udp_stats_in6);
+#endif
return 0;
}
diff -urN linux-2.6.11/net/ipv6/raw.c linux.sinabox/net/ipv6/raw.c
--- linux-2.6.11/net/ipv6/raw.c 2005-03-02 08:38:07.000000000 +0100
+++ linux.sinabox/net/ipv6/raw.c 2005-03-26 19:02:06.000000000 +0100
@@ -13,6 +13,10 @@
* Hideaki YOSHIFUJI : sin6_scope_id support
* YOSHIFUJI,H.@USAGI : raw checksum (RFC2292(bis) compliance)
* Kazunori MIYAZAWA @USAGI: change process style to use ip6_append_data
+ * Hoerdt Mickael : Added Ipv6 multicast routing support.
+ *
+ * Changes:
+ * Kazunori MIYAZAWA @USAGI: change datagram transmit routine to ip6_append_data
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -55,6 +59,10 @@
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#ifdef CONFIG_IPV6_MROUTE
+#include <linux/mroute6.h>
+#endif
+
struct hlist_head raw_v6_htable[RAWV6_HTABLE_SIZE];
DEFINE_RWLOCK(raw_v6_lock);
@@ -162,7 +170,19 @@
sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr);
while (sk) {
- if (nexthdr != IPPROTO_ICMPV6 || !icmpv6_filter(sk, skb)) {
+ int filtered;
+
+ switch (nexthdr) {
+ case IPPROTO_ICMPV6:
+ filtered = icmpv6_filter(sk, skb);
+ break;
+ default:
+ filtered = 0;
+ }
+
+ if (filtered < 0)
+ break;
+ if (filtered == 0) {
struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);
/* Not releasing hash table! */
@@ -199,6 +219,10 @@
if (sk->sk_state != TCP_CLOSE)
goto out;
+ if (addr->sin6_port &&
+ ntohs(addr->sin6_port) != inet->num)
+ goto out;
+
/* Check if the address belongs to the host. */
if (addr_type != IPV6_ADDR_ANY) {
struct net_device *dev = NULL;
@@ -407,8 +431,11 @@
/* Copy the address. */
if (sin6) {
+ struct inet_sock *inet = inet_sk(sk);
+
sin6->sin6_family = AF_INET6;
ipv6_addr_copy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr);
+ sin6->sin6_port = htons(inet->num);
sin6->sin6_flowinfo = 0;
sin6->sin6_scope_id = 0;
if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
@@ -509,6 +536,9 @@
struct inet_sock *inet = inet_sk(sk);
struct ipv6hdr *iph;
struct sk_buff *skb;
+#ifdef CONFIG_IPV6_STATISTICS
+ struct inet6_dev *idev = NULL;
+#endif
unsigned int hh_len;
int err;
@@ -539,7 +569,12 @@
if (err)
goto error_fault;
+#ifdef CONFIG_IPV6_STATISTICS
+ idev = rt->rt6i_idev;
+ IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS);
+#else
IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS);
+#endif
err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
dst_output);
if (err > 0)
@@ -553,7 +588,11 @@
err = -EFAULT;
kfree_skb(skb);
error:
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS(idev, IPSTATS_MIB_OUTDISCARDS);
+#else
IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS);
+#endif
return err;
}
@@ -756,6 +795,8 @@
hlimit = np->hop_limit;
if (hlimit < 0)
hlimit = dst_metric(dst, RTAX_HOPLIMIT);
+ if (hlimit < 0)
+ hlimit = ipv6_get_hoplimit(dst->dev);
}
if (msg->msg_flags&MSG_CONFIRM)
@@ -952,7 +993,11 @@
}
default:
+#ifdef CONFIG_IPV6_MROUTE
+ return ip6mr_ioctl(sk,cmd,(void __user *)arg);
+#else
return -ENOIOCTLCMD;
+#endif
}
}
@@ -960,7 +1005,12 @@
{
if (inet_sk(sk)->num == IPPROTO_RAW)
ip6_ra_control(sk, -1, NULL);
-
+#ifdef CONFIG_IPV6_MROUTE
+ if (sk == mroute6_socket) {
+ printk(KERN_DEBUG "closing mroute6 socket.\n");
+ ip6_ra_control(sk, -1, NULL);
+ }
+#endif
sk_common_release(sk);
}
diff -urN linux-2.6.11/net/ipv6/reassembly.c linux.sinabox/net/ipv6/reassembly.c
--- linux-2.6.11/net/ipv6/reassembly.c 2005-03-02 08:37:53.000000000 +0100
+++ linux.sinabox/net/ipv6/reassembly.c 2005-03-26 19:02:06.000000000 +0100
@@ -53,6 +53,9 @@
#include <net/rawv6.h>
#include <net/ndisc.h>
#include <net/addrconf.h>
+#ifdef CONFIG_IPV6_STATISTICS
+#include <net/ip6_fib.h>
+#endif
int sysctl_ip6frag_high_thresh = 256*1024;
int sysctl_ip6frag_low_thresh = 192*1024;
@@ -264,7 +267,7 @@
}
}
-static void ip6_evictor(void)
+static void ip6_evictor(struct inet6_dev *idev)
{
struct frag_queue *fq;
struct list_head *tmp;
@@ -291,14 +294,21 @@
spin_unlock(&fq->lock);
fq_put(fq, &work);
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_REASMFAILS);
+#else
IP6_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);
+#endif
}
}
static void ip6_frag_expire(unsigned long data)
{
struct frag_queue *fq = (struct frag_queue *) data;
-
+ struct net_device *dev = NULL;
+#ifdef CONFIG_IPV6_STATISTICS
+ struct inet6_dev *idev = NULL;
+#endif
spin_lock(&fq->lock);
if (fq->last_in & COMPLETE)
@@ -306,13 +316,19 @@
fq_kill(fq);
+#ifdef CONFIG_IPV6_STATISTICS
+ dev = dev_get_by_index(fq->iif);
+ idev = dev ? in6_dev_get(dev) : NULL;
+
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_REASMTIMEOUT);
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_REASMFAILS);
+#else
IP6_INC_STATS_BH(IPSTATS_MIB_REASMTIMEOUT);
IP6_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);
+#endif
/* Send error only if the first segment arrived. */
if (fq->last_in&FIRST_IN && fq->fragments) {
- struct net_device *dev = dev_get_by_index(fq->iif);
-
/*
But use as source device on which LAST ARRIVED
segment was received. And do not use fq->dev
@@ -322,9 +338,14 @@
fq->fragments->dev = dev;
icmpv6_send(fq->fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0,
dev);
- dev_put(dev);
}
}
+#ifdef CONFIG_IPV6_STATISTICS
+ if (idev)
+ in6_dev_put(idev);
+ if (dev)
+ dev_put(dev);
+#endif
out:
spin_unlock(&fq->lock);
fq_put(fq, NULL);
@@ -371,7 +392,11 @@
static struct frag_queue *
+#ifdef CONFIG_IPV6_STATISTICS
+ip6_frag_create(unsigned int hash, u32 id, struct in6_addr *src, struct in6_addr *dst, struct inet6_dev *idev)
+#else
ip6_frag_create(unsigned int hash, u32 id, struct in6_addr *src, struct in6_addr *dst)
+#endif
{
struct frag_queue *fq;
@@ -393,12 +418,20 @@
return ip6_frag_intern(hash, fq);
oom:
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_REASMFAILS);
+#else
IP6_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);
+#endif
return NULL;
}
static __inline__ struct frag_queue *
+#ifdef CONFIG_IPV6_STATISTICS
+fq_find(u32 id, struct in6_addr *src, struct in6_addr *dst, struct inet6_dev *idev)
+#else
fq_find(u32 id, struct in6_addr *src, struct in6_addr *dst)
+#endif
{
struct frag_queue *fq;
unsigned int hash = ip6qhashfn(id, src, dst);
@@ -415,7 +448,11 @@
}
read_unlock(&ip6_frag_lock);
+#ifdef CONFIG_IPV6_STATISTICS
+ return ip6_frag_create(hash, id, src, dst, idev);
+#else
return ip6_frag_create(hash, id, src, dst);
+#endif
}
@@ -423,6 +460,11 @@
struct frag_hdr *fhdr, int nhoff)
{
struct sk_buff *prev, *next;
+#ifdef CONFIG_IPV6_STATISTICS
+ struct dst_entry *dst = skb->dst;
+ struct inet6_dev *idev = ((struct rt6_info *)dst)->rt6i_idev;
+#endif
+
int offset, end;
if (fq->last_in & COMPLETE)
@@ -433,7 +475,11 @@
((u8 *) (fhdr + 1) - (u8 *) (skb->nh.ipv6h + 1)));
if ((unsigned int)end > IPV6_MAXPLEN) {
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS);
+#else
IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
+#endif
icmpv6_param_prob(skb,ICMPV6_HDR_FIELD, (u8*)&fhdr->frag_off - skb->nh.raw);
return;
}
@@ -460,7 +506,11 @@
/* RFC2460 says always send parameter problem in
* this case. -DaveM
*/
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS);
+#else
IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
+#endif
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
offsetof(struct ipv6hdr, payload_len));
return;
@@ -579,7 +629,11 @@
return;
err:
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS(idev, IPSTATS_MIB_REASMFAILS);
+#else
IP6_INC_STATS(IPSTATS_MIB_REASMFAILS);
+#endif
kfree_skb(skb);
}
@@ -597,6 +651,11 @@
struct net_device *dev)
{
struct sk_buff *fp, *head = fq->fragments;
+#ifdef CONFIG_IPV6_STATISTICS
+ struct sk_buff *skb = *skb_in;
+ struct dst_entry *dst = skb->dst;
+ struct inet6_dev *idev = ((struct rt6_info *)dst)->rt6i_idev;
+#endif
int payload_len;
unsigned int nhoff;
@@ -673,7 +732,11 @@
if (head->ip_summed == CHECKSUM_HW)
head->csum = csum_partial(head->nh.raw, head->h.raw-head->nh.raw, head->csum);
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_REASMOKS);
+#else
IP6_INC_STATS_BH(IPSTATS_MIB_REASMOKS);
+#endif
fq->fragments = NULL;
*nhoffp = nhoff;
return 1;
@@ -686,7 +749,11 @@
if (net_ratelimit())
printk(KERN_DEBUG "ip6_frag_reasm: no memory for reassembly\n");
out_fail:
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_REASMFAILS);
+#else
IP6_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);
+#endif
return -1;
}
@@ -697,19 +764,35 @@
struct frag_hdr *fhdr;
struct frag_queue *fq;
struct ipv6hdr *hdr;
+#ifdef CONFIG_IPV6_STATISTICS
+ struct dst_entry *dst = skb->dst;
+ struct inet6_dev *idev = ((struct rt6_info *)dst)->rt6i_idev;
+#endif
hdr = skb->nh.ipv6h;
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_REASMREQDS);
+#else
IP6_INC_STATS_BH(IPSTATS_MIB_REASMREQDS);
+#endif
/* Jumbo payload inhibits frag. header */
if (hdr->payload_len==0) {
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS(idev, IPSTATS_MIB_INHDRERRORS);
+#else
IP6_INC_STATS(IPSTATS_MIB_INHDRERRORS);
+#endif
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw-skb->nh.raw);
return -1;
}
if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+sizeof(struct frag_hdr))) {
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS(idev, IPSTATS_MIB_INHDRERRORS);
+#else
IP6_INC_STATS(IPSTATS_MIB_INHDRERRORS);
+#endif
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw-skb->nh.raw);
return -1;
}
@@ -720,16 +803,29 @@
if (!(fhdr->frag_off & htons(0xFFF9))) {
/* It is not a fragmented frame */
skb->h.raw += sizeof(struct frag_hdr);
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_REASMOKS);
+#else
IP6_INC_STATS_BH(IPSTATS_MIB_REASMOKS);
+#endif
*nhoffp = (u8*)fhdr - skb->nh.raw;
return 1;
}
- if (atomic_read(&ip6_frag_mem) > sysctl_ip6frag_high_thresh)
- ip6_evictor();
+ if (atomic_read(&ip6_frag_mem) > sysctl_ip6frag_high_thresh) {
+#ifdef CONFIG_IPV6_STATISTICS
+ ip6_evictor(idev);
+#else
+ ip6_evictor(NULL);
+#endif
+ }
+#ifdef CONFIG_IPV6_STATISTICS
+ if ((fq = fq_find(fhdr->identification, &hdr->saddr, &hdr->daddr, idev)) != NULL) {
+#else
if ((fq = fq_find(fhdr->identification, &hdr->saddr, &hdr->daddr)) != NULL) {
+#endif
int ret = -1;
spin_lock(&fq->lock);
@@ -745,7 +841,11 @@
return ret;
}
+#ifdef CONFIG_IPV6_STATISTICS
+ IP6_INC_STATS_BH(idev, IPSTATS_MIB_REASMFAILS);
+#else
IP6_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);
+#endif
kfree_skb(skb);
return -1;
}
diff -urN linux-2.6.11/net/ipv6/route.c linux.sinabox/net/ipv6/route.c
--- linux-2.6.11/net/ipv6/route.c 2005-03-02 08:38:17.000000000 +0100
+++ linux.sinabox/net/ipv6/route.c 2005-03-26 19:02:06.000000000 +0100
@@ -136,7 +136,6 @@
DEFINE_RWLOCK(rt6_lock);
-
/* allocate dst with ip6_dst_ops */
static __inline__ struct rt6_info *ip6_dst_alloc(void)
{
@@ -216,8 +215,9 @@
/*
* pointer to the last default router chosen. BH is disabled locally.
*/
-static struct rt6_info *rt6_dflt_pointer;
-static DEFINE_SPINLOCK(rt6_dflt_lock);
+#if !defined(CONFIG_IPV6_NEW_ROUNDROBIN)
+struct rt6_info *rt6_dflt_pointer;
+spinlock_t rt6_dflt_lock = SPIN_LOCK_UNLOCKED;
void rt6_reset_dflt_pointer(struct rt6_info *rt)
{
@@ -228,61 +228,168 @@
}
spin_unlock_bh(&rt6_dflt_lock);
}
+#endif
/* Default Router Selection (RFC 2461 6.3.6) */
-static struct rt6_info *rt6_best_dflt(struct rt6_info *rt, int oif)
+static int __rt6_score_dflt(struct rt6_info *sprt, struct rt6_info *dflt, int oif)
{
- struct rt6_info *match = NULL;
- struct rt6_info *sprt;
- int mpri = 0;
+ struct neighbour *neigh = sprt->rt6i_nexthop;
+ int m = oif ? 0 : 8;
- for (sprt = rt; sprt; sprt = sprt->u.next) {
- struct neighbour *neigh;
- int m = 0;
+ if (!neigh)
+ return -1;
- if (!oif ||
- (sprt->rt6i_dev &&
- sprt->rt6i_dev->ifindex == oif))
- m += 8;
+ if (rt6_check_expired(sprt))
+ return -1;
- if (rt6_check_expired(sprt))
- continue;
+ if (oif && sprt->rt6i_dev &&
+ sprt->rt6i_dev->ifindex == oif)
+ m += 8;
+
+#if !defined(CONFIG_IPV6_ROUTER_PREF)
+ if (sprt == dflt)
+ m += 4;
+#endif
- if (sprt == rt6_dflt_pointer)
- m += 4;
+ read_lock_bh(&neigh->lock);
+ switch (neigh->nud_state) {
+ case NUD_REACHABLE:
+ m += 3;
+ break;
- if ((neigh = sprt->rt6i_nexthop) != NULL) {
- read_lock_bh(&neigh->lock);
- switch (neigh->nud_state) {
- case NUD_REACHABLE:
- m += 3;
- break;
+ case NUD_STALE:
+ case NUD_DELAY:
+ case NUD_PROBE:
+ m += 2;
+ break;
- case NUD_STALE:
- case NUD_DELAY:
- case NUD_PROBE:
- m += 2;
- break;
+ case NUD_NOARP:
+ case NUD_PERMANENT:
+ m += 1;
+ break;
- case NUD_NOARP:
- case NUD_PERMANENT:
- m += 1;
+ case NUD_INCOMPLETE:
+ default:
+ m = -1;
+ }
+ read_unlock_bh(&neigh->lock);
+
+ return m;
+}
+
+static struct rt6_info *rt6_best_dflt(struct rt6_info *rt, struct rt6_info **head, int oif)
+{
+ struct rt6_info *match = NULL;
+ struct rt6_info *sprt;
+#if defined(CONFIG_IPV6_NEW_ROUNDROBIN)
+ struct rt6_info *last = NULL;
+#endif
+ int mpri = 0;
+#if defined(CONFIG_IPV6_ROUTER_PREF)
+ u32 metric = 0;
+ int pref = -3;
+#else
+ static const int okpri = 12; /* device match, prob. reachable */
+#endif
+
+ if (head != NULL && *head != rt)
+ head = NULL; /*XXX*/
+
+#if !defined(CONFIG_IPV6_NEW_ROUNDROBIN)
+ spin_lock(&rt6_dflt_lock);
+#endif
+#if !defined(CONFIG_IPV6_NEW_ROUNDROBIN)
+ if (rt6_dflt_pointer) {
+ for (sprt = rt; sprt; sprt = sprt->u.next) {
+ if (sprt == rt6_dflt_pointer)
break;
+ }
+ if (!sprt)
+ rt6_dflt_pointer = NULL; /* for sure */
+ }
+#endif
- case NUD_INCOMPLETE:
- default:
- read_unlock_bh(&neigh->lock);
+#if defined(CONFIG_IPV6_ROUTER_PREF)
+#if !defined(CONFIG_IPV6_NEW_ROUNDROBIN)
+ if (rt6_dflt_pointer) {
+ for (sprt = rt6_dflt_pointer->u.next; sprt; sprt = sprt->u.next) {
+ int m, p;
+
+ if ((metric != 0 && sprt->rt6i_metric > metric) ||
+ sprt->u.dst.obsolete > 0 ||
+ sprt->u.dst.error != 0)
continue;
+
+#if defined(CONFIG_IPV6_NEW_ROUNDROBIN)
+ m = __rt6_score_dflt(sprt, rt, oif);
+#else
+ m = __rt6_score_dflt(sprt, rt6_dflt_pointer, oif);
+#endif
+ if (m < mpri)
+ continue;
+ p = IPV6_SIGNEDPREF(IPV6_UNSHIFT_PREF(sprt->rt6i_flags));
+ if (sprt->rt6i_metric < metric || m > mpri || p > pref) {
+ match = sprt;
+ metric = sprt->rt6i_metric;
+ mpri = m;
+ pref = p;
}
- read_unlock_bh(&neigh->lock);
- } else {
+ }
+ }
+#endif
+#if defined(CONFIG_IPV6_NEW_ROUNDROBIN)
+ metric = rt->rt6i_metric;
+#endif
+ for (sprt = rt; sprt; sprt = sprt->u.next) {
+ int m, p;
+#if defined(CONFIG_IPV6_NEW_ROUNDROBIN)
+ if (sprt->rt6i_metric > metric)
+ break;
+#else
+ if ((metric != 0 && sprt->rt6i_metric > metric) ||
+ sprt->u.dst.obsolete > 0 ||
+ sprt->u.dst.error != 0)
continue;
+
+#endif
+#if defined(CONFIG_IPV6_NEW_ROUNDROBIN)
+ m = __rt6_score_dflt(sprt, rt, oif);
+#else
+ m = __rt6_score_dflt(sprt, rt6_dflt_pointer, oif);
+#endif
+ if (m < mpri)
+ continue;
+ p = IPV6_SIGNEDPREF(IPV6_UNSHIFT_PREF(sprt->rt6i_flags));
+ if (
+#if !defined(CONFIG_IPV6_NEW_ROUNDROBIN)
+ sprt->rt6i_metric < metric ||
+#endif
+ m > mpri || p > pref) {
+ match = sprt;
+ metric = sprt->rt6i_metric;
+ mpri = m;
+ pref = p;
}
+#if defined(CONFIG_IPV6_NEW_ROUNDROBIN)
+ last = sprt;
+#else
+ if (sprt == rt6_dflt_pointer)
+ break;
+#endif
+ }
+#else /* CONFIG_IPV6_ROUTER_PREF / !CONFIG_IPV6_ROUTER_PREF */
+ for (sprt = rt; sprt; sprt = sprt->u.next) {
+ int m;
+#if defined(CONFIG_IPV6_NEW_ROUNDROBIN)
+ m = __rt6_score_dflt(sprt, rt, oif);
+#else
+ m = __rt6_score_dflt(sprt, rt6_dflt_pointer, oif);
+#endif
- if (m > mpri || m >= 12) {
+ if (m > mpri || m >= okpri) {
match = sprt;
mpri = m;
- if (m >= 12) {
+ if (m >= okpri) {
/* we choose the last default router if it
* is in (probably) reachable state.
* If route changed, we should do pmtu
@@ -293,7 +400,6 @@
}
}
- spin_lock(&rt6_dflt_lock);
if (!match) {
/*
* No default routers are known to be reachable.
@@ -323,14 +429,25 @@
}
}
}
+#endif /* !CONFIG_IPV6_ROUTER_PREF */
if (match) {
+#if defined(CONFIG_IPV6_NEW_ROUNDROBIN)
+ if (rt != last && last) {
+ *head = rt->u.next;
+ rt->u.next = last->u.next;
+ last->u.next = rt;
+ }
+#else
if (rt6_dflt_pointer != match)
RT6_TRACE("changed default router: %p->%p\n",
rt6_dflt_pointer, match);
rt6_dflt_pointer = match;
+#endif
}
+#if !defined(CONFIG_IPV6_NEW_ROUNDROBIN)
spin_unlock(&rt6_dflt_lock);
+#endif
if (!match) {
/*
@@ -540,7 +657,7 @@
}
if (rt->rt6i_flags & RTF_DEFAULT) {
if (rt->rt6i_metric >= IP6_RT_PRIO_ADDRCONF)
- rt = rt6_best_dflt(rt, fl->oif);
+ rt = rt6_best_dflt(rt, &fn->leaf, fl->oif);
} else {
rt = rt6_device_match(rt, fl->oif, strict);
BACKTRACK();
@@ -575,7 +692,6 @@
return &rt->u.dst;
}
-
/*
* Destination cache support functions
*/
@@ -628,8 +744,10 @@
if (mtu < dst_pmtu(dst) && rt6->rt6i_dst.plen == 128) {
rt6->rt6i_flags |= RTF_MODIFIED;
- if (mtu < IPV6_MIN_MTU)
+ if (mtu < IPV6_MIN_MTU) {
mtu = IPV6_MIN_MTU;
+ dst->metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG;
+ }
dst->metrics[RTAX_MTU-1] = mtu;
}
}
@@ -769,7 +887,7 @@
return mtu;
}
-static int ipv6_get_hoplimit(struct net_device *dev)
+int ipv6_get_hoplimit(struct net_device *dev)
{
int hoplimit = ipv6_devconf.hop_limit;
struct inet6_dev *idev;
@@ -965,14 +1083,8 @@
}
}
- if (rt->u.dst.metrics[RTAX_HOPLIMIT-1] == 0) {
- if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr))
- rt->u.dst.metrics[RTAX_HOPLIMIT-1] =
- IPV6_DEFAULT_MCASTHOPS;
- else
- rt->u.dst.metrics[RTAX_HOPLIMIT-1] =
- ipv6_get_hoplimit(dev);
- }
+ if (rt->u.dst.metrics[RTAX_HOPLIMIT-1] == 0)
+ rt->u.dst.metrics[RTAX_HOPLIMIT-1] = -1;
if (!rt->u.dst.metrics[RTAX_MTU-1])
rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(dev);
@@ -998,7 +1110,9 @@
write_lock_bh(&rt6_lock);
+#ifndef CONFIG_IPV6_NEW_ROUNDROBIN
rt6_reset_dflt_pointer(NULL);
+#endif
err = fib6_del(rt, nlh, _rtattr);
dst_release(&rt->u.dst);
@@ -1051,11 +1165,24 @@
{
struct rt6_info *rt, *nrt;
+#ifdef CONFIG_IPV6_NDISC_DEBUG
+ printk(KERN_DEBUG
+ "%s("
+ "dest=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x, "
+ "saddr=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x, "
+ "neigh=%p(%s), "
+ "lladdr=%p, on_link=%d)\n",
+ __FUNCTION__,
+ NIP6(*dest), NIP6(*saddr),
+ neigh, neigh_state(neigh->nud_state),
+ lladdr, on_link);
+#endif
+
/* Locate old route to this destination. */
rt = rt6_lookup(dest, NULL, neigh->dev->ifindex, 1);
if (rt == NULL)
- return;
+ goto out;
if (neigh->dev != rt->rt6i_dev)
goto out;
@@ -1068,8 +1195,12 @@
* But then router serving it might decide, that we should
* know truth 8)8) --ANK (980726).
*/
- if (!(rt->rt6i_flags&RTF_GATEWAY))
+ if (!(rt->rt6i_flags&RTF_GATEWAY)) {
+ if (net_ratelimit())
+ printk(KERN_DEBUG "%s(): rt=%p is on-link; ignored.\n",
+ __FUNCTION__, rt);
goto out;
+ }
/*
* RFC 2461 specifies that redirects should only be
@@ -1101,9 +1232,8 @@
}
source_ok:
-
/*
- * We have finally decided to accept it.
+ * Okay, we have finally decided to accept it.
*/
neigh_update(neigh, lladdr, NUD_STALE,
@@ -1152,7 +1282,6 @@
out:
dst_release(&rt->u.dst);
- return;
}
/*
@@ -1164,17 +1293,7 @@
struct net_device *dev, u32 pmtu)
{
struct rt6_info *rt, *nrt;
-
- if (pmtu < IPV6_MIN_MTU) {
- if (net_ratelimit())
- printk(KERN_DEBUG "rt6_pmtu_discovery: invalid MTU value %d\n",
- pmtu);
- /* According to RFC1981, the PMTU is set to the IPv6 minimum
- link MTU if the node receives a Packet Too Big message
- reporting next-hop MTU that is less than the IPv6 minimum MTU.
- */
- pmtu = IPV6_MIN_MTU;
- }
+ int allfrag = 0;
rt = rt6_lookup(daddr, saddr, dev->ifindex, 0);
@@ -1184,6 +1303,17 @@
if (pmtu >= dst_pmtu(&rt->u.dst))
goto out;
+ if (pmtu < IPV6_MIN_MTU) {
+ /*
+ * According to RFC2461, pmtu is set to the IPv6 minimum MTU
+ * (1280) and a fragment header is included after a node
+ * receiving Too Big message reporting PMTU is less than
+ * the IPv6 minimum MTU.
+ */
+ pmtu = IPV6_MIN_MTU;
+ allfrag = 1;
+ }
+
/* New mtu received -> path was valid.
They are sent only in response to data packets,
so that this nexthop apparently is reachable. --ANK
@@ -1197,6 +1327,8 @@
*/
if (rt->rt6i_flags & RTF_CACHE) {
rt->u.dst.metrics[RTAX_MTU-1] = pmtu;
+ if (allfrag)
+ rt->u.dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG;
dst_set_expires(&rt->u.dst, ip6_rt_mtu_expires);
rt->rt6i_flags |= RTF_MODIFIED|RTF_EXPIRES;
goto out;
@@ -1211,6 +1343,8 @@
nrt = rt6_cow(rt, daddr, saddr);
if (!nrt->u.dst.error) {
nrt->u.dst.metrics[RTAX_MTU-1] = pmtu;
+ if (allfrag)
+ nrt->u.dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG;
/* According to RFC 1981, detecting PMTU increase shouldn't be
happened within 5 mins, the recommended timer is 10 mins.
Here this route expiration time is set to ip6_rt_mtu_expires
@@ -1232,6 +1366,8 @@
dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires);
nrt->rt6i_flags |= RTF_DYNAMIC|RTF_CACHE|RTF_EXPIRES;
nrt->u.dst.metrics[RTAX_MTU-1] = pmtu;
+ if (allfrag)
+ nrt->u.dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG;
ip6_ins_rt(nrt, NULL, NULL);
}
@@ -1293,7 +1429,8 @@
}
struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr,
- struct net_device *dev)
+ struct net_device *dev,
+ int pref)
{
struct in6_rtmsg rtmsg;
@@ -1301,7 +1438,7 @@
rtmsg.rtmsg_type = RTMSG_NEWROUTE;
ipv6_addr_copy(&rtmsg.rtmsg_gateway, gwaddr);
rtmsg.rtmsg_metric = 1024;
- rtmsg.rtmsg_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | RTF_UP | RTF_EXPIRES;
+ rtmsg.rtmsg_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | RTF_UP | RTF_PREF(pref&3) | RTF_EXPIRES;
rtmsg.rtmsg_ifindex = dev->ifindex;
@@ -1319,7 +1456,9 @@
if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) {
dst_hold(&rt->u.dst);
+#ifndef CONFIG_IPV6_NEW_ROUNDROBIN
rt6_reset_dflt_pointer(NULL);
+#endif
read_unlock_bh(&rt6_lock);
@@ -1371,7 +1510,13 @@
int ip6_pkt_discard(struct sk_buff *skb)
{
+#ifdef CONFIG_IPV6_STATISTICS
+ struct dst_entry *dst = skb->dst;
+ struct inet6_dev *idev = ((struct rt6_info *)dst)->rt6i_idev;
+ IP6_INC_STATS(idev, IPSTATS_MIB_OUTNOROUTES);
+#else
IP6_INC_STATS(IPSTATS_MIB_OUTNOROUTES);
+#endif
icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_NOROUTE, 0, skb->dev);
kfree_skb(skb);
return 0;
@@ -1406,7 +1551,7 @@
rt->rt6i_idev = idev;
rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev);
rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_pmtu(&rt->u.dst));
- rt->u.dst.metrics[RTAX_HOPLIMIT-1] = ipv6_get_hoplimit(rt->rt6i_dev);
+ rt->u.dst.metrics[RTAX_HOPLIMIT-1] = -1;
rt->u.dst.obsolete = -1;
rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;
@@ -1877,7 +2022,6 @@
static int rt6_info_route(struct rt6_info *rt, void *p_arg)
{
struct rt6_proc_arg *arg = (struct rt6_proc_arg *) p_arg;
- int i;
if (arg->skip < arg->offset / RT6_INFO_LEN) {
arg->skip++;
@@ -1887,39 +2031,29 @@
if (arg->len >= arg->length)
return 0;
- for (i=0; i<16; i++) {
- sprintf(arg->buffer + arg->len, "%02x",
- rt->rt6i_dst.addr.s6_addr[i]);
- arg->len += 2;
- }
- arg->len += sprintf(arg->buffer + arg->len, " %02x ",
+ arg->len += sprintf(arg->buffer + arg->len,
+ "%04x%04x%04x%04x%04x%04x%04x%04x %02x ",
+ NIP6(rt->rt6i_dst.addr),
rt->rt6i_dst.plen);
#ifdef CONFIG_IPV6_SUBTREES
- for (i=0; i<16; i++) {
- sprintf(arg->buffer + arg->len, "%02x",
- rt->rt6i_src.addr.s6_addr[i]);
- arg->len += 2;
- }
- arg->len += sprintf(arg->buffer + arg->len, " %02x ",
+ arg->len += sprintf(arg->buffer + arg->len,
+ "%04x%04x%04x%04x%04x%04x%04x%04x %02x ",
+ NIP6(rt->rt6i_src.addr),
rt->rt6i_src.plen);
#else
- sprintf(arg->buffer + arg->len,
- "00000000000000000000000000000000 00 ");
- arg->len += 36;
+ arg->len += sprintf(arg->buffer + arg->len,
+ "00000000000000000000000000000000 00 ");
#endif
- if (rt->rt6i_nexthop) {
- for (i=0; i<16; i++) {
- sprintf(arg->buffer + arg->len, "%02x",
- rt->rt6i_nexthop->primary_key[i]);
- arg->len += 2;
- }
- } else {
- sprintf(arg->buffer + arg->len,
- "00000000000000000000000000000000");
- arg->len += 32;
- }
+ if (rt->rt6i_nexthop)
+ arg->len += sprintf(arg->buffer + arg->len,
+ "%04x%04x%04x%04x%04x%04x%04x%04x",
+ NIP6(*((struct in6_addr *)rt->rt6i_nexthop->primary_key)));
+ else
+ arg->len += sprintf(arg->buffer + arg->len,
+ "00000000000000000000000000000000");
+
arg->len += sprintf(arg->buffer + arg->len,
" %08x %08x %08x %08x %8s\n",
rt->rt6i_metric, atomic_read(&rt->u.dst.__refcnt),
@@ -2080,6 +2214,15 @@
.proc_handler = &proc_dointvec_jiffies,
.strategy = &sysctl_jiffies,
},
+ {
+ .ctl_name = NET_IPV6_ROUTE_GC_MIN_INTERVAL_MS,
+ .procname = "gc_min_interval_ms",
+ .data = &ip6_rt_gc_min_interval,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_ms_jiffies,
+ .strategy = &sysctl_ms_jiffies,
+ },
{ .ctl_name = 0 }
};
diff -urN linux-2.6.11/net/ipv6/udp.c linux.sinabox/net/ipv6/udp.c
--- linux-2.6.11/net/ipv6/udp.c 2005-03-02 08:38:20.000000000 +0100
+++ linux.sinabox/net/ipv6/udp.c 2005-03-26 19:02:06.000000000 +0100
@@ -277,7 +277,6 @@
if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
sin6->sin6_scope_id = IP6CB(skb)->iif;
}
-
}
if (skb->protocol == htons(ETH_P_IP)) {
if (inet->cmsg_flags)
@@ -811,6 +810,8 @@
hlimit = np->hop_limit;
if (hlimit < 0)
hlimit = dst_metric(dst, RTAX_HOPLIMIT);
+ if (hlimit < 0)
+ hlimit = ipv6_get_hoplimit(dst->dev);
}
if (msg->msg_flags&MSG_CONFIRM)
diff -urN linux-2.6.11/net/ipv6/xfrm6_input.c linux.sinabox/net/ipv6/xfrm6_input.c
--- linux-2.6.11/net/ipv6/xfrm6_input.c 2005-03-02 08:38:33.000000000 +0100
+++ linux.sinabox/net/ipv6/xfrm6_input.c 2005-03-26 19:02:06.000000000 +0100
@@ -42,7 +42,7 @@
nexthdr = skb->nh.raw[nhoff];
seq = 0;
- if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0)
+ if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi)) != 0)
goto drop;
do {
@@ -58,9 +58,6 @@
if (unlikely(x->km.state != XFRM_STATE_VALID))
goto drop_unlock;
- if (x->props.replay_window && xfrm_replay_check(x, seq))
- goto drop_unlock;
-
if (xfrm_state_check_expire(x))
goto drop_unlock;
@@ -70,9 +67,6 @@
skb->nh.raw[nhoff] = nexthdr;
- if (x->props.replay_window)
- xfrm_replay_advance(x, seq);
-
x->curlft.bytes += skb->len;
x->curlft.packets++;
@@ -99,8 +93,9 @@
break;
}
- if ((err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) < 0)
+ if ((err = xfrm_parse_spi(skb, nexthdr, &spi)) < 0)
goto drop;
+
} while (!err);
/* Allocate new secpath or COW existing one. */
diff -urN linux-2.6.11/net/ipv6/xfrm6_policy.c linux.sinabox/net/ipv6/xfrm6_policy.c
--- linux-2.6.11/net/ipv6/xfrm6_policy.c 2005-03-02 08:37:50.000000000 +0100
+++ linux.sinabox/net/ipv6/xfrm6_policy.c 2005-03-26 19:02:06.000000000 +0100
@@ -25,8 +25,8 @@
static int xfrm6_dst_lookup(struct xfrm_dst **dst, struct flowi *fl)
{
int err = 0;
- *dst = (struct xfrm_dst*)ip6_route_output(NULL, fl);
- if (!*dst)
+ err = ip6_dst_lookup(NULL, (struct dst_entry **)dst, fl);
+ if (err)
err = -ENETUNREACH;
return err;
}
@@ -56,7 +56,6 @@
{
struct dst_entry *dst;
- /* Still not clear if we should set fl->fl6_{src,dst}... */
read_lock_bh(&policy->lock);
for (dst = policy->bundles; dst; dst = dst->next) {
struct xfrm_dst *xdst = (struct xfrm_dst*)dst;
diff -urN linux-2.6.11/net/Kconfig linux.sinabox/net/Kconfig
--- linux-2.6.11/net/Kconfig 2005-03-02 08:38:34.000000000 +0100
+++ linux.sinabox/net/Kconfig 2005-03-26 19:02:06.000000000 +0100
@@ -81,6 +81,18 @@
Say Y unless you know what you are doing.
+config USE_POLICY_FWD
+ bool "Use xfrm policy fwd"
+ default y
+ ---help---
+ Using XFRM_POLICY_FWD which corespond to fwd in setkey
+ when specifing inbound forwarding policy.
+ This is USAGI original changes. If you want the original
+ kernel behavior of IPsec, say Y. If you want behavior
+ which is similar to KAME IPsec stack, say N.
+
+ Unsure, Say Y.
+
config INET
bool "TCP/IP networking"
---help---
@@ -107,12 +119,12 @@
# IPv6 as module will cause a CRASH if you try to unload it
config IPV6
- tristate "The IPv6 protocol (EXPERIMENTAL)"
- depends on INET && EXPERIMENTAL
- select CRYPTO if IPV6_PRIVACY
- select CRYPTO_MD5 if IPV6_PRIVACY
+ tristate "The IPv6 protocol"
+ depends on INET
+ select CRYPTO if IPV6_PRIVACY_MD5
+ select CRYPTO_MD5 if IPV6_PRIVACY_MD5
---help---
- This is experimental support for the IP version 6 (formerly called
+ This is additional support for the IP version 6 (formerly called
IPng "IP next generation"). You will still be able to do
regular IPv4 networking as well.
@@ -127,8 +139,6 @@
To compile this protocol support as a module, choose M here: the
module will be called ipv6.
- It is safe to say N here for now.
-
source "net/ipv6/Kconfig"
menuconfig NETFILTER
diff -urN linux-2.6.11/net/netrom/nr_in.c linux.sinabox/net/netrom/nr_in.c
--- linux-2.6.11/net/netrom/nr_in.c 2005-03-02 08:38:01.000000000 +0100
+++ linux.sinabox/net/netrom/nr_in.c 2005-03-19 07:34:55.000000000 +0100
@@ -74,7 +74,6 @@
static int nr_state1_machine(struct sock *sk, struct sk_buff *skb,
int frametype)
{
- bh_lock_sock(sk);
switch (frametype) {
case NR_CONNACK: {
nr_cb *nr = nr_sk(sk);
@@ -103,8 +102,6 @@
default:
break;
}
- bh_unlock_sock(sk);
-
return 0;
}
@@ -116,7 +113,6 @@
static int nr_state2_machine(struct sock *sk, struct sk_buff *skb,
int frametype)
{
- bh_lock_sock(sk);
switch (frametype) {
case NR_CONNACK | NR_CHOKE_FLAG:
nr_disconnect(sk, ECONNRESET);
@@ -132,8 +128,6 @@
default:
break;
}
- bh_unlock_sock(sk);
-
return 0;
}
@@ -154,7 +148,6 @@
nr = skb->data[18];
ns = skb->data[17];
- bh_lock_sock(sk);
switch (frametype) {
case NR_CONNREQ:
nr_write_internal(sk, NR_CONNACK);
@@ -265,8 +258,6 @@
default:
break;
}
- bh_unlock_sock(sk);
-
return queued;
}
diff -urN linux-2.6.11/net/sched/sch_generic.c linux.sinabox/net/sched/sch_generic.c
--- linux-2.6.11/net/sched/sch_generic.c 2005-03-02 08:37:45.000000000 +0100
+++ linux.sinabox/net/sched/sch_generic.c 2005-03-26 00:49:04.000000000 +0100
@@ -29,6 +29,9 @@
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/rtnetlink.h>
+#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
+#include <linux/imq.h>
+#endif
#include <linux/init.h>
#include <linux/rcupdate.h>
#include <linux/list.h>
@@ -136,7 +139,13 @@
if (!netif_queue_stopped(dev)) {
int ret;
- if (netdev_nit)
+
+ if (netdev_nit
+#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
+ && !(skb->imq_flags & IMQ_F_ENQUEUE)
+#endif
+ )
+
dev_queue_xmit_nit(skb, dev);
ret = dev->hard_start_xmit(skb, dev);
diff -urN linux-2.6.11/net/xfrm/xfrm_input.c linux.sinabox/net/xfrm/xfrm_input.c
--- linux-2.6.11/net/xfrm/xfrm_input.c 2005-03-02 08:38:34.000000000 +0100
+++ linux.sinabox/net/xfrm/xfrm_input.c 2005-03-26 19:02:06.000000000 +0100
@@ -46,24 +46,21 @@
/* Fetch spi and seq from ipsec header */
-int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq)
+int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi)
{
- int offset, offset_seq;
+ int offset;
switch (nexthdr) {
case IPPROTO_AH:
offset = offsetof(struct ip_auth_hdr, spi);
- offset_seq = offsetof(struct ip_auth_hdr, seq_no);
break;
case IPPROTO_ESP:
offset = offsetof(struct ip_esp_hdr, spi);
- offset_seq = offsetof(struct ip_esp_hdr, seq_no);
break;
case IPPROTO_COMP:
if (!pskb_may_pull(skb, sizeof(struct ip_comp_hdr)))
return -EINVAL;
*spi = ntohl(ntohs(*(u16*)(skb->h.raw + 2)));
- *seq = 0;
return 0;
default:
return 1;
@@ -73,7 +70,6 @@
return -EINVAL;
*spi = *(u32*)(skb->h.raw + offset);
- *seq = *(u32*)(skb->h.raw + offset_seq);
return 0;
}
EXPORT_SYMBOL(xfrm_parse_spi);
diff -urN linux-2.6.11/net/xfrm/xfrm_policy.c linux.sinabox/net/xfrm/xfrm_policy.c
--- linux-2.6.11/net/xfrm/xfrm_policy.c 2005-03-02 08:38:09.000000000 +0100
+++ linux.sinabox/net/xfrm/xfrm_policy.c 2005-03-26 19:02:06.000000000 +0100
@@ -703,9 +703,14 @@
static inline int policy_to_flow_dir(int dir)
{
+#ifdef CONFIG_USE_POLICY_FWD
if (XFRM_POLICY_IN == FLOW_DIR_IN &&
XFRM_POLICY_OUT == FLOW_DIR_OUT &&
XFRM_POLICY_FWD == FLOW_DIR_FWD)
+#else
+ if (XFRM_POLICY_IN == FLOW_DIR_IN &&
+ XFRM_POLICY_OUT == FLOW_DIR_OUT)
+#endif
return dir;
switch (dir) {
default:
@@ -713,8 +718,10 @@
return FLOW_DIR_IN;
case XFRM_POLICY_OUT:
return FLOW_DIR_OUT;
+#ifdef CONFIG_USE_POLICY_FWD
case XFRM_POLICY_FWD:
return FLOW_DIR_FWD;
+#endif
};
}
diff -urN linux-2.6.11/net/xfrm/xfrm_state.c linux.sinabox/net/xfrm/xfrm_state.c
--- linux-2.6.11/net/xfrm/xfrm_state.c 2005-03-02 08:38:17.000000000 +0100
+++ linux.sinabox/net/xfrm/xfrm_state.c 2005-03-19 07:35:00.000000000 +0100
@@ -609,7 +609,7 @@
for (i = 0; i < XFRM_DST_HSIZE; i++) {
list_for_each_entry(x, xfrm_state_bydst+i, bydst) {
- if (x->km.seq == seq) {
+ if (x->km.seq == seq && x->km.state == XFRM_STATE_ACQ) {
xfrm_state_hold(x);
return x;
}
diff -urN linux-2.6.11/net/xfrm/xfrm_user.c linux.sinabox/net/xfrm/xfrm_user.c
--- linux-2.6.11/net/xfrm/xfrm_user.c 2005-03-02 08:38:10.000000000 +0100
+++ linux.sinabox/net/xfrm/xfrm_user.c 2005-03-26 19:02:06.000000000 +0100
@@ -530,7 +530,9 @@
switch (dir) {
case XFRM_POLICY_IN:
case XFRM_POLICY_OUT:
+#ifdef CONFIG_USE_POLICY_FWD
case XFRM_POLICY_FWD:
+#endif
break;
default:
@@ -1136,14 +1138,14 @@
switch (family) {
case AF_INET:
- if (opt != IP_XFRM_POLICY) {
+ if (opt != IP_XFRM_POLICY && opt != IP_IPSEC_POLICY) {
*dir = -EOPNOTSUPP;
return NULL;
}
break;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
case AF_INET6:
- if (opt != IPV6_XFRM_POLICY) {
+ if (opt != IPV6_XFRM_POLICY && opt != IPV6_IPSEC_POLICY) {
*dir = -EOPNOTSUPP;
return NULL;
}
diff -urN linux-2.6.11/scripts/package/builddeb linux.sinabox/scripts/package/builddeb
--- linux-2.6.11/scripts/package/builddeb 2005-03-02 08:38:37.000000000 +0100
+++ linux.sinabox/scripts/package/builddeb 1970-01-01 01:00:00.000000000 +0100
@@ -1,79 +0,0 @@
-#!/bin/sh
-#
-# builddeb 1.2
-# Copyright 2003 Wichert Akkerman <wichert@wiggy.net>
-#
-# Simple script to generate a deb package for a Linux kernel. All the
-# complexity of what to do with a kernel after it is installer or removed
-# is left to other scripts and packages: they can install scripts in the
-# /etc/kernel/{pre,post}{inst,rm}.d/ directories that will be called on
-# package install and removal.
-
-set -e
-
-# Some variables and settings used throughout the script
-version=$KERNELRELEASE
-tmpdir="$objtree/debian/tmp"
-
-# Setup the directory structure
-rm -rf "$tmpdir"
-mkdir -p "$tmpdir/DEBIAN" "$tmpdir/lib" "$tmpdir/boot"
-
-# Build and install the kernel
-cp System.map "$tmpdir/boot/System.map-$version"
-cp .config "$tmpdir/boot/config-$version"
-cp $KBUILD_IMAGE "$tmpdir/boot/vmlinuz-$version"
-
-if grep -q '^CONFIG_MODULES=y' .config ; then
- INSTALL_MOD_PATH="$tmpdir" make modules_install
-fi
-
-# Install the maintainer scripts
-for script in postinst postrm preinst prerm ; do
- mkdir -p "$tmpdir/etc/kernel/$script.d"
- cat <<EOF > "$tmpdir/DEBIAN/$script"
-#!/bin/sh
-
-set -e
-
-test -d /etc/kernel/$script.d && run-parts --arg="$version" /etc/kernel/$script.d
-exit 0
-EOF
- chmod 755 "$tmpdir/DEBIAN/$script"
-done
-
-name="Kernel Compiler <$(id -nu)@$(hostname -f)>"
-# Generate a simple changelog template
-cat <<EOF > debian/changelog
-linux ($version) unstable; urgency=low
-
- * A standard release
-
- -- $name $(date -R)
-EOF
-
-# Generate a control file
-cat <<EOF > debian/control
-Source: linux
-Section: base
-Priority: optional
-Maintainer: $name
-Standards-Version: 3.6.1
-
-Package: linux-$version
-Architecture: any
-Description: Linux kernel, version $version
- This package contains the Linux kernel, modules and corresponding other
- files version $version.
-EOF
-
-# Fix some ownership and permissions
-chown -R root:root "$tmpdir"
-chmod -R go-w "$tmpdir"
-
-# Perform the final magic
-dpkg-gencontrol -isp
-dpkg --build "$tmpdir" ..
-
-exit 0
-
diff -urN linux-2.6.11/scripts/package/builddeb.dist linux.sinabox/scripts/package/builddeb.dist
--- linux-2.6.11/scripts/package/builddeb.dist 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/scripts/package/builddeb.dist 2005-03-19 07:35:06.000000000 +0100
@@ -0,0 +1,79 @@
+#!/bin/sh
+#
+# builddeb 1.2
+# Copyright 2003 Wichert Akkerman <wichert@wiggy.net>
+#
+# Simple script to generate a deb package for a Linux kernel. All the
+# complexity of what to do with a kernel after it is installer or removed
+# is left to other scripts and packages: they can install scripts in the
+# /etc/kernel/{pre,post}{inst,rm}.d/ directories that will be called on
+# package install and removal.
+
+set -e
+
+# Some variables and settings used throughout the script
+version=$KERNELRELEASE
+tmpdir="$objtree/debian/tmp"
+
+# Setup the directory structure
+rm -rf "$tmpdir"
+mkdir -p "$tmpdir/DEBIAN" "$tmpdir/lib" "$tmpdir/boot"
+
+# Build and install the kernel
+cp System.map "$tmpdir/boot/System.map-$version"
+cp .config "$tmpdir/boot/config-$version"
+cp $KBUILD_IMAGE "$tmpdir/boot/vmlinuz-$version"
+
+if grep -q '^CONFIG_MODULES=y' .config ; then
+ INSTALL_MOD_PATH="$tmpdir" make modules_install
+fi
+
+# Install the maintainer scripts
+for script in postinst postrm preinst prerm ; do
+ mkdir -p "$tmpdir/etc/kernel/$script.d"
+ cat <<EOF > "$tmpdir/DEBIAN/$script"
+#!/bin/sh
+
+set -e
+
+test -d /etc/kernel/$script.d && run-parts --arg="$version" /etc/kernel/$script.d
+exit 0
+EOF
+ chmod 755 "$tmpdir/DEBIAN/$script"
+done
+
+name="Kernel Compiler <$(id -nu)@$(hostname -f)>"
+# Generate a simple changelog template
+cat <<EOF > debian/changelog
+linux ($version) unstable; urgency=low
+
+ * A standard release
+
+ -- $name $(date -R)
+EOF
+
+# Generate a control file
+cat <<EOF > debian/control
+Source: linux
+Section: base
+Priority: optional
+Maintainer: $name
+Standards-Version: 3.6.1
+
+Package: linux-$version
+Architecture: any
+Description: Linux kernel, version $version
+ This package contains the Linux kernel, modules and corresponding other
+ files version $version.
+EOF
+
+# Fix some ownership and permissions
+chown -R root:root "$tmpdir"
+chmod -R go-w "$tmpdir"
+
+# Perform the final magic
+dpkg-gencontrol -isp
+dpkg --build "$tmpdir" ..
+
+exit 0
+
diff -urN linux-2.6.11/scripts/package/Makefile linux.sinabox/scripts/package/Makefile
--- linux-2.6.11/scripts/package/Makefile 2005-03-02 08:38:11.000000000 +0100
+++ linux.sinabox/scripts/package/Makefile 2005-03-24 19:30:47.000000000 +0100
@@ -1,89 +1,2 @@
-# Makefile for the different targets used to generate full packages of a kernel
-# It uses the generic clean infrastructure of kbuild
-
-# Ignore the following files/directories during tar operation
-TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn --exclude CVS
-
-
-# RPM target
-# ---------------------------------------------------------------------------
-# The rpm target generates two rpm files:
-# /usr/src/packages/SRPMS/kernel-2.6.7rc2-1.src.rpm
-# /usr/src/packages/RPMS/i386/kernel-2.6.7rc2-1.<arch>.rpm
-# The src.rpm files includes all source for the kernel being built
-# The <arch>.rpm includes kernel configuration, modules etc.
-#
-# Process to create the rpm files
-# a) clean the kernel
-# b) Generate .spec file
-# c) Build a tar ball, using symlink to make kernel version
-# first entry in the path
-# d) and pack the result to a tar.gz file
-# e) generate the rpm files, based on kernel.spec
-# - Use /. to avoid tar packing just the symlink
-
-# Do we have rpmbuild, otherwise fall back to the older rpm
-RPM := $(shell if [ -x "/usr/bin/rpmbuild" ]; then echo rpmbuild; \
- else echo rpm; fi)
-
-# Remove hyphens since they have special meaning in RPM filenames
-KERNELPATH := kernel-$(subst -,,$(KERNELRELEASE))
-MKSPEC := $(srctree)/scripts/package/mkspec
-PREV := set -e; cd ..;
-
-# rpm-pkg
-.PHONY: rpm-pkg rpm
-
-$(objtree)/kernel.spec: $(MKSPEC) $(srctree)/Makefile
- $(CONFIG_SHELL) $(MKSPEC) > $@
-
-rpm-pkg rpm: $(objtree)/kernel.spec
- $(MAKE) clean
- $(PREV) ln -sf $(srctree) $(KERNELPATH)
- $(PREV) tar -cz $(RCS_TAR_IGNORE) -f $(KERNELPATH).tar.gz $(KERNELPATH)/.
- $(PREV) rm $(KERNELPATH)
-
- set -e; \
- $(CONFIG_SHELL) $(srctree)/scripts/mkversion > $(objtree)/.tmp_version
- set -e; \
- mv -f $(objtree)/.tmp_version $(objtree)/.version
-
- $(RPM) --target $(UTS_MACHINE) -ta ../$(KERNELPATH).tar.gz
- rm ../$(KERNELPATH).tar.gz
-
-clean-files := $(objtree)/kernel.spec
-
-# binrpm-pkg
-.PHONY: binrpm-pkg
-$(objtree)/binkernel.spec: $(MKSPEC) $(srctree)/Makefile
- $(CONFIG_SHELL) $(MKSPEC) prebuilt > $@
-
-binrpm-pkg: $(objtree)/binkernel.spec
- $(MAKE)
- set -e; \
- $(CONFIG_SHELL) $(srctree)/scripts/mkversion > $(objtree)/.tmp_version
- set -e; \
- mv -f $(objtree)/.tmp_version $(objtree)/.version
-
- $(RPM) --define "_builddir $(srctree)" --target $(UTS_MACHINE) -bb $<
-
-clean-files += $(objtree)/binkernel.spec
-
-# Deb target
-# ---------------------------------------------------------------------------
-#
-.PHONY: deb-pkg
-deb-pkg:
- $(MAKE)
- $(CONFIG_SHELL) $(srctree)/scripts/package/builddeb
-
-clean-dirs += $(objtree)/debian/
-
-
-# Help text displayed when executing 'make help'
-# ---------------------------------------------------------------------------
+# Dummy file
help:
- @echo ' rpm-pkg - Build the kernel as an RPM package'
- @echo ' binrpm-pkg - Build an rpm package containing the compiled kernel & modules'
- @echo ' deb-pkg - Build the kernel as an deb package'
-
diff -urN linux-2.6.11/scripts/package/Makefile.dist linux.sinabox/scripts/package/Makefile.dist
--- linux-2.6.11/scripts/package/Makefile.dist 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/scripts/package/Makefile.dist 2005-03-19 07:34:59.000000000 +0100
@@ -0,0 +1,89 @@
+# Makefile for the different targets used to generate full packages of a kernel
+# It uses the generic clean infrastructure of kbuild
+
+# Ignore the following files/directories during tar operation
+TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn --exclude CVS
+
+
+# RPM target
+# ---------------------------------------------------------------------------
+# The rpm target generates two rpm files:
+# /usr/src/packages/SRPMS/kernel-2.6.7rc2-1.src.rpm
+# /usr/src/packages/RPMS/i386/kernel-2.6.7rc2-1.<arch>.rpm
+# The src.rpm files includes all source for the kernel being built
+# The <arch>.rpm includes kernel configuration, modules etc.
+#
+# Process to create the rpm files
+# a) clean the kernel
+# b) Generate .spec file
+# c) Build a tar ball, using symlink to make kernel version
+# first entry in the path
+# d) and pack the result to a tar.gz file
+# e) generate the rpm files, based on kernel.spec
+# - Use /. to avoid tar packing just the symlink
+
+# Do we have rpmbuild, otherwise fall back to the older rpm
+RPM := $(shell if [ -x "/usr/bin/rpmbuild" ]; then echo rpmbuild; \
+ else echo rpm; fi)
+
+# Remove hyphens since they have special meaning in RPM filenames
+KERNELPATH := kernel-$(subst -,,$(KERNELRELEASE))
+MKSPEC := $(srctree)/scripts/package/mkspec
+PREV := set -e; cd ..;
+
+# rpm-pkg
+.PHONY: rpm-pkg rpm
+
+$(objtree)/kernel.spec: $(MKSPEC) $(srctree)/Makefile
+ $(CONFIG_SHELL) $(MKSPEC) > $@
+
+rpm-pkg rpm: $(objtree)/kernel.spec
+ $(MAKE) clean
+ $(PREV) ln -sf $(srctree) $(KERNELPATH)
+ $(PREV) tar -cz $(RCS_TAR_IGNORE) -f $(KERNELPATH).tar.gz $(KERNELPATH)/.
+ $(PREV) rm $(KERNELPATH)
+
+ set -e; \
+ $(CONFIG_SHELL) $(srctree)/scripts/mkversion > $(objtree)/.tmp_version
+ set -e; \
+ mv -f $(objtree)/.tmp_version $(objtree)/.version
+
+ $(RPM) --target $(UTS_MACHINE) -ta ../$(KERNELPATH).tar.gz
+ rm ../$(KERNELPATH).tar.gz
+
+clean-files := $(objtree)/kernel.spec
+
+# binrpm-pkg
+.PHONY: binrpm-pkg
+$(objtree)/binkernel.spec: $(MKSPEC) $(srctree)/Makefile
+ $(CONFIG_SHELL) $(MKSPEC) prebuilt > $@
+
+binrpm-pkg: $(objtree)/binkernel.spec
+ $(MAKE)
+ set -e; \
+ $(CONFIG_SHELL) $(srctree)/scripts/mkversion > $(objtree)/.tmp_version
+ set -e; \
+ mv -f $(objtree)/.tmp_version $(objtree)/.version
+
+ $(RPM) --define "_builddir $(srctree)" --target $(UTS_MACHINE) -bb $<
+
+clean-files += $(objtree)/binkernel.spec
+
+# Deb target
+# ---------------------------------------------------------------------------
+#
+.PHONY: deb-pkg
+deb-pkg:
+ $(MAKE)
+ $(CONFIG_SHELL) $(srctree)/scripts/package/builddeb
+
+clean-dirs += $(objtree)/debian/
+
+
+# Help text displayed when executing 'make help'
+# ---------------------------------------------------------------------------
+help:
+ @echo ' rpm-pkg - Build the kernel as an RPM package'
+ @echo ' binrpm-pkg - Build an rpm package containing the compiled kernel & modules'
+ @echo ' deb-pkg - Build the kernel as an deb package'
+
diff -urN linux-2.6.11/sound/pci/ac97/ac97_codec.c linux.sinabox/sound/pci/ac97/ac97_codec.c
--- linux-2.6.11/sound/pci/ac97/ac97_codec.c 2005-03-02 08:38:37.000000000 +0100
+++ linux.sinabox/sound/pci/ac97/ac97_codec.c 2005-03-19 07:35:06.000000000 +0100
@@ -1185,7 +1185,7 @@
/*
* create mute switch(es) for normal stereo controls
*/
-static int snd_ac97_cmute_new(snd_card_t *card, char *name, int reg, ac97_t *ac97)
+static int snd_ac97_cmute_new_stereo(snd_card_t *card, char *name, int reg, int check_stereo, ac97_t *ac97)
{
snd_kcontrol_t *kctl;
int err;
@@ -1196,7 +1196,7 @@
mute_mask = 0x8000;
val = snd_ac97_read(ac97, reg);
- if (ac97->flags & AC97_STEREO_MUTES) {
+ if (check_stereo || (ac97->flags & AC97_STEREO_MUTES)) {
/* check whether both mute bits work */
val1 = val | 0x8080;
snd_ac97_write(ac97, reg, val1);
@@ -1254,7 +1254,7 @@
/*
* create a mute-switch and a volume for normal stereo/mono controls
*/
-static int snd_ac97_cmix_new(snd_card_t *card, const char *pfx, int reg, ac97_t *ac97)
+static int snd_ac97_cmix_new_stereo(snd_card_t *card, const char *pfx, int reg, int check_stereo, ac97_t *ac97)
{
int err;
char name[44];
@@ -1265,7 +1265,7 @@
if (snd_ac97_try_bit(ac97, reg, 15)) {
sprintf(name, "%s Switch", pfx);
- if ((err = snd_ac97_cmute_new(card, name, reg, ac97)) < 0)
+ if ((err = snd_ac97_cmute_new_stereo(card, name, reg, check_stereo, ac97)) < 0)
return err;
}
check_volume_resolution(ac97, reg, &lo_max, &hi_max);
@@ -1277,6 +1277,8 @@
return 0;
}
+#define snd_ac97_cmix_new(card, pfx, reg, ac97) snd_ac97_cmix_new_stereo(card, pfx, reg, 0, ac97)
+#define snd_ac97_cmute_new(card, name, reg, ac97) snd_ac97_cmute_new_stereo(card, name, reg, 0, ac97)
static unsigned int snd_ac97_determine_spdif_rates(ac97_t *ac97);
@@ -1327,7 +1329,8 @@
/* build surround controls */
if (snd_ac97_try_volume_mix(ac97, AC97_SURROUND_MASTER)) {
- if ((err = snd_ac97_cmix_new(card, "Surround Playback", AC97_SURROUND_MASTER, ac97)) < 0)
+ /* Surround Master (0x38) is with stereo mutes */
+ if ((err = snd_ac97_cmix_new_stereo(card, "Surround Playback", AC97_SURROUND_MASTER, 1, ac97)) < 0)
return err;
}
diff -urN linux-2.6.11/stamp-build linux.sinabox/stamp-build
--- linux-2.6.11/stamp-build 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/stamp-build 2005-03-24 19:40:43.000000000 +0100
@@ -0,0 +1 @@
+done
diff -urN linux-2.6.11/stamp-configure linux.sinabox/stamp-configure
--- linux-2.6.11/stamp-configure 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/stamp-configure 2005-03-27 04:28:14.000000000 +0200
@@ -0,0 +1 @@
+done
diff -urN linux-2.6.11/stamp-debian linux.sinabox/stamp-debian
--- linux-2.6.11/stamp-debian 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/stamp-debian 2005-03-24 19:30:47.000000000 +0100
@@ -0,0 +1 @@
+done
diff -urN linux-2.6.11/stamp-image linux.sinabox/stamp-image
--- linux-2.6.11/stamp-image 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/stamp-image 2005-03-27 04:28:28.000000000 +0200
@@ -0,0 +1 @@
+done
diff -urN linux-2.6.11/stamp-kernel-configure linux.sinabox/stamp-kernel-configure
--- linux-2.6.11/stamp-kernel-configure 1970-01-01 01:00:00.000000000 +0100
+++ linux.sinabox/stamp-kernel-configure 2005-03-27 04:28:14.000000000 +0200
@@ -0,0 +1 @@
+done