26282 lines
772 KiB
Diff
26282 lines
772 KiB
Diff
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, ®);
|
|
@@ -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
|