diff options
Diffstat (limited to 'obsolete-buildroot/sources/openwrt')
40 files changed, 21035 insertions, 0 deletions
diff --git a/obsolete-buildroot/sources/openwrt/busybox/busybox.config b/obsolete-buildroot/sources/openwrt/busybox/busybox.config new file mode 100644 index 0000000000..2d7c51fb34 --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/busybox/busybox.config @@ -0,0 +1,459 @@ +# +# Automatically generated make config: don't edit +# +HAVE_DOT_CONFIG=y + +# +# General Configuration +# +# CONFIG_FEATURE_BUFFERS_USE_MALLOC is not set +CONFIG_FEATURE_BUFFERS_GO_ON_STACK=y +# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set +CONFIG_FEATURE_VERBOSE_USAGE=y +# CONFIG_FEATURE_INSTALLER is not set +# CONFIG_LOCALE_SUPPORT is not set +CONFIG_FEATURE_DEVFS=y +CONFIG_FEATURE_DEVPTS=y +# CONFIG_FEATURE_CLEAN_UP is not set +# CONFIG_FEATURE_SUID is not set +# CONFIG_SELINUX is not set + +# +# Build Options +# +# CONFIG_STATIC is not set +CONFIG_LFS=y +USING_CROSS_COMPILER=y +CROSS_COMPILER_PREFIX="mipsel-uclibc-" +EXTRA_CFLAGS_OPTIONS="-Os " + +# +# Installation Options +# +# CONFIG_INSTALL_NO_USR is not set +PREFIX="./_install" + +# +# Archival Utilities +# +# CONFIG_AR is not set +CONFIG_BUNZIP2=y +# CONFIG_CPIO is not set +# CONFIG_DPKG is not set +# CONFIG_DPKG_DEB is not set +CONFIG_GUNZIP=y +CONFIG_FEATURE_GUNZIP_UNCOMPRESS=y +CONFIG_GZIP=y +# CONFIG_RPM2CPIO is not set +# CONFIG_RPM is not set +CONFIG_TAR=y +CONFIG_FEATURE_TAR_CREATE=y +CONFIG_FEATURE_TAR_BZIP2=y +# CONFIG_FEATURE_TAR_FROM is not set +CONFIG_FEATURE_TAR_GZIP=y +# CONFIG_FEATURE_TAR_COMPRESS is not set +# CONFIG_FEATURE_TAR_OLDGNU_COMPATABILITY is not set +CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y +# CONFIG_FEATURE_TAR_LONG_OPTIONS is not set +# CONFIG_UNCOMPRESS is not set +# CONFIG_UNZIP is not set + +# +# Common options for cpio and tar +# +# CONFIG_FEATURE_UNARCHIVE_TAPE is not set + +# +# Coreutils +# +CONFIG_BASENAME=y +# CONFIG_CAL is not set +CONFIG_CAT=y +CONFIG_CHGRP=y +CONFIG_CHMOD=y +CONFIG_CHOWN=y +CONFIG_CHROOT=y +# CONFIG_CMP is not set +CONFIG_CP=y +CONFIG_CUT=y +CONFIG_DATE=y +CONFIG_FEATURE_DATE_ISOFMT=y +CONFIG_DD=y +CONFIG_DF=y +# CONFIG_DIRNAME is not set +# CONFIG_DOS2UNIX is not set +# CONFIG_DU is not set +CONFIG_ECHO=y +CONFIG_FEATURE_FANCY_ECHO=y +CONFIG_ENV=y +CONFIG_EXPR=y +CONFIG_FALSE=y +# CONFIG_FOLD is not set +CONFIG_HEAD=y +# CONFIG_FEATURE_FANCY_HEAD is not set +CONFIG_HOSTID=y +# CONFIG_ID is not set +CONFIG_INSTALL=y +CONFIG_LENGTH=y +CONFIG_LN=y +# CONFIG_LOGNAME is not set +CONFIG_LS=y +CONFIG_FEATURE_LS_FILETYPES=y +CONFIG_FEATURE_LS_FOLLOWLINKS=y +CONFIG_FEATURE_LS_RECURSIVE=y +CONFIG_FEATURE_LS_SORTFILES=y +CONFIG_FEATURE_LS_TIMESTAMPS=y +CONFIG_FEATURE_LS_USERNAME=y +CONFIG_FEATURE_LS_COLOR=y +CONFIG_MD5SUM=y +CONFIG_MKDIR=y +CONFIG_MKFIFO=y +# CONFIG_MKNOD is not set +CONFIG_MV=y +# CONFIG_OD is not set +# CONFIG_PRINTF is not set +CONFIG_PWD=y +# CONFIG_REALPATH is not set +CONFIG_RM=y +CONFIG_RMDIR=y +# CONFIG_SEQ is not set +# CONFIG_SHA1SUM is not set +CONFIG_SLEEP=y +CONFIG_FEATURE_FANCY_SLEEP=y +CONFIG_SORT=y +# CONFIG_STTY is not set +CONFIG_SYNC=y +CONFIG_TAIL=y +CONFIG_FEATURE_FANCY_TAIL=y +CONFIG_TEE=y +CONFIG_FEATURE_TEE_USE_BLOCK_IO=y +CONFIG_TEST=y + +# +# test (forced enabled for use with shell) +# +CONFIG_TOUCH=y +# CONFIG_TR is not set +CONFIG_TRUE=y +# CONFIG_TTY is not set +CONFIG_UNAME=y +CONFIG_UNIQ=y +# CONFIG_USLEEP is not set +# CONFIG_UUDECODE is not set +# CONFIG_UUENCODE is not set +# CONFIG_WATCH is not set +CONFIG_WC=y +# CONFIG_WHO is not set +# CONFIG_WHOAMI is not set +CONFIG_YES=y + +# +# Common options for cp and mv +# +CONFIG_FEATURE_PRESERVE_HARDLINKS=y + +# +# Common options for ls and more +# +CONFIG_FEATURE_AUTOWIDTH=y + +# +# Common options for df, du, ls +# +CONFIG_FEATURE_HUMAN_READABLE=y + +# +# Common options for md5sum, sha1sum +# +CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y + +# +# Console Utilities +# +# CONFIG_CHVT is not set +CONFIG_CLEAR=y +# CONFIG_DEALLOCVT is not set +# CONFIG_DUMPKMAP is not set +# CONFIG_LOADFONT is not set +# CONFIG_LOADKMAP is not set +# CONFIG_OPENVT is not set +CONFIG_RESET=y +# CONFIG_SETKEYCODES is not set + +# +# Debian Utilities +# +CONFIG_MKTEMP=y +# CONFIG_PIPE_PROGRESS is not set +# CONFIG_READLINK is not set +CONFIG_RUN_PARTS=y +# CONFIG_START_STOP_DAEMON is not set +CONFIG_WHICH=y + +# +# Editors +# +CONFIG_AWK=y +CONFIG_FEATURE_AWK_MATH=y +# CONFIG_PATCH is not set +CONFIG_SED=y +CONFIG_VI=y +CONFIG_FEATURE_VI_COLON=y +CONFIG_FEATURE_VI_YANKMARK=y +CONFIG_FEATURE_VI_SEARCH=y +CONFIG_FEATURE_VI_USE_SIGNALS=y +CONFIG_FEATURE_VI_DOT_CMD=y +CONFIG_FEATURE_VI_READONLY=y +CONFIG_FEATURE_VI_SETOPTS=y +CONFIG_FEATURE_VI_SET=y +CONFIG_FEATURE_VI_WIN_RESIZE=y +CONFIG_FEATURE_VI_OPTIMIZE_CURSOR=y + +# +# Finding Utilities +# +CONFIG_FIND=y +# CONFIG_FEATURE_FIND_MTIME is not set +CONFIG_FEATURE_FIND_PERM=y +CONFIG_FEATURE_FIND_TYPE=y +CONFIG_FEATURE_FIND_XDEV=y +# CONFIG_FEATURE_FIND_NEWER is not set +# CONFIG_FEATURE_FIND_INUM is not set +CONFIG_GREP=y +CONFIG_FEATURE_GREP_EGREP_ALIAS=y +CONFIG_FEATURE_GREP_FGREP_ALIAS=y +CONFIG_FEATURE_GREP_CONTEXT=y +CONFIG_XARGS=y +CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y +CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y +CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y +CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y + +# +# Init Utilities +# +CONFIG_INIT=y +CONFIG_FEATURE_USE_INITTAB=y +# CONFIG_FEATURE_INITRD is not set +# CONFIG_FEATURE_INIT_COREDUMPS is not set +# CONFIG_FEATURE_EXTRA_QUIET is not set +# CONFIG_HALT is not set +# CONFIG_POWEROFF is not set +CONFIG_REBOOT=y +CONFIG_MESG=y + +# +# Login/Password Management Utilities +# +# CONFIG_USE_BB_PWD_GRP is not set +# CONFIG_ADDGROUP is not set +# CONFIG_DELGROUP is not set +# CONFIG_ADDUSER is not set +# CONFIG_DELUSER is not set +# CONFIG_GETTY is not set +# CONFIG_LOGIN is not set +CONFIG_PASSWD=y +# CONFIG_SU is not set +# CONFIG_SULOGIN is not set +# CONFIG_VLOCK is not set + +# +# Miscellaneous Utilities +# +# CONFIG_ADJTIMEX is not set +CONFIG_CROND=y +# CONFIG_FEATURE_CROND_CALL_SENDMAIL is not set +CONFIG_CRONTAB=y +# CONFIG_DC is not set +# CONFIG_DEVFSD is not set +# CONFIG_LAST is not set +# CONFIG_HDPARM is not set +# CONFIG_MAKEDEVS is not set +# CONFIG_MT is not set +CONFIG_RESETMON=y +# CONFIG_RX is not set +CONFIG_STRINGS=y +CONFIG_TIME=y +# CONFIG_WATCHDOG is not set + +# +# Linux Module Utilities +# +CONFIG_INSMOD=y +CONFIG_FEATURE_2_4_MODULES=y +# CONFIG_FEATURE_2_6_MODULES is not set +# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set +# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set +# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set +# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set +CONFIG_LSMOD=y +CONFIG_FEATURE_QUERY_MODULE_INTERFACE=y +# CONFIG_MODPROBE is not set +CONFIG_RMMOD=y +# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set + +# +# Networking Utilities +# +CONFIG_FEATURE_IPV6=y +CONFIG_ARPING=y +# CONFIG_FTPGET is not set +# CONFIG_FTPPUT is not set +# CONFIG_HOSTNAME is not set +CONFIG_HTTPD=y +# CONFIG_FEATURE_HTTPD_USAGE_FROM_INETD_ONLY is not set +CONFIG_FEATURE_HTTPD_BASIC_AUTH=y +CONFIG_FEATURE_HTTPD_AUTH_MD5=y +CONFIG_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP=y +# CONFIG_FEATURE_HTTPD_SETUID is not set +CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES=y +CONFIG_FEATURE_HTTPD_CGI=y +CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV=y +CONFIG_FEATURE_HTTPD_ENCODE_URL_STR=y +CONFIG_IFCONFIG=y +CONFIG_FEATURE_IFCONFIG_STATUS=y +# CONFIG_FEATURE_IFCONFIG_SLIP is not set +# CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ is not set +CONFIG_FEATURE_IFCONFIG_HW=y +CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS=y +# CONFIG_IFUPDOWN is not set +# CONFIG_INETD is not set +# CONFIG_IP is not set +CONFIG_IPCALC=y +CONFIG_FEATURE_IPCALC_FANCY=y +# CONFIG_IPADDR is not set +# CONFIG_IPLINK is not set +# CONFIG_IPROUTE is not set +# CONFIG_IPTUNNEL is not set +# CONFIG_NAMEIF is not set +CONFIG_NC=y +CONFIG_NETSTAT=y +CONFIG_NSLOOKUP=y +CONFIG_PING=y +CONFIG_FEATURE_FANCY_PING=y +CONFIG_PING6=y +CONFIG_FEATURE_FANCY_PING6=y +CONFIG_ROUTE=y +# CONFIG_TELNET is not set +CONFIG_TELNETD=y +# CONFIG_FEATURE_TELNETD_INETD is not set +# CONFIG_TFTP is not set +CONFIG_TRACEROUTE=y +CONFIG_FEATURE_TRACEROUTE_VERBOSE=y +CONFIG_VCONFIG=y +CONFIG_WGET=y +CONFIG_FEATURE_WGET_STATUSBAR=y +CONFIG_FEATURE_WGET_AUTHENTICATION=y +CONFIG_FEATURE_WGET_IP6_LITERAL=y + +# +# udhcp Server/Client +# +# CONFIG_UDHCPD is not set +CONFIG_UDHCPC=y +# CONFIG_FEATURE_UDHCP_SYSLOG is not set +# CONFIG_FEATURE_UDHCP_DEBUG is not set + +# +# Process Utilities +# +CONFIG_FREE=y +CONFIG_KILL=y +CONFIG_KILLALL=y +CONFIG_KILLALL5=y +CONFIG_PIDOF=y +CONFIG_PS=y +# CONFIG_RENICE is not set +CONFIG_TOP=y +FEATURE_CPU_USAGE_PERCENTAGE=y +CONFIG_UPTIME=y +CONFIG_SYSCTL=y + +# +# Another Bourne-like Shell +# +CONFIG_FEATURE_SH_IS_ASH=y +# CONFIG_FEATURE_SH_IS_HUSH is not set +# CONFIG_FEATURE_SH_IS_LASH is not set +# CONFIG_FEATURE_SH_IS_MSH is not set +# CONFIG_FEATURE_SH_IS_NONE is not set +CONFIG_ASH=y + +# +# Ash Shell Options +# +CONFIG_ASH_JOB_CONTROL=y +CONFIG_ASH_ALIAS=y +CONFIG_ASH_MATH_SUPPORT=y +# CONFIG_ASH_MATH_SUPPORT_64 is not set +CONFIG_ASH_GETOPTS=y +CONFIG_ASH_CMDCMD=y +# CONFIG_ASH_MAIL is not set +CONFIG_ASH_OPTIMIZE_FOR_SIZE=y +# CONFIG_ASH_RANDOM_SUPPORT is not set +# CONFIG_HUSH is not set +# CONFIG_LASH is not set +# CONFIG_MSH is not set + +# +# Bourne Shell Options +# +# CONFIG_FEATURE_SH_EXTRA_QUIET is not set +# CONFIG_FEATURE_SH_STANDALONE_SHELL is not set +CONFIG_FEATURE_COMMAND_EDITING=y +CONFIG_FEATURE_COMMAND_HISTORY=15 +# CONFIG_FEATURE_COMMAND_SAVEHISTORY is not set +CONFIG_FEATURE_COMMAND_TAB_COMPLETION=y +# CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION is not set +CONFIG_FEATURE_SH_FANCY_PROMPT=y + +# +# System Logging Utilities +# +CONFIG_SYSLOGD=y +CONFIG_FEATURE_ROTATE_LOGFILE=y +CONFIG_FEATURE_REMOTE_LOG=y +CONFIG_FEATURE_IPC_SYSLOG=y +CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=16 +CONFIG_LOGREAD=y +# CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set +CONFIG_KLOGD=y +CONFIG_LOGGER=y + +# +# Linux System Utilities +# +CONFIG_DMESG=y +# CONFIG_FBSET is not set +# CONFIG_FDFLUSH is not set +# CONFIG_FDFORMAT is not set +# CONFIG_FDISK is not set +FDISK_SUPPORT_LARGE_DISKS=y +# CONFIG_FREERAMDISK is not set +# CONFIG_FSCK_MINIX is not set +# CONFIG_MKFS_MINIX is not set +# CONFIG_GETOPT is not set +CONFIG_HEXDUMP=y +# CONFIG_HWCLOCK is not set +# CONFIG_LOSETUP is not set +# CONFIG_MKSWAP is not set +CONFIG_MORE=y +CONFIG_FEATURE_USE_TERMIOS=y +CONFIG_PIVOT_ROOT=y +CONFIG_RDATE=y +# CONFIG_SWAPONOFF is not set +CONFIG_MOUNT=y +CONFIG_NFSMOUNT=y +CONFIG_UMOUNT=y +CONFIG_FEATURE_MOUNT_FORCE=y + +# +# Common options for mount/umount +# +CONFIG_FEATURE_MOUNT_LOOP=y +# CONFIG_FEATURE_MTAB_SUPPORT is not set + +# +# Debugging Options +# +# CONFIG_DEBUG is not set diff --git a/obsolete-buildroot/sources/openwrt/busybox/patches/100-killall5.patch b/obsolete-buildroot/sources/openwrt/busybox/patches/100-killall5.patch new file mode 100644 index 0000000000..161b7e6f25 --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/busybox/patches/100-killall5.patch @@ -0,0 +1,87 @@ +diff -urN busybox-dist/include/applets.h busybox/include/applets.h +--- busybox-dist/include/applets.h 2004-03-13 02:33:09.000000000 -0600 ++++ busybox/include/applets.h 2004-03-16 09:45:29.000000000 -0600 +@@ -313,6 +313,9 @@ + #ifdef CONFIG_KILLALL + APPLET(killall, kill_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER) + #endif ++#ifdef CONFIG_KILLALL5 ++ APPLET(killall5, kill_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER) ++#endif + #ifdef CONFIG_KLOGD + APPLET(klogd, klogd_main, _BB_DIR_SBIN, _BB_SUID_NEVER) + #endif +diff -urN busybox-dist/include/usage.h busybox/include/usage.h +--- busybox-dist/include/usage.h 2004-03-13 02:33:09.000000000 -0600 ++++ busybox/include/usage.h 2004-03-16 09:45:29.000000000 -0600 +@@ -1389,6 +1389,13 @@ + #define killall_example_usage \ + "$ killall apache\n" + ++#define killall5_trivial_usage \ ++ "" ++#define killall5_full_usage \ ++ "" ++#define killall5_example_usage \ ++ "" ++ + #define klogd_trivial_usage \ + "[-c n] [-n]" + #define klogd_full_usage \ +diff -urN busybox-dist/procps/Config.in busybox/procps/Config.in +--- busybox-dist/procps/Config.in 2003-12-24 00:02:11.000000000 -0600 ++++ busybox/procps/Config.in 2004-03-16 09:45:29.000000000 -0600 +@@ -30,6 +30,11 @@ + specified commands. If no signal name is specified, SIGTERM is + sent. + ++config CONFIG_KILLALL5 ++ bool "killall5" ++ default n ++ depends on CONFIG_KILL ++ + config CONFIG_PIDOF + bool "pidof" + default n +diff -urN busybox-dist/procps/kill.c busybox/procps/kill.c +--- busybox-dist/procps/kill.c 2004-03-15 02:29:03.000000000 -0600 ++++ busybox/procps/kill.c 2004-03-16 09:45:29.000000000 -0600 +@@ -34,6 +34,7 @@ + + #define KILL 0 + #define KILLALL 1 ++#define KILLALL5 2 + + extern int kill_main(int argc, char **argv) + { +@@ -47,6 +48,9 @@ + #else + whichApp = KILL; + #endif ++#ifdef CONFIG_KILLALL5 ++ whichApp = (strcmp(bb_applet_name, "killall5") == 0)? KILLALL5 : whichApp; ++#endif + + /* Parse any options */ + if (argc < 2) +@@ -119,6 +123,20 @@ + } + + } ++#ifdef CONFIG_KILLALL5 ++ else if (whichApp == KILLALL5) { ++ procps_status_t * p; ++ pid_t myPid=getpid(); ++ while ((p = procps_scan(0)) != 0) { ++ if (p->pid != 1 && p->pid != myPid && p->pid != p->ppid) { ++ if (kill(p->pid, signo) != 0) { ++ bb_perror_msg( "Could not kill pid '%d'", p->pid); ++ errors++; ++ } ++ } ++ } ++ } ++#endif + #ifdef CONFIG_KILLALL + else { + pid_t myPid=getpid(); diff --git a/obsolete-buildroot/sources/openwrt/busybox/patches/110-telnetd.patch b/obsolete-buildroot/sources/openwrt/busybox/patches/110-telnetd.patch new file mode 100644 index 0000000000..e95757ee4e --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/busybox/patches/110-telnetd.patch @@ -0,0 +1,53 @@ +diff -urN busybox-1.00-pre8/networking/telnetd.c busybox-1.00-pre8-openwrt/networking/telnetd.c +--- busybox-1.00-pre8/networking/telnetd.c 2004-02-22 03:45:57.000000000 -0600 ++++ busybox-1.00-pre8-openwrt/networking/telnetd.c 2004-03-05 01:32:57.000000000 -0600 +@@ -44,6 +44,8 @@ + #include <arpa/telnet.h> + #include <ctype.h> + #include <sys/syslog.h> ++#include <net/if.h> ++ + + #include "busybox.h" + +@@ -384,11 +386,13 @@ + int portnbr = 23; + #endif /* CONFIG_FEATURE_TELNETD_INETD */ + int c; ++ char *interface_name = NULL; ++ struct ifreq interface; + static const char options[] = + #ifdef CONFIG_FEATURE_TELNETD_INETD +- "f:l:"; +-#else /* CONFIG_EATURE_TELNETD_INETD */ +- "f:l:p:"; ++ "i:f:l:"; ++#else /* CONFIG_FEATURE_TELNETD_INETD */ ++ "i:f:l:p:"; + #endif /* CONFIG_FEATURE_TELNETD_INETD */ + int maxlen, w, r; + +@@ -403,6 +407,9 @@ + case 'f': + issuefile = strdup (optarg); + break; ++ case 'i': ++ interface_name = strdup(optarg); ++ break; + case 'l': + loginpath = strdup (optarg); + break; +@@ -442,6 +449,13 @@ + sa.sin_family = AF_INET; + sa.sin_port = htons(portnbr); + ++ /* Set it to listen on the specified interface */ ++ if (interface_name) { ++ strncpy(interface.ifr_ifrn.ifrn_name, interface_name, IFNAMSIZ); ++ (void)setsockopt(master_fd, SOL_SOCKET, ++ SO_BINDTODEVICE, &interface, sizeof(interface)); ++ } ++ + if (bind(master_fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) { + bb_perror_msg_and_die("bind"); + } diff --git a/obsolete-buildroot/sources/openwrt/busybox/patches/130-resetmon.patch b/obsolete-buildroot/sources/openwrt/busybox/patches/130-resetmon.patch new file mode 100644 index 0000000000..b41315e1f7 --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/busybox/patches/130-resetmon.patch @@ -0,0 +1,89 @@ +diff -urN busybox-dist/include/applets.h busybox/include/applets.h +--- busybox-dist/include/applets.h 2004-03-16 09:56:27.000000000 -0600 ++++ busybox/include/applets.h 2004-03-16 10:00:14.000000000 -0600 +@@ -484,6 +484,9 @@ + #ifdef CONFIG_RESET + APPLET(reset, reset_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER) + #endif ++#ifdef CONFIG_RESETMON ++ APPLET(resetmon, resetmon_main, _BB_DIR_SBIN, _BB_SUID_NEVER) ++#endif + #ifdef CONFIG_RM + APPLET(rm, rm_main, _BB_DIR_BIN, _BB_SUID_NEVER) + #endif +diff -urN busybox-dist/include/usage.h busybox/include/usage.h +--- busybox-dist/include/usage.h 2004-03-16 09:56:27.000000000 -0600 ++++ busybox/include/usage.h 2004-03-16 10:00:14.000000000 -0600 +@@ -2024,6 +2024,11 @@ + #define reset_full_usage \ + "Resets the screen." + ++#define resetmon_trivial_usage \ ++ "" ++#define resetmon_full_usage \ ++ "Return an exit code of TRUE (0) if reset is NOT pressed." ++ + #define rm_trivial_usage \ + "[OPTION]... FILE..." + #define rm_full_usage \ +diff -urN busybox-dist/miscutils/Config.in busybox/miscutils/Config.in +--- busybox-dist/miscutils/Config.in 2004-03-15 02:28:46.000000000 -0600 ++++ busybox/miscutils/Config.in 2004-03-16 10:00:14.000000000 -0600 +@@ -156,6 +156,12 @@ + to advance or rewind a tape past a specified number of archive + files on the tape. + ++config CONFIG_RESETMON ++ bool "resetmon" ++ default y ++ help ++ Linksys wrt54g reset button monitor. Returns TRUE if NOT pressed. ++ + config CONFIG_RX + bool "rx" + default n +diff -urN busybox-dist/miscutils/Makefile.in busybox/miscutils/Makefile.in +--- busybox-dist/miscutils/Makefile.in 2004-03-15 02:28:46.000000000 -0600 ++++ busybox/miscutils/Makefile.in 2004-03-16 10:00:14.000000000 -0600 +@@ -33,6 +33,7 @@ + MISCUTILS-$(CONFIG_LAST) += last.o + MISCUTILS-$(CONFIG_MAKEDEVS) += makedevs.o + MISCUTILS-$(CONFIG_MT) += mt.o ++MISCUTILS-$(CONFIG_RESETMON) += resetmon.o + MISCUTILS-$(CONFIG_RX) += rx.o + MISCUTILS-$(CONFIG_STRINGS) += strings.o + MISCUTILS-$(CONFIG_TIME) += time.o +diff -urN busybox-dist/miscutils/resetmon.c busybox/miscutils/resetmon.c +--- busybox-dist/miscutils/resetmon.c 1969-12-31 18:00:00.000000000 -0600 ++++ busybox/miscutils/resetmon.c 2004-03-16 10:00:14.000000000 -0600 +@@ -0,0 +1,30 @@ ++#include <unistd.h> ++#include <fcntl.h> ++#include "busybox.h" ++ ++#define RESET (1<<6) ++ ++int resetmon_main(int argc, char **argv) { ++ int fd = -1; ++ unsigned int val=0; ++ ++#if 0 ++ if ((fd = open("/dev/gpio/control",O_RDWR))<0) goto error; ++ read(fd,&val,4); ++ val|=RESET; ++ write(fd,&val,4); ++ ++ if ((fd = open("/dev/gpio/outen",O_RDWR))<0) goto error; ++ read(fd,&val,4); ++ val&=~RESET; ++ write(fd,&val,4); ++#endif ++ ++ if ((fd = open("/dev/gpio/in",O_RDONLY))<0) goto error; ++ read(fd,&val,4); ++ ++ return !(val&RESET); ++ ++error: ++ return 1; ++} diff --git a/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.client.conffiles b/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.client.conffiles new file mode 100644 index 0000000000..cb3c639ba6 --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.client.conffiles @@ -0,0 +1 @@ +/etc/ssh_config diff --git a/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.client.control b/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.client.control new file mode 100644 index 0000000000..358525098c --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.client.control @@ -0,0 +1,12 @@ +Package: openssh-client +Priority: optional +Version: 3.8p1-1 +Architecture: mipsel +Maintainer: below0 +Section: net +Depends: zlib libssl +Source: Embedded in the main OpenWrt buildroot +Description: The OpenSSH client. Allows for access to remote systems via the SSH protocol. + Includes: ssh, scp + + diff --git a/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.client.ex.control b/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.client.ex.control new file mode 100644 index 0000000000..5eb808a979 --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.client.ex.control @@ -0,0 +1,12 @@ +Package: openssh-client-extras +Priority: optional +Version: 3.8p1-1 +Architecture: mipsel +Maintainer: below0 +Section: net +Depends: openssh-client +Source: Embedded in the main OpenWrt buildroot +Description: Various optional OpenSSH client tools. + Includes: ssh-add, ssh-agent, ssh-keyscan, ssk-keysign + + diff --git a/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.client.preinst b/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.client.preinst new file mode 100644 index 0000000000..029c78978a --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.client.preinst @@ -0,0 +1,10 @@ +#!/bin/sh + +# Make sure password and group databases exist +if [ ! -f /etc/passwd ]; then + echo -e "root::0:0::/tmp:/bin/sh\nnobody:x:65534:65534:nobody:/tmp:/bin/sh\nsshd:x:100:65534:sshd:/var:/bin/false\n" > /etc/passwd + [ -f /etc/group ] || echo -e "root:x:0:\nnogroup:x:65534:\n" > /etc/group + echo "\n\nNOTICE: SSH requires proper root password to be configured, set it now." + passwd +fi + diff --git a/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.client.ssh_config b/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.client.ssh_config new file mode 100644 index 0000000000..2692e89137 --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.client.ssh_config @@ -0,0 +1,37 @@ +# $OpenBSD: ssh_config,v 1.19 2003/08/13 08:46:31 markus Exp $ + +# This is the ssh client system-wide configuration file. See +# ssh_config(5) for more information. This file provides defaults for +# users, and the values can be changed in per-user configuration files +# or on the command line. + +# Configuration data is parsed as follows: +# 1. command line options +# 2. user-specific file +# 3. system-wide file +# Any configuration value is only changed the first time it is set. +# Thus, host-specific definitions should be at the beginning of the +# configuration file, and defaults at the end. + +# Site-wide defaults for various options + +# Host * +# ForwardAgent no +# ForwardX11 no +# RhostsRSAAuthentication no +# RSAAuthentication yes +# PasswordAuthentication yes +# HostbasedAuthentication no +# BatchMode no +# CheckHostIP yes +# AddressFamily any +# ConnectTimeout 0 +# StrictHostKeyChecking ask +# IdentityFile ~/.ssh/identity +# IdentityFile ~/.ssh/id_rsa +# IdentityFile ~/.ssh/id_dsa +# Port 22 +# Protocol 2,1 +# Cipher 3des +# Ciphers aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour,aes192-cbc,aes256-cbc +# EscapeChar ~ diff --git a/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.patch b/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.patch new file mode 100644 index 0000000000..7d85a0400e --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.patch @@ -0,0 +1,289 @@ +--- openssh-3.6.1p1/Makefile.in.orig 2003-03-20 17:34:34.000000000 -0700 ++++ openssh-3.6.1p1/Makefile.in 2003-04-25 17:09:00.000000000 -0600 +@@ -27,7 +27,7 @@ + RAND_HELPER=$(libexecdir)/ssh-rand-helper + PRIVSEP_PATH=@PRIVSEP_PATH@ + SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@ +-STRIP_OPT=@STRIP_OPT@ ++STRIP_OPT= + + PATHS= -DSSHDIR=\"$(sysconfdir)\" \ + -D_PATH_SSH_PROGRAM=\"$(SSH_PROGRAM)\" \ +--- openssh-3.8p1/configure.ac.orig 2004-02-23 22:47:04.000000000 -0700 ++++ openssh-3.8p1/configure.ac 2004-03-19 01:41:47.000000000 -0700 +@@ -481,6 +481,9 @@ + [ + AC_MSG_RESULT(no) + AC_MSG_ERROR([*** compiler cannot create working executables, check config.log ***]) ++ ], ++ [AC_MSG_RESULT(yes) ++ AC_MSG_WARN([Cannot run test when crosscompiling, defaulted to yes.]) + ] + ) + +@@ -632,6 +635,9 @@ + else + AC_MSG_WARN([zlib version may have security problems]) + fi ++ ], ++ [AC_MSG_RESULT(yes) ++ AC_MSG_WARN([Cannot run test when crosscompiling, defaulted to yes.]) + ] + ) + +@@ -696,6 +702,9 @@ + [ + AC_MSG_RESULT(no) + AC_DEFINE(BROKEN_ONE_BYTE_DIRENT_D_NAME) ++ ], ++ [AC_MSG_RESULT(yes) ++ AC_MSG_WARN([Cannot run test when crosscompiling, defaulted to yes.]) + ] + ) + +@@ -727,6 +736,9 @@ + [ + AC_MSG_RESULT(no) + AC_MSG_ERROR([** Incomplete or missing s/key libraries.]) ++ ], ++ [AC_MSG_RESULT(yes) ++ AC_MSG_WARN([Cannot run test when crosscompiling, defaulted to yes.]) + ]) + fi + ] +@@ -840,7 +852,11 @@ + ], + [AC_MSG_RESULT(yes)], + [AC_DEFINE(BROKEN_SETRESUID) +- AC_MSG_RESULT(not implemented)] ++ AC_MSG_RESULT(not implemented) ++ ], ++ [AC_MSG_RESULT(yes) ++ AC_MSG_WARN([Cannot run test when crosscompiling, defaulted to yes.]) ++ ] + ) + ]) + +@@ -854,7 +870,11 @@ + ], + [AC_MSG_RESULT(yes)], + [AC_DEFINE(BROKEN_SETRESGID) +- AC_MSG_RESULT(not implemented)] ++ AC_MSG_RESULT(not implemented) ++ ], ++ [AC_MSG_RESULT(yes) ++ AC_MSG_WARN([Cannot run test when crosscompiling, defaulted to yes.]) ++ ] + ) + ]) + +@@ -890,6 +910,9 @@ + AC_MSG_RESULT(no) + AC_DEFINE(BROKEN_SNPRINTF) + AC_MSG_WARN([****** Your snprintf() function is broken, complain to your vendor]) ++ ], ++ [AC_MSG_RESULT(yes) ++ AC_MSG_WARN([Cannot run test when crosscompiling, defaulted to yes.]) + ] + ) + fi +@@ -963,7 +986,10 @@ + [ + AC_MSG_RESULT(no) + AC_DEFINE(SSHD_ACQUIRES_CTTY) +- ] ++ ], ++ [AC_MSG_RESULT(yes) ++ AC_MSG_WARN([Cannot run test when crosscompiling, defaulted to yes.]) ++ ] + ) + fi + +@@ -1096,6 +1122,10 @@ + [ + AC_MSG_RESULT(not found) + AC_MSG_ERROR(OpenSSL version header not found.) ++ ], ++ [ ++ ssl_header_ver="0x0090704fL (OpenSSL 0.9.7d 17 Mar 2004)" ++ AC_MSG_WARN([Cannot run test when crosscompiling, defaulted to $ssl_header_ver]) + ] + ) + +@@ -1129,6 +1159,10 @@ + [ + AC_MSG_RESULT(not found) + AC_MSG_ERROR(OpenSSL library not found.) ++ ], ++ [ ++ ssl_header_ver="0x0090704fL (OpenSSL 0.9.7d 17 Mar 2004)" ++ AC_MSG_WARN([Cannot run test when crosscompiling, defaulted to $ssl_library_ver]) + ] + ) + +@@ -1148,7 +1182,11 @@ + AC_MSG_ERROR([Your OpenSSL headers do not match your library. + Check config.log for details. + Also see contrib/findssl.sh for help identifying header/library mismatches.]) +- ] ++ ], ++ [ ++ AC_MSG_RESULT(yes) ++ AC_MSG_WARN([Cannot run test when crosscompiling, defaulted to yes.]) ++ ] + ) + + # Some systems want crypt() from libcrypt, *not* the version in OpenSSL, +@@ -1183,6 +1221,11 @@ + # Default to use of the rand helper if OpenSSL doesn't + # seed itself + USE_RAND_HELPER=yes ++ ], ++ [ ++ OPENSSL_SEEDS_ITSELF=yes ++ AC_MSG_RESULT(yes) ++ AC_MSG_WARN([Cannot run test when crosscompiling, defaulted to yes.]) + ] + ) + +@@ -1773,7 +1816,8 @@ + #else + main() { exit(0); } + #endif +- ], [ true ], [ AC_DEFINE(BROKEN_SNPRINTF) ] ++ ], [ true ], [ AC_DEFINE(BROKEN_SNPRINTF) ], ++ [ true ] + ) + fi + +@@ -1893,6 +1937,7 @@ + } + ], + [ ac_cv_have_accrights_in_msghdr="yes" ], ++ [ ac_cv_have_accrights_in_msghdr="no" ], + [ ac_cv_have_accrights_in_msghdr="no" ] + ) + ]) +@@ -1917,7 +1962,8 @@ + } + ], + [ ac_cv_have_control_in_msghdr="yes" ], +- [ ac_cv_have_control_in_msghdr="no" ] ++ [ ac_cv_have_control_in_msghdr="no" ], ++ [ ac_cv_have_control_in_msghdr="yes" ] + ) + ]) + if test "x$ac_cv_have_control_in_msghdr" = "xyes" ; then +@@ -2229,12 +2275,9 @@ + ) + fi + fi +-AC_CHECK_FILE("/dev/ptc", +- [ +- AC_DEFINE_UNQUOTED(HAVE_DEV_PTS_AND_PTC) +- have_dev_ptc=1 +- ] +-) ++AC_MSG_CHECKING([for "/dev/ptc"]) ++AC_MSG_RESULT(no) ++have_dev_ptc=0 + + # Options from here on. Some of these are preset by platform above + AC_ARG_WITH(mantype, +@@ -2329,15 +2372,8 @@ + fi + + # check for /etc/default/login and use it if present. +-AC_ARG_ENABLE(etc-default-login, +- [ --disable-etc-default-login Disable using PATH from /etc/default/login [no]],, +-[ +-AC_CHECK_FILE("/etc/default/login", [ external_path_file=/etc/default/login ]) +- +-if test "x$external_path_file" = "x/etc/default/login"; then +- AC_DEFINE(HAVE_ETC_DEFAULT_LOGIN) +-fi +-]) ++AC_MSG_CHECKING([for "/etc/default/login"]) ++AC_MSG_RESULT(no) + + dnl BSD systems use /etc/login.conf so --with-default-path= has no effect + if test $ac_cv_func_login_getcapbool = "yes" -a \ +--- openssh-3.8p1.orig/sshd_config Fri Sep 27 05:21:58 2002 ++++ openssh-3.8p1/sshd_config Mon Mar 17 14:55:00 2003 +@@ -89,5 +89,8 @@ + #Banner /some/path + #VerifyReverseMapping no + ++ClientAliveInterval 15 ++ClientAliveCountMax 4 ++ + # override default of no subsystems +-Subsystem sftp /usr/libexec/sftp-server ++Subsystem sftp /usr/sbin/sftp-server +--- openssh-3.6.1p1/S50sshd Fri Sep 27 05:21:58 2002 ++++ openssh-3.6.1p1/S50sshd Mon Mar 17 14:55:00 2003 +@@ -0,0 +1,64 @@ ++#!/bin/sh ++# ++# sshd Starts sshd. ++# ++ ++# Make sure the ssh-keygen progam exists ++[ -f /usr/bin/ssh-keygen ] || exit 0 ++ ++# Check for the SSH1 RSA key ++if [ ! -f /etc/ssh_host_key ] ; then ++ echo Generating RSA Key... ++ /usr/bin/ssh-keygen -t rsa1 -f /etc/ssh_host_key -C '' -N '' ++fi ++ ++# Check for the SSH2 RSA key ++if [ ! -f /etc/ssh_host_rsa_key ] ; then ++ echo Generating RSA Key... ++ /usr/bin/ssh-keygen -t rsa -f /etc/ssh_host_rsa_key -C '' -N '' ++fi ++ ++# Check for the SSH2 DSA key ++if [ ! -f /etc/ssh_host_dsa_key ] ; then ++ echo Generating DSA Key... ++ echo THIS CAN TAKE A MINUTE OR TWO DEPENDING ON YOUR PROCESSOR! ++ echo ++ /usr/bin/ssh-keygen -t dsa -f /etc/ssh_host_dsa_key -C '' -N '' ++fi ++ ++umask 077 ++ ++start() { ++ echo -n "Starting sshd: " ++ /usr/sbin/sshd ++ touch /var/lock/sshd ++ echo "OK" ++} ++stop() { ++ echo -n "Stopping sshd: " ++ killall sshd ++ rm -f /var/lock/sshd ++ echo "OK" ++} ++restart() { ++ stop ++ start ++} ++ ++case "$1" in ++ start) ++ start ++ ;; ++ stop) ++ stop ++ ;; ++ restart|reload) ++ restart ++ ;; ++ *) ++ echo $"Usage: $0 {start|stop|restart}" ++ exit 1 ++esac ++ ++exit $? ++ diff --git a/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.server.S50sshd-ipk b/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.server.S50sshd-ipk new file mode 100644 index 0000000000..6f77ad9b1c --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.server.S50sshd-ipk @@ -0,0 +1,45 @@ +#!/bin/sh +# +# sshd Starts sshd. +# + +mkdir -p /var/lock +mkdir -p /var/empty +chmod 600 /var/empty + +umask 077 + +start() { + echo -n "Starting sshd: " + /usr/sbin/sshd + touch /var/lock/sshd + echo "OK" +} +stop() { + echo -n "Stopping sshd: " + killall sshd + rm -f /var/lock/sshd + echo "OK" +} +restart() { + stop + start +} + +case "$1" in + start) + start + ;; + stop) + stop + ;; + restart|reload) + restart + ;; + *) + echo $"Usage: $0 {start|stop|restart}" + exit 1 +esac + +exit $? + diff --git a/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.server.conffiles b/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.server.conffiles new file mode 100644 index 0000000000..5877b3bdbc --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.server.conffiles @@ -0,0 +1 @@ +/etc/sshd_config diff --git a/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.server.control b/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.server.control new file mode 100644 index 0000000000..943da932d3 --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.server.control @@ -0,0 +1,13 @@ +Package: openssh-server +Priority: optional +Version: 3.8p1-1 +Architecture: mipsel +Maintainer: below0 +Section: net +Depends: zlib libssl +Source: Embedded in the main OpenWrt buildroot +Description: The OpenSSH server daemon. + Allows for access to the system via the SSH client. + Includes: sshd, ssh-keygen + + diff --git a/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.server.postinst b/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.server.postinst new file mode 100644 index 0000000000..16d2bf4d76 --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.server.postinst @@ -0,0 +1,20 @@ +#!/bin/sh + +# Check for the SSH1 RSA key +if [ ! -f /etc/ssh_host_key ] ; then + echo Generating RSA Key... + /usr/bin/ssh-keygen -t rsa1 -f /etc/ssh_host_key -C '' -N '' +fi + +# Check for the SSH2 RSA key +if [ ! -f /etc/ssh_host_rsa_key ] ; then + echo Generating RSA Key... + /usr/bin/ssh-keygen -t rsa -f /etc/ssh_host_rsa_key -C '' -N '' +fi + +# Check for the SSH2 DSA key +if [ ! -f /etc/ssh_host_dsa_key ] ; then + echo "Generating DSA Key... (Takes a few minutes)" + /usr/bin/ssh-keygen -t dsa -f /etc/ssh_host_dsa_key -C '' -N '' +fi + diff --git a/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.server.preinst b/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.server.preinst new file mode 100644 index 0000000000..029c78978a --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.server.preinst @@ -0,0 +1,10 @@ +#!/bin/sh + +# Make sure password and group databases exist +if [ ! -f /etc/passwd ]; then + echo -e "root::0:0::/tmp:/bin/sh\nnobody:x:65534:65534:nobody:/tmp:/bin/sh\nsshd:x:100:65534:sshd:/var:/bin/false\n" > /etc/passwd + [ -f /etc/group ] || echo -e "root:x:0:\nnogroup:x:65534:\n" > /etc/group + echo "\n\nNOTICE: SSH requires proper root password to be configured, set it now." + passwd +fi + diff --git a/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.server.sshd_config b/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.server.sshd_config new file mode 100644 index 0000000000..22e5dc2128 --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.server.sshd_config @@ -0,0 +1,100 @@ +# $OpenBSD: sshd_config,v 1.68 2003/12/29 16:39:50 millert Exp $ + +# This is the sshd server system-wide configuration file. See +# sshd_config(5) for more information. + +# This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin + +# The strategy used for options in the default sshd_config shipped with +# OpenSSH is to specify options with their default value where +# possible, but leave them commented. Uncommented options change a +# default value. + +#Port 22 +#Protocol 2,1 +#ListenAddress 0.0.0.0 +#ListenAddress :: + +# HostKey for protocol version 1 +#HostKey /etc/ssh_host_key +# HostKeys for protocol version 2 +#HostKey /etc/ssh_host_rsa_key +#HostKey /etc/ssh_host_dsa_key + +# Lifetime and size of ephemeral version 1 server key +#KeyRegenerationInterval 1h +#ServerKeyBits 768 + +# Logging +#obsoletes QuietMode and FascistLogging +#SyslogFacility AUTH +#LogLevel INFO + +# Authentication: + +#LoginGraceTime 2m +#PermitRootLogin yes +#StrictModes yes + +#RSAAuthentication yes +#PubkeyAuthentication yes +#AuthorizedKeysFile .ssh/authorized_keys + +# For this to work you will also need host keys in /etc/ssh_known_hosts +#RhostsRSAAuthentication no +# similar for protocol version 2 +#HostbasedAuthentication no +# Change to yes if you don't trust ~/.ssh/known_hosts for +# RhostsRSAAuthentication and HostbasedAuthentication +#IgnoreUserKnownHosts no +# Don't read the user's ~/.rhosts and ~/.shosts files +#IgnoreRhosts yes + +# To disable tunneled clear text passwords, change to no here! +#PasswordAuthentication yes +#PermitEmptyPasswords no + +# Change to no to disable s/key passwords +#ChallengeResponseAuthentication yes + +# Kerberos options +#KerberosAuthentication no +#KerberosOrLocalPasswd yes +#KerberosTicketCleanup yes +#KerberosGetAFSToken no + +# GSSAPI options +#GSSAPIAuthentication no +#GSSAPICleanupCredentials yes + +# Set this to 'yes' to enable PAM authentication (via challenge-response) +# and session processing. Depending on your PAM configuration, this may +# bypass the setting of 'PasswordAuthentication' and 'PermitEmptyPasswords' +#UsePAM no + +#AllowTcpForwarding yes +#GatewayPorts no +#X11Forwarding no +#X11DisplayOffset 10 +#X11UseLocalhost yes +#PrintMotd yes +#PrintLastLog yes +#TCPKeepAlive yes +#UseLogin no +#UsePrivilegeSeparation yes +#PermitUserEnvironment no +#Compression yes +#ClientAliveInterval 0 +#ClientAliveCountMax 3 +#UseDNS yes +#PidFile /var/run/sshd.pid +#MaxStartups 10 + +# no default banner path +#Banner /some/path + +ClientAliveInterval 15 +ClientAliveCountMax 4 + +# override default of no subsystems +Subsystem sftp /usr/sbin/sftp-server diff --git a/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.sftp-client.control b/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.sftp-client.control new file mode 100644 index 0000000000..12949f18f3 --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.sftp-client.control @@ -0,0 +1,12 @@ +Package: openssh-sftp-client +Priority: optional +Version: 3.8p1-1 +Architecture: mipsel +Maintainer: below0 +Section: net +Depends: openssh-client +Source: Embedded in the main OpenWrt buildroot +Description: OpenSSH Secure FTP server. + Includes: sftp-server + + diff --git a/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.sftp-server.control b/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.sftp-server.control new file mode 100644 index 0000000000..45f5c9aaea --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/ipkg/openssh/openssh.sftp-server.control @@ -0,0 +1,12 @@ +Package: openssh-sftp-server +Priority: optional +Version: 3.8p1-1 +Architecture: mipsel +Maintainer: below0 +Section: net +Depends: openssh-server +Source: Embedded in the main OpenWrt buildroot +Description: OpenSSH Secure FTP server. + Includes: sftp-server + + diff --git a/obsolete-buildroot/sources/openwrt/ipkg/openssl/control b/obsolete-buildroot/sources/openwrt/ipkg/openssl/control new file mode 100644 index 0000000000..cc679a6569 --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/ipkg/openssl/control @@ -0,0 +1,9 @@ +Package: openssl +Priority: optional +Version: 0.9.7d-1 +Architecture: mipsel +Maintainer: below0 +Section: libs +Source: Embedded in the main OpenWrt buildroot +Description: OpenSSL libraries used for SSL encryption. + diff --git a/obsolete-buildroot/sources/openwrt/ipkg/openssl/openssl.patch b/obsolete-buildroot/sources/openwrt/ipkg/openssl/openssl.patch new file mode 100644 index 0000000000..2e8d50f1cb --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/ipkg/openssl/openssl.patch @@ -0,0 +1,238 @@ +--- openssl-0.9.7.orig/Configure ++++ openssl-0.9.7/Configure +@@ -1,4 +1,4 @@ +-: ++#!/usr/bin/perl + eval 'exec perl -S $0 ${1+"$@"}' + if $running_under_some_shell; + ## +@@ -373,6 +373,40 @@ + # assembler versions -- currently defunct: + ##"OpenBSD-alpha","gcc:-DTERMIOS -O3 -fomit-frame-pointer:::(unknown):SIXTY_FOUR_BIT_LONG DES_INT DES_PTR DES_RISC2:${alpha_asm}", + ++# Sane Linux configuration values, stolen from the Debian package.... ++"linux-alpha","gcc:-DTERMIO -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_RISC1 DES_UNROLL:${alpha_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++"linux-alpha-ev4","gcc:-DTERMIO -O3 -mcpu=ev4 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_RISC1 DES_UNROLL:${alpha_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++"linux-alpha-ev5","gcc:-DTERMIO -O3 -mcpu=ev5 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_RISC1 DES_UNROLL:${alpha_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++"linux-arm","gcc:-DL_ENDIAN -DTERMIO -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG DES_RISC1::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++"linux-freebsd-alpha","gcc:-DTERMIOS -O -fomit-frame-pointer::(unknown):::SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_INT DES_PTR DES_RISC2::::::::::dlfcn:bsd-gcc-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++"linux-freebsd-i386", "gcc:-DTERMIOS -DL_ENDIAN -fomit-frame-pointer -O3 -m486 -Wall::-pthread -D_REENTRANT -D_THREAD_SAFE -D_THREADSAFE:::BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:${x86_elf_asm}:dlfcn:bsd-gcc-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++"linux-hppa","gcc:-DB_ENDIAN -DTERMIO -O2 -Wall::-D_REENTRANT::-ldl:BN_LLONG MD2_CHAR RC4_INDEX::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++"linux-hurd-i386","gcc:-DL_ENDIAN -DTERMIOS -O3 -fomit-frame-pointer -m486 -Wall::-D_REENTRANT::-ldl:BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:${x86_elf_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++"linux-ia64","gcc:-DTERMIO -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC4_CHUNK RC4_CHAR:asm/ia64.o:::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++#"linux-i386","gcc:-DL_ENDIAN -DTERMIO -O3 -fomit-frame-pointer -m486 -Wall::-D_REENTRANT::-ldl:BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}::::::::::dlfcn:linux-shared:-fPIC", ++"linux-i386","gcc:-DL_ENDIAN -DTERMIO -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++"linux-i386-i486","gcc:-DL_ENDIAN -DTERMIO -O3 -march=i486 -mcpu=i486 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:${x86_elf_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++"linux-i386-i586","gcc:-DL_ENDIAN -DTERMIO -O3 -march=i586 -mcpu=i586 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:${x86_elf_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++"linux-i386-i686/cmov","gcc:-DL_ENDIAN -DTERMIO -O3 -march=i686 -mcpu=i686 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:${x86_elf_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++"linux-m68k","gcc:-DB_ENDIAN -DTERMIO -O2 -Wall::-D_REENTRANT::-ldl:BN_LLONG MD2_CHAR RC4_INDEX::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++"linux-mips", "gcc:-DB_ENDIAN -DTERMIO -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++"linux-mipsel", "gcc:-DL_ENDIAN -DTERMIO -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++"linux-netbsd-i386", "gcc:-DL_ENDIAN -DTERMIOS -O3 -fomit-frame-pointer -m486 -Wall::(unknown):::BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}::::::::::dlfcn:bsd-gcc-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++"linux-netbsd-m68k", "gcc:-DB_ENDIAN -DTERMIOS -O3 -fomit-frame-pointer -Wall::(unknown):::BN_LLONG MD2_CHAR RC4_INDEX DES_UNROLL::::::::::dlfcn:bsd-gcc-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++"linux-netbsd-sparc", "gcc:-DB_ENDIAN -DTERMIOS -O3 -fomit-frame-pointer -mv8 -Wall::(unknown):::BN_LLONG MD2_CHAR RC4_INDEX DES_UNROLL::::::::::dlfcn:bsd-gcc-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++"linux-openbsd-alpha","gcc:-DTERMIOS -O3 -fomit-frame-pointer::(unknown):::SIXTY_FOUR_BIT_LONG DES_INT DES_PTR DES_RISC2::::::::::dlfcn:bsd-gcc-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++"linux-openbsd-i386", "gcc:-DL_ENDIAN -DTERMIOS -O3 -fomit-frame-pointer -m486::(unknown):::BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:${x86_out_asm}:dlfcn:bsd-gcc-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++"linux-openbsd-mips","gcc:-O2 -DL_ENDIAN::(unknown)::BN_LLONG MD2_CHAR RC4_INDEX RC4_CHAR DES_UNROLL DES_RISC2 DES_PTR BF_PTR:::::::::::dlfcn:bsd-gcc-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++"linux-powerpc","gcc:-DB_ENDIAN -DTERMIO -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG DES_UNROLL DES_RISC2 DES_PTR MD2_CHAR RC4_INDEX::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++"linux-s390","gcc:-DB_ENDIAN -DTERMIO -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++"linux-sh3", "gcc:-DL_ENDIAN -DTERMIO -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++"linux-sh4", "gcc:-DL_ENDIAN -DTERMIO -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++"linux-sh3eb", "gcc:-DB_ENDIAN -DTERMIO -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++"linux-sh4eb", "gcc:-DB_ENDIAN -DTERMIO -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++"linux-sparc","gcc:-DB_ENDIAN -DTERMIO -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_UNROLL BF_PTR::::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++"linux-sparc-v8","gcc:-DB_ENDIAN -DTERMIO -O3 -mcpu=v8 -fomit-frame-pointer -Wall -DBN_DIV2W::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_UNROLL BF_PTR:asm/sparcv8.o:::::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++"linux-sparc-v9","gcc:-DB_ENDIAN -DTERMIO -O3 -mcpu=v9 -Wa,-Av8plus -fomit-frame-pointer -Wall -DULTRASPARC -DBN_DIV2W::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_UNROLL BF_PTR:asm/sparcv8plus.o:::asm/md5-sparcv8plus.o::::::dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", ++"linux-cris", "gcc:-DL_ENDIAN -DTERMIO -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG::::::::::dlfcn:linux-shared:-fpic::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", + # The intel boxes :-), It would be worth seeing if bsdi-gcc can use the + # bn86-elf.o file file since it is hand tweaked assembler. + "linux-elf", "gcc:-DL_ENDIAN -DTERMIO -O3 -fomit-frame-pointer -m486 -Wall::-D_REENTRANT::-ldl:BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:${x86_elf_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)", +--- openssl-0.9.7.orig/crypto/md5/asm/md5-sparcv9.S ++++ openssl-0.9.7/crypto/md5/asm/md5-sparcv9.S +@@ -72,14 +72,14 @@ + #define Dval R8 + + #if defined(MD5_BLOCK_DATA_ORDER) +-# if defined(OPENSSL_SYSNAME_ULTRASPARC) ++/*# if defined(OPENSSL_SYSNAME_ULTRASPARC)*/ + # define LOAD lda + # define X(i) [%i1+i*4]%asi + # define md5_block md5_block_asm_data_order_aligned + # define ASI_PRIMARY_LITTLE 0x88 +-# else ++/*# else + # error "MD5_BLOCK_DATA_ORDER is supported only on UltraSPARC!" +-# endif ++# endif*/ + #else + # define LOAD ld + # define X(i) [%i1+i*4] +--- openssl-0.9.7.orig/crypto/opensslconf.h ++++ openssl-0.9.7/crypto/opensslconf.h +@@ -4,17 +4,38 @@ + /* OpenSSL was configured with the following options: */ + #ifndef OPENSSL_DOING_MAKEDEPEND + ++#ifndef OPENSSL_NO_IDEA ++# define OPENSSL_NO_IDEA ++#endif ++#ifndef OPENSSL_NO_MDC2 ++# define OPENSSL_NO_MDC2 ++#endif ++#ifndef OPENSSL_NO_RC5 ++# define OPENSSL_NO_RC5 ++#endif + #ifndef OPENSSL_NO_KRB5 + # define OPENSSL_NO_KRB5 + #endif + + #endif /* OPENSSL_DOING_MAKEDEPEND */ ++#ifndef OPENSSL_THREADS ++# define OPENSSL_THREADS ++#endif + + /* The OPENSSL_NO_* macros are also defined as NO_* if the application + asks for it. This is a transient feature that is provided for those + who haven't had the time to do the appropriate changes in their + applications. */ + #ifdef OPENSSL_ALGORITHM_DEFINES ++# if defined(OPENSSL_NO_IDEA) && !defined(NO_IDEA) ++# define NO_IDEA ++# endif ++# if defined(OPENSSL_NO_MDC2) && !defined(NO_MDC2) ++# define NO_MDC2 ++# endif ++# if defined(OPENSSL_NO_RC5) && !defined(NO_RC5) ++# define NO_RC5 ++# endif + # if defined(OPENSSL_NO_KRB5) && !defined(NO_KRB5) + # define NO_KRB5 + # endif +@@ -27,7 +48,7 @@ + + #if !(defined(VMS) || defined(__VMS)) /* VMS uses logical names instead */ + #if defined(HEADER_CRYPTLIB_H) && !defined(OPENSSLDIR) +-#define OPENSSLDIR "/usr/local/ssl" ++#define OPENSSLDIR "/usr/lib/ssl" + #endif + #endif + +@@ -79,7 +100,7 @@ + + #if defined(HEADER_BN_H) && !defined(CONFIG_HEADER_BN_H) + #define CONFIG_HEADER_BN_H +-#undef BN_LLONG ++#define BN_LLONG + + /* Should we define BN_DIV2W here? */ + +@@ -98,7 +119,7 @@ + #define CONFIG_HEADER_RC4_LOCL_H + /* if this is defined data[i] is used instead of *data, this is a %20 + * speedup on x86 */ +-#undef RC4_INDEX ++#define RC4_INDEX + #endif + + #if defined(HEADER_BF_LOCL_H) && !defined(CONFIG_HEADER_BF_LOCL_H) +@@ -112,14 +133,14 @@ + /* the following is tweaked from a config script, that is why it is a + * protected undef/define */ + #ifndef DES_PTR +-#undef DES_PTR ++#define DES_PTR + #endif + + /* This helps C compiler generate the correct code for multiple functional + * units. It reduces register dependancies at the expense of 2 more + * registers */ + #ifndef DES_RISC1 +-#undef DES_RISC1 ++#define DES_RISC1 + #endif + + #ifndef DES_RISC2 +@@ -133,7 +154,7 @@ + /* Unroll the inner loop, this sometimes helps, sometimes hinders. + * Very mucy CPU dependant */ + #ifndef DES_UNROLL +-#undef DES_UNROLL ++#define DES_UNROLL + #endif + + /* These default values were supplied by +--- openssl-0.9.7.orig/ssl/ssl_algs.c ++++ openssl-0.9.7/ssl/ssl_algs.c +@@ -109,3 +109,8 @@ + return(1); + } + ++#undef SSLeay_add_ssl_algorithms ++int SSLeay_add_ssl_algorithms(void) ++ { ++ return SSL_library_init(); ++ } +--- openssl-0.9.7.orig/tools/c_rehash.in ++++ openssl-0.9.7/tools/c_rehash.in +@@ -1,4 +1,4 @@ +-#!/usr/local/bin/perl ++#!/usr/bin/perl + + + # Perl c_rehash script, scan all files in a directory +--- openssl-0.9.7.orig/util/clean-depend.pl ++++ openssl-0.9.7/util/clean-depend.pl +@@ -1,4 +1,4 @@ +-#!/usr/local/bin/perl -w ++#!/usr/bin/perl + # Clean the dependency list in a makefile of standard includes... + # Written by Ben Laurie <ben@algroup.co.uk> 19 Jan 1999 + +--- openssl-0.9.7.orig/util/extract-names.pl ++++ openssl-0.9.7/util/extract-names.pl +@@ -1,4 +1,4 @@ +-#!/usr/bin/perl ++#!/usr/bin/perl + + $/ = ""; # Eat a paragraph at once. + while(<STDIN>) { +--- openssl-0.9.7.orig/util/mkdef.pl ++++ openssl-0.9.7/util/mkdef.pl +@@ -1,4 +1,4 @@ +-#!/usr/local/bin/perl -w ++#!/usr/bin/perl + # + # generate a .def file + # +--- openssl-0.9.7.orig/util/mkerr.pl ++++ openssl-0.9.7/util/mkerr.pl +@@ -1,4 +1,4 @@ +-#!/usr/local/bin/perl -w ++#!/usr/bin/perl + + my $config = "crypto/err/openssl.ec"; + my $debug = 0; +--- openssl-0.9.7.orig/util/mkstack.pl ++++ openssl-0.9.7/util/mkstack.pl +@@ -1,4 +1,4 @@ +-#!/usr/local/bin/perl -w ++#!/usr/bin/perl + + # This is a utility that searches out "DECLARE_STACK_OF()" + # declarations in .h and .c files, and updates/creates/replaces +--- openssl-0.9.7.orig/util/pod2man.pl ++++ openssl-0.9.7/util/pod2man.pl +@@ -1,4 +1,4 @@ +-: #!/usr/bin/perl-5.005 ++#!/usr/bin/perl + eval 'exec /usr/bin/perl -S $0 ${1+"$@"}' + if $running_under_some_shell; + +--- openssl-0.9.7.orig/util/selftest.pl ++++ openssl-0.9.7/util/selftest.pl +@@ -1,4 +1,4 @@ +-#!/usr/local/bin/perl -w ++#!/usr/bin/perl + # + # Run the test suite and generate a report + # diff --git a/obsolete-buildroot/sources/openwrt/ipkg/pppoecd/CONTROL/conffiles b/obsolete-buildroot/sources/openwrt/ipkg/pppoecd/CONTROL/conffiles new file mode 100644 index 0000000000..7ebe1156e0 --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/ipkg/pppoecd/CONTROL/conffiles @@ -0,0 +1 @@ +/etc/ppp/ip-up diff --git a/obsolete-buildroot/sources/openwrt/ipkg/pppoecd/CONTROL/control b/obsolete-buildroot/sources/openwrt/ipkg/pppoecd/CONTROL/control new file mode 100644 index 0000000000..6996b8ecab --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/ipkg/pppoecd/CONTROL/control @@ -0,0 +1,10 @@ +Package: pppoecd +Priority: optional +Version: 1.0 +Architecture: mipsel +Maintainer: below0 +Section: net +Source: Embedded in the main openwrt tarball +Description: Linksys PPPoE daemon for access to internet using DSL modems + + diff --git a/obsolete-buildroot/sources/openwrt/ipkg/pppoecd/CONTROL/postrm b/obsolete-buildroot/sources/openwrt/ipkg/pppoecd/CONTROL/postrm new file mode 100644 index 0000000000..0d53d99f0f --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/ipkg/pppoecd/CONTROL/postrm @@ -0,0 +1,4 @@ +#!/bin/sh + +rm -rf /etc/ppp + diff --git a/obsolete-buildroot/sources/openwrt/ipkg/pppoecd/CONTROL/prerm b/obsolete-buildroot/sources/openwrt/ipkg/pppoecd/CONTROL/prerm new file mode 100644 index 0000000000..092bf00640 --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/ipkg/pppoecd/CONTROL/prerm @@ -0,0 +1,5 @@ +#!/bin/sh + +killall pppoecd +sleep 3 +killall -9 pppoecd
\ No newline at end of file diff --git a/obsolete-buildroot/sources/openwrt/ipkg/pppoecd/pppoecd-pathnames.patch b/obsolete-buildroot/sources/openwrt/ipkg/pppoecd/pppoecd-pathnames.patch new file mode 100644 index 0000000000..e6c1099674 --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/ipkg/pppoecd/pppoecd-pathnames.patch @@ -0,0 +1,66 @@ +--- pathnames.h.orig Tue Oct 14 03:09:53 2003 ++++ pathnames.h Sat Jul 10 21:04:34 2004 +@@ -9,37 +9,37 @@ + + #else /* HAVE_PATHS_H */ + #ifndef _PATH_VARRUN +-#define _PATH_VARRUN "/tmp/ppp/" ++#define _PATH_VARRUN "/var/run" + #endif + #define _PATH_DEVNULL "/dev/null" + #endif /* HAVE_PATHS_H */ + + #ifndef _ROOT_PATH +-#define _ROOT_PATH ++#define _ROOT_PATH "/etc" + #endif + +-#define _PATH_UPAPFILE _ROOT_PATH "/tmp/ppp/pap-secrets" +-#define _PATH_CHAPFILE _ROOT_PATH "/tmp/ppp/chap-secrets" +-#define _PATH_SYSOPTIONS _ROOT_PATH "/tmp/ppp/options" +-#define _PATH_IPUP _ROOT_PATH "/tmp/ppp/ip-up" +-#define _PATH_IPDOWN _ROOT_PATH "/tmp/ppp/ip-down" +-#define _PATH_AUTHUP _ROOT_PATH "/tmp/ppp/auth-up" +-#define _PATH_AUTHDOWN _ROOT_PATH "/tmp/ppp/auth-down" +-#define _PATH_TTYOPT _ROOT_PATH "/tmp/ppp/options." +-#define _PATH_CONNERRS _ROOT_PATH "/tmp/ppp/connect-errors" +-#define _PATH_PEERFILES _ROOT_PATH "/tmp/ppp/peers/" +-#define _PATH_RESOLV _ROOT_PATH "/tmp/ppp/resolv.conf" ++#define _PATH_UPAPFILE _ROOT_PATH "/ppp/pap-secrets" ++#define _PATH_CHAPFILE _ROOT_PATH "/ppp/chap-secrets" ++#define _PATH_SYSOPTIONS _ROOT_PATH "/ppp/options" ++#define _PATH_IPUP _ROOT_PATH "/ppp/ip-up" ++#define _PATH_IPDOWN _ROOT_PATH "/ppp/ip-down" ++#define _PATH_AUTHUP _ROOT_PATH "/ppp/auth-up" ++#define _PATH_AUTHDOWN _ROOT_PATH "/ppp/auth-down" ++#define _PATH_TTYOPT _ROOT_PATH "/ppp/options." ++#define _PATH_CONNERRS "/tmp/connect-errors" ++#define _PATH_PEERFILES _ROOT_PATH "/ppp/peers/" ++#define _PATH_RESOLV "/tmp/resolv.conf" + + #define _PATH_USEROPT ".ppprc" + + #ifdef INET6 +-#define _PATH_IPV6UP _ROOT_PATH "/tmp/ppp/ipv6-up" +-#define _PATH_IPV6DOWN _ROOT_PATH "/tmp/ppp/ipv6-down" ++#define _PATH_IPV6UP _ROOT_PATH "/ppp/ipv6-up" ++#define _PATH_IPV6DOWN _ROOT_PATH "/ppp/ipv6-down" + #endif + + #ifdef IPX_CHANGE +-#define _PATH_IPXUP _ROOT_PATH "/tmp/ppp/ipx-up" +-#define _PATH_IPXDOWN _ROOT_PATH "/tmp/ppp/ipx-down" ++#define _PATH_IPXUP _ROOT_PATH "/ppp/ipx-up" ++#define _PATH_IPXDOWN _ROOT_PATH "/ppp/ipx-down" + #endif /* IPX_CHANGE */ + + #ifdef __STDC__ +@@ -48,7 +48,7 @@ + #ifdef HAVE_PATHS_H + #define _PATH_PPPDB "/var/run/pppd.tdb" + #else +-#define _PATH_PPPDB "/tmp/ppp/pppd.tdb" ++#define _PATH_PPPDB "/tmp/pppd.tdb" + #endif + #endif /* __STDC__ */ + diff --git a/obsolete-buildroot/sources/openwrt/ipkg/pppoecd/pppoecd.patch b/obsolete-buildroot/sources/openwrt/ipkg/pppoecd/pppoecd.patch new file mode 100644 index 0000000000..4fa4afc254 --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/ipkg/pppoecd/pppoecd.patch @@ -0,0 +1,27 @@ +--- pppoe.c.orig Sat Jul 10 20:55:38 2004 ++++ pppoe.c Sat Jul 10 20:55:55 2004 +@@ -131,8 +131,7 @@ + + if (pppoe_srv_name !=NULL) { + if (strlen (pppoe_srv_name) > 255) { +- poe_error (ses," Service name too long +- (maximum allowed 256 chars)"); ++ poe_error (ses," Service name too long (maximum allowed 256 chars)"); + poe_die(-1); + } + ses->filt->stag = make_filter_tag(PTT_SRV_NAME, +--- Makefile.orig Sun Jul 11 03:26:49 2004 ++++ Makefile Sun Jul 11 03:27:18 2004 +@@ -68,9 +68,9 @@ + all: pppoecd + + install: all +- install -d $(INSTALLDIR)/usr/sbin +- install -m 755 pppoecd $(INSTALLDIR)/usr/sbin +- $(STRIP) $(INSTALLDIR)/usr/sbin/pppoecd ++ install -d $(INSTALLDIR)/sbin ++ install -m 755 pppoecd $(INSTALLDIR)/sbin ++ $(STRIP) $(INSTALLDIR)/sbin/pppoecd + + pppoecd: $(OBJS) + $(LD) -r -o .$@ $^ $(LIBCRYPT) diff --git a/obsolete-buildroot/sources/openwrt/ipkg/pppoecd/root/etc/ppp/ip-up b/obsolete-buildroot/sources/openwrt/ipkg/pppoecd/root/etc/ppp/ip-up new file mode 100644 index 0000000000..da432949e7 --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/ipkg/pppoecd/root/etc/ppp/ip-up @@ -0,0 +1,5 @@ +#!/bin/sh + +# set default route +/sbin/route add default gw $IPREMOTE + diff --git a/obsolete-buildroot/sources/openwrt/ipkg/zlib/control b/obsolete-buildroot/sources/openwrt/ipkg/zlib/control new file mode 100644 index 0000000000..608176d812 --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/ipkg/zlib/control @@ -0,0 +1,10 @@ +Package: zlib +Priority: optional +Version: 1.1.4-1 +Architecture: mipsel +Maintainer: below0 +Section: libs +Source: Embedded in the main OpenWrt buildroot +Description: zlib is a library implementing the 'deflate' compression system used by many programs. + + diff --git a/obsolete-buildroot/sources/openwrt/kernel/compressed-20040531.tar.bz2 b/obsolete-buildroot/sources/openwrt/kernel/compressed-20040531.tar.bz2 Binary files differnew file mode 100644 index 0000000000..c8e06b8a9b --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/kernel/compressed-20040531.tar.bz2 diff --git a/obsolete-buildroot/sources/openwrt/kernel/diag.c b/obsolete-buildroot/sources/openwrt/kernel/diag.c new file mode 100644 index 0000000000..6d93542f84 --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/kernel/diag.c @@ -0,0 +1,145 @@ +// replacement diag module +// (c) 2004 openwrt +// mbm at alt dot org +// +// initial release 2004/03/28 + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/timer.h> +#include <linux/sysctl.h> +#include <asm/io.h> +#include <typedefs.h> +#include <bcm4710.h> +#include <sbutils.h> + +static void *sbh; + +// v2.x - - - - - +#define DIAG_GPIO (1<<1) +#define DMZ_GPIO (1<<7) + +static void set_gpio(uint32 mask, uint32 value) { + sb_gpiocontrol(sbh,mask,0); + sb_gpioouten(sbh,mask,mask); + sb_gpioout(sbh,mask,value); +} + +static void v2_set_diag(u8 state) { + set_gpio(DIAG_GPIO,state); +} +static void v2_set_dmz(u8 state) { + set_gpio(DMZ_GPIO,state); +} + +// v1.x - - - - - +#define LED_DIAG 0x13 +#define LED_DMZ 0x12 + +static void v1_set_diag(u8 state) { + if (!state) { + *(volatile u8*)(KSEG1ADDR(BCM4710_EUART)+LED_DIAG)=0xFF; + } else { + *(volatile u8*)(KSEG1ADDR(BCM4710_EUART)+LED_DIAG); + } +} +static void v1_set_dmz(u8 state) { + if (!state) { + *(volatile u8*)(KSEG1ADDR(BCM4710_EUART)+LED_DMZ)=0xFF; + } else { + *(volatile u8*)(KSEG1ADDR(BCM4710_EUART)+LED_DMZ); + } +} + +// - - - - - +static void ignore(u8 ignored) {}; + +// - - - - - +#define BIT_DMZ 0x01 +#define BIT_DIAG 0x04 + +void (*set_diag)(u8 state); +void (*set_dmz)(u8 state); + +static unsigned int diag = 0; +static struct timer_list timer; + +static void diag_change() +{ + printk(KERN_INFO "led -> %02x\n",diag); + + set_diag(0xFF); // off + set_dmz(0xFF); // off + + if(diag & BIT_DIAG) + set_diag(0x00); // on + if(diag & BIT_DMZ) + set_dmz(0x00); // on +} + +static int proc_diag(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + int r; + r = proc_dointvec(table, write, filp, buffer, lenp); + if (write && !r) { + diag_change(); + } + return r; +} + +// - - - - - +static struct ctl_table_header *diag_sysctl_header; + +static ctl_table sys_diag[] = { + { + ctl_name: 2000, + procname: "diag", + data: &diag, + maxlen: sizeof(diag), + mode: 0644, + proc_handler: proc_diag + }, + { 0 } +}; + +static int __init diag_init() +{ + u32 board_type; + sbh = sb_kattach(); + sb_gpiosetcore(sbh); + + board_type = sb_boardtype(sbh); + printk(KERN_INFO "diag board_type: %08x\n",board_type); + + if (board_type & 0x400) { + set_diag=v1_set_diag; + set_dmz=v1_set_dmz; + if (board_type==0x41d) { + printk(KERN_INFO "buffalo hack.\n"); + set_diag=ignore; + set_dmz=v2_set_dmz; + } + board_type=1; + } else { + board_type=2; + set_diag=v2_set_diag; + set_dmz=v2_set_dmz; + } + printk(KERN_INFO "using v%d hardware\n",board_type); + + diag_sysctl_header = register_sysctl_table(sys_diag, 0); + diag_change(); + + return 0; +} + +static void __exit diag_exit() +{ + unregister_sysctl_table(diag_sysctl_header); + del_timer(&timer); +} + +module_init(diag_init); +module_exit(diag_exit); diff --git a/obsolete-buildroot/sources/openwrt/kernel/linux.config b/obsolete-buildroot/sources/openwrt/kernel/linux.config new file mode 100644 index 0000000000..69e7c6e7e1 --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/kernel/linux.config @@ -0,0 +1,872 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_MIPS=y +CONFIG_MIPS32=y +# CONFIG_MIPS64 is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# +# Machine selection +# +# CONFIG_ACER_PICA_61 is not set +# CONFIG_MIPS_DB1000 is not set +# CONFIG_MIPS_DB1100 is not set +# CONFIG_MIPS_DB1500 is not set +# CONFIG_MIPS_PB1000 is not set +# CONFIG_MIPS_PB1100 is not set +# CONFIG_MIPS_PB1500 is not set +# CONFIG_BAGET_MIPS is not set +# CONFIG_CASIO_E55 is not set +# CONFIG_MIPS_COBALT is not set +# CONFIG_DECSTATION is not set +# CONFIG_MIPS_EV64120 is not set +# CONFIG_MIPS_EV96100 is not set +# CONFIG_MIPS_IVR is not set +# CONFIG_HP_LASERJET is not set +# CONFIG_IBM_WORKPAD is not set +# CONFIG_LASAT is not set +# CONFIG_MIPS_ITE8172 is not set +# CONFIG_MIPS_ATLAS is not set +# CONFIG_MIPS_MAGNUM_4000 is not set +# CONFIG_MIPS_MALTA is not set +# CONFIG_MIPS_SEAD is not set +# CONFIG_MOMENCO_OCELOT is not set +# CONFIG_MOMENCO_OCELOT_G is not set +# CONFIG_DDB5074 is not set +# CONFIG_DDB5476 is not set +# CONFIG_DDB5477 is not set +# CONFIG_NEC_OSPREY is not set +# CONFIG_NEC_EAGLE is not set +# CONFIG_OLIVETTI_M700 is not set +# CONFIG_NINO is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SGI_IP27 is not set +# CONFIG_SGI_IP32 is not set +# CONFIG_SIBYTE_SB1xxx_SOC is not set +CONFIG_MIPS_BRCM=y +CONFIG_BCM947XX=y +CONFIG_BCM4710=y +CONFIG_BCM4310=y +CONFIG_BCM4704=y +# CONFIG_BCM5365 is not set +# CONFIG_SNI_RM200_PCI is not set +# CONFIG_TOSHIBA_JMR3927 is not set +# CONFIG_VICTOR_MPC30X is not set +# CONFIG_ZAO_CAPCELLA is not set +# CONFIG_HIGHMEM is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_CMDLINE="root=/dev/mtdblock2 rootfstype=squashfs init=/etc/preinit noinitrd console=ttyS0,115200" +CONFIG_PCI=y +CONFIG_NONCOHERENT_IO=y +CONFIG_NEW_TIME_C=y +CONFIG_NEW_IRQ=y +CONFIG_HND=y +# CONFIG_MIPS_AU1000 is not set + +# +# CPU selection +# +CONFIG_CPU_MIPS32=y +# CONFIG_CPU_MIPS64 is not set +# CONFIG_CPU_R3000 is not set +# CONFIG_CPU_TX39XX is not set +# CONFIG_CPU_VR41XX is not set +# CONFIG_CPU_R4300 is not set +# CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_TX49XX is not set +# CONFIG_CPU_R5000 is not set +# CONFIG_CPU_R5432 is not set +# CONFIG_CPU_R6000 is not set +# CONFIG_CPU_NEVADA is not set +# CONFIG_CPU_R8000 is not set +# CONFIG_CPU_R10000 is not set +# CONFIG_CPU_RM7000 is not set +# CONFIG_CPU_SB1 is not set +CONFIG_CPU_HAS_PREFETCH=y +# CONFIG_VTAG_ICACHE is not set +# CONFIG_64BIT_PHYS_ADDR is not set +# CONFIG_CPU_ADVANCED is not set +CONFIG_CPU_HAS_LLSC=y +# CONFIG_CPU_HAS_LLDSCD is not set +# CONFIG_CPU_HAS_WB is not set +CONFIG_CPU_HAS_SYNC=y + +# +# General setup +# +CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_NET=y +# CONFIG_PCI_NAMES is not set +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_TC is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_HOTPLUG=y + +# +# PCMCIA/CardBus support +# +# CONFIG_PCMCIA is not set + +# +# PCI Hotplug Support +# +# CONFIG_HOTPLUG_PCI is not set +# CONFIG_HOTPLUG_PCI_COMPAQ is not set +# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set +# CONFIG_HOTPLUG_PCI_ACPI is not set +# CONFIG_SYSVIPC is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_PRINT_SYSCALLS is not set +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_MIPS32_COMPAT is not set +# CONFIG_MIPS32_O32 is not set +# CONFIG_MIPS32_N32 is not set +# CONFIG_BINFMT_ELF32 is not set +# CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_CONCAT is not set +# CONFIG_MTD_REDBOOT_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +# CONFIG_MTD_BLOCK is not set +CONFIG_MTD_BLOCK_RO=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_GEOMETRY=y +# CONFIG_MTD_CFI_B1 is not set +CONFIG_MTD_CFI_B2=y +# CONFIG_MTD_CFI_B4 is not set +CONFIG_MTD_CFI_I1=y +# CONFIG_MTD_CFI_I2 is not set +# CONFIG_MTD_CFI_I4 is not set +CONFIG_MTD_CFI_INTELEXT=y +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_CFI_SSTSTD=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set +# CONFIG_MTD_AMDSTD is not set +# CONFIG_MTD_SHARP is not set +# CONFIG_MTD_JEDEC is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_PHYSMAP is not set +CONFIG_MTD_BCM947XX=y +# CONFIG_MTD_PB1000 is not set +# CONFIG_MTD_PB1500 is not set +# CONFIG_MTD_PB1100 is not set +# CONFIG_MTD_CSTM_MIPS_IXX is not set +# CONFIG_MTD_OCELOT is not set +# CONFIG_MTD_LASAT is not set +# CONFIG_MTD_PCI is not set + +# +# Self-contained MTD device drivers +# +CONFIG_MTD_SFLASH=y +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC1000 is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOCPROBE is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_MSYS is not set +# CONFIG_NOROOT is not set +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_NBD=m +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_BLK_STATS is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_NETLINK_DEV=m +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_NETSWAP=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_FWMARK=y +CONFIG_IP_ROUTE_NAT=y +# CONFIG_IP_ROUTE_MULTIPATH is not set +CONFIG_IP_ROUTE_TOS=y +# CONFIG_IP_ROUTE_VERBOSE is not set +# CONFIG_IP_ROUTE_LARGE_TABLES is not set +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=y +CONFIG_IP_NF_FTP=y +CONFIG_IP_NF_H323=y +CONFIG_IP_NF_CONNTRACK_MARK=y +# CONFIG_IP_NF_AMANDA is not set +CONFIG_IP_NF_TFTP=y +CONFIG_IP_NF_IRC=y +CONFIG_IP_NF_CT_PROTO_GRE=y +CONFIG_IP_NF_PPTP=y +CONFIG_IP_NF_MMS=y +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_LIMIT=m +CONFIG_IP_NF_SET=m +CONFIG_IP_NF_SET_MAX=256 +CONFIG_IP_NF_SET_IPMAP=m +CONFIG_IP_NF_SET_PORTMAP=m +CONFIG_IP_NF_SET_MACIPMAP=m +CONFIG_IP_NF_SET_IPHASH=m +CONFIG_IP_NF_MATCH_QUOTA=m +CONFIG_IP_NF_POOL=m +CONFIG_IP_POOL_STATISTICS=y +CONFIG_IP_NF_MATCH_IPRANGE=m +CONFIG_IP_NF_MATCH_DSTLIMIT=m +CONFIG_IP_NF_MATCH_MAC=m +CONFIG_IP_NF_MATCH_PKTTYPE=m +CONFIG_IP_NF_MATCH_MARK=y +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_CONDITION=m +# CONFIG_IP_NF_MATCH_RANDOM is not set +CONFIG_IP_NF_MATCH_PSD=m +# CONFIG_IP_NF_MATCH_OSF is not set +# CONFIG_IP_NF_MATCH_NTH is not set +CONFIG_IP_NF_MATCH_IPV4OPTIONS=m +# CONFIG_IP_NF_MATCH_FUZZY is not set +CONFIG_IP_NF_MATCH_RECENT=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_DSCP=m +CONFIG_IP_NF_MATCH_AH_ESP=m +CONFIG_IP_NF_MATCH_LENGTH=m +# CONFIG_IP_NF_MATCH_U32 is not set +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_TCPMSS=y +# CONFIG_IP_NF_MATCH_REALM is not set +CONFIG_IP_NF_MATCH_HELPER=m +CONFIG_IP_NF_MATCH_STATE=y +CONFIG_IP_NF_MATCH_CONNMARK=m +CONFIG_IP_NF_MATCH_CONNLIMIT=m +CONFIG_IP_NF_MATCH_CONNTRACK=m +CONFIG_IP_NF_MATCH_UNCLEAN=m +CONFIG_IP_NF_MATCH_STRING=m +# CONFIG_IP_NF_MATCH_OWNER is not set +CONFIG_IP_NF_MATCH_PHYSDEV=m +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_TARGET_NETLINK=m +CONFIG_IP_NF_TARGET_IPV4OPTSSTRIP=m +CONFIG_IP_NF_TARGET_MIRROR=m +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_NAT_H323=y +# CONFIG_IP_NF_TARGET_SAME is not set +# CONFIG_IP_NF_TARGET_NETMAP is not set +CONFIG_IP_NF_NAT_PPTP=y +CONFIG_IP_NF_NAT_PROTO_GRE=y +# CONFIG_IP_NF_NAT_LOCAL is not set +CONFIG_IP_NF_NAT_SNMP_BASIC=m +CONFIG_IP_NF_NAT_IRC=y +CONFIG_IP_NF_NAT_MMS=y +CONFIG_IP_NF_NAT_FTP=y +CONFIG_IP_NF_NAT_TFTP=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_DSCP=m +CONFIG_IP_NF_TARGET_MARK=y +CONFIG_IP_NF_TARGET_IPMARK=m +CONFIG_IP_NF_TARGET_CLASSIFY=m +CONFIG_IP_NF_TARGET_LOG=y +CONFIG_IP_NF_TARGET_CONNMARK=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_NF_TARGET_TCPMSS=y +# CONFIG_IP_NF_RAW is not set +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m +CONFIG_IPV6=m + +# +# IPv6: Netfilter Configuration +# +CONFIG_IP6_NF_QUEUE=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_LIMIT=m +CONFIG_IP6_NF_MATCH_MAC=m +# CONFIG_IP6_NF_MATCH_RANDOM is not set +# CONFIG_IP6_NF_MATCH_NTH is not set +# CONFIG_IP6_NF_MATCH_FUZZY is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_HL is not set +CONFIG_IP6_NF_MATCH_MULTIPORT=m +CONFIG_IP6_NF_MATCH_OWNER=m +CONFIG_IP6_NF_MATCH_MARK=m +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +# CONFIG_IP6_NF_MATCH_AHESP is not set +CONFIG_IP6_NF_MATCH_LENGTH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_REJECT=m +# CONFIG_IP6_NF_TARGET_HL is not set +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_TARGET_MARK=m +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +CONFIG_VLAN_8021Q=y + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +CONFIG_BRIDGE=y +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_BRIDGE_EBT_IPF=m +CONFIG_BRIDGE_EBT_ARPF=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_VLANF=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_MARKF=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_MARK_T=m +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +CONFIG_WAN_ROUTER=m +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_CSZ=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_QOS=y +CONFIG_NET_ESTIMATOR=y +CONFIG_NET_CLS=y +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_POLICE=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set +# CONFIG_PHONE_IXJ is not set +# CONFIG_PHONE_IXJ_PCMCIA is not set + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# Broadcom HND network devices +# +CONFIG_HND=y +# CONFIG_IL is not set +CONFIG_ET=m +# CONFIG_ET_4413 is not set +CONFIG_ET_47XX=y +CONFIG_WL=m +CONFIG_WL_AP=y +CONFIG_WL_STA=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +CONFIG_PPP=y +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_ASYNC=y +# CONFIG_PPP_SYNC_TTY is not set +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPPOE=m +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y +# CONFIG_STRIP is not set +# CONFIG_WAVELAN is not set +# CONFIG_ARLAN is not set +# CONFIG_AIRONET4500 is not set +# CONFIG_AIRONET4500_NONCS is not set +# CONFIG_AIRONET4500_PROC is not set +# CONFIG_AIRO is not set +# CONFIG_HERMES is not set +# CONFIG_PLX_HERMES is not set +# CONFIG_PCI_HERMES is not set +CONFIG_NET_WIRELESS=y + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +CONFIG_SHAPER=m + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input core support +# +# CONFIG_INPUT is not set +# CONFIG_INPUT_KEYBDEV is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=128 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_NOWAYOUT=y +# CONFIG_ACQUIRE_WDT is not set +# CONFIG_ADVANTECH_WDT is not set +# CONFIG_ALIM7101_WDT is not set +# CONFIG_SC520_WDT is not set +# CONFIG_PCWATCHDOG is not set +# CONFIG_EUROTECH_WDT is not set +# CONFIG_IB700_WDT is not set +# CONFIG_WAFER_WDT is not set +# CONFIG_I810_TCO is not set +# CONFIG_MIXCOMWD is not set +# CONFIG_60XX_WDT is not set +# CONFIG_SC1200_WDT is not set +CONFIG_SOFT_WATCHDOG=y +# CONFIG_W83877F_WDT is not set +# CONFIG_WDT is not set +# CONFIG_WDTPCI is not set +# CONFIG_MACHZ_WDT is not set +# CONFIG_INDYDOG is not set +# CONFIG_AMD7XX_TCO is not set +# CONFIG_AMD_PM768 is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# File systems +# +CONFIG_BLKDEV_SWAP=m +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BEFS_DEBUG is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_BBC_ARMLIB is not set +CONFIG_JFFS2_BBC_LZO=y +CONFIG_JFFS2_BBC_LZARI=y +CONFIG_JFFS2_BBC_LZHD=y +CONFIG_JFFS2_BBC_LZSS=y +# CONFIG_CRAMFS is not set +CONFIG_SQUASHFS=y +# CONFIG_TMPFS is not set +CONFIG_RAMFS=y +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_JFS_FS is not set +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_STATISTICS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_EXT2_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +# CONFIG_ROOT_NFS is not set +CONFIG_SWAP_VIA_NFS=m +CONFIG_NETSWAP=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +# CONFIG_NFSD_TCP is not set +CONFIG_SUNRPC=m +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Support for USB gadgets +# +# CONFIG_USB_GADGET is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +CONFIG_CROSSCOMPILE=y +# CONFIG_KERNPROF is not set +# CONFIG_MCOUNT is not set +# CONFIG_DEBUG is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_MIPS_UNCACHED is not set +# CONFIG_KTRACE is not set +# CONFIG_HWSIM is not set + +# +# Library routines +# +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y diff --git a/obsolete-buildroot/sources/openwrt/kernel/patches/100-revert_netfilter.patch b/obsolete-buildroot/sources/openwrt/kernel/patches/100-revert_netfilter.patch new file mode 100644 index 0000000000..4d8b0a1f62 --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/kernel/patches/100-revert_netfilter.patch @@ -0,0 +1,5823 @@ +diff -Nurb src/linux/linux/include/linux/netfilter_ipv4/ip_conntrack.h src/linux/linux.stock/include/linux/netfilter_ipv4/ip_conntrack.h +--- src/linux/linux/include/linux/netfilter_ipv4/ip_conntrack.h 2003-08-12 07:43:11.000000000 -0400 ++++ src/linux/linux.stock/include/linux/netfilter_ipv4/ip_conntrack.h 2004-05-09 04:13:03.000000000 -0400 +@@ -45,39 +45,27 @@ + + #include <linux/netfilter_ipv4/ip_conntrack_tcp.h> + #include <linux/netfilter_ipv4/ip_conntrack_icmp.h> +-#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h> + + /* per conntrack: protocol private data */ + union ip_conntrack_proto { + /* insert conntrack proto private data here */ +- struct ip_ct_gre gre; + struct ip_ct_tcp tcp; + struct ip_ct_icmp icmp; + }; + + union ip_conntrack_expect_proto { + /* insert expect proto private data here */ +- struct ip_ct_gre_expect gre; + }; + + /* Add protocol helper include file here */ +-#include <linux/netfilter_ipv4/ip_conntrack_pptp.h> +-#include <linux/netfilter_ipv4/ip_conntrack_mms.h> +-#include <linux/netfilter_ipv4/ip_conntrack_h323.h> +- + #include <linux/netfilter_ipv4/ip_conntrack_ftp.h> + #include <linux/netfilter_ipv4/ip_conntrack_irc.h> +-#include <linux/netfilter_ipv4/ip_autofw.h> + + /* per expectation: application helper private data */ + union ip_conntrack_expect_help { + /* insert conntrack helper private data (expect) here */ +- struct ip_ct_pptp_expect exp_pptp_info; +- struct ip_ct_mms_expect exp_mms_info; +- struct ip_ct_h225_expect exp_h225_info; + struct ip_ct_ftp_expect exp_ftp_info; + struct ip_ct_irc_expect exp_irc_info; +- struct ip_autofw_expect exp_autofw_info; + + #ifdef CONFIG_IP_NF_NAT_NEEDED + union { +@@ -89,21 +77,16 @@ + /* per conntrack: application helper private data */ + union ip_conntrack_help { + /* insert conntrack helper private data (master) here */ +- struct ip_ct_pptp_master ct_pptp_info; +- struct ip_ct_mms_master ct_mms_info; +- struct ip_ct_h225_master ct_h225_info; + struct ip_ct_ftp_master ct_ftp_info; + struct ip_ct_irc_master ct_irc_info; + }; + + #ifdef CONFIG_IP_NF_NAT_NEEDED + #include <linux/netfilter_ipv4/ip_nat.h> +-#include <linux/netfilter_ipv4/ip_nat_pptp.h> + + /* per conntrack: nat application helper private data */ + union ip_conntrack_nat_help { + /* insert nat helper private data here */ +- struct ip_nat_pptp nat_pptp_info; + }; + #endif + +@@ -275,9 +258,5 @@ + } + + extern unsigned int ip_conntrack_htable_size; +- +-/* connection tracking time out variables. */ +-extern int sysctl_ip_conntrack_tcp_timeouts[10]; +-extern int sysctl_ip_conntrack_udp_timeouts[2]; + #endif /* __KERNEL__ */ + #endif /* _IP_CONNTRACK_H */ +diff -Nurb src/linux/linux/include/linux/netfilter_ipv4/ip_conntrack_h323.h src/linux/linux.stock/include/linux/netfilter_ipv4/ip_conntrack_h323.h +--- src/linux/linux/include/linux/netfilter_ipv4/ip_conntrack_h323.h 2003-07-04 04:12:27.000000000 -0400 ++++ src/linux/linux.stock/include/linux/netfilter_ipv4/ip_conntrack_h323.h 1969-12-31 19:00:00.000000000 -0500 +@@ -1,30 +0,0 @@ +-#ifndef _IP_CONNTRACK_H323_H +-#define _IP_CONNTRACK_H323_H +-/* H.323 connection tracking. */ +- +-#ifdef __KERNEL__ +-/* Protects H.323 related data */ +-DECLARE_LOCK_EXTERN(ip_h323_lock); +-#endif +- +-/* Default H.225 port */ +-#define H225_PORT 1720 +- +-/* This structure is per expected connection */ +-struct ip_ct_h225_expect { +- u_int16_t port; /* Port of the H.225 helper/RTCP/RTP channel */ +- enum ip_conntrack_dir dir; /* Direction of the original connection */ +- unsigned int offset; /* offset of the address in the payload */ +-}; +- +-/* This structure exists only once per master */ +-struct ip_ct_h225_master { +- int is_h225; /* H.225 or H.245 connection */ +-#ifdef CONFIG_IP_NF_NAT_NEEDED +- enum ip_conntrack_dir dir; /* Direction of the original connection */ +- u_int32_t seq[IP_CT_DIR_MAX]; /* Exceptional packet mangling for signal addressess... */ +- unsigned int offset[IP_CT_DIR_MAX]; /* ...and the offset of the addresses in the payload */ +-#endif +-}; +- +-#endif /* _IP_CONNTRACK_H323_H */ +diff -Nurb src/linux/linux/include/linux/netfilter_ipv4/ip_conntrack_mms.h src/linux/linux.stock/include/linux/netfilter_ipv4/ip_conntrack_mms.h +--- src/linux/linux/include/linux/netfilter_ipv4/ip_conntrack_mms.h 2003-07-04 04:12:27.000000000 -0400 ++++ src/linux/linux.stock/include/linux/netfilter_ipv4/ip_conntrack_mms.h 1969-12-31 19:00:00.000000000 -0500 +@@ -1,31 +0,0 @@ +-#ifndef _IP_CONNTRACK_MMS_H +-#define _IP_CONNTRACK_MMS_H +-/* MMS tracking. */ +- +-#ifdef __KERNEL__ +-#include <linux/netfilter_ipv4/lockhelp.h> +- +-DECLARE_LOCK_EXTERN(ip_mms_lock); +- +-#define MMS_PORT 1755 +-#define MMS_SRV_MSG_ID 196610 +- +-#define MMS_SRV_MSG_OFFSET 36 +-#define MMS_SRV_UNICODE_STRING_OFFSET 60 +-#define MMS_SRV_CHUNKLENLV_OFFSET 16 +-#define MMS_SRV_CHUNKLENLM_OFFSET 32 +-#define MMS_SRV_MESSAGELENGTH_OFFSET 8 +-#endif +- +-/* This structure is per expected connection */ +-struct ip_ct_mms_expect { +- u_int32_t len; +- u_int32_t padding; +- u_int16_t port; +-}; +- +-/* This structure exists only once per master */ +-struct ip_ct_mms_master { +-}; +- +-#endif /* _IP_CONNTRACK_MMS_H */ +diff -Nurb src/linux/linux/include/linux/netfilter_ipv4/ip_conntrack_pptp.h src/linux/linux.stock/include/linux/netfilter_ipv4/ip_conntrack_pptp.h +--- src/linux/linux/include/linux/netfilter_ipv4/ip_conntrack_pptp.h 2003-07-04 04:12:27.000000000 -0400 ++++ src/linux/linux.stock/include/linux/netfilter_ipv4/ip_conntrack_pptp.h 1969-12-31 19:00:00.000000000 -0500 +@@ -1,313 +0,0 @@ +-/* PPTP constants and structs */ +-#ifndef _CONNTRACK_PPTP_H +-#define _CONNTRACK_PPTP_H +- +-/* state of the control session */ +-enum pptp_ctrlsess_state { +- PPTP_SESSION_NONE, /* no session present */ +- PPTP_SESSION_ERROR, /* some session error */ +- PPTP_SESSION_STOPREQ, /* stop_sess request seen */ +- PPTP_SESSION_REQUESTED, /* start_sess request seen */ +- PPTP_SESSION_CONFIRMED, /* session established */ +-}; +- +-/* state of the call inside the control session */ +-enum pptp_ctrlcall_state { +- PPTP_CALL_NONE, +- PPTP_CALL_ERROR, +- PPTP_CALL_OUT_REQ, +- PPTP_CALL_OUT_CONF, +- PPTP_CALL_IN_REQ, +- PPTP_CALL_IN_REP, +- PPTP_CALL_IN_CONF, +- PPTP_CALL_CLEAR_REQ, +-}; +- +- +-/* conntrack private data */ +-struct ip_ct_pptp_master { +- enum pptp_ctrlsess_state sstate; /* session state */ +- +- /* everything below is going to be per-expectation in newnat, +- * since there could be more than one call within one session */ +- enum pptp_ctrlcall_state cstate; /* call state */ +- u_int16_t pac_call_id; /* call id of PAC, host byte order */ +- u_int16_t pns_call_id; /* call id of PNS, host byte order */ +-}; +- +-/* conntrack_expect private member */ +-struct ip_ct_pptp_expect { +- enum pptp_ctrlcall_state cstate; /* call state */ +- u_int16_t pac_call_id; /* call id of PAC */ +- u_int16_t pns_call_id; /* call id of PNS */ +-}; +- +- +-#ifdef __KERNEL__ +- +-#include <linux/netfilter_ipv4/lockhelp.h> +-DECLARE_LOCK_EXTERN(ip_pptp_lock); +- +-#define IP_CONNTR_PPTP PPTP_CONTROL_PORT +- +-union pptp_ctrl_union { +- void *rawreq; +- struct PptpStartSessionRequest *sreq; +- struct PptpStartSessionReply *srep; +- struct PptpStopSessionReqest *streq; +- struct PptpStopSessionReply *strep; +- struct PptpOutCallRequest *ocreq; +- struct PptpOutCallReply *ocack; +- struct PptpInCallRequest *icreq; +- struct PptpInCallReply *icack; +- struct PptpInCallConnected *iccon; +- struct PptpClearCallRequest *clrreq; +- struct PptpCallDisconnectNotify *disc; +- struct PptpWanErrorNotify *wanerr; +- struct PptpSetLinkInfo *setlink; +-}; +- +- +- +-#define PPTP_CONTROL_PORT 1723 +- +-#define PPTP_PACKET_CONTROL 1 +-#define PPTP_PACKET_MGMT 2 +- +-#define PPTP_MAGIC_COOKIE 0x1a2b3c4d +- +-struct pptp_pkt_hdr { +- __u16 packetLength; +- __u16 packetType; +- __u32 magicCookie; +-}; +- +-/* PptpControlMessageType values */ +-#define PPTP_START_SESSION_REQUEST 1 +-#define PPTP_START_SESSION_REPLY 2 +-#define PPTP_STOP_SESSION_REQUEST 3 +-#define PPTP_STOP_SESSION_REPLY 4 +-#define PPTP_ECHO_REQUEST 5 +-#define PPTP_ECHO_REPLY 6 +-#define PPTP_OUT_CALL_REQUEST 7 +-#define PPTP_OUT_CALL_REPLY 8 +-#define PPTP_IN_CALL_REQUEST 9 +-#define PPTP_IN_CALL_REPLY 10 +-#define PPTP_IN_CALL_CONNECT 11 +-#define PPTP_CALL_CLEAR_REQUEST 12 +-#define PPTP_CALL_DISCONNECT_NOTIFY 13 +-#define PPTP_WAN_ERROR_NOTIFY 14 +-#define PPTP_SET_LINK_INFO 15 +- +-#define PPTP_MSG_MAX 15 +- +-/* PptpGeneralError values */ +-#define PPTP_ERROR_CODE_NONE 0 +-#define PPTP_NOT_CONNECTED 1 +-#define PPTP_BAD_FORMAT 2 +-#define PPTP_BAD_VALUE 3 +-#define PPTP_NO_RESOURCE 4 +-#define PPTP_BAD_CALLID 5 +-#define PPTP_REMOVE_DEVICE_ERROR 6 +- +-struct PptpControlHeader { +- __u16 messageType; +- __u16 reserved; +-}; +- +-/* FramingCapability Bitmap Values */ +-#define PPTP_FRAME_CAP_ASYNC 0x1 +-#define PPTP_FRAME_CAP_SYNC 0x2 +- +-/* BearerCapability Bitmap Values */ +-#define PPTP_BEARER_CAP_ANALOG 0x1 +-#define PPTP_BEARER_CAP_DIGITAL 0x2 +- +-struct PptpStartSessionRequest { +- __u16 protocolVersion; +- __u8 reserved1; +- __u8 reserved2; +- __u32 framingCapability; +- __u32 bearerCapability; +- __u16 maxChannels; +- __u16 firmwareRevision; +- __u8 hostName[64]; +- __u8 vendorString[64]; +-}; +- +-/* PptpStartSessionResultCode Values */ +-#define PPTP_START_OK 1 +-#define PPTP_START_GENERAL_ERROR 2 +-#define PPTP_START_ALREADY_CONNECTED 3 +-#define PPTP_START_NOT_AUTHORIZED 4 +-#define PPTP_START_UNKNOWN_PROTOCOL 5 +- +-struct PptpStartSessionReply { +- __u16 protocolVersion; +- __u8 resultCode; +- __u8 generalErrorCode; +- __u32 framingCapability; +- __u32 bearerCapability; +- __u16 maxChannels; +- __u16 firmwareRevision; +- __u8 hostName[64]; +- __u8 vendorString[64]; +-}; +- +-/* PptpStopReasons */ +-#define PPTP_STOP_NONE 1 +-#define PPTP_STOP_PROTOCOL 2 +-#define PPTP_STOP_LOCAL_SHUTDOWN 3 +- +-struct PptpStopSessionRequest { +- __u8 reason; +-}; +- +-/* PptpStopSessionResultCode */ +-#define PPTP_STOP_OK 1 +-#define PPTP_STOP_GENERAL_ERROR 2 +- +-struct PptpStopSessionReply { +- __u8 resultCode; +- __u8 generalErrorCode; +-}; +- +-struct PptpEchoRequest { +- __u32 identNumber; +-}; +- +-/* PptpEchoReplyResultCode */ +-#define PPTP_ECHO_OK 1 +-#define PPTP_ECHO_GENERAL_ERROR 2 +- +-struct PptpEchoReply { +- __u32 identNumber; +- __u8 resultCode; +- __u8 generalErrorCode; +- __u16 reserved; +-}; +- +-/* PptpFramingType */ +-#define PPTP_ASYNC_FRAMING 1 +-#define PPTP_SYNC_FRAMING 2 +-#define PPTP_DONT_CARE_FRAMING 3 +- +-/* PptpCallBearerType */ +-#define PPTP_ANALOG_TYPE 1 +-#define PPTP_DIGITAL_TYPE 2 +-#define PPTP_DONT_CARE_BEARER_TYPE 3 +- +-struct PptpOutCallRequest { +- __u16 callID; +- __u16 callSerialNumber; +- __u32 minBPS; +- __u32 maxBPS; +- __u32 bearerType; +- __u32 framingType; +- __u16 packetWindow; +- __u16 packetProcDelay; +- __u16 reserved1; +- __u16 phoneNumberLength; +- __u16 reserved2; +- __u8 phoneNumber[64]; +- __u8 subAddress[64]; +-}; +- +-/* PptpCallResultCode */ +-#define PPTP_OUTCALL_CONNECT 1 +-#define PPTP_OUTCALL_GENERAL_ERROR 2 +-#define PPTP_OUTCALL_NO_CARRIER 3 +-#define PPTP_OUTCALL_BUSY 4 +-#define PPTP_OUTCALL_NO_DIAL_TONE 5 +-#define PPTP_OUTCALL_TIMEOUT 6 +-#define PPTP_OUTCALL_DONT_ACCEPT 7 +- +-struct PptpOutCallReply { +- __u16 callID; +- __u16 peersCallID; +- __u8 resultCode; +- __u8 generalErrorCode; +- __u16 causeCode; +- __u32 connectSpeed; +- __u16 packetWindow; +- __u16 packetProcDelay; +- __u32 physChannelID; +-}; +- +-struct PptpInCallRequest { +- __u16 callID; +- __u16 callSerialNumber; +- __u32 callBearerType; +- __u32 physChannelID; +- __u16 dialedNumberLength; +- __u16 dialingNumberLength; +- __u8 dialedNumber[64]; +- __u8 dialingNumber[64]; +- __u8 subAddress[64]; +-}; +- +-/* PptpInCallResultCode */ +-#define PPTP_INCALL_ACCEPT 1 +-#define PPTP_INCALL_GENERAL_ERROR 2 +-#define PPTP_INCALL_DONT_ACCEPT 3 +- +-struct PptpInCallReply { +- __u16 callID; +- __u16 peersCallID; +- __u8 resultCode; +- __u8 generalErrorCode; +- __u16 packetWindow; +- __u16 packetProcDelay; +- __u16 reserved; +-}; +- +-struct PptpInCallConnected { +- __u16 peersCallID; +- __u16 reserved; +- __u32 connectSpeed; +- __u16 packetWindow; +- __u16 packetProcDelay; +- __u32 callFramingType; +-}; +- +-struct PptpClearCallRequest { +- __u16 callID; +- __u16 reserved; +-}; +- +-struct PptpCallDisconnectNotify { +- __u16 callID; +- __u8 resultCode; +- __u8 generalErrorCode; +- __u16 causeCode; +- __u16 reserved; +- __u8 callStatistics[128]; +-}; +- +-struct PptpWanErrorNotify { +- __u16 peersCallID; +- __u16 reserved; +- __u32 crcErrors; +- __u32 framingErrors; +- __u32 hardwareOverRuns; +- __u32 bufferOverRuns; +- __u32 timeoutErrors; +- __u32 alignmentErrors; +-}; +- +-struct PptpSetLinkInfo { +- __u16 peersCallID; +- __u16 reserved; +- __u32 sendAccm; +- __u32 recvAccm; +-}; +- +- +-struct pptp_priv_data { +- __u16 call_id; +- __u16 mcall_id; +- __u16 pcall_id; +-}; +- +-#endif /* __KERNEL__ */ +-#endif /* _CONNTRACK_PPTP_H */ +diff -Nurb src/linux/linux/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h src/linux/linux.stock/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h +--- src/linux/linux/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h 2003-07-04 04:12:27.000000000 -0400 ++++ src/linux/linux.stock/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h 1969-12-31 19:00:00.000000000 -0500 +@@ -1,121 +0,0 @@ +-#ifndef _CONNTRACK_PROTO_GRE_H +-#define _CONNTRACK_PROTO_GRE_H +-#include <asm/byteorder.h> +- +-/* GRE PROTOCOL HEADER */ +- +-/* GRE Version field */ +-#define GRE_VERSION_1701 0x0 +-#define GRE_VERSION_PPTP 0x1 +- +-/* GRE Protocol field */ +-#define GRE_PROTOCOL_PPTP 0x880B +- +-/* GRE Flags */ +-#define GRE_FLAG_C 0x80 +-#define GRE_FLAG_R 0x40 +-#define GRE_FLAG_K 0x20 +-#define GRE_FLAG_S 0x10 +-#define GRE_FLAG_A 0x80 +- +-#define GRE_IS_C(f) ((f)&GRE_FLAG_C) +-#define GRE_IS_R(f) ((f)&GRE_FLAG_R) +-#define GRE_IS_K(f) ((f)&GRE_FLAG_K) +-#define GRE_IS_S(f) ((f)&GRE_FLAG_S) +-#define GRE_IS_A(f) ((f)&GRE_FLAG_A) +- +-/* GRE is a mess: Four different standards */ +-struct gre_hdr { +-#if defined(__LITTLE_ENDIAN_BITFIELD) +- __u16 rec:3, +- srr:1, +- seq:1, +- key:1, +- routing:1, +- csum:1, +- version:3, +- reserved:4, +- ack:1; +-#elif defined(__BIG_ENDIAN_BITFIELD) +- __u16 csum:1, +- routing:1, +- key:1, +- seq:1, +- srr:1, +- rec:3, +- ack:1, +- reserved:4, +- version:3; +-#else +-#error "Adjust your <asm/byteorder.h> defines" +-#endif +- __u16 protocol; +-}; +- +-/* modified GRE header for PPTP */ +-struct gre_hdr_pptp { +- __u8 flags; /* bitfield */ +- __u8 version; /* should be GRE_VERSION_PPTP */ +- __u16 protocol; /* should be GRE_PROTOCOL_PPTP */ +- __u16 payload_len; /* size of ppp payload, not inc. gre header */ +- __u16 call_id; /* peer's call_id for this session */ +- __u32 seq; /* sequence number. Present if S==1 */ +- __u32 ack; /* seq number of highest packet recieved by */ +- /* sender in this session */ +-}; +- +- +-/* this is part of ip_conntrack */ +-struct ip_ct_gre { +- unsigned int stream_timeout; +- unsigned int timeout; +-}; +- +-/* this is part of ip_conntrack_expect */ +-struct ip_ct_gre_expect { +- struct ip_ct_gre_keymap *keymap_orig, *keymap_reply; +-}; +- +-#ifdef __KERNEL__ +- +-/* structure for original <-> reply keymap */ +-struct ip_ct_gre_keymap { +- struct list_head list; +- +- struct ip_conntrack_tuple tuple; +- struct ip_conntrack_expect *master; +-}; +- +- +-/* add new tuple->key_reply pair to keymap */ +-int ip_ct_gre_keymap_add(struct ip_conntrack_expect *exp, +- struct ip_conntrack_tuple *t, +- int reply); +- +-/* change an existing keymap entry */ +-void ip_ct_gre_keymap_change(struct ip_ct_gre_keymap *km, +- struct ip_conntrack_tuple *t); +- +- +- +-/* get pointer to gre key, if present */ +-static inline u_int32_t *gre_key(struct gre_hdr *greh) +-{ +- if (!greh->key) +- return NULL; +- if (greh->csum || greh->routing) +- return (u_int32_t *) (greh+sizeof(*greh)+4); +- return (u_int32_t *) (greh+sizeof(*greh)); +-} +- +-/* get pointer ot gre csum, if present */ +-static inline u_int16_t *gre_csum(struct gre_hdr *greh) +-{ +- if (!greh->csum) +- return NULL; +- return (u_int16_t *) (greh+sizeof(*greh)); +-} +- +-#endif /* __KERNEL__ */ +- +-#endif /* _CONNTRACK_PROTO_GRE_H */ +diff -Nurb src/linux/linux/include/linux/netfilter_ipv4/ip_conntrack_tftp.h src/linux/linux.stock/include/linux/netfilter_ipv4/ip_conntrack_tftp.h +--- src/linux/linux/include/linux/netfilter_ipv4/ip_conntrack_tftp.h 2003-07-04 04:12:27.000000000 -0400 ++++ src/linux/linux.stock/include/linux/netfilter_ipv4/ip_conntrack_tftp.h 1969-12-31 19:00:00.000000000 -0500 +@@ -1,13 +0,0 @@ +-#ifndef _IP_CT_TFTP +-#define _IP_CT_TFTP +- +-#define TFTP_PORT 69 +- +-struct tftphdr { +- u_int16_t opcode; +-}; +- +-#define TFTP_OPCODE_READ 1 +-#define TFTP_OPCODE_WRITE 2 +- +-#endif /* _IP_CT_TFTP */ +diff -Nurb src/linux/linux/include/linux/netfilter_ipv4/ip_conntrack_tuple.h src/linux/linux.stock/include/linux/netfilter_ipv4/ip_conntrack_tuple.h +--- src/linux/linux/include/linux/netfilter_ipv4/ip_conntrack_tuple.h 2003-07-04 04:12:27.000000000 -0400 ++++ src/linux/linux.stock/include/linux/netfilter_ipv4/ip_conntrack_tuple.h 2004-05-09 04:13:03.000000000 -0400 +@@ -14,7 +14,7 @@ + union ip_conntrack_manip_proto + { + /* Add other protocols here. */ +- u_int32_t all; ++ u_int16_t all; + + struct { + u_int16_t port; +@@ -25,9 +25,6 @@ + struct { + u_int16_t id; + } icmp; +- struct { +- u_int32_t key; +- } gre; + }; + + /* The manipulable part of the tuple. */ +@@ -47,7 +44,7 @@ + u_int32_t ip; + union { + /* Add other protocols here. */ +- u_int64_t all; ++ u_int16_t all; + + struct { + u_int16_t port; +@@ -58,11 +55,6 @@ + struct { + u_int8_t type, code; + } icmp; +- struct { +- u_int16_t protocol; +- u_int8_t version; +- u_int32_t key; +- } gre; + } u; + + /* The protocol. */ +@@ -80,16 +72,10 @@ + #ifdef __KERNEL__ + + #define DUMP_TUPLE(tp) \ +-DEBUGP("tuple %p: %u %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u\n", \ ++DEBUGP("tuple %p: %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n", \ + (tp), (tp)->dst.protonum, \ +- NIPQUAD((tp)->src.ip), ntohl((tp)->src.u.all), \ +- NIPQUAD((tp)->dst.ip), ntohl((tp)->dst.u.all)) +- +-#define DUMP_TUPLE_RAW(x) \ +- DEBUGP("tuple %p: %u %u.%u.%u.%u:0x%08x -> %u.%u.%u.%u:0x%08x\n",\ +- (x), (x)->dst.protonum, \ +- NIPQUAD((x)->src.ip), ntohl((x)->src.u.all), \ +- NIPQUAD((x)->dst.ip), ntohl((x)->dst.u.all)) ++ NIPQUAD((tp)->src.ip), ntohs((tp)->src.u.all), \ ++ NIPQUAD((tp)->dst.ip), ntohs((tp)->dst.u.all)) + + #define CTINFO2DIR(ctinfo) ((ctinfo) >= IP_CT_IS_REPLY ? IP_CT_DIR_REPLY : IP_CT_DIR_ORIGINAL) + +diff -Nurb src/linux/linux/include/linux/netfilter_ipv4/ip_nat_pptp.h src/linux/linux.stock/include/linux/netfilter_ipv4/ip_nat_pptp.h +--- src/linux/linux/include/linux/netfilter_ipv4/ip_nat_pptp.h 2003-07-04 04:12:27.000000000 -0400 ++++ src/linux/linux.stock/include/linux/netfilter_ipv4/ip_nat_pptp.h 1969-12-31 19:00:00.000000000 -0500 +@@ -1,11 +0,0 @@ +-/* PPTP constants and structs */ +-#ifndef _NAT_PPTP_H +-#define _NAT_PPTP_H +- +-/* conntrack private data */ +-struct ip_nat_pptp { +- u_int16_t pns_call_id; /* NAT'ed PNS call id */ +- u_int16_t pac_call_id; /* NAT'ed PAC call id */ +-}; +- +-#endif /* _NAT_PPTP_H */ +diff -Nurb src/linux/linux/include/linux/netfilter_ipv4/ip_pool.h src/linux/linux.stock/include/linux/netfilter_ipv4/ip_pool.h +--- src/linux/linux/include/linux/netfilter_ipv4/ip_pool.h 2003-07-04 04:12:27.000000000 -0400 ++++ src/linux/linux.stock/include/linux/netfilter_ipv4/ip_pool.h 1969-12-31 19:00:00.000000000 -0500 +@@ -1,64 +0,0 @@ +-#ifndef _IP_POOL_H +-#define _IP_POOL_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. */ +-/* */ +-/* This program is distributed in the hope that it will be useful, */ +-/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +-/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +-/* GNU General Public License for more details. */ +-/* */ +-/* You should have received a copy of the GNU General Public License */ +-/* along with this program; if not, write to the Free Software */ +-/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +-/***************************************************************************/ +- +-/* 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_POOL 81 +- +-typedef int ip_pool_t; /* pool index */ +-#define IP_POOL_NONE ((ip_pool_t)-1) +- +-struct ip_pool_request { +- int op; +- ip_pool_t index; +- u_int32_t addr; +- u_int32_t addr2; +-}; +- +-/* NOTE: I deliberately break the first cut ippool utility. Nobody uses it. */ +- +-#define IP_POOL_BAD001 0x00000010 +- +-#define IP_POOL_FLUSH 0x00000011 /* req.index, no arguments */ +-#define IP_POOL_INIT 0x00000012 /* from addr to addr2 incl. */ +-#define IP_POOL_DESTROY 0x00000013 /* req.index, no arguments */ +-#define IP_POOL_ADD_ADDR 0x00000014 /* add addr to pool */ +-#define IP_POOL_DEL_ADDR 0x00000015 /* del addr from pool */ +-#define IP_POOL_HIGH_NR 0x00000016 /* result in req.index */ +-#define IP_POOL_LOOKUP 0x00000017 /* result in addr and addr2 */ +-#define IP_POOL_USAGE 0x00000018 /* result in addr */ +-#define IP_POOL_TEST_ADDR 0x00000019 /* result (0/1) returned */ +- +-#ifdef __KERNEL__ +- +-/* NOTE: ip_pool_match() and ip_pool_mod() expect ADDR to be host byte order */ +-extern int ip_pool_match(ip_pool_t pool, u_int32_t addr); +-extern int ip_pool_mod(ip_pool_t pool, u_int32_t addr, int isdel); +- +-#endif +- +-#endif /*_IP_POOL_H*/ +diff -Nurb src/linux/linux/include/linux/netfilter_ipv4/ipt_pool.h src/linux/linux.stock/include/linux/netfilter_ipv4/ipt_pool.h +--- src/linux/linux/include/linux/netfilter_ipv4/ipt_pool.h 2003-07-04 04:12:27.000000000 -0400 ++++ src/linux/linux.stock/include/linux/netfilter_ipv4/ipt_pool.h 1969-12-31 19:00:00.000000000 -0500 +@@ -1,25 +0,0 @@ +-#ifndef _IPT_POOL_H +-#define _IPT_POOL_H +- +-#include <linux/netfilter_ipv4/ip_pool.h> +- +-#define IPT_POOL_INV_SRC 0x00000001 +-#define IPT_POOL_INV_DST 0x00000002 +-#define IPT_POOL_DEL_SRC 0x00000004 +-#define IPT_POOL_DEL_DST 0x00000008 +-#define IPT_POOL_INV_MOD_SRC 0x00000010 +-#define IPT_POOL_INV_MOD_DST 0x00000020 +-#define IPT_POOL_MOD_SRC_ACCEPT 0x00000040 +-#define IPT_POOL_MOD_DST_ACCEPT 0x00000080 +-#define IPT_POOL_MOD_SRC_DROP 0x00000100 +-#define IPT_POOL_MOD_DST_DROP 0x00000200 +- +-/* match info */ +-struct ipt_pool_info +-{ +- ip_pool_t src; +- ip_pool_t dst; +- unsigned flags; +-}; +- +-#endif /*_IPT_POOL_H*/ +diff -Nurb src/linux/linux/net/ipv4/netfilter/Config.in src/linux/linux.stock/net/ipv4/netfilter/Config.in +--- src/linux/linux/net/ipv4/netfilter/Config.in 2004-02-19 06:04:35.000000000 -0500 ++++ src/linux/linux.stock/net/ipv4/netfilter/Config.in 2004-05-09 04:13:03.000000000 -0400 +@@ -7,12 +7,7 @@ + tristate 'Connection tracking (required for masq/NAT)' CONFIG_IP_NF_CONNTRACK + if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then + dep_tristate ' FTP protocol support' CONFIG_IP_NF_FTP $CONFIG_IP_NF_CONNTRACK +- dep_tristate ' TFTP protocol support' CONFIG_IP_NF_TFTP $CONFIG_IP_NF_CONNTRACK +- dep_tristate ' H.323 (netmeeting) support' CONFIG_IP_NF_H323 $CONFIG_IP_NF_CONNTRACK + dep_tristate ' IRC protocol support' CONFIG_IP_NF_IRC $CONFIG_IP_NF_CONNTRACK +- dep_tristate ' MMS protocol support' CONFIG_IP_NF_MMS $CONFIG_IP_NF_CONNTRACK +- dep_tristate ' GRE protocol support' CONFIG_IP_NF_CT_PROTO_GRE $CONFIG_IP_NF_CONNTRACK +- dep_tristate ' PPTP protocol support' CONFIG_IP_NF_PPTP $CONFIG_IP_NF_CT_PROTO_GRE + fi + + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then +@@ -22,19 +17,11 @@ + if [ "$CONFIG_IP_NF_IPTABLES" != "n" ]; then + # The simple matches. + dep_tristate ' limit match support' CONFIG_IP_NF_MATCH_LIMIT $CONFIG_IP_NF_IPTABLES +- +- dep_tristate ' IP address pool support' CONFIG_IP_NF_POOL $CONFIG_IP_NF_IPTABLES +- if [ "$CONFIG_IP_NF_POOL" = "y" -o "$CONFIG_IP_NF_POOL" = "m" ]; then +- bool ' enable statistics on pool usage' CONFIG_IP_POOL_STATISTICS n +- fi +- + dep_tristate ' MAC address match support' CONFIG_IP_NF_MATCH_MAC $CONFIG_IP_NF_IPTABLES + dep_tristate ' Packet type match support' CONFIG_IP_NF_MATCH_PKTTYPE $CONFIG_IP_NF_IPTABLES + dep_tristate ' netfilter MARK match support' CONFIG_IP_NF_MATCH_MARK $CONFIG_IP_NF_IPTABLES + dep_tristate ' Multiple port match support' CONFIG_IP_NF_MATCH_MULTIPORT $CONFIG_IP_NF_IPTABLES +- dep_tristate ' Multiple port with ranges match support' CONFIG_IP_NF_MATCH_MPORT $CONFIG_IP_NF_IPTABLES + dep_tristate ' TOS match support' CONFIG_IP_NF_MATCH_TOS $CONFIG_IP_NF_IPTABLES +- dep_tristate ' TIME match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_TIME $CONFIG_IP_NF_IPTABLES + dep_tristate ' ECN match support' CONFIG_IP_NF_MATCH_ECN $CONFIG_IP_NF_IPTABLES + + dep_tristate ' DSCP match support' CONFIG_IP_NF_MATCH_DSCP $CONFIG_IP_NF_IPTABLES +@@ -52,7 +39,6 @@ + fi + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate ' Unclean match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_UNCLEAN $CONFIG_IP_NF_IPTABLES +- dep_tristate ' Webstr match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_WEBSTR $CONFIG_IP_NF_IPTABLES + dep_tristate ' Owner match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_OWNER $CONFIG_IP_NF_IPTABLES + fi + # The targets +@@ -70,29 +56,6 @@ + define_bool CONFIG_IP_NF_NAT_NEEDED y + dep_tristate ' MASQUERADE target support' CONFIG_IP_NF_TARGET_MASQUERADE $CONFIG_IP_NF_NAT + dep_tristate ' REDIRECT target support' CONFIG_IP_NF_TARGET_REDIRECT $CONFIG_IP_NF_NAT +- dep_tristate ' Automatic port forwarding (autofw) target support' CONFIG_IP_NF_AUTOFW $CONFIG_IP_NF_NAT +- dep_tristate ' TRIGGER target support (port-trigger)' CONFIG_IP_NF_TARGET_TRIGGER $CONFIG_IP_NF_NAT +- if [ "$CONFIG_IP_NF_H323" = "m" ]; then +- define_tristate CONFIG_IP_NF_NAT_H323 m +- else +- if [ "$CONFIG_IP_NF_H323" = "y" ]; then +- define_tristate CONFIG_IP_NF_NAT_H323 $CONFIG_IP_NF_NAT +- fi +- fi +- if [ "$CONFIG_IP_NF_PPTP" = "m" ]; then +- define_tristate CONFIG_IP_NF_NAT_PPTP m +- else +- if [ "$CONFIG_IP_NF_PPTP" = "y" ]; then +- define_tristate CONFIG_IP_NF_NAT_PPTP $CONFIG_IP_NF_NAT +- fi +- fi +- if [ "$CONFIG_IP_NF_CT_PROTO_GRE" = "m" ]; then +- define_tristate CONFIG_IP_NF_NAT_PROTO_GRE m +- else +- if [ "$CONFIG_IP_NF_CT_PROTO_GRE" = "y" ]; then +- define_tristate CONFIG_IP_NF_NAT_PROTO_GRE $CONFIG_IP_NF_NAT +- fi +- fi + bool ' NAT of local connections (READ HELP)' CONFIG_IP_NF_NAT_LOCAL + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate ' Basic SNMP-ALG support (EXPERIMENTAL)' CONFIG_IP_NF_NAT_SNMP_BASIC $CONFIG_IP_NF_NAT +@@ -104,13 +67,6 @@ + define_tristate CONFIG_IP_NF_NAT_IRC $CONFIG_IP_NF_NAT + fi + fi +- if [ "$CONFIG_IP_NF_MMS" = "m" ]; then +- define_tristate CONFIG_IP_NF_NAT_MMS m +- else +- if [ "$CONFIG_IP_NF_MMS" = "y" ]; then +- define_tristate CONFIG_IP_NF_NAT_MMS $CONFIG_IP_NF_NAT +- fi +- fi + # 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. + if [ "$CONFIG_IP_NF_FTP" = "m" ]; then +@@ -120,13 +76,6 @@ + define_tristate CONFIG_IP_NF_NAT_FTP $CONFIG_IP_NF_NAT + fi + fi +- if [ "$CONFIG_IP_NF_TFTP" = "m" ]; then +- define_tristate CONFIG_IP_NF_NAT_TFTP m +- else +- if [ "$CONFIG_IP_NF_TFTP" = "y" ]; then +- define_tristate CONFIG_IP_NF_NAT_TFTP $CONFIG_IP_NF_NAT +- fi +- fi + fi + fi + +diff -Nurb src/linux/linux/net/ipv4/netfilter/Makefile src/linux/linux.stock/net/ipv4/netfilter/Makefile +--- src/linux/linux/net/ipv4/netfilter/Makefile 2004-02-19 06:04:35.000000000 -0500 ++++ src/linux/linux.stock/net/ipv4/netfilter/Makefile 2004-05-09 04:13:03.000000000 -0400 +@@ -31,48 +31,20 @@ + # connection tracking + obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o + +-# H.323 support +-obj-$(CONFIG_IP_NF_H323) += ip_conntrack_h323.o +-obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o +-ifdef CONFIG_IP_NF_NAT_H323 +- export-objs += ip_conntrack_h323.o +-endif +- +- +-# connection tracking protocol helpers +-obj-$(CONFIG_IP_NF_CT_PROTO_GRE) += ip_conntrack_proto_gre.o +-ifdef CONFIG_IP_NF_CT_PROTO_GRE +- export-objs += ip_conntrack_proto_gre.o +-endif +- +-# NAT protocol helpers +-obj-$(CONFIG_IP_NF_NAT_PROTO_GRE) += ip_nat_proto_gre.o +- + # connection tracking helpers +-obj-$(CONFIG_IP_NF_MMS) += ip_conntrack_mms.o +-ifdef CONFIG_IP_NF_NAT_MMS +- export-objs += ip_conntrack_mms.o +-endif +-obj-$(CONFIG_IP_NF_PPTP) += ip_conntrack_pptp.o +-ifdef CONFIG_IP_NF_NAT_PPTP +- export-objs += ip_conntrack_pptp.o +-endif +-obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o + obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o + ifdef CONFIG_IP_NF_NAT_FTP + export-objs += ip_conntrack_ftp.o + endif ++ + obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o + ifdef CONFIG_IP_NF_NAT_IRC + export-objs += ip_conntrack_irc.o + endif + + # NAT helpers +-obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.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 +-obj-$(CONFIG_IP_NF_NAT_MMS) += ip_nat_mms.o + + # generic IP tables + obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o +@@ -86,19 +58,12 @@ + obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o + obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o + obj-$(CONFIG_IP_NF_MATCH_MARK) += ipt_mark.o +-obj-$(CONFIG_IP_NF_POOL) += ipt_pool.o ip_pool.o + obj-$(CONFIG_IP_NF_MATCH_MAC) += ipt_mac.o + + obj-$(CONFIG_IP_NF_MATCH_PKTTYPE) += ipt_pkttype.o + obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o +- +-obj-$(CONFIG_IP_NF_MATCH_MPORT) += ipt_mport.o +- + obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o + obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o +- +-obj-$(CONFIG_IP_NF_MATCH_TIME) += ipt_time.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 +@@ -109,7 +74,6 @@ + obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o + obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o + obj-$(CONFIG_IP_NF_MATCH_UNCLEAN) += ipt_unclean.o +-obj-$(CONFIG_IP_NF_MATCH_WEBSTR) += ipt_webstr.o + obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o + + # targets +@@ -125,8 +89,6 @@ + obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o + obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o + obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o +-obj-$(CONFIG_IP_NF_AUTOFW) += ip_autofw.o +-obj-$(CONFIG_IP_NF_TARGET_TRIGGER) += ipt_TRIGGER.o + + # generic ARP tables + obj-$(CONFIG_IP_NF_ARPTABLES) += arp_tables.o +diff -Nurb src/linux/linux/net/ipv4/netfilter/ip_conntrack_core.c src/linux/linux.stock/net/ipv4/netfilter/ip_conntrack_core.c +--- src/linux/linux/net/ipv4/netfilter/ip_conntrack_core.c 2003-08-12 07:33:45.000000000 -0400 ++++ src/linux/linux.stock/net/ipv4/netfilter/ip_conntrack_core.c 2004-05-09 04:13:03.000000000 -0400 +@@ -47,7 +47,11 @@ + + #define IP_CONNTRACK_VERSION "2.1" + ++#if 0 ++#define DEBUGP printk ++#else + #define DEBUGP(format, args...) ++#endif + + DECLARE_RWLOCK(ip_conntrack_lock); + DECLARE_RWLOCK(ip_conntrack_expect_tuple_lock); +@@ -62,29 +66,6 @@ + struct list_head *ip_conntrack_hash; + static kmem_cache_t *ip_conntrack_cachep; + +-#define SECS * HZ +-#define MINS * 60 SECS +-#define HOURS * 60 MINS +-#define DAYS * 24 HOURS +- +-int sysctl_ip_conntrack_tcp_timeouts[10] = { +- 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, */ +-}; +- +-int sysctl_ip_conntrack_udp_timeouts[2] = { +- 30 SECS, /* UNREPLIED */ +- 180 SECS /* ASSURED */ +-}; +- + extern struct ip_conntrack_protocol ip_conntrack_generic_protocol; + + static inline int proto_cmpfn(const struct ip_conntrack_protocol *curr, +@@ -129,6 +110,9 @@ + static inline u_int32_t + hash_conntrack(const struct ip_conntrack_tuple *tuple) + { ++#if 0 ++ dump_tuple(tuple); ++#endif + /* ntohl because more differences in low bits. */ + /* To ensure that halves of the same connection don't hash + clash, we add the source per-proto again. */ +@@ -160,8 +144,6 @@ + tuple->dst.ip = iph->daddr; + tuple->dst.protonum = iph->protocol; + +- tuple->src.u.all = tuple->dst.u.all = 0; +- + ret = protocol->pkt_to_tuple((u_int32_t *)iph + iph->ihl, + len - 4*iph->ihl, + tuple); +@@ -177,8 +159,6 @@ + inverse->dst.ip = orig->src.ip; + inverse->dst.protonum = orig->dst.protonum; + +- inverse->src.u.all = inverse->dst.u.all = 0; +- + return protocol->invert_tuple(inverse, orig); + } + +@@ -196,8 +176,8 @@ + static void + destroy_expect(struct ip_conntrack_expect *exp) + { +- DEBUGP("destroy_expect(%p) use=%d\n", exp, atomic_read(&exp->use)); +- IP_NF_ASSERT(atomic_read(&exp->use)); ++ DEBUGP("destroy_expect(%p) use=%d\n", exp, atomic_read(exp->use)); ++ IP_NF_ASSERT(atomic_read(exp->use)); + IP_NF_ASSERT(!timer_pending(&exp->timeout)); + + kfree(exp); +@@ -267,11 +247,11 @@ + static void unexpect_related(struct ip_conntrack_expect *expect) + { + IP_NF_ASSERT(expect->expectant); ++ IP_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 +- && expect->expectant->helper->timeout ++ if (expect->expectant->helper->timeout + && !del_timer(&expect->timeout)) + return; + +@@ -580,6 +560,7 @@ + if (!h) { + /* Locally generated ICMPs will match inverted if they + haven't been SNAT'ed yet */ ++ /* FIXME: NAT code has to handle half-done double NAT --RR */ + if (hooknum == NF_IP_LOCAL_OUT) + h = ip_conntrack_find_get(&origtuple, NULL); + +@@ -725,7 +706,6 @@ + + /* If the expectation is dying, then this is a looser. */ + if (expected +- && expected->expectant->helper + && expected->expectant->helper->timeout + && ! del_timer(&expected->timeout)) + expected = NULL; +@@ -744,7 +724,6 @@ + conntrack->master = expected; + expected->sibling = conntrack; + LIST_DELETE(&ip_conntrack_expect_list, expected); +- INIT_LIST_HEAD(&expected->list); + expected->expectant->expecting--; + nf_conntrack_get(&master_ct(conntrack)->infos[0]); + } +@@ -821,9 +800,23 @@ + int set_reply; + int ret; + ++ /* FIXME: Do this right please. --RR */ + (*pskb)->nfcache |= NFC_UNKNOWN; + + /* Doesn't cover locally-generated broadcast, so not worth it. */ ++#if 0 ++ /* Ignore broadcast: no `connection'. */ ++ if ((*pskb)->pkt_type == PACKET_BROADCAST) { ++ printk("Broadcast packet!\n"); ++ return NF_ACCEPT; ++ } else if (((*pskb)->nh.iph->daddr & htonl(0x000000FF)) ++ == htonl(0x000000FF)) { ++ printk("Should bcast: %u.%u.%u.%u->%u.%u.%u.%u (sk=%p, ptype=%u)\n", ++ NIPQUAD((*pskb)->nh.iph->saddr), ++ NIPQUAD((*pskb)->nh.iph->daddr), ++ (*pskb)->sk, (*pskb)->pkt_type); ++ } ++#endif + + /* Previously seen (loopback)? Ignore. Do this before + fragment check. */ +@@ -943,8 +936,8 @@ + * so there is no need to use the tuple lock too */ + + DEBUGP("ip_conntrack_expect_related %p\n", related_to); +- DEBUGP("tuple: "); DUMP_TUPLE_RAW(&expect->tuple); +- DEBUGP("mask: "); DUMP_TUPLE_RAW(&expect->mask); ++ DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple); ++ DEBUGP("mask: "); DUMP_TUPLE(&expect->mask); + + old = LIST_FIND(&ip_conntrack_expect_list, resent_expect, + struct ip_conntrack_expect *, &expect->tuple, +@@ -954,8 +947,7 @@ + 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 && +- related_to->helper->timeout) { ++ if (related_to->helper->timeout) { + if (!del_timer(&old->timeout)) { + /* expectation is dying. Fall through */ + old = NULL; +@@ -970,32 +962,26 @@ + WRITE_UNLOCK(&ip_conntrack_lock); + return -EEXIST; + } +- } else if (related_to->helper && +- related_to->helper->max_expected && ++ } 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 & +- IP_CT_HELPER_F_REUSE_EXPECT)) { +- WRITE_UNLOCK(&ip_conntrack_lock); + if (net_ratelimit()) + printk(KERN_WARNING + "ip_conntrack: max number of expected " + "connections %i of %s reached for " +- "%u.%u.%u.%u->%u.%u.%u.%u\n", ++ "%u.%u.%u.%u->%u.%u.%u.%u%s\n", + related_to->helper->max_expected, + related_to->helper->name, + NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip), +- NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip)); ++ NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip), ++ related_to->helper->flags & IP_CT_HELPER_F_REUSE_EXPECT ? ++ ", reusing" : ""); ++ if (!(related_to->helper->flags & ++ IP_CT_HELPER_F_REUSE_EXPECT)) { ++ WRITE_UNLOCK(&ip_conntrack_lock); + return -EPERM; + } +- DEBUGP("ip_conntrack: max number of expected " +- "connections %i of %s reached for " +- "%u.%u.%u.%u->%u.%u.%u.%u, reusing\n", +- related_to->helper->max_expected, +- related_to->helper->name, +- NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip), +- NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip)); + + /* choose the the oldest expectation to evict */ + list_for_each(cur_item, &related_to->sibling_list) { +@@ -1055,8 +1041,7 @@ + /* add to global list of expectations */ + list_prepend(&ip_conntrack_expect_list, &new->list); + /* add and start timer if required */ +- if (related_to->helper && +- related_to->helper->timeout) { ++ if (related_to->helper->timeout) { + init_timer(&new->timeout); + new->timeout.data = (unsigned long)new; + new->timeout.function = expectation_timed_out; +@@ -1079,10 +1064,11 @@ + + MUST_BE_READ_LOCKED(&ip_conntrack_lock); + WRITE_LOCK(&ip_conntrack_expect_tuple_lock); ++ + DEBUGP("change_expect:\n"); +- DEBUGP("exp tuple: "); DUMP_TUPLE_RAW(&expect->tuple); +- DEBUGP("exp mask: "); DUMP_TUPLE_RAW(&expect->mask); +- DEBUGP("newtuple: "); DUMP_TUPLE_RAW(newtuple); ++ DEBUGP("exp tuple: "); DUMP_TUPLE(&expect->tuple); ++ DEBUGP("exp mask: "); DUMP_TUPLE(&expect->mask); ++ DEBUGP("newtuple: "); DUMP_TUPLE(newtuple); + if (expect->ct_tuple.dst.protonum == 0) { + /* Never seen before */ + DEBUGP("change expect: never seen before\n"); +@@ -1360,8 +1346,6 @@ + 0, NULL }; + + #define NET_IP_CONNTRACK_MAX 2089 +-#define NET_IP_CONNTRACK_TCP_TIMEOUTS 2090 +-#define NET_IP_CONNTRACK_UDP_TIMEOUTS 2091 + #define NET_IP_CONNTRACK_MAX_NAME "ip_conntrack_max" + + #ifdef CONFIG_SYSCTL +@@ -1370,14 +1354,6 @@ + static ctl_table ip_conntrack_table[] = { + { NET_IP_CONNTRACK_MAX, NET_IP_CONNTRACK_MAX_NAME, &ip_conntrack_max, + sizeof(ip_conntrack_max), 0644, NULL, proc_dointvec }, +- { NET_IP_CONNTRACK_TCP_TIMEOUTS, "ip_conntrack_tcp_timeouts", +- &sysctl_ip_conntrack_tcp_timeouts, +- sizeof(sysctl_ip_conntrack_tcp_timeouts), +- 0644, NULL, &proc_dointvec_jiffies, &sysctl_jiffies }, +- { NET_IP_CONNTRACK_UDP_TIMEOUTS, "ip_conntrack_udp_timeouts", +- &sysctl_ip_conntrack_udp_timeouts, +- sizeof(sysctl_ip_conntrack_udp_timeouts), +- 0644, NULL, &proc_dointvec_jiffies, &sysctl_jiffies }, + { 0 } + }; + +diff -Nurb src/linux/linux/net/ipv4/netfilter/ip_conntrack_ftp.c src/linux/linux.stock/net/ipv4/netfilter/ip_conntrack_ftp.c +--- src/linux/linux/net/ipv4/netfilter/ip_conntrack_ftp.c 2003-07-04 04:12:31.000000000 -0400 ++++ src/linux/linux.stock/net/ipv4/netfilter/ip_conntrack_ftp.c 2004-05-09 04:13:03.000000000 -0400 +@@ -24,7 +24,11 @@ + static int loose = 0; + MODULE_PARM(loose, "i"); + ++#if 0 ++#define DEBUGP printk ++#else + #define DEBUGP(format, args...) ++#endif + + static int try_rfc959(const char *, size_t, u_int32_t [], char); + static int try_eprt(const char *, size_t, u_int32_t [], char); +@@ -191,6 +195,16 @@ + } + + if (strnicmp(data, pattern, plen) != 0) { ++#if 0 ++ size_t i; ++ ++ DEBUGP("ftp: string mismatch\n"); ++ for (i = 0; i < plen; i++) { ++ DEBUGFTP("ftp:char %u `%c'(%u) vs `%c'(%u)\n", ++ i, data[i], data[i], ++ pattern[i], pattern[i]); ++ } ++#endif + return 0; + } + +@@ -214,6 +228,7 @@ + return 1; + } + ++/* FIXME: This should be in userspace. Later. */ + static int help(const struct iphdr *iph, size_t len, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo) +@@ -249,6 +264,7 @@ + } + + /* Checksum invalid? Ignore. */ ++ /* FIXME: Source route IP option packets --RR */ + if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, + csum_partial((char *)tcph, tcplen, 0))) { + DEBUGP("ftp_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", +diff -Nurb src/linux/linux/net/ipv4/netfilter/ip_conntrack_h323.c src/linux/linux.stock/net/ipv4/netfilter/ip_conntrack_h323.c +--- src/linux/linux/net/ipv4/netfilter/ip_conntrack_h323.c 2003-07-04 04:12:31.000000000 -0400 ++++ src/linux/linux.stock/net/ipv4/netfilter/ip_conntrack_h323.c 1969-12-31 19:00:00.000000000 -0500 +@@ -1,302 +0,0 @@ +-/* +- * H.323 'brute force' extension for H.323 connection tracking. +- * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> +- * +- * Based on ip_masq_h323.c for 2.2 kernels from CoRiTel, Sofia project. +- * (http://www.coritel.it/projects/sofia/nat/) +- * Uses Sampsa Ranta's excellent idea on using expectfn to 'bind' +- * the unregistered helpers to the conntrack entries. +- */ +- +- +-#include <linux/module.h> +-#include <linux/netfilter.h> +-#include <linux/ip.h> +-#include <net/checksum.h> +-#include <net/tcp.h> +- +-#include <linux/netfilter_ipv4/lockhelp.h> +-#include <linux/netfilter_ipv4/ip_conntrack.h> +-#include <linux/netfilter_ipv4/ip_conntrack_core.h> +-#include <linux/netfilter_ipv4/ip_conntrack_helper.h> +-#include <linux/netfilter_ipv4/ip_conntrack_tuple.h> +-#include <linux/netfilter_ipv4/ip_conntrack_h323.h> +- +-MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); +-MODULE_DESCRIPTION("H.323 'brute force' connection tracking module"); +-MODULE_LICENSE("GPL"); +- +-DECLARE_LOCK(ip_h323_lock); +-struct module *ip_conntrack_h323 = THIS_MODULE; +- +-#define DEBUGP(format, args...) +- +-static int h245_help(const struct iphdr *iph, size_t len, +- struct ip_conntrack *ct, +- enum ip_conntrack_info ctinfo) +-{ +- struct tcphdr *tcph = (void *)iph + iph->ihl * 4; +- unsigned char *data = (unsigned char *) tcph + tcph->doff * 4; +- unsigned char *data_limit; +- u_int32_t tcplen = len - iph->ihl * 4; +- u_int32_t datalen = tcplen - tcph->doff * 4; +- int dir = CTINFO2DIR(ctinfo); +- struct ip_ct_h225_master *info = &ct->help.ct_h225_info; +- struct ip_conntrack_expect expect, *exp = &expect; +- struct ip_ct_h225_expect *exp_info = &exp->help.exp_h225_info; +- u_int16_t data_port; +- u_int32_t data_ip; +- unsigned int i; +- +- DEBUGP("ct_h245_help: help entered %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n", +- NIPQUAD(iph->saddr), ntohs(tcph->source), +- NIPQUAD(iph->daddr), ntohs(tcph->dest)); +- +- /* Can't track connections formed before we registered */ +- if (!info) +- return NF_ACCEPT; +- +- /* Until there's been traffic both ways, don't look in packets. */ +- if (ctinfo != IP_CT_ESTABLISHED +- && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { +- DEBUGP("ct_h245_help: Conntrackinfo = %u\n", ctinfo); +- return NF_ACCEPT; +- } +- +- /* Not whole TCP header or too short packet? */ +- if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4 + 5) { +- DEBUGP("ct_h245_help: tcplen = %u\n", (unsigned)tcplen); +- return NF_ACCEPT; +- } +- +- /* Checksum invalid? Ignore. */ +- if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, +- csum_partial((char *)tcph, tcplen, 0))) { +- DEBUGP("ct_h245_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", +- tcph, tcplen, NIPQUAD(iph->saddr), +- NIPQUAD(iph->daddr)); +- return NF_ACCEPT; +- } +- +- data_limit = (unsigned char *) data + datalen; +- /* bytes: 0123 45 +- ipadrr port */ +- for (i = 0; data < (data_limit - 5); data++, i++) { +- memcpy(&data_ip, data, sizeof(u_int32_t)); +- if (data_ip == iph->saddr) { +- memcpy(&data_port, data + 4, sizeof(u_int16_t)); +- memset(&expect, 0, sizeof(expect)); +- /* update the H.225 info */ +- DEBUGP("ct_h245_help: new RTCP/RTP requested %u.%u.%u.%u:->%u.%u.%u.%u:%u\n", +- NIPQUAD(ct->tuplehash[!dir].tuple.src.ip), +- NIPQUAD(iph->saddr), ntohs(data_port)); +- LOCK_BH(&ip_h323_lock); +- info->is_h225 = H225_PORT + 1; +- exp_info->port = data_port; +- exp_info->dir = dir; +- exp_info->offset = i; +- +- exp->seq = ntohl(tcph->seq) + i; +- +- exp->tuple = ((struct ip_conntrack_tuple) +- { { ct->tuplehash[!dir].tuple.src.ip, +- { 0 } }, +- { data_ip, +- { data_port }, +- IPPROTO_UDP }}); +- exp->mask = ((struct ip_conntrack_tuple) +- { { 0xFFFFFFFF, { 0 } }, +- { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }}); +- +- exp->expectfn = NULL; +- +- /* Ignore failure; should only happen with NAT */ +- ip_conntrack_expect_related(ct, exp); +- +- UNLOCK_BH(&ip_h323_lock); +- } +- } +- +- return NF_ACCEPT; +- +-} +- +-/* H.245 helper is not registered! */ +-static struct ip_conntrack_helper h245 = +- { { NULL, NULL }, +- "H.245", /* name */ +- IP_CT_HELPER_F_REUSE_EXPECT, /* flags */ +- NULL, /* module */ +- 8, /* max_ expected */ +- 240, /* timeout */ +- { { 0, { 0 } }, /* tuple */ +- { 0, { 0 }, IPPROTO_TCP } }, +- { { 0, { 0xFFFF } }, /* mask */ +- { 0, { 0 }, 0xFFFF } }, +- h245_help /* helper */ +- }; +- +-static int h225_expect(struct ip_conntrack *ct) +-{ +- WRITE_LOCK(&ip_conntrack_lock); +- ct->helper = &h245; +- DEBUGP("h225_expect: helper for %p added\n", ct); +- WRITE_UNLOCK(&ip_conntrack_lock); +- +- return NF_ACCEPT; /* unused */ +-} +- +-static int h225_help(const struct iphdr *iph, size_t len, +- struct ip_conntrack *ct, +- enum ip_conntrack_info ctinfo) +-{ +- struct tcphdr *tcph = (void *)iph + iph->ihl * 4; +- unsigned char *data = (unsigned char *) tcph + tcph->doff * 4; +- unsigned char *data_limit; +- u_int32_t tcplen = len - iph->ihl * 4; +- u_int32_t datalen = tcplen - tcph->doff * 4; +- int dir = CTINFO2DIR(ctinfo); +- struct ip_ct_h225_master *info = &ct->help.ct_h225_info; +- struct ip_conntrack_expect expect, *exp = &expect; +- struct ip_ct_h225_expect *exp_info = &exp->help.exp_h225_info; +- u_int16_t data_port; +- u_int32_t data_ip; +- unsigned int i; +- +- DEBUGP("ct_h225_help: help entered %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n", +- NIPQUAD(iph->saddr), ntohs(tcph->source), +- NIPQUAD(iph->daddr), ntohs(tcph->dest)); +- +- /* Can't track connections formed before we registered */ +- if (!info) +- return NF_ACCEPT; +- +- /* Until there's been traffic both ways, don't look in packets. */ +- if (ctinfo != IP_CT_ESTABLISHED +- && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { +- DEBUGP("ct_h225_help: Conntrackinfo = %u\n", ctinfo); +- return NF_ACCEPT; +- } +- +- /* Not whole TCP header or too short packet? */ +- if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4 + 5) { +- DEBUGP("ct_h225_help: tcplen = %u\n", (unsigned)tcplen); +- return NF_ACCEPT; +- } +- +- /* Checksum invalid? Ignore. */ +- if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, +- csum_partial((char *)tcph, tcplen, 0))) { +- DEBUGP("ct_h225_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", +- tcph, tcplen, NIPQUAD(iph->saddr), +- NIPQUAD(iph->daddr)); +- return NF_ACCEPT; +- } +- +- data_limit = (unsigned char *) data + datalen; +- /* bytes: 0123 45 +- ipadrr port */ +- for (i = 0; data < (data_limit - 5); data++, i++) { +- memcpy(&data_ip, data, sizeof(u_int32_t)); +- if (data_ip == iph->saddr) { +- memcpy(&data_port, data + 4, sizeof(u_int16_t)); +- if (data_port == tcph->source) { +- /* Signal address */ +- DEBUGP("ct_h225_help: sourceCallSignalAddress from %u.%u.%u.%u\n", +- NIPQUAD(iph->saddr)); +- /* Update the H.225 info so that NAT can mangle the address/port +- even when we have no expected connection! */ +-#ifdef CONFIG_IP_NF_NAT_NEEDED +- LOCK_BH(&ip_h323_lock); +- info->dir = dir; +- info->seq[IP_CT_DIR_ORIGINAL] = ntohl(tcph->seq) + i; +- info->offset[IP_CT_DIR_ORIGINAL] = i; +- UNLOCK_BH(&ip_h323_lock); +-#endif +- } else { +- memset(&expect, 0, sizeof(expect)); +- +- /* update the H.225 info */ +- LOCK_BH(&ip_h323_lock); +- info->is_h225 = H225_PORT; +- exp_info->port = data_port; +- exp_info->dir = dir; +- exp_info->offset = i; +- +- exp->seq = ntohl(tcph->seq) + i; +- +- exp->tuple = ((struct ip_conntrack_tuple) +- { { ct->tuplehash[!dir].tuple.src.ip, +- { 0 } }, +- { data_ip, +- { data_port }, +- IPPROTO_TCP }}); +- exp->mask = ((struct ip_conntrack_tuple) +- { { 0xFFFFFFFF, { 0 } }, +- { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }}); +- +- exp->expectfn = h225_expect; +- +- /* Ignore failure */ +- ip_conntrack_expect_related(ct, exp); +- +- DEBUGP("ct_h225_help: new H.245 requested %u.%u.%u.%u->%u.%u.%u.%u:%u\n", +- NIPQUAD(ct->tuplehash[!dir].tuple.src.ip), +- NIPQUAD(iph->saddr), ntohs(data_port)); +- +- UNLOCK_BH(&ip_h323_lock); +- } +-#ifdef CONFIG_IP_NF_NAT_NEEDED +- } else if (data_ip == iph->daddr) { +- memcpy(&data_port, data + 4, sizeof(u_int16_t)); +- if (data_port == tcph->dest) { +- /* Signal address */ +- DEBUGP("ct_h225_help: destCallSignalAddress %u.%u.%u.%u\n", +- NIPQUAD(iph->daddr)); +- /* Update the H.225 info so that NAT can mangle the address/port +- even when we have no expected connection! */ +- LOCK_BH(&ip_h323_lock); +- info->dir = dir; +- info->seq[IP_CT_DIR_REPLY] = ntohl(tcph->seq) + i; +- info->offset[IP_CT_DIR_REPLY] = i; +- UNLOCK_BH(&ip_h323_lock); +- } +-#endif +- } +- } +- +- return NF_ACCEPT; +- +-} +- +-static struct ip_conntrack_helper h225 = +- { { NULL, NULL }, +- "H.225", /* name */ +- IP_CT_HELPER_F_REUSE_EXPECT, /* flags */ +- THIS_MODULE, /* module */ +- 2, /* max_expected */ +- 240, /* timeout */ +- { { 0, { __constant_htons(H225_PORT) } }, /* tuple */ +- { 0, { 0 }, IPPROTO_TCP } }, +- { { 0, { 0xFFFF } }, /* mask */ +- { 0, { 0 }, 0xFFFF } }, +- h225_help /* helper */ +- }; +- +-static int __init init(void) +-{ +- return ip_conntrack_helper_register(&h225); +-} +- +-static void __exit fini(void) +-{ +- /* Unregister H.225 helper */ +- ip_conntrack_helper_unregister(&h225); +-} +- +-#ifdef CONFIG_IP_NF_NAT_NEEDED +-EXPORT_SYMBOL(ip_h323_lock); +-#endif +- +-module_init(init); +-module_exit(fini); +diff -Nurb src/linux/linux/net/ipv4/netfilter/ip_conntrack_mms.c src/linux/linux.stock/net/ipv4/netfilter/ip_conntrack_mms.c +--- src/linux/linux/net/ipv4/netfilter/ip_conntrack_mms.c 2003-07-04 04:12:31.000000000 -0400 ++++ src/linux/linux.stock/net/ipv4/netfilter/ip_conntrack_mms.c 1969-12-31 19:00:00.000000000 -0500 +@@ -1,292 +0,0 @@ +-/* MMS extension for IP connection tracking +- * (C) 2002 by Filip Sneppe <filip.sneppe@cronos.be> +- * based on ip_conntrack_ftp.c and ip_conntrack_irc.c +- * +- * ip_conntrack_mms.c v0.3 2002-09-22 +- * +- * 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. +- * +- * Module load syntax: +- * insmod ip_conntrack_mms.o ports=port1,port2,...port<MAX_PORTS> +- * +- * Please give the ports of all MMS servers You wish to connect to. +- * If you don't specify ports, the default will be TCP port 1755. +- * +- * More info on MMS protocol, firewalls and NAT: +- * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwmt/html/MMSFirewall.asp +- * http://www.microsoft.com/windows/windowsmedia/serve/firewall.asp +- * +- * The SDP project people are reverse-engineering MMS: +- * http://get.to/sdp +- */ +- +-#include <linux/config.h> +-#include <linux/module.h> +-#include <linux/netfilter.h> +-#include <linux/ip.h> +-#include <linux/ctype.h> +-#include <net/checksum.h> +-#include <net/tcp.h> +- +-#include <linux/netfilter_ipv4/lockhelp.h> +-#include <linux/netfilter_ipv4/ip_conntrack_helper.h> +-#include <linux/netfilter_ipv4/ip_conntrack_mms.h> +- +-DECLARE_LOCK(ip_mms_lock); +-struct module *ip_conntrack_mms = THIS_MODULE; +- +-#define MAX_PORTS 8 +-static int ports[MAX_PORTS]; +-static int ports_c; +-#ifdef MODULE_PARM +-MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); +-#endif +- +-#define DEBUGP(format, args...) +- +-#ifdef CONFIG_IP_NF_NAT_NEEDED +-EXPORT_SYMBOL(ip_mms_lock); +-#endif +- +-MODULE_AUTHOR("Filip Sneppe <filip.sneppe@cronos.be>"); +-MODULE_DESCRIPTION("Microsoft Windows Media Services (MMS) connection tracking module"); +-MODULE_LICENSE("GPL"); +- +-/* #define isdigit(c) (c >= '0' && c <= '9') */ +- +-/* copied from drivers/usb/serial/io_edgeport.c - not perfect but will do the trick */ +-static void unicode_to_ascii (char *string, short *unicode, int unicode_size) +-{ +- int i; +- for (i = 0; i < unicode_size; ++i) { +- string[i] = (char)(unicode[i]); +- } +- string[unicode_size] = 0x00; +-} +- +-__inline static int atoi(char *s) +-{ +- int i=0; +- while (isdigit(*s)) { +- i = i*10 + *(s++) - '0'; +- } +- return i; +-} +- +-/* convert ip address string like "192.168.0.10" to unsigned int */ +-__inline static u_int32_t asciiiptoi(char *s) +-{ +- unsigned int i, j, k; +- +- for(i=k=0; k<3; ++k, ++s, i<<=8) { +- i+=atoi(s); +- for(j=0; (*(++s) != '.') && (j<3); ++j) +- ; +- } +- i+=atoi(s); +- return ntohl(i); +-} +- +-int parse_mms(const char *data, +- const unsigned int datalen, +- u_int32_t *mms_ip, +- u_int16_t *mms_proto, +- u_int16_t *mms_port, +- char **mms_string_b, +- char **mms_string_e, +- char **mms_padding_e) +-{ +- int unicode_size, i; +- char tempstring[28]; /* "\\255.255.255.255\UDP\65535" */ +- char getlengthstring[28]; +- +- for(unicode_size=0; +- (char) *(data+(MMS_SRV_UNICODE_STRING_OFFSET+unicode_size*2)) != (char)0; +- unicode_size++) +- if ((unicode_size == 28) || (MMS_SRV_UNICODE_STRING_OFFSET+unicode_size*2 >= datalen)) +- return -1; /* out of bounds - incomplete packet */ +- +- unicode_to_ascii(tempstring, (short *)(data+MMS_SRV_UNICODE_STRING_OFFSET), unicode_size); +- DEBUGP("ip_conntrack_mms: offset 60: %s\n", (const char *)(tempstring)); +- +- /* IP address ? */ +- *mms_ip = asciiiptoi(tempstring+2); +- +- i=sprintf(getlengthstring, "%u.%u.%u.%u", HIPQUAD(*mms_ip)); +- +- /* protocol ? */ +- if(strncmp(tempstring+3+i, "TCP", 3)==0) +- *mms_proto = IPPROTO_TCP; +- else if(strncmp(tempstring+3+i, "UDP", 3)==0) +- *mms_proto = IPPROTO_UDP; +- +- /* port ? */ +- *mms_port = atoi(tempstring+7+i); +- +- /* we store a pointer to the beginning of the "\\a.b.c.d\proto\port" +- unicode string, one to the end of the string, and one to the end +- of the packet, since we must keep track of the number of bytes +- between end of the unicode string and the end of packet (padding) */ +- *mms_string_b = (char *)(data + MMS_SRV_UNICODE_STRING_OFFSET); +- *mms_string_e = (char *)(data + MMS_SRV_UNICODE_STRING_OFFSET + unicode_size * 2); +- *mms_padding_e = (char *)(data + datalen); /* looks funny, doesn't it */ +- return 0; +-} +- +- +-static int help(const struct iphdr *iph, size_t len, +- struct ip_conntrack *ct, +- enum ip_conntrack_info ctinfo) +-{ +- /* tcplen not negative guaranteed by ip_conntrack_tcp.c */ +- struct tcphdr *tcph = (void *)iph + iph->ihl * 4; +- const char *data = (const char *)tcph + tcph->doff * 4; +- unsigned int tcplen = len - iph->ihl * 4; +- unsigned int datalen = tcplen - tcph->doff * 4; +- int dir = CTINFO2DIR(ctinfo); +- struct ip_conntrack_expect expect, *exp = &expect; +- struct ip_ct_mms_expect *exp_mms_info = &exp->help.exp_mms_info; +- +- u_int32_t mms_ip; +- u_int16_t mms_proto; +- char mms_proto_string[8]; +- u_int16_t mms_port; +- char *mms_string_b, *mms_string_e, *mms_padding_e; +- +- /* Until there's been traffic both ways, don't look in packets. */ +- if (ctinfo != IP_CT_ESTABLISHED +- && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) { +- DEBUGP("ip_conntrack_mms: Conntrackinfo = %u\n", ctinfo); +- return NF_ACCEPT; +- } +- +- /* Not whole TCP header? */ +- if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff*4) { +- DEBUGP("ip_conntrack_mms: tcplen = %u\n", (unsigned)tcplen); +- return NF_ACCEPT; +- } +- +- /* Checksum invalid? Ignore. */ +- if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, +- csum_partial((char *)tcph, tcplen, 0))) { +- DEBUGP("mms_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", +- tcph, tcplen, NIPQUAD(iph->saddr), +- NIPQUAD(iph->daddr)); +- return NF_ACCEPT; +- } +- +- /* Only look at packets with 0x00030002/196610 on bytes 36->39 of TCP payload */ +- if( (MMS_SRV_MSG_OFFSET < datalen) && +- ((*(u32 *)(data+MMS_SRV_MSG_OFFSET)) == MMS_SRV_MSG_ID)) { +- DEBUGP("ip_conntrack_mms: offset 37: %u %u %u %u, datalen:%u\n", +- (u8)*(data+36), (u8)*(data+37), +- (u8)*(data+38), (u8)*(data+39), +- datalen); +- if(parse_mms(data, datalen, &mms_ip, &mms_proto, &mms_port, +- &mms_string_b, &mms_string_e, &mms_padding_e)) +- if(net_ratelimit()) +- printk(KERN_WARNING +- "ip_conntrack_mms: Unable to parse data payload\n"); +- +- memset(&expect, 0, sizeof(expect)); +- +- sprintf(mms_proto_string, "(%u)", mms_proto); +- DEBUGP("ip_conntrack_mms: adding %s expectation %u.%u.%u.%u -> %u.%u.%u.%u:%u\n", +- mms_proto == IPPROTO_TCP ? "TCP" +- : mms_proto == IPPROTO_UDP ? "UDP":mms_proto_string, +- NIPQUAD(ct->tuplehash[!dir].tuple.src.ip), +- NIPQUAD(mms_ip), +- mms_port); +- +- /* it's possible that the client will just ask the server to tunnel +- the stream over the same TCP session (from port 1755): there's +- shouldn't be a need to add an expectation in that case, but it +- makes NAT packet mangling so much easier */ +- LOCK_BH(&ip_mms_lock); +- +- DEBUGP("ip_conntrack_mms: tcph->seq = %u\n", tcph->seq); +- +- exp->seq = ntohl(tcph->seq) + (mms_string_b - data); +- exp_mms_info->len = (mms_string_e - mms_string_b); +- exp_mms_info->padding = (mms_padding_e - mms_string_e); +- exp_mms_info->port = mms_port; +- +- DEBUGP("ip_conntrack_mms: wrote info seq=%u (ofs=%u), len=%d, padding=%u\n", +- exp->seq, (mms_string_e - data), exp_mms_info->len, exp_mms_info->padding); +- +- exp->tuple = ((struct ip_conntrack_tuple) +- { { ct->tuplehash[!dir].tuple.src.ip, { 0 } }, +- { mms_ip, +- { (__u16) ntohs(mms_port) }, +- mms_proto } } +- ); +- exp->mask = ((struct ip_conntrack_tuple) +- { { 0xFFFFFFFF, { 0 } }, +- { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }}); +- exp->expectfn = NULL; +- ip_conntrack_expect_related(ct, &expect); +- UNLOCK_BH(&ip_mms_lock); +- } +- +- return NF_ACCEPT; +-} +- +-static struct ip_conntrack_helper mms[MAX_PORTS]; +-static char mms_names[MAX_PORTS][10]; +- +-/* Not __exit: called from init() */ +-static void fini(void) +-{ +- int i; +- for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { +- DEBUGP("ip_conntrack_mms: unregistering helper for port %d\n", +- ports[i]); +- ip_conntrack_helper_unregister(&mms[i]); +- } +-} +- +-static int __init init(void) +-{ +- int i, ret; +- char *tmpname; +- +- if (ports[0] == 0) +- ports[0] = MMS_PORT; +- +- for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { +- memset(&mms[i], 0, sizeof(struct ip_conntrack_helper)); +- mms[i].tuple.src.u.tcp.port = htons(ports[i]); +- mms[i].tuple.dst.protonum = IPPROTO_TCP; +- mms[i].mask.src.u.tcp.port = 0xFFFF; +- mms[i].mask.dst.protonum = 0xFFFF; +- mms[i].max_expected = 1; +- mms[i].timeout = 0; +- mms[i].flags = IP_CT_HELPER_F_REUSE_EXPECT; +- mms[i].me = THIS_MODULE; +- mms[i].help = help; +- +- tmpname = &mms_names[i][0]; +- if (ports[i] == MMS_PORT) +- sprintf(tmpname, "mms"); +- else +- sprintf(tmpname, "mms-%d", ports[i]); +- mms[i].name = tmpname; +- +- DEBUGP("ip_conntrack_mms: registering helper for port %d\n", +- ports[i]); +- ret = ip_conntrack_helper_register(&mms[i]); +- +- if (ret) { +- fini(); +- return ret; +- } +- ports_c++; +- } +- return 0; +-} +- +-module_init(init); +-module_exit(fini); +diff -Nurb src/linux/linux/net/ipv4/netfilter/ip_conntrack_pptp.c src/linux/linux.stock/net/ipv4/netfilter/ip_conntrack_pptp.c +--- src/linux/linux/net/ipv4/netfilter/ip_conntrack_pptp.c 2003-07-04 04:12:31.000000000 -0400 ++++ src/linux/linux.stock/net/ipv4/netfilter/ip_conntrack_pptp.c 1969-12-31 19:00:00.000000000 -0500 +@@ -1,531 +0,0 @@ +-/* +- * ip_conntrack_pptp.c - Version 1.11 +- * +- * Connection tracking support for PPTP (Point to Point Tunneling Protocol). +- * PPTP is a a protocol for creating virtual private networks. +- * It is a specification defined by Microsoft and some vendors +- * working with Microsoft. PPTP is built on top of a modified +- * version of the Internet Generic Routing Encapsulation Protocol. +- * GRE is defined in RFC 1701 and RFC 1702. Documentation of +- * PPTP can be found in RFC 2637 +- * +- * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>, +- * +- * Development of this code funded by Astaro AG (http://www.astaro.com/) +- * +- * Limitations: +- * - We blindly assume that control connections are always +- * established in PNS->PAC direction. This is a violation +- * of RFFC2673 +- * +- * TODO: - finish support for multiple calls within one session +- * (needs expect reservations in newnat) +- * - testing of incoming PPTP calls +- */ +- +-#include <linux/config.h> +-#include <linux/module.h> +-#include <linux/netfilter.h> +-#include <linux/ip.h> +-#include <net/checksum.h> +-#include <net/tcp.h> +- +-#include <linux/netfilter_ipv4/lockhelp.h> +-#include <linux/netfilter_ipv4/ip_conntrack_helper.h> +-#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h> +-#include <linux/netfilter_ipv4/ip_conntrack_pptp.h> +- +-MODULE_LICENSE("GPL"); +-MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); +-MODULE_DESCRIPTION("Netfilter connection tracking helper module for PPTP"); +- +-DECLARE_LOCK(ip_pptp_lock); +- +-#define DEBUGP(format, args...) +- +-#define SECS *HZ +-#define MINS * 60 SECS +-#define HOURS * 60 MINS +-#define DAYS * 24 HOURS +- +-#define PPTP_GRE_TIMEOUT (10 MINS) +-#define PPTP_GRE_STREAM_TIMEOUT (5 DAYS) +- +-static int pptp_expectfn(struct ip_conntrack *ct) +-{ +- struct ip_conntrack_expect *exp, *other_exp; +- struct ip_conntrack *master; +- +- DEBUGP("increasing timeouts\n"); +- /* increase timeout of GRE data channel conntrack entry */ +- ct->proto.gre.timeout = PPTP_GRE_TIMEOUT; +- ct->proto.gre.stream_timeout = PPTP_GRE_STREAM_TIMEOUT; +- +- master = master_ct(ct); +- if (!master) { +- DEBUGP(" no master!!!\n"); +- return 0; +- } +- +- DEBUGP("completing tuples with ct info\n"); +- /* we can do this, since we're unconfirmed */ +- if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key == +- htonl(master->help.ct_pptp_info.pac_call_id)) { +- /* assume PNS->PAC */ +- ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key = +- htonl(master->help.ct_pptp_info.pns_call_id); +- ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key = +- htonl(master->help.ct_pptp_info.pns_call_id); +- } else { +- /* assume PAC->PNS */ +- ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key = +- htonl(master->help.ct_pptp_info.pac_call_id); +- ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key = +- htonl(master->help.ct_pptp_info.pns_call_id); +- } +- +- return 0; +-} +- +-/* timeout GRE data connections */ +-static int pptp_timeout_related(struct ip_conntrack *ct) +-{ +- struct list_head *cur_item; +- struct ip_conntrack_expect *exp; +- +- list_for_each(cur_item, &ct->sibling_list) { +- exp = list_entry(cur_item, struct ip_conntrack_expect, +- expected_list); +- +- if (!exp->sibling) +- continue; +- +- DEBUGP("setting timeout of conntrack %p to 0\n", +- exp->sibling); +- exp->sibling->proto.gre.timeout = 0; +- exp->sibling->proto.gre.stream_timeout = 0; +- ip_ct_refresh(exp->sibling, 0); +- } +- +- return 0; +-} +- +-/* expect GRE connection in PNS->PAC direction */ +-static inline int +-exp_gre(struct ip_conntrack *master, +- u_int32_t seq, +- u_int16_t callid, +- u_int16_t peer_callid) +-{ +- struct ip_conntrack_expect exp; +- struct ip_conntrack_tuple inv_tuple; +- +- memset(&exp, 0, sizeof(exp)); +- /* tuple in original direction, PAC->PNS */ +- exp.tuple.src.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; +- exp.tuple.src.u.gre.key = htonl(ntohs(peer_callid)); +- exp.tuple.dst.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; +- exp.tuple.dst.u.gre.key = htonl(ntohs(callid)); +- exp.tuple.dst.u.gre.protocol = __constant_htons(GRE_PROTOCOL_PPTP); +- exp.tuple.dst.u.gre.version = GRE_VERSION_PPTP; +- exp.tuple.dst.protonum = IPPROTO_GRE; +- +- exp.mask.src.ip = 0xffffffff; +- exp.mask.src.u.all = 0; +- exp.mask.dst.u.all = 0; +- exp.mask.dst.u.gre.key = 0xffffffff; +- exp.mask.dst.u.gre.version = 0xff; +- exp.mask.dst.u.gre.protocol = 0xffff; +- exp.mask.dst.ip = 0xffffffff; +- exp.mask.dst.protonum = 0xffff; +- +- exp.seq = seq; +- exp.expectfn = pptp_expectfn; +- +- exp.help.exp_pptp_info.pac_call_id = ntohs(callid); +- exp.help.exp_pptp_info.pns_call_id = ntohs(peer_callid); +- +- DEBUGP("calling expect_related "); +- DUMP_TUPLE_RAW(&exp.tuple); +- +- /* Add GRE keymap entries */ +- ip_ct_gre_keymap_add(&exp, &exp.tuple, 0); +- invert_tuplepr(&inv_tuple, &exp.tuple); +- ip_ct_gre_keymap_add(&exp, &inv_tuple, 1); +- +- ip_conntrack_expect_related(master, &exp); +- +- return 0; +-} +- +-static inline int +-pptp_inbound_pkt(struct tcphdr *tcph, +- struct pptp_pkt_hdr *pptph, +- size_t datalen, +- struct ip_conntrack *ct, +- enum ip_conntrack_info ctinfo) +-{ +- struct PptpControlHeader *ctlh; +- union pptp_ctrl_union pptpReq; +- +- struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; +- u_int16_t msg, *cid, *pcid; +- u_int32_t seq; +- +- ctlh = (struct PptpControlHeader *) +- ((char *) pptph + sizeof(struct pptp_pkt_hdr)); +- pptpReq.rawreq = (void *) +- ((char *) ctlh + sizeof(struct PptpControlHeader)); +- +- msg = ntohs(ctlh->messageType); +- DEBUGP("inbound control message %s\n", strMName[msg]); +- +- switch (msg) { +- case PPTP_START_SESSION_REPLY: +- /* server confirms new control session */ +- if (info->sstate < PPTP_SESSION_REQUESTED) { +- DEBUGP("%s without START_SESS_REQUEST\n", +- strMName[msg]); +- break; +- } +- if (pptpReq.srep->resultCode == PPTP_START_OK) +- info->sstate = PPTP_SESSION_CONFIRMED; +- else +- info->sstate = PPTP_SESSION_ERROR; +- break; +- +- case PPTP_STOP_SESSION_REPLY: +- /* server confirms end of control session */ +- if (info->sstate > PPTP_SESSION_STOPREQ) { +- DEBUGP("%s without STOP_SESS_REQUEST\n", +- strMName[msg]); +- break; +- } +- if (pptpReq.strep->resultCode == PPTP_STOP_OK) +- info->sstate = PPTP_SESSION_NONE; +- else +- info->sstate = PPTP_SESSION_ERROR; +- break; +- +- case PPTP_OUT_CALL_REPLY: +- /* server accepted call, we now expect GRE frames */ +- if (info->sstate != PPTP_SESSION_CONFIRMED) { +- DEBUGP("%s but no session\n", strMName[msg]); +- break; +- } +- if (info->cstate != PPTP_CALL_OUT_REQ && +- info->cstate != PPTP_CALL_OUT_CONF) { +- DEBUGP("%s without OUTCALL_REQ\n", strMName[msg]); +- break; +- } +- if (pptpReq.ocack->resultCode != PPTP_OUTCALL_CONNECT) { +- info->cstate = PPTP_CALL_NONE; +- break; +- } +- +- cid = &pptpReq.ocack->callID; +- pcid = &pptpReq.ocack->peersCallID; +- +- info->pac_call_id = ntohs(*cid); +- +- if (htons(info->pns_call_id) != *pcid) { +- DEBUGP("%s for unknown callid %u\n", +- strMName[msg], ntohs(*pcid)); +- break; +- } +- +- DEBUGP("%s, CID=%X, PCID=%X\n", strMName[msg], +- ntohs(*cid), ntohs(*pcid)); +- +- info->cstate = PPTP_CALL_OUT_CONF; +- +- seq = ntohl(tcph->seq) + ((void *)pcid - (void *)pptph); +- exp_gre(ct, seq, *cid, *pcid); +- break; +- +- case PPTP_IN_CALL_REQUEST: +- /* server tells us about incoming call request */ +- if (info->sstate != PPTP_SESSION_CONFIRMED) { +- DEBUGP("%s but no session\n", strMName[msg]); +- break; +- } +- pcid = &pptpReq.icack->peersCallID; +- DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid)); +- info->cstate = PPTP_CALL_IN_REQ; +- info->pac_call_id= ntohs(*pcid); +- break; +- +- case PPTP_IN_CALL_CONNECT: +- /* server tells us about incoming call established */ +- if (info->sstate != PPTP_SESSION_CONFIRMED) { +- DEBUGP("%s but no session\n", strMName[msg]); +- break; +- } +- if (info->sstate != PPTP_CALL_IN_REP +- && info->sstate != PPTP_CALL_IN_CONF) { +- DEBUGP("%s but never sent IN_CALL_REPLY\n", +- strMName[msg]); +- break; +- } +- +- pcid = &pptpReq.iccon->peersCallID; +- cid = &info->pac_call_id; +- +- if (info->pns_call_id != ntohs(*pcid)) { +- DEBUGP("%s for unknown CallID %u\n", +- strMName[msg], ntohs(*cid)); +- break; +- } +- +- DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid)); +- info->cstate = PPTP_CALL_IN_CONF; +- +- /* we expect a GRE connection from PAC to PNS */ +- seq = ntohl(tcph->seq) + ((void *)pcid - (void *)pptph); +- exp_gre(ct, seq, *cid, *pcid); +- +- break; +- +- case PPTP_CALL_DISCONNECT_NOTIFY: +- /* server confirms disconnect */ +- cid = &pptpReq.disc->callID; +- DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid)); +- info->cstate = PPTP_CALL_NONE; +- +- /* untrack this call id, unexpect GRE packets */ +- pptp_timeout_related(ct); +- /* NEWNAT: look up exp for call id and unexpct_related */ +- break; +- +- case PPTP_WAN_ERROR_NOTIFY: +- break; +- +- case PPTP_ECHO_REQUEST: +- case PPTP_ECHO_REPLY: +- /* I don't have to explain these ;) */ +- break; +- default: +- DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX) +- ? strMName[msg]:strMName[0], msg); +- break; +- } +- +- return NF_ACCEPT; +- +-} +- +-static inline int +-pptp_outbound_pkt(struct tcphdr *tcph, +- struct pptp_pkt_hdr *pptph, +- size_t datalen, +- struct ip_conntrack *ct, +- enum ip_conntrack_info ctinfo) +-{ +- struct PptpControlHeader *ctlh; +- union pptp_ctrl_union pptpReq; +- struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; +- u_int16_t msg, *cid, *pcid; +- +- ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph)); +- pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh)); +- +- msg = ntohs(ctlh->messageType); +- DEBUGP("outbound control message %s\n", strMName[msg]); +- +- switch (msg) { +- case PPTP_START_SESSION_REQUEST: +- /* client requests for new control session */ +- if (info->sstate != PPTP_SESSION_NONE) { +- DEBUGP("%s but we already have one", +- strMName[msg]); +- } +- info->sstate = PPTP_SESSION_REQUESTED; +- break; +- case PPTP_STOP_SESSION_REQUEST: +- /* client requests end of control session */ +- info->sstate = PPTP_SESSION_STOPREQ; +- break; +- +- case PPTP_OUT_CALL_REQUEST: +- /* client initiating connection to server */ +- if (info->sstate != PPTP_SESSION_CONFIRMED) { +- DEBUGP("%s but no session\n", +- strMName[msg]); +- break; +- } +- info->cstate = PPTP_CALL_OUT_REQ; +- /* track PNS call id */ +- cid = &pptpReq.ocreq->callID; +- DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid)); +- info->pns_call_id = ntohs(*cid); +- break; +- case PPTP_IN_CALL_REPLY: +- /* client answers incoming call */ +- if (info->cstate != PPTP_CALL_IN_REQ +- && info->cstate != PPTP_CALL_IN_REP) { +- DEBUGP("%s without incall_req\n", +- strMName[msg]); +- break; +- } +- if (pptpReq.icack->resultCode != PPTP_INCALL_ACCEPT) { +- info->cstate = PPTP_CALL_NONE; +- break; +- } +- pcid = &pptpReq.icack->peersCallID; +- if (info->pac_call_id != ntohs(*pcid)) { +- DEBUGP("%s for unknown call %u\n", +- strMName[msg], ntohs(*pcid)); +- break; +- } +- DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*pcid)); +- /* part two of the three-way handshake */ +- info->cstate = PPTP_CALL_IN_REP; +- info->pns_call_id = ntohs(pptpReq.icack->callID); +- break; +- +- case PPTP_CALL_CLEAR_REQUEST: +- /* client requests hangup of call */ +- if (info->sstate != PPTP_SESSION_CONFIRMED) { +- DEBUGP("CLEAR_CALL but no session\n"); +- break; +- } +- /* FUTURE: iterate over all calls and check if +- * call ID is valid. We don't do this without newnat, +- * because we only know about last call */ +- info->cstate = PPTP_CALL_CLEAR_REQ; +- break; +- case PPTP_SET_LINK_INFO: +- break; +- case PPTP_ECHO_REQUEST: +- case PPTP_ECHO_REPLY: +- /* I don't have to explain these ;) */ +- break; +- default: +- DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX)? +- strMName[msg]:strMName[0], msg); +- /* unknown: no need to create GRE masq table entry */ +- break; +- } +- +- return NF_ACCEPT; +-} +- +- +-/* track caller id inside control connection, call expect_related */ +-static int +-conntrack_pptp_help(const struct iphdr *iph, size_t len, +- struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) +- +-{ +- struct pptp_pkt_hdr *pptph; +- +- struct tcphdr *tcph = (void *) iph + iph->ihl * 4; +- u_int32_t tcplen = len - iph->ihl * 4; +- u_int32_t datalen = tcplen - tcph->doff * 4; +- void *datalimit; +- int dir = CTINFO2DIR(ctinfo); +- struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; +- +- int oldsstate, oldcstate; +- int ret; +- +- /* don't do any tracking before tcp handshake complete */ +- if (ctinfo != IP_CT_ESTABLISHED +- && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) { +- DEBUGP("ctinfo = %u, skipping\n", ctinfo); +- return NF_ACCEPT; +- } +- +- /* not a complete TCP header? */ +- if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) { +- DEBUGP("tcplen = %u\n", tcplen); +- return NF_ACCEPT; +- } +- +- /* checksum invalid? */ +- if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, +- csum_partial((char *) tcph, tcplen, 0))) { +- printk(KERN_NOTICE __FILE__ ": bad csum\n"); +-// return NF_ACCEPT; +- } +- +- if (tcph->fin || tcph->rst) { +- DEBUGP("RST/FIN received, timeouting GRE\n"); +- /* can't do this after real newnat */ +- info->cstate = PPTP_CALL_NONE; +- +- /* untrack this call id, unexpect GRE packets */ +- pptp_timeout_related(ct); +- /* no need to call unexpect_related since master conn +- * dies anyway */ +- } +- +- +- pptph = (struct pptp_pkt_hdr *) ((void *) tcph + tcph->doff * 4); +- datalimit = (void *) pptph + datalen; +- +- /* not a full pptp packet header? */ +- if ((void *) pptph+sizeof(*pptph) >= datalimit) { +- DEBUGP("no full PPTP header, can't track\n"); +- return NF_ACCEPT; +- } +- +- /* if it's not a control message we can't do anything with it */ +- if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL || +- ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) { +- DEBUGP("not a control packet\n"); +- return NF_ACCEPT; +- } +- +- oldsstate = info->sstate; +- oldcstate = info->cstate; +- +- LOCK_BH(&ip_pptp_lock); +- +- if (dir == IP_CT_DIR_ORIGINAL) +- /* client -> server (PNS -> PAC) */ +- ret = pptp_outbound_pkt(tcph, pptph, datalen, ct, ctinfo); +- else +- /* server -> client (PAC -> PNS) */ +- ret = pptp_inbound_pkt(tcph, pptph, datalen, ct, ctinfo); +- DEBUGP("sstate: %d->%d, cstate: %d->%d\n", +- oldsstate, info->sstate, oldcstate, info->cstate); +- UNLOCK_BH(&ip_pptp_lock); +- +- return ret; +-} +- +-/* control protocol helper */ +-static struct ip_conntrack_helper pptp = { +- { NULL, NULL }, +- "pptp", IP_CT_HELPER_F_REUSE_EXPECT, THIS_MODULE, 2, 0, +- { { 0, { tcp: { port: __constant_htons(PPTP_CONTROL_PORT) } } }, +- { 0, { 0 }, IPPROTO_TCP } }, +- { { 0, { tcp: { port: 0xffff } } }, +- { 0, { 0 }, 0xffff } }, +- conntrack_pptp_help }; +- +-/* ip_conntrack_pptp initialization */ +-static int __init init(void) +-{ +- int retcode; +- +- DEBUGP(__FILE__ ": registering helper\n"); +- if ((retcode = ip_conntrack_helper_register(&pptp))) { +- printk(KERN_ERR "Unable to register conntrack application " +- "helper for pptp: %d\n", retcode); +- return -EIO; +- } +- +- return 0; +-} +- +-static void __exit fini(void) +-{ +- ip_conntrack_helper_unregister(&pptp); +-} +- +-module_init(init); +-module_exit(fini); +- +-EXPORT_SYMBOL(ip_pptp_lock); +diff -Nurb src/linux/linux/net/ipv4/netfilter/ip_conntrack_pptp_priv.h src/linux/linux.stock/net/ipv4/netfilter/ip_conntrack_pptp_priv.h +--- src/linux/linux/net/ipv4/netfilter/ip_conntrack_pptp_priv.h 2003-07-04 04:12:31.000000000 -0400 ++++ src/linux/linux.stock/net/ipv4/netfilter/ip_conntrack_pptp_priv.h 1969-12-31 19:00:00.000000000 -0500 +@@ -1,24 +0,0 @@ +-#ifndef _IP_CT_PPTP_PRIV_H +-#define _IP_CT_PPTP_PRIV_H +- +-/* PptpControlMessageType names */ +-static const char *strMName[] = { +- "UNKNOWN_MESSAGE", +- "START_SESSION_REQUEST", +- "START_SESSION_REPLY", +- "STOP_SESSION_REQUEST", +- "STOP_SESSION_REPLY", +- "ECHO_REQUEST", +- "ECHO_REPLY", +- "OUT_CALL_REQUEST", +- "OUT_CALL_REPLY", +- "IN_CALL_REQUEST", +- "IN_CALL_REPLY", +- "IN_CALL_CONNECT", +- "CALL_CLEAR_REQUEST", +- "CALL_DISCONNECT_NOTIFY", +- "WAN_ERROR_NOTIFY", +- "SET_LINK_INFO" +-}; +- +-#endif +diff -Nurb src/linux/linux/net/ipv4/netfilter/ip_conntrack_proto_gre.c src/linux/linux.stock/net/ipv4/netfilter/ip_conntrack_proto_gre.c +--- src/linux/linux/net/ipv4/netfilter/ip_conntrack_proto_gre.c 2003-07-04 04:12:31.000000000 -0400 ++++ src/linux/linux.stock/net/ipv4/netfilter/ip_conntrack_proto_gre.c 1969-12-31 19:00:00.000000000 -0500 +@@ -1,320 +0,0 @@ +-/* +- * ip_conntrack_proto_gre.c - Version 1.11 +- * +- * Connection tracking protocol helper module for GRE. +- * +- * GRE is a generic encapsulation protocol, which is generally not very +- * suited for NAT, as it has no protocol-specific part as port numbers. +- * +- * It has an optional key field, which may help us distinguishing two +- * connections between the same two hosts. +- * +- * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784 +- * +- * PPTP is built on top of a modified version of GRE, and has a mandatory +- * field called "CallID", which serves us for the same purpose as the key +- * field in plain GRE. +- * +- * Documentation about PPTP can be found in RFC 2637 +- * +- * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org> +- * +- * Development of this code funded by Astaro AG (http://www.astaro.com/) +- * +- */ +- +-#include <linux/config.h> +-#include <linux/module.h> +-#include <linux/types.h> +-#include <linux/timer.h> +-#include <linux/netfilter.h> +-#include <linux/ip.h> +-#include <linux/in.h> +-#include <linux/list.h> +- +-#include <linux/netfilter_ipv4/lockhelp.h> +- +-DECLARE_RWLOCK(ip_ct_gre_lock); +-#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_ct_gre_lock) +-#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_ct_gre_lock) +- +-#include <linux/netfilter_ipv4/listhelp.h> +-#include <linux/netfilter_ipv4/ip_conntrack_protocol.h> +-#include <linux/netfilter_ipv4/ip_conntrack_helper.h> +-#include <linux/netfilter_ipv4/ip_conntrack_core.h> +- +-#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h> +-#include <linux/netfilter_ipv4/ip_conntrack_pptp.h> +- +-MODULE_LICENSE("GPL"); +-MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); +-MODULE_DESCRIPTION("netfilter connection tracking protocol helper for GRE"); +- +-/* shamelessly stolen from ip_conntrack_proto_udp.c */ +-#define GRE_TIMEOUT (30*HZ) +-#define GRE_STREAM_TIMEOUT (180*HZ) +- +-#define DEBUGP(x, args...) +-#define DUMP_TUPLE_GRE(x) +- +-/* GRE KEYMAP HANDLING FUNCTIONS */ +-static LIST_HEAD(gre_keymap_list); +- +-static inline int gre_key_cmpfn(const struct ip_ct_gre_keymap *km, +- const struct ip_conntrack_tuple *t) +-{ +- return ((km->tuple.src.ip == t->src.ip) && +- (km->tuple.dst.ip == t->dst.ip) && +- (km->tuple.dst.protonum == t->dst.protonum) && +- (km->tuple.dst.u.all == t->dst.u.all)); +-} +- +-/* look up the source key for a given tuple */ +-static u_int32_t gre_keymap_lookup(struct ip_conntrack_tuple *t) +-{ +- struct ip_ct_gre_keymap *km; +- u_int32_t key; +- +- READ_LOCK(&ip_ct_gre_lock); +- km = LIST_FIND(&gre_keymap_list, gre_key_cmpfn, +- struct ip_ct_gre_keymap *, t); +- if (!km) { +- READ_UNLOCK(&ip_ct_gre_lock); +- return 0; +- } +- +- key = km->tuple.src.u.gre.key; +- READ_UNLOCK(&ip_ct_gre_lock); +- +- return key; +-} +- +-/* add a single keymap entry, associate with specified expect */ +-int ip_ct_gre_keymap_add(struct ip_conntrack_expect *exp, +- struct ip_conntrack_tuple *t, int reply) +-{ +- struct ip_ct_gre_keymap *km; +- +- km = kmalloc(sizeof(*km), GFP_ATOMIC); +- if (!km) +- return -1; +- +- /* initializing list head should be sufficient */ +- memset(km, 0, sizeof(*km)); +- +- memcpy(&km->tuple, t, sizeof(*t)); +- km->master = exp; +- +- if (!reply) +- exp->proto.gre.keymap_orig = km; +- else +- exp->proto.gre.keymap_reply = km; +- +- DEBUGP("adding new entry %p: ", km); +- DUMP_TUPLE_GRE(&km->tuple); +- +- WRITE_LOCK(&ip_ct_gre_lock); +- list_append(&gre_keymap_list, km); +- WRITE_UNLOCK(&ip_ct_gre_lock); +- +- return 0; +-} +- +-/* change the tuple of a keymap entry (used by nat helper) */ +-void ip_ct_gre_keymap_change(struct ip_ct_gre_keymap *km, +- struct ip_conntrack_tuple *t) +-{ +- DEBUGP("changing entry %p to: ", km); +- DUMP_TUPLE_GRE(t); +- +- WRITE_LOCK(&ip_ct_gre_lock); +- memcpy(&km->tuple, t, sizeof(km->tuple)); +- WRITE_UNLOCK(&ip_ct_gre_lock); +-} +- +- +-/* PUBLIC CONNTRACK PROTO HELPER FUNCTIONS */ +- +-/* invert gre part of tuple */ +-static int gre_invert_tuple(struct ip_conntrack_tuple *tuple, +- const struct ip_conntrack_tuple *orig) +-{ +- tuple->dst.u.gre.protocol = orig->dst.u.gre.protocol; +- tuple->dst.u.gre.version = orig->dst.u.gre.version; +- +- tuple->dst.u.gre.key = orig->src.u.gre.key; +- tuple->src.u.gre.key = orig->dst.u.gre.key; +- +- return 1; +-} +- +-/* gre hdr info to tuple */ +-static int gre_pkt_to_tuple(const void *datah, size_t datalen, +- struct ip_conntrack_tuple *tuple) +-{ +- struct gre_hdr *grehdr = (struct gre_hdr *) datah; +- struct gre_hdr_pptp *pgrehdr = (struct gre_hdr_pptp *) datah; +- u_int32_t srckey; +- +- /* core guarantees 8 protocol bytes, no need for size check */ +- +- tuple->dst.u.gre.version = grehdr->version; +- tuple->dst.u.gre.protocol = grehdr->protocol; +- +- switch (grehdr->version) { +- case GRE_VERSION_1701: +- if (!grehdr->key) { +- DEBUGP("Can't track GRE without key\n"); +- return 0; +- } +- tuple->dst.u.gre.key = *(gre_key(grehdr)); +- break; +- +- case GRE_VERSION_PPTP: +- if (ntohs(grehdr->protocol) != GRE_PROTOCOL_PPTP) { +- DEBUGP("GRE_VERSION_PPTP but unknown proto\n"); +- return 0; +- } +- tuple->dst.u.gre.key = htonl(ntohs(pgrehdr->call_id)); +- break; +- +- default: +- printk(KERN_WARNING "unknown GRE version %hu\n", +- tuple->dst.u.gre.version); +- return 0; +- } +- +- srckey = gre_keymap_lookup(tuple); +- +- tuple->src.u.gre.key = srckey; +- +- return 1; +-} +- +-/* print gre part of tuple */ +-static unsigned int gre_print_tuple(char *buffer, +- const struct ip_conntrack_tuple *tuple) +-{ +- return sprintf(buffer, "version=%d protocol=0x%04x srckey=0x%x dstkey=0x%x ", +- tuple->dst.u.gre.version, +- ntohs(tuple->dst.u.gre.protocol), +- ntohl(tuple->src.u.gre.key), +- ntohl(tuple->dst.u.gre.key)); +-} +- +-/* print private data for conntrack */ +-static unsigned int gre_print_conntrack(char *buffer, +- const struct ip_conntrack *ct) +-{ +- return sprintf(buffer, "timeout=%u, stream_timeout=%u ", +- (ct->proto.gre.timeout / HZ), +- (ct->proto.gre.stream_timeout / HZ)); +-} +- +-/* Returns verdict for packet, and may modify conntrack */ +-static int gre_packet(struct ip_conntrack *ct, +- struct iphdr *iph, size_t len, +- enum ip_conntrack_info conntrackinfo) +-{ +- /* If we've seen traffic both ways, this is a GRE connection. +- * Extend timeout. */ +- if (ct->status & IPS_SEEN_REPLY) { +- ip_ct_refresh(ct, ct->proto.gre.stream_timeout); +- /* Also, more likely to be important, and not a probe. */ +- set_bit(IPS_ASSURED_BIT, &ct->status); +- } else +- ip_ct_refresh(ct, ct->proto.gre.timeout); +- +- return NF_ACCEPT; +-} +- +-/* Called when a new connection for this protocol found. */ +-static int gre_new(struct ip_conntrack *ct, +- struct iphdr *iph, size_t len) +-{ +- DEBUGP(": "); +- DUMP_TUPLE_GRE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); +- +- /* initialize to sane value. Ideally a conntrack helper +- * (e.g. in case of pptp) is increasing them */ +- ct->proto.gre.stream_timeout = GRE_STREAM_TIMEOUT; +- ct->proto.gre.timeout = GRE_TIMEOUT; +- +- return 1; +-} +- +-/* Called when a conntrack entry has already been removed from the hashes +- * and is about to be deleted from memory */ +-static void gre_destroy(struct ip_conntrack *ct) +-{ +- struct ip_conntrack_expect *master = ct->master; +- +- DEBUGP(" entering\n"); +- +- if (!master) { +- DEBUGP("no master exp for ct %p\n", ct); +- return; +- } +- +- WRITE_LOCK(&ip_ct_gre_lock); +- if (master->proto.gre.keymap_orig) { +- DEBUGP("removing %p from list\n", master->proto.gre.keymap_orig); +- list_del(&master->proto.gre.keymap_orig->list); +- kfree(master->proto.gre.keymap_orig); +- } +- if (master->proto.gre.keymap_reply) { +- DEBUGP("removing %p from list\n", master->proto.gre.keymap_reply); +- list_del(&master->proto.gre.keymap_reply->list); +- kfree(master->proto.gre.keymap_reply); +- } +- WRITE_UNLOCK(&ip_ct_gre_lock); +-} +- +-/* protocol helper struct */ +-static struct ip_conntrack_protocol gre = { { NULL, NULL }, IPPROTO_GRE, +- "gre", +- gre_pkt_to_tuple, +- gre_invert_tuple, +- gre_print_tuple, +- gre_print_conntrack, +- gre_packet, +- gre_new, +- gre_destroy, +- NULL, +- THIS_MODULE }; +- +-/* ip_conntrack_proto_gre initialization */ +-static int __init init(void) +-{ +- int retcode; +- +- if ((retcode = ip_conntrack_protocol_register(&gre))) { +- printk(KERN_ERR "Unable to register conntrack protocol " +- "helper for gre: %d\n", retcode); +- return -EIO; +- } +- +- return 0; +-} +- +-static void __exit fini(void) +-{ +- struct list_head *pos, *n; +- +- /* delete all keymap entries */ +- WRITE_LOCK(&ip_ct_gre_lock); +- list_for_each_safe(pos, n, &gre_keymap_list) { +- DEBUGP("deleting keymap %p\n", pos); +- list_del(pos); +- kfree(pos); +- } +- WRITE_UNLOCK(&ip_ct_gre_lock); +- +- ip_conntrack_protocol_unregister(&gre); +-} +- +-EXPORT_SYMBOL(ip_ct_gre_keymap_add); +-EXPORT_SYMBOL(ip_ct_gre_keymap_change); +- +-module_init(init); +-module_exit(fini); +diff -Nurb src/linux/linux/net/ipv4/netfilter/ip_conntrack_proto_tcp.c src/linux/linux.stock/net/ipv4/netfilter/ip_conntrack_proto_tcp.c +--- src/linux/linux/net/ipv4/netfilter/ip_conntrack_proto_tcp.c 2003-08-12 07:33:45.000000000 -0400 ++++ src/linux/linux.stock/net/ipv4/netfilter/ip_conntrack_proto_tcp.c 2004-05-09 04:13:03.000000000 -0400 +@@ -15,11 +15,17 @@ + #include <linux/netfilter_ipv4/ip_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 +@@ -39,6 +45,25 @@ + "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 +@@ -161,13 +186,13 @@ + && tcph->syn && tcph->ack) + conntrack->proto.tcp.handshake_ack + = htonl(ntohl(tcph->seq) + 1); ++ WRITE_UNLOCK(&tcp_lock); + + /* 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 (!(conntrack->status & IPS_SEEN_REPLY) && tcph->rst) { +- WRITE_UNLOCK(&tcp_lock); + if (del_timer(&conntrack->timeout)) + conntrack->timeout.function((unsigned long)conntrack); + } else { +@@ -178,9 +203,7 @@ + && tcph->ack_seq == conntrack->proto.tcp.handshake_ack) + set_bit(IPS_ASSURED_BIT, &conntrack->status); + +- WRITE_UNLOCK(&tcp_lock); +- ip_ct_refresh(conntrack, +- sysctl_ip_conntrack_tcp_timeouts[newconntrack]); ++ ip_ct_refresh(conntrack, tcp_timeouts[newconntrack]); + } + + return NF_ACCEPT; +diff -Nurb src/linux/linux/net/ipv4/netfilter/ip_conntrack_proto_udp.c src/linux/linux.stock/net/ipv4/netfilter/ip_conntrack_proto_udp.c +--- src/linux/linux/net/ipv4/netfilter/ip_conntrack_proto_udp.c 2003-08-12 07:33:45.000000000 -0400 ++++ src/linux/linux.stock/net/ipv4/netfilter/ip_conntrack_proto_udp.c 2004-05-09 04:13:03.000000000 -0400 +@@ -5,7 +5,9 @@ + #include <linux/in.h> + #include <linux/udp.h> + #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> +-#include <linux/netfilter_ipv4/ip_conntrack_udp.h> ++ ++#define UDP_TIMEOUT (30*HZ) ++#define UDP_STREAM_TIMEOUT (180*HZ) + + static int udp_pkt_to_tuple(const void *datah, size_t datalen, + struct ip_conntrack_tuple *tuple) +@@ -50,13 +52,11 @@ + /* If we've seen traffic both ways, this is some kind of UDP + stream. Extend timeout. */ + if (conntrack->status & IPS_SEEN_REPLY) { +- ip_ct_refresh(conntrack, +- sysctl_ip_conntrack_udp_timeouts[UDP_STREAM_TIMEOUT]); ++ ip_ct_refresh(conntrack, UDP_STREAM_TIMEOUT); + /* Also, more likely to be important, and not a probe */ + set_bit(IPS_ASSURED_BIT, &conntrack->status); + } else +- ip_ct_refresh(conntrack, +- sysctl_ip_conntrack_udp_timeouts[UDP_TIMEOUT]); ++ ip_ct_refresh(conntrack, UDP_TIMEOUT); + + return NF_ACCEPT; + } +diff -Nurb src/linux/linux/net/ipv4/netfilter/ip_conntrack_standalone.c src/linux/linux.stock/net/ipv4/netfilter/ip_conntrack_standalone.c +--- src/linux/linux/net/ipv4/netfilter/ip_conntrack_standalone.c 2003-08-12 07:33:45.000000000 -0400 ++++ src/linux/linux.stock/net/ipv4/netfilter/ip_conntrack_standalone.c 2004-05-09 04:13:03.000000000 -0400 +@@ -27,7 +27,11 @@ + #include <linux/netfilter_ipv4/ip_conntrack_helper.h> + #include <linux/netfilter_ipv4/listhelp.h> + ++#if 0 ++#define DEBUGP printk ++#else + #define DEBUGP(format, args...) ++#endif + + struct module *ip_conntrack_module = THIS_MODULE; + MODULE_LICENSE("GPL"); +@@ -52,17 +56,12 @@ + return len; + } + ++/* FIXME: Don't print source proto part. --RR */ + static unsigned int + print_expect(char *buffer, const struct ip_conntrack_expect *expect) + { + unsigned int len; + +- if (!expect || !expect->expectant || !expect->expectant->helper) { +- DEBUGP("expect %x expect->expectant %x expect->expectant->helper %x\n", +- expect, expect->expectant, expect->expectant->helper); +- return 0; +- } +- + if (expect->expectant->helper->timeout) + len = sprintf(buffer, "EXPECTING: %lu ", + timer_pending(&expect->timeout) +@@ -294,6 +293,8 @@ + return ret; + } + ++/* FIXME: Allow NULL functions and sub in pointers to generic for ++ them. --RR */ + int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto) + { + int ret = 0; +@@ -362,8 +363,6 @@ + EXPORT_SYMBOL(ip_ct_find_proto); + EXPORT_SYMBOL(__ip_ct_find_proto); + EXPORT_SYMBOL(ip_ct_find_helper); +-EXPORT_SYMBOL(sysctl_ip_conntrack_tcp_timeouts); +-EXPORT_SYMBOL(sysctl_ip_conntrack_udp_timeouts); + EXPORT_SYMBOL(ip_conntrack_expect_related); + EXPORT_SYMBOL(ip_conntrack_change_expect); + EXPORT_SYMBOL(ip_conntrack_unexpect_related); +diff -Nurb src/linux/linux/net/ipv4/netfilter/ip_conntrack_tftp.c src/linux/linux.stock/net/ipv4/netfilter/ip_conntrack_tftp.c +--- src/linux/linux/net/ipv4/netfilter/ip_conntrack_tftp.c 2003-07-04 04:12:31.000000000 -0400 ++++ src/linux/linux.stock/net/ipv4/netfilter/ip_conntrack_tftp.c 1969-12-31 19:00:00.000000000 -0500 +@@ -1,126 +0,0 @@ +-/* +- * Licensed under GNU GPL version 2 Copyright Magnus Boden <mb@ozaba.mine.nu> +- * Version: 0.0.7 +- * +- * Thu 21 Mar 2002 Harald Welte <laforge@gnumonks.org> +- * - port to newnat API +- * +- */ +- +-#include <linux/module.h> +-#include <linux/ip.h> +-#include <linux/udp.h> +- +-#include <linux/netfilter.h> +-#include <linux/netfilter_ipv4/ip_tables.h> +-#include <linux/netfilter_ipv4/ip_conntrack_helper.h> +-#include <linux/netfilter_ipv4/ip_conntrack_tftp.h> +- +-MODULE_AUTHOR("Magnus Boden <mb@ozaba.mine.nu>"); +-MODULE_DESCRIPTION("Netfilter connection tracking module for tftp"); +-MODULE_LICENSE("GPL"); +- +-#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"); +-MODULE_PARM_DESC(ports, "port numbers of tftp servers"); +-#endif +- +-#define DEBUGP(format, args...) +- +-static int tftp_help(const struct iphdr *iph, size_t len, +- struct ip_conntrack *ct, +- enum ip_conntrack_info ctinfo) +-{ +- struct udphdr *udph = (void *)iph + iph->ihl * 4; +- struct tftphdr *tftph = (void *)udph + 8; +- struct ip_conntrack_expect exp; +- +- switch (ntohs(tftph->opcode)) { +- /* RRQ and WRQ works the same way */ +- case TFTP_OPCODE_READ: +- case TFTP_OPCODE_WRITE: +- DEBUGP(""); +- DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); +- DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); +- memset(&exp, 0, sizeof(exp)); +- +- exp.tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple; +- exp.mask.src.ip = 0xffffffff; +- exp.mask.dst.ip = 0xffffffff; +- exp.mask.dst.u.udp.port = 0xffff; +- exp.mask.dst.protonum = 0xffff; +- exp.expectfn = NULL; +- +- DEBUGP("expect: "); +- DUMP_TUPLE(&exp.tuple); +- DUMP_TUPLE(&exp.mask); +- ip_conntrack_expect_related(ct, &exp); +- break; +- default: +- DEBUGP("Unknown opcode\n"); +- } +- return NF_ACCEPT; +-} +- +-static struct ip_conntrack_helper tftp[MAX_PORTS]; +-static char tftp_names[MAX_PORTS][10]; +- +-static void fini(void) +-{ +- int i; +- +- for (i = 0 ; i < ports_c; i++) { +- DEBUGP("unregistering helper for port %d\n", +- ports[i]); +- ip_conntrack_helper_unregister(&tftp[i]); +- } +-} +- +-static int __init init(void) +-{ +- int i, ret; +- char *tmpname; +- +- if (!ports[0]) +- ports[0]=TFTP_PORT; +- +- for (i = 0 ; (i < MAX_PORTS) && ports[i] ; i++) { +- /* Create helper structure */ +- memset(&tftp[i], 0, sizeof(struct ip_conntrack_helper)); +- +- tftp[i].tuple.dst.protonum = IPPROTO_UDP; +- tftp[i].tuple.src.u.udp.port = htons(ports[i]); +- tftp[i].mask.dst.protonum = 0xFFFF; +- tftp[i].mask.src.u.udp.port = 0xFFFF; +- tftp[i].max_expected = 1; +- tftp[i].timeout = 0; +- tftp[i].flags = IP_CT_HELPER_F_REUSE_EXPECT; +- tftp[i].me = THIS_MODULE; +- tftp[i].help = tftp_help; +- +- tmpname = &tftp_names[i][0]; +- if (ports[i] == TFTP_PORT) +- sprintf(tmpname, "tftp"); +- else +- sprintf(tmpname, "tftp-%d", i); +- tftp[i].name = tmpname; +- +- DEBUGP("port #%d: %d\n", i, ports[i]); +- +- ret=ip_conntrack_helper_register(&tftp[i]); +- if (ret) { +- printk("ERROR registering helper for port %d\n", +- ports[i]); +- fini(); +- return(ret); +- } +- ports_c++; +- } +- return(0); +-} +- +-module_init(init); +-module_exit(fini); +diff -Nurb src/linux/linux/net/ipv4/netfilter/ip_nat_core.c src/linux/linux.stock/net/ipv4/netfilter/ip_nat_core.c +--- src/linux/linux/net/ipv4/netfilter/ip_nat_core.c 2003-07-04 04:12:31.000000000 -0400 ++++ src/linux/linux.stock/net/ipv4/netfilter/ip_nat_core.c 2004-05-09 04:13:03.000000000 -0400 +@@ -31,7 +31,11 @@ + #include <linux/netfilter_ipv4/ip_conntrack_helper.h> + #include <linux/netfilter_ipv4/listhelp.h> + ++#if 0 ++#define DEBUGP printk ++#else + #define DEBUGP(format, args...) ++#endif + + DECLARE_RWLOCK(ip_nat_lock); + DECLARE_RWLOCK_EXTERN(ip_conntrack_lock); +@@ -207,6 +211,7 @@ + { + struct rtable *rt; + ++ /* FIXME: IPTOS_TOS(iph->tos) --RR */ + if (ip_route_output(&rt, var_ip, 0, 0, 0) != 0) { + DEBUGP("do_extra_mangle: Can't get route to %u.%u.%u.%u\n", + NIPQUAD(var_ip)); +@@ -429,7 +434,7 @@ + *tuple = *orig_tuple; + while ((rptr = find_best_ips_proto_fast(tuple, mr, conntrack, hooknum)) + != NULL) { +- DEBUGP("Found best for "); DUMP_TUPLE_RAW(tuple); ++ DEBUGP("Found best for "); DUMP_TUPLE(tuple); + /* 3) The per-protocol part of the manip is made to + map into the range to make a unique tuple. */ + +@@ -529,6 +534,31 @@ + invert_tuplepr(&orig_tp, + &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple); + ++#if 0 ++ { ++ unsigned int i; ++ ++ DEBUGP("Hook %u (%s), ", hooknum, ++ HOOK2MANIP(hooknum)==IP_NAT_MANIP_SRC ? "SRC" : "DST"); ++ DUMP_TUPLE(&orig_tp); ++ DEBUGP("Range %p: ", mr); ++ for (i = 0; i < mr->rangesize; i++) { ++ DEBUGP("%u:%s%s%s %u.%u.%u.%u - %u.%u.%u.%u %u - %u\n", ++ i, ++ (mr->range[i].flags & IP_NAT_RANGE_MAP_IPS) ++ ? " MAP_IPS" : "", ++ (mr->range[i].flags ++ & IP_NAT_RANGE_PROTO_SPECIFIED) ++ ? " PROTO_SPECIFIED" : "", ++ (mr->range[i].flags & IP_NAT_RANGE_FULL) ++ ? " FULL" : "", ++ NIPQUAD(mr->range[i].min_ip), ++ NIPQUAD(mr->range[i].max_ip), ++ mr->range[i].min.all, ++ mr->range[i].max.all); ++ } ++ } ++#endif + + do { + if (!get_unique_tuple(&new_tuple, &orig_tp, mr, conntrack, +@@ -538,6 +568,15 @@ + return NF_DROP; + } + ++#if 0 ++ DEBUGP("Hook %u (%s) %p\n", hooknum, ++ HOOK2MANIP(hooknum)==IP_NAT_MANIP_SRC ? "SRC" : "DST", ++ conntrack); ++ DEBUGP("Original: "); ++ DUMP_TUPLE(&orig_tp); ++ DEBUGP("New: "); ++ DUMP_TUPLE(&new_tuple); ++#endif + + /* We now have two tuples (SRCIP/SRCPT/DSTIP/DSTPT): + the original (A/B/C/D') and the mangled one (E/F/G/H'). +@@ -554,6 +593,8 @@ + If fail this race (reply tuple now used), repeat. */ + } while (!ip_conntrack_alter_reply(conntrack, &reply)); + ++ /* FIXME: We can simply used existing conntrack reply tuple ++ here --RR */ + /* Create inverse of original: C/D/A/B' */ + invert_tuplepr(&inv_tuple, &orig_tp); + +@@ -678,6 +719,17 @@ + iph->check); + iph->daddr = manip->ip; + } ++#if 0 ++ if (ip_fast_csum((u8 *)iph, iph->ihl) != 0) ++ DEBUGP("IP: checksum on packet bad.\n"); ++ ++ if (proto == IPPROTO_TCP) { ++ void *th = (u_int32_t *)iph + iph->ihl; ++ if (tcp_v4_check(th, len - 4*iph->ihl, iph->saddr, iph->daddr, ++ csum_partial((char *)th, len-4*iph->ihl, 0))) ++ DEBUGP("TCP: checksum on packet bad\n"); ++ } ++#endif + } + + static inline int exp_for_packet(struct ip_conntrack_expect *exp, +@@ -765,6 +817,7 @@ + continue; + + if (exp_for_packet(exp, pskb)) { ++ /* FIXME: May be true multiple times in the case of UDP!! */ + DEBUGP("calling nat helper (exp=%p) for packet\n", + exp); + ret = helper->help(ct, exp, info, ctinfo, +@@ -926,6 +979,7 @@ + INIT_LIST_HEAD(&byipsproto[i]); + } + ++ /* FIXME: Man, this is a hack. <SIGH> */ + IP_NF_ASSERT(ip_conntrack_destroyed == NULL); + ip_conntrack_destroyed = &ip_nat_cleanup_conntrack; + +diff -Nurb src/linux/linux/net/ipv4/netfilter/ip_nat_h323.c src/linux/linux.stock/net/ipv4/netfilter/ip_nat_h323.c +--- src/linux/linux/net/ipv4/netfilter/ip_nat_h323.c 2003-07-04 04:12:31.000000000 -0400 ++++ src/linux/linux.stock/net/ipv4/netfilter/ip_nat_h323.c 1969-12-31 19:00:00.000000000 -0500 +@@ -1,403 +0,0 @@ +-/* +- * H.323 'brute force' extension for NAT alteration. +- * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> +- * +- * Based on ip_masq_h323.c for 2.2 kernels from CoRiTel, Sofia project. +- * (http://www.coritel.it/projects/sofia/nat.html) +- * Uses Sampsa Ranta's excellent idea on using expectfn to 'bind' +- * the unregistered helpers to the conntrack entries. +- */ +- +- +-#include <linux/module.h> +-#include <linux/netfilter.h> +-#include <linux/ip.h> +-#include <net/checksum.h> +-#include <net/tcp.h> +- +-#include <linux/netfilter_ipv4/lockhelp.h> +-#include <linux/netfilter_ipv4/ip_nat.h> +-#include <linux/netfilter_ipv4/ip_nat_helper.h> +-#include <linux/netfilter_ipv4/ip_nat_rule.h> +-#include <linux/netfilter_ipv4/ip_conntrack_tuple.h> +-#include <linux/netfilter_ipv4/ip_conntrack_helper.h> +-#include <linux/netfilter_ipv4/ip_conntrack_h323.h> +- +-MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); +-MODULE_DESCRIPTION("H.323 'brute force' connection tracking module"); +-MODULE_LICENSE("GPL"); +- +-DECLARE_LOCK_EXTERN(ip_h323_lock); +-struct module *ip_nat_h323 = THIS_MODULE; +- +-#define DEBUGP(format, args...) +- +- +-static unsigned int +-h225_nat_expected(struct sk_buff **pskb, +- unsigned int hooknum, +- struct ip_conntrack *ct, +- struct ip_nat_info *info); +- +-static unsigned int h225_nat_help(struct ip_conntrack *ct, +- struct ip_conntrack_expect *exp, +- struct ip_nat_info *info, +- enum ip_conntrack_info ctinfo, +- unsigned int hooknum, +- struct sk_buff **pskb); +- +-static struct ip_nat_helper h245 = +- { { NULL, NULL }, +- "H.245", /* name */ +- 0, /* flags */ +- NULL, /* module */ +- { { 0, { 0 } }, /* tuple */ +- { 0, { 0 }, IPPROTO_TCP } }, +- { { 0, { 0xFFFF } }, /* mask */ +- { 0, { 0 }, 0xFFFF } }, +- h225_nat_help, /* helper */ +- h225_nat_expected /* expectfn */ +- }; +- +-static unsigned int +-h225_nat_expected(struct sk_buff **pskb, +- unsigned int hooknum, +- struct ip_conntrack *ct, +- struct ip_nat_info *info) +-{ +- struct ip_nat_multi_range mr; +- u_int32_t newdstip, newsrcip, newip; +- u_int16_t port; +- struct ip_ct_h225_expect *exp_info; +- struct ip_ct_h225_master *master_info; +- struct ip_conntrack *master = master_ct(ct); +- unsigned int is_h225, ret; +- +- IP_NF_ASSERT(info); +- IP_NF_ASSERT(master); +- +- IP_NF_ASSERT(!(info->initialized & (1<<HOOK2MANIP(hooknum)))); +- +- DEBUGP("h225_nat_expected: We have a connection!\n"); +- master_info = &ct->master->expectant->help.ct_h225_info; +- exp_info = &ct->master->help.exp_h225_info; +- +- LOCK_BH(&ip_h323_lock); +- +- DEBUGP("master: "); +- DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_ORIGINAL].tuple); +- DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_REPLY].tuple); +- DEBUGP("conntrack: "); +- DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); +- if (exp_info->dir == IP_CT_DIR_ORIGINAL) { +- /* Make connection go to the client. */ +- newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; +- newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; +- DEBUGP("h225_nat_expected: %u.%u.%u.%u->%u.%u.%u.%u (to client)\n", +- NIPQUAD(newsrcip), NIPQUAD(newdstip)); +- } else { +- /* Make the connection go to the server */ +- newdstip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; +- newsrcip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; +- DEBUGP("h225_nat_expected: %u.%u.%u.%u->%u.%u.%u.%u (to server)\n", +- NIPQUAD(newsrcip), NIPQUAD(newdstip)); +- } +- port = exp_info->port; +- is_h225 = master_info->is_h225 == H225_PORT; +- UNLOCK_BH(&ip_h323_lock); +- +- if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) +- newip = newsrcip; +- else +- newip = newdstip; +- +- DEBUGP("h225_nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip)); +- +- mr.rangesize = 1; +- /* We don't want to manip the per-protocol, just the IPs... */ +- mr.range[0].flags = IP_NAT_RANGE_MAP_IPS; +- mr.range[0].min_ip = mr.range[0].max_ip = newip; +- +- /* ... unless we're doing a MANIP_DST, in which case, make +- sure we map to the correct port */ +- if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) { +- mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED; +- mr.range[0].min = mr.range[0].max +- = ((union ip_conntrack_manip_proto) +- { port }); +- } +- +- ret = ip_nat_setup_info(ct, &mr, hooknum); +- +- if (is_h225) { +- DEBUGP("h225_nat_expected: H.225, setting NAT helper for %p\n", ct); +- /* NAT expectfn called with ip_nat_lock write-locked */ +- info->helper = &h245; +- } +- return ret; +-} +- +-static int h323_signal_address_fixup(struct ip_conntrack *ct, +- struct sk_buff **pskb, +- enum ip_conntrack_info ctinfo) +-{ +- struct iphdr *iph = (*pskb)->nh.iph; +- struct tcphdr *tcph = (void *)iph + iph->ihl*4; +- unsigned char *data; +- u_int32_t tcplen = (*pskb)->len - iph->ihl*4; +- u_int32_t datalen = tcplen - tcph->doff*4; +- struct ip_ct_h225_master *info = &ct->help.ct_h225_info; +- u_int32_t newip; +- u_int16_t port; +- u_int8_t buffer[6]; +- int i; +- +- MUST_BE_LOCKED(&ip_h323_lock); +- +- DEBUGP("h323_signal_address_fixup: %s %s\n", +- between(info->seq[IP_CT_DIR_ORIGINAL], ntohl(tcph->seq), ntohl(tcph->seq) + datalen) +- ? "yes" : "no", +- between(info->seq[IP_CT_DIR_REPLY], ntohl(tcph->seq), ntohl(tcph->seq) + datalen) +- ? "yes" : "no"); +- if (!(between(info->seq[IP_CT_DIR_ORIGINAL], ntohl(tcph->seq), ntohl(tcph->seq) + datalen) +- || between(info->seq[IP_CT_DIR_REPLY], ntohl(tcph->seq), ntohl(tcph->seq) + datalen))) +- return 1; +- +- DEBUGP("h323_signal_address_fixup: offsets %u + 6 and %u + 6 in %u\n", +- info->offset[IP_CT_DIR_ORIGINAL], +- info->offset[IP_CT_DIR_REPLY], +- tcplen); +- DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); +- DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); +- +- for (i = 0; i < IP_CT_DIR_MAX; i++) { +- DEBUGP("h323_signal_address_fixup: %s %s\n", +- info->dir == IP_CT_DIR_ORIGINAL ? "original" : "reply", +- i == IP_CT_DIR_ORIGINAL ? "caller" : "callee"); +- if (!between(info->seq[i], ntohl(tcph->seq), +- ntohl(tcph->seq) + datalen)) +- continue; +- if (!between(info->seq[i] + 6, ntohl(tcph->seq), +- ntohl(tcph->seq) + datalen)) { +- /* Partial retransmisison. It's a cracker being funky. */ +- if (net_ratelimit()) { +- printk("H.323_NAT: partial packet %u/6 in %u/%u\n", +- info->seq[i], +- ntohl(tcph->seq), +- ntohl(tcph->seq) + datalen); +- } +- return 0; +- } +- +- /* Change address inside packet to match way we're mapping +- this connection. */ +- if (i == IP_CT_DIR_ORIGINAL) { +- newip = ct->tuplehash[!info->dir].tuple.dst.ip; +- port = ct->tuplehash[!info->dir].tuple.dst.u.tcp.port; +- } else { +- newip = ct->tuplehash[!info->dir].tuple.src.ip; +- port = ct->tuplehash[!info->dir].tuple.src.u.tcp.port; +- } +- +- data = (char *) tcph + tcph->doff * 4 + info->offset[i]; +- +- DEBUGP("h323_signal_address_fixup: orig %s IP:port %u.%u.%u.%u:%u\n", +- i == IP_CT_DIR_ORIGINAL ? "source" : "dest ", +- data[0], data[1], data[2], data[3], +- (data[4] << 8 | data[5])); +- +- /* Modify the packet */ +- memcpy(buffer, &newip, 4); +- memcpy(buffer + 4, &port, 2); +- if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, info->offset[i], +- 6, buffer, 6)) +- return 0; +- +- DEBUGP("h323_signal_address_fixup: new %s IP:port %u.%u.%u.%u:%u\n", +- i == IP_CT_DIR_ORIGINAL ? "source" : "dest ", +- data[0], data[1], data[2], data[3], +- (data[4] << 8 | data[5])); +- } +- +- return 1; +-} +- +-static int h323_data_fixup(struct ip_ct_h225_expect *info, +- struct ip_conntrack *ct, +- struct sk_buff **pskb, +- enum ip_conntrack_info ctinfo, +- struct ip_conntrack_expect *expect) +-{ +- u_int32_t newip; +- u_int16_t port; +- u_int8_t buffer[6]; +- struct ip_conntrack_tuple newtuple; +- struct iphdr *iph = (*pskb)->nh.iph; +- struct tcphdr *tcph = (void *)iph + iph->ihl*4; +- unsigned char *data; +- u_int32_t tcplen = (*pskb)->len - iph->ihl*4; +- struct ip_ct_h225_master *master_info = &ct->help.ct_h225_info; +- int is_h225; +- +- MUST_BE_LOCKED(&ip_h323_lock); +- DEBUGP("h323_data_fixup: offset %u + 6 in %u\n", info->offset, tcplen); +- DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); +- DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); +- +- if (!between(expect->seq + 6, ntohl(tcph->seq), +- ntohl(tcph->seq) + tcplen - tcph->doff * 4)) { +- /* Partial retransmisison. It's a cracker being funky. */ +- if (net_ratelimit()) { +- printk("H.323_NAT: partial packet %u/6 in %u/%u\n", +- expect->seq, +- ntohl(tcph->seq), +- ntohl(tcph->seq) + tcplen - tcph->doff * 4); +- } +- return 0; +- } +- +- /* Change address inside packet to match way we're mapping +- this connection. */ +- if (info->dir == IP_CT_DIR_REPLY) { +- /* Must be where client thinks server is */ +- newip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; +- /* Expect something from client->server */ +- newtuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; +- newtuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; +- } else { +- /* Must be where server thinks client is */ +- newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; +- /* Expect something from server->client */ +- newtuple.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; +- newtuple.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; +- } +- +- is_h225 = (master_info->is_h225 == H225_PORT); +- +- if (is_h225) { +- newtuple.dst.protonum = IPPROTO_TCP; +- newtuple.src.u.tcp.port = expect->tuple.src.u.tcp.port; +- } else { +- newtuple.dst.protonum = IPPROTO_UDP; +- newtuple.src.u.udp.port = expect->tuple.src.u.udp.port; +- } +- +- /* Try to get same port: if not, try to change it. */ +- for (port = ntohs(info->port); port != 0; port++) { +- if (is_h225) +- newtuple.dst.u.tcp.port = htons(port); +- else +- newtuple.dst.u.udp.port = htons(port); +- +- if (ip_conntrack_change_expect(expect, &newtuple) == 0) +- break; +- } +- if (port == 0) { +- DEBUGP("h323_data_fixup: no free port found!\n"); +- return 0; +- } +- +- port = htons(port); +- +- data = (char *) tcph + tcph->doff * 4 + info->offset; +- +- DEBUGP("h323_data_fixup: orig IP:port %u.%u.%u.%u:%u\n", +- data[0], data[1], data[2], data[3], +- (data[4] << 8 | data[5])); +- +- /* Modify the packet */ +- memcpy(buffer, &newip, 4); +- memcpy(buffer + 4, &port, 2); +- if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, info->offset, +- 6, buffer, 6)) +- return 0; +- +- DEBUGP("h323_data_fixup: new IP:port %u.%u.%u.%u:%u\n", +- data[0], data[1], data[2], data[3], +- (data[4] << 8 | data[5])); +- +- return 1; +-} +- +-static unsigned int h225_nat_help(struct ip_conntrack *ct, +- struct ip_conntrack_expect *exp, +- struct ip_nat_info *info, +- enum ip_conntrack_info ctinfo, +- unsigned int hooknum, +- struct sk_buff **pskb) +-{ +- int dir; +- struct ip_ct_h225_expect *exp_info; +- +- /* Only mangle things once: original direction in POST_ROUTING +- and reply direction on PRE_ROUTING. */ +- dir = CTINFO2DIR(ctinfo); +- DEBUGP("nat_h323: dir %s at hook %s\n", +- dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", +- hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" +- : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" +- : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???"); +- if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL) +- || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) { +- DEBUGP("nat_h323: Not touching dir %s at hook %s\n", +- dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", +- hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" +- : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" +- : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???"); +- return NF_ACCEPT; +- } +- +- if (!exp) { +- LOCK_BH(&ip_h323_lock); +- if (!h323_signal_address_fixup(ct, pskb, ctinfo)) { +- UNLOCK_BH(&ip_h323_lock); +- return NF_DROP; +- } +- UNLOCK_BH(&ip_h323_lock); +- return NF_ACCEPT; +- } +- +- exp_info = &exp->help.exp_h225_info; +- +- LOCK_BH(&ip_h323_lock); +- if (!h323_data_fixup(exp_info, ct, pskb, ctinfo, exp)) { +- UNLOCK_BH(&ip_h323_lock); +- return NF_DROP; +- } +- UNLOCK_BH(&ip_h323_lock); +- +- return NF_ACCEPT; +-} +- +-static struct ip_nat_helper h225 = +- { { NULL, NULL }, +- "H.225", /* name */ +- IP_NAT_HELPER_F_ALWAYS, /* flags */ +- THIS_MODULE, /* module */ +- { { 0, { __constant_htons(H225_PORT) } }, /* tuple */ +- { 0, { 0 }, IPPROTO_TCP } }, +- { { 0, { 0xFFFF } }, /* mask */ +- { 0, { 0 }, 0xFFFF } }, +- h225_nat_help, /* helper */ +- h225_nat_expected /* expectfn */ +- }; +- +-static int __init init(void) +-{ +- int ret; +- +- ret = ip_nat_helper_register(&h225); +- +- if (ret != 0) +- printk("ip_nat_h323: cannot initialize the module!\n"); +- +- return ret; +-} +- +-static void __exit fini(void) +-{ +- ip_nat_helper_unregister(&h225); +-} +- +-module_init(init); +-module_exit(fini); +diff -Nurb src/linux/linux/net/ipv4/netfilter/ip_nat_helper.c src/linux/linux.stock/net/ipv4/netfilter/ip_nat_helper.c +--- src/linux/linux/net/ipv4/netfilter/ip_nat_helper.c 2003-07-04 04:12:31.000000000 -0400 ++++ src/linux/linux.stock/net/ipv4/netfilter/ip_nat_helper.c 2004-05-09 04:13:03.000000000 -0400 +@@ -8,9 +8,6 @@ + * - add support for SACK adjustment + * 14 Mar 2002 Harald Welte <laforge@gnumonks.org>: + * - merge SACK support into newnat API +- * 16 Aug 2002 Brian J. Murrell <netfilter@interlinx.bc.ca>: +- * - make ip_nat_resize_packet more generic (TCP and UDP) +- * - add ip_nat_mangle_udp_packet + */ + #include <linux/version.h> + #include <linux/config.h> +@@ -25,7 +22,6 @@ + #include <net/icmp.h> + #include <net/ip.h> + #include <net/tcp.h> +-#include <net/udp.h> + + #define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock) + #define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock) +@@ -38,8 +34,13 @@ + #include <linux/netfilter_ipv4/ip_nat_helper.h> + #include <linux/netfilter_ipv4/listhelp.h> + ++#if 0 ++#define DEBUGP printk ++#define DUMP_OFFSET(x) printk("offset_before=%d, offset_after=%d, correction_pos=%u\n", x->offset_before, x->offset_after, x->correction_pos); ++#else + #define DEBUGP(format, args...) + #define DUMP_OFFSET(x) ++#endif + + DECLARE_LOCK(ip_nat_seqofs_lock); + +@@ -50,12 +51,18 @@ + int new_size) + { + struct iphdr *iph; ++ struct tcphdr *tcph; ++ void *data; + int dir; + struct ip_nat_seq *this_way, *other_way; + + DEBUGP("ip_nat_resize_packet: old_size = %u, new_size = %u\n", + (*skb)->len, new_size); + ++ iph = (*skb)->nh.iph; ++ tcph = (void *)iph + iph->ihl*4; ++ data = (void *)tcph + tcph->doff*4; ++ + dir = CTINFO2DIR(ctinfo); + + this_way = &ct->nat.info.seq[dir]; +@@ -77,9 +84,8 @@ + } + + iph = (*skb)->nh.iph; +- if (iph->protocol == IPPROTO_TCP) { +- struct tcphdr *tcph = (void *)iph + iph->ihl*4; +- void *data = (void *)tcph + tcph->doff*4; ++ tcph = (void *)iph + iph->ihl*4; ++ data = (void *)tcph + tcph->doff*4; + + DEBUGP("ip_nat_resize_packet: Seq_offset before: "); + DUMP_OFFSET(this_way); +@@ -95,20 +101,25 @@ + this_way->correction_pos = ntohl(tcph->seq); + this_way->offset_before = this_way->offset_after; + this_way->offset_after = (int32_t) +- this_way->offset_before + new_size - +- (*skb)->len; ++ this_way->offset_before + new_size - (*skb)->len; + } + + UNLOCK_BH(&ip_nat_seqofs_lock); + + DEBUGP("ip_nat_resize_packet: Seq_offset after: "); + DUMP_OFFSET(this_way); +- } + + return 1; + } + + ++/* Generic function for mangling variable-length address changes inside ++ * NATed connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX command in FTP). ++ * ++ * Takes care about all the nasty sequence number changes, checksumming, ++ * skb enlargement, ... ++ * ++ * */ + int + ip_nat_mangle_tcp_packet(struct sk_buff **skb, + struct ip_conntrack *ct, +@@ -163,7 +174,6 @@ + tcph = (void *)iph + iph->ihl*4; + data = (void *)tcph + tcph->doff*4; + +- if (rep_len != match_len) + /* move post-replacement */ + memmove(data + match_offset + rep_len, + data + match_offset + match_len, +@@ -198,104 +208,6 @@ + return 1; + } + +-int +-ip_nat_mangle_udp_packet(struct sk_buff **skb, +- struct ip_conntrack *ct, +- enum ip_conntrack_info ctinfo, +- unsigned int match_offset, +- unsigned int match_len, +- char *rep_buffer, +- unsigned int rep_len) +-{ +- struct iphdr *iph = (*skb)->nh.iph; +- struct udphdr *udph = (void *)iph + iph->ihl * 4; +- unsigned char *data; +- u_int32_t udplen, newlen, newudplen; +- +- udplen = (*skb)->len - iph->ihl*4; +- newudplen = udplen - match_len + rep_len; +- newlen = iph->ihl*4 + newudplen; +- +- if (newlen > 65535) { +- if (net_ratelimit()) +- printk("ip_nat_mangle_udp_packet: nat'ed packet " +- "exceeds maximum packet size\n"); +- return 0; +- } +- +- if ((*skb)->len != newlen) { +- if (!ip_nat_resize_packet(skb, ct, ctinfo, newlen)) { +- printk("resize_packet failed!!\n"); +- return 0; +- } +- } +- +- /* Alexey says: if a hook changes _data_ ... it can break +- original packet sitting in tcp queue and this is fatal */ +- if (skb_cloned(*skb)) { +- struct sk_buff *nskb = skb_copy(*skb, GFP_ATOMIC); +- if (!nskb) { +- if (net_ratelimit()) +- printk("Out of memory cloning TCP packet\n"); +- return 0; +- } +- /* Rest of kernel will get very unhappy if we pass it +- a suddenly-orphaned skbuff */ +- if ((*skb)->sk) +- skb_set_owner_w(nskb, (*skb)->sk); +- kfree_skb(*skb); +- *skb = nskb; +- } +- +- /* skb may be copied !! */ +- iph = (*skb)->nh.iph; +- udph = (void *)iph + iph->ihl*4; +- data = (void *)udph + sizeof(struct udphdr); +- +- if (rep_len != match_len) +- /* move post-replacement */ +- memmove(data + match_offset + rep_len, +- data + match_offset + match_len, +- (*skb)->tail - (data + match_offset + match_len)); +- +- /* insert data from buffer */ +- memcpy(data + match_offset, rep_buffer, rep_len); +- +- /* update skb info */ +- if (newlen > (*skb)->len) { +- DEBUGP("ip_nat_mangle_udp_packet: Extending packet by " +- "%u to %u bytes\n", newlen - (*skb)->len, newlen); +- skb_put(*skb, newlen - (*skb)->len); +- } else { +- DEBUGP("ip_nat_mangle_udp_packet: Shrinking packet from " +- "%u to %u bytes\n", (*skb)->len, newlen); +- skb_trim(*skb, newlen); +- } +- +- /* update the length of the UDP and IP packets to the new values*/ +- udph->len = htons((*skb)->len - iph->ihl*4); +- iph->tot_len = htons(newlen); +- +- /* fix udp checksum if udp checksum was previously calculated */ +- if ((*skb)->csum != 0) { +- (*skb)->csum = csum_partial((char *)udph + +- sizeof(struct udphdr), +- newudplen - sizeof(struct udphdr), +- 0); +- +- udph->check = 0; +- udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, +- newudplen, IPPROTO_UDP, +- csum_partial((char *)udph, +- sizeof(struct udphdr), +- (*skb)->csum)); +- } +- +- ip_send_check(iph); +- +- return 1; +-} +- + /* Adjust one found SACK option including checksum correction */ + static void + sack_adjust(struct tcphdr *tcph, +diff -Nurb src/linux/linux/net/ipv4/netfilter/ip_nat_mms.c src/linux/linux.stock/net/ipv4/netfilter/ip_nat_mms.c +--- src/linux/linux/net/ipv4/netfilter/ip_nat_mms.c 2003-07-04 04:12:31.000000000 -0400 ++++ src/linux/linux.stock/net/ipv4/netfilter/ip_nat_mms.c 1969-12-31 19:00:00.000000000 -0500 +@@ -1,330 +0,0 @@ +-/* MMS extension for TCP NAT alteration. +- * (C) 2002 by Filip Sneppe <filip.sneppe@cronos.be> +- * based on ip_nat_ftp.c and ip_nat_irc.c +- * +- * ip_nat_mms.c v0.3 2002-09-22 +- * +- * 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. +- * +- * Module load syntax: +- * insmod ip_nat_mms.o ports=port1,port2,...port<MAX_PORTS> +- * +- * Please give the ports of all MMS servers You wish to connect to. +- * If you don't specify ports, the default will be TCP port 1755. +- * +- * More info on MMS protocol, firewalls and NAT: +- * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwmt/html/MMSFirewall.asp +- * http://www.microsoft.com/windows/windowsmedia/serve/firewall.asp +- * +- * The SDP project people are reverse-engineering MMS: +- * http://get.to/sdp +- */ +- +- +-#include <linux/module.h> +-#include <linux/netfilter_ipv4.h> +-#include <linux/ip.h> +-#include <linux/tcp.h> +-#include <net/tcp.h> +-#include <linux/netfilter_ipv4/ip_nat.h> +-#include <linux/netfilter_ipv4/ip_nat_helper.h> +-#include <linux/netfilter_ipv4/ip_nat_rule.h> +-#include <linux/netfilter_ipv4/ip_conntrack_mms.h> +-#include <linux/netfilter_ipv4/ip_conntrack_helper.h> +- +-#define DEBUGP(format, args...) +-#define DUMP_BYTES(address, counter) +- +-#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 +- +-MODULE_AUTHOR("Filip Sneppe <filip.sneppe@cronos.be>"); +-MODULE_DESCRIPTION("Microsoft Windows Media Services (MMS) NAT module"); +-MODULE_LICENSE("GPL"); +- +-DECLARE_LOCK_EXTERN(ip_mms_lock); +- +- +-static int mms_data_fixup(const struct ip_ct_mms_expect *ct_mms_info, +- struct ip_conntrack *ct, +- struct sk_buff **pskb, +- enum ip_conntrack_info ctinfo, +- struct ip_conntrack_expect *expect) +-{ +- u_int32_t newip; +- struct ip_conntrack_tuple t; +- struct iphdr *iph = (*pskb)->nh.iph; +- struct tcphdr *tcph = (void *) iph + iph->ihl * 4; +- char *data = (char *)tcph + tcph->doff * 4; +- int i, j, k, port; +- u_int16_t mms_proto; +- +- u_int32_t *mms_chunkLenLV = (u_int32_t *)(data + MMS_SRV_CHUNKLENLV_OFFSET); +- u_int32_t *mms_chunkLenLM = (u_int32_t *)(data + MMS_SRV_CHUNKLENLM_OFFSET); +- u_int32_t *mms_messageLength = (u_int32_t *)(data + MMS_SRV_MESSAGELENGTH_OFFSET); +- +- int zero_padding; +- +- char buffer[28]; /* "\\255.255.255.255\UDP\65635" * 2 (for unicode) */ +- char unicode_buffer[75]; /* 27*2 (unicode) + 20 + 1 */ +- char proto_string[6]; +- +- MUST_BE_LOCKED(&ip_mms_lock); +- +- /* what was the protocol again ? */ +- mms_proto = expect->tuple.dst.protonum; +- sprintf(proto_string, "%u", mms_proto); +- +- DEBUGP("ip_nat_mms: mms_data_fixup: info (seq %u + %u) in %u, proto %s\n", +- expect->seq, ct_mms_info->len, ntohl(tcph->seq), +- mms_proto == IPPROTO_UDP ? "UDP" +- : mms_proto == IPPROTO_TCP ? "TCP":proto_string); +- +- newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; +- +- /* Alter conntrack's expectations. */ +- t = expect->tuple; +- t.dst.ip = newip; +- for (port = ct_mms_info->port; port != 0; port++) { +- t.dst.u.tcp.port = htons(port); +- if (ip_conntrack_change_expect(expect, &t) == 0) { +- DEBUGP("ip_nat_mms: mms_data_fixup: using port %d\n", port); +- break; +- } +- } +- +- if(port == 0) +- return 0; +- +- sprintf(buffer, "\\\\%u.%u.%u.%u\\%s\\%u", +- NIPQUAD(newip), +- expect->tuple.dst.protonum == IPPROTO_UDP ? "UDP" +- : expect->tuple.dst.protonum == IPPROTO_TCP ? "TCP":proto_string, +- port); +- DEBUGP("ip_nat_mms: new unicode string=%s\n", buffer); +- +- memset(unicode_buffer, 0, sizeof(char)*75); +- +- for (i=0; i<strlen(buffer); ++i) +- *(unicode_buffer+i*2)=*(buffer+i); +- +- DEBUGP("ip_nat_mms: mms_data_fixup: padding: %u len: %u\n", ct_mms_info->padding, ct_mms_info->len); +- DEBUGP("ip_nat_mms: mms_data_fixup: offset: %u\n", MMS_SRV_UNICODE_STRING_OFFSET+ct_mms_info->len); +- DUMP_BYTES(data+MMS_SRV_UNICODE_STRING_OFFSET, 60); +- +- /* add end of packet to it */ +- for (j=0; j<ct_mms_info->padding; ++j) { +- DEBUGP("ip_nat_mms: mms_data_fixup: i=%u j=%u byte=%u\n", +- i, j, (u8)*(data+MMS_SRV_UNICODE_STRING_OFFSET+ct_mms_info->len+j)); +- *(unicode_buffer+i*2+j) = *(data+MMS_SRV_UNICODE_STRING_OFFSET+ct_mms_info->len+j); +- } +- +- /* pad with zeroes at the end ? see explanation of weird math below */ +- zero_padding = (8-(strlen(buffer)*2 + ct_mms_info->padding + 4)%8)%8; +- for (k=0; k<zero_padding; ++k) +- *(unicode_buffer+i*2+j+k)= (char)0; +- +- DEBUGP("ip_nat_mms: mms_data_fixup: zero_padding = %u\n", zero_padding); +- DEBUGP("ip_nat_mms: original=> chunkLenLV=%u chunkLenLM=%u messageLength=%u\n", +- *mms_chunkLenLV, *mms_chunkLenLM, *mms_messageLength); +- +- /* explanation, before I forget what I did: +- strlen(buffer)*2 + ct_mms_info->padding + 4 must be divisable by 8; +- divide by 8 and add 3 to compute the mms_chunkLenLM field, +- but note that things may have to be padded with zeroes to align by 8 +- bytes, hence we add 7 and divide by 8 to get the correct length */ +- *mms_chunkLenLM = (u_int32_t) (3+(strlen(buffer)*2+ct_mms_info->padding+11)/8); +- *mms_chunkLenLV = *mms_chunkLenLM+2; +- *mms_messageLength = *mms_chunkLenLV*8; +- +- DEBUGP("ip_nat_mms: modified=> chunkLenLV=%u chunkLenLM=%u messageLength=%u\n", +- *mms_chunkLenLV, *mms_chunkLenLM, *mms_messageLength); +- +- ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, +- expect->seq - ntohl(tcph->seq), +- ct_mms_info->len + ct_mms_info->padding, unicode_buffer, +- strlen(buffer)*2 + ct_mms_info->padding + zero_padding); +- DUMP_BYTES(unicode_buffer, 60); +- +- return 1; +-} +- +-static unsigned int +-mms_nat_expected(struct sk_buff **pskb, +- unsigned int hooknum, +- struct ip_conntrack *ct, +- struct ip_nat_info *info) +-{ +- struct ip_nat_multi_range mr; +- u_int32_t newdstip, newsrcip, newip; +- +- struct ip_conntrack *master = master_ct(ct); +- +- IP_NF_ASSERT(info); +- IP_NF_ASSERT(master); +- +- IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum)))); +- +- DEBUGP("ip_nat_mms: mms_nat_expected: We have a connection!\n"); +- +- newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; +- newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; +- DEBUGP("ip_nat_mms: mms_nat_expected: hook %s: newsrc->newdst %u.%u.%u.%u->%u.%u.%u.%u\n", +- hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" +- : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" +- : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???", +- NIPQUAD(newsrcip), NIPQUAD(newdstip)); +- +- if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) +- newip = newsrcip; +- else +- newip = newdstip; +- +- DEBUGP("ip_nat_mms: mms_nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip)); +- +- mr.rangesize = 1; +- /* We don't want to manip the per-protocol, just the IPs. */ +- mr.range[0].flags = IP_NAT_RANGE_MAP_IPS; +- mr.range[0].min_ip = mr.range[0].max_ip = newip; +- +- return ip_nat_setup_info(ct, &mr, hooknum); +-} +- +- +-static unsigned int mms_nat_help(struct ip_conntrack *ct, +- struct ip_conntrack_expect *exp, +- struct ip_nat_info *info, +- enum ip_conntrack_info ctinfo, +- unsigned int hooknum, +- struct sk_buff **pskb) +-{ +- struct iphdr *iph = (*pskb)->nh.iph; +- struct tcphdr *tcph = (void *) iph + iph->ihl * 4; +- unsigned int datalen; +- int dir; +- struct ip_ct_mms_expect *ct_mms_info; +- +- if (!exp) +- DEBUGP("ip_nat_mms: no exp!!"); +- +- ct_mms_info = &exp->help.exp_mms_info; +- +- /* Only mangle things once: original direction in POST_ROUTING +- and reply direction on PRE_ROUTING. */ +- dir = CTINFO2DIR(ctinfo); +- if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL) +- ||(hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) { +- DEBUGP("ip_nat_mms: mms_nat_help: not touching dir %s at hook %s\n", +- dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", +- hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" +- : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" +- : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???"); +- return NF_ACCEPT; +- } +- DEBUGP("ip_nat_mms: mms_nat_help: beyond not touching (dir %s at hook %s)\n", +- dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", +- hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" +- : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" +- : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???"); +- +- datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4; +- +- DEBUGP("ip_nat_mms: mms_nat_help: %u+%u=%u %u %u\n", exp->seq, ct_mms_info->len, +- exp->seq + ct_mms_info->len, +- ntohl(tcph->seq), +- ntohl(tcph->seq) + datalen); +- +- LOCK_BH(&ip_mms_lock); +- /* Check wether the whole IP/proto/port pattern is carried in the payload */ +- if (between(exp->seq + ct_mms_info->len, +- ntohl(tcph->seq), +- ntohl(tcph->seq) + datalen)) { +- if (!mms_data_fixup(ct_mms_info, ct, pskb, ctinfo, exp)) { +- UNLOCK_BH(&ip_mms_lock); +- return NF_DROP; +- } +- } else { +- /* Half a match? This means a partial retransmisison. +- It's a cracker being funky. */ +- if (net_ratelimit()) { +- printk("ip_nat_mms: partial packet %u/%u in %u/%u\n", +- exp->seq, ct_mms_info->len, +- ntohl(tcph->seq), +- ntohl(tcph->seq) + datalen); +- } +- UNLOCK_BH(&ip_mms_lock); +- return NF_DROP; +- } +- UNLOCK_BH(&ip_mms_lock); +- +- return NF_ACCEPT; +-} +- +-static struct ip_nat_helper mms[MAX_PORTS]; +-static char mms_names[MAX_PORTS][10]; +- +-/* Not __exit: called from init() */ +-static void fini(void) +-{ +- int i; +- +- for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { +- DEBUGP("ip_nat_mms: unregistering helper for port %d\n", ports[i]); +- ip_nat_helper_unregister(&mms[i]); +- } +-} +- +-static int __init init(void) +-{ +- int i, ret = 0; +- char *tmpname; +- +- if (ports[0] == 0) +- ports[0] = MMS_PORT; +- +- for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { +- +- memset(&mms[i], 0, sizeof(struct ip_nat_helper)); +- +- mms[i].tuple.dst.protonum = IPPROTO_TCP; +- mms[i].tuple.src.u.tcp.port = htons(ports[i]); +- mms[i].mask.dst.protonum = 0xFFFF; +- mms[i].mask.src.u.tcp.port = 0xFFFF; +- mms[i].help = mms_nat_help; +- mms[i].me = THIS_MODULE; +- mms[i].flags = 0; +- mms[i].expect = mms_nat_expected; +- +- tmpname = &mms_names[i][0]; +- if (ports[i] == MMS_PORT) +- sprintf(tmpname, "mms"); +- else +- sprintf(tmpname, "mms-%d", i); +- mms[i].name = tmpname; +- +- DEBUGP("ip_nat_mms: register helper for port %d\n", +- ports[i]); +- ret = ip_nat_helper_register(&mms[i]); +- +- if (ret) { +- printk("ip_nat_mms: error registering " +- "helper for port %d\n", ports[i]); +- fini(); +- return ret; +- } +- ports_c++; +- } +- +- return ret; +-} +- +-module_init(init); +-module_exit(fini); +diff -Nurb src/linux/linux/net/ipv4/netfilter/ip_nat_pptp.c src/linux/linux.stock/net/ipv4/netfilter/ip_nat_pptp.c +--- src/linux/linux/net/ipv4/netfilter/ip_nat_pptp.c 2003-07-04 04:12:31.000000000 -0400 ++++ src/linux/linux.stock/net/ipv4/netfilter/ip_nat_pptp.c 1969-12-31 19:00:00.000000000 -0500 +@@ -1,412 +0,0 @@ +-/* +- * ip_nat_pptp.c - Version 1.11 +- * +- * NAT support for PPTP (Point to Point Tunneling Protocol). +- * PPTP is a a protocol for creating virtual private networks. +- * It is a specification defined by Microsoft and some vendors +- * working with Microsoft. PPTP is built on top of a modified +- * version of the Internet Generic Routing Encapsulation Protocol. +- * GRE is defined in RFC 1701 and RFC 1702. Documentation of +- * PPTP can be found in RFC 2637 +- * +- * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org> +- * +- * Development of this code funded by Astaro AG (http://www.astaro.com/) +- * +- * TODO: - Support for multiple calls within one session +- * (needs netfilter newnat code) +- * - NAT to a unique tuple, not to TCP source port +- * (needs netfilter tuple reservation) +- * - Support other NAT scenarios than SNAT of PNS +- * +- */ +- +-#include <linux/config.h> +-#include <linux/module.h> +-#include <linux/ip.h> +-#include <linux/tcp.h> +-#include <net/tcp.h> +-#include <linux/netfilter_ipv4/ip_nat.h> +-#include <linux/netfilter_ipv4/ip_nat_rule.h> +-#include <linux/netfilter_ipv4/ip_nat_helper.h> +-#include <linux/netfilter_ipv4/ip_nat_pptp.h> +-#include <linux/netfilter_ipv4/ip_conntrack_helper.h> +-#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h> +-#include <linux/netfilter_ipv4/ip_conntrack_pptp.h> +- +-MODULE_LICENSE("GPL"); +-MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); +-MODULE_DESCRIPTION("Netfilter NAT helper module for PPTP"); +- +- +-#define DEBUGP(format, args...) +- +-static unsigned int +-pptp_nat_expected(struct sk_buff **pskb, +- unsigned int hooknum, +- struct ip_conntrack *ct, +- struct ip_nat_info *info) +-{ +- struct ip_conntrack *master = master_ct(ct); +- struct ip_nat_multi_range mr; +- struct ip_ct_pptp_master *ct_pptp_info; +- struct ip_nat_pptp *nat_pptp_info; +- u_int32_t newsrcip, newdstip, newcid; +- int ret; +- +- IP_NF_ASSERT(info); +- IP_NF_ASSERT(master); +- IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum)))); +- +- DEBUGP("we have a connection!\n"); +- +- LOCK_BH(&ip_pptp_lock); +- ct_pptp_info = &master->help.ct_pptp_info; +- nat_pptp_info = &master->nat.help.nat_pptp_info; +- +- /* need to alter GRE tuple because conntrack expectfn() used 'wrong' +- * (unmanipulated) values */ +- if (hooknum == NF_IP_PRE_ROUTING) { +- DEBUGP("completing tuples with NAT info \n"); +- /* we can do this, since we're unconfirmed */ +- if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key == +- htonl(ct_pptp_info->pac_call_id)) { +- /* assume PNS->PAC */ +- ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key = +- htonl(nat_pptp_info->pns_call_id); +-// ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.gre.key = +-// htonl(nat_pptp_info->pac_call_id); +- ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key = +- htonl(nat_pptp_info->pns_call_id); +- } else { +- /* assume PAC->PNS */ +- DEBUGP("WRONG DIRECTION\n"); +- ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key = +- htonl(nat_pptp_info->pac_call_id); +- ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key = +- htonl(nat_pptp_info->pns_call_id); +- } +- } +- +- if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) { +- newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; +- newcid = htonl(master->nat.help.nat_pptp_info.pac_call_id); +- +- mr.rangesize = 1; +- mr.range[0].flags = IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED; +- mr.range[0].min_ip = mr.range[0].max_ip = newdstip; +- mr.range[0].min = mr.range[0].max = +- ((union ip_conntrack_manip_proto ) { newcid }); +- DEBUGP("change dest ip to %u.%u.%u.%u\n", +- NIPQUAD(newdstip)); +- DEBUGP("change dest key to 0x%x\n", ntohl(newcid)); +- ret = ip_nat_setup_info(ct, &mr, hooknum); +- } else { +- newsrcip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; +- /* nat_multi_range is in network byte order, and GRE tuple +- * is 32 bits, not 16 like callID */ +- newcid = htonl(master->help.ct_pptp_info.pns_call_id); +- +- mr.rangesize = 1; +- mr.range[0].flags = IP_NAT_RANGE_MAP_IPS +- |IP_NAT_RANGE_PROTO_SPECIFIED; +- mr.range[0].min_ip = mr.range[0].max_ip = newsrcip; +- mr.range[0].min = mr.range[0].max = +- ((union ip_conntrack_manip_proto ) { newcid }); +- DEBUGP("change src ip to %u.%u.%u.%u\n", +- NIPQUAD(newsrcip)); +- DEBUGP("change 'src' key to 0x%x\n", ntohl(newcid)); +- ret = ip_nat_setup_info(ct, &mr, hooknum); +- } +- +- UNLOCK_BH(&ip_pptp_lock); +- +- return ret; +- +-} +- +-/* outbound packets == from PNS to PAC */ +-static inline unsigned int +-pptp_outbound_pkt(struct tcphdr *tcph, struct pptp_pkt_hdr *pptph, +- size_t datalen, +- struct ip_conntrack *ct, +- enum ip_conntrack_info ctinfo, +- struct ip_conntrack_expect *exp) +- +-{ +- struct PptpControlHeader *ctlh; +- union pptp_ctrl_union pptpReq; +- struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info; +- struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info; +- +- u_int16_t msg, *cid = NULL, new_callid; +- +- ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph)); +- pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh)); +- +- new_callid = htons(ct_pptp_info->pns_call_id); +- +- switch (msg = ntohs(ctlh->messageType)) { +- case PPTP_OUT_CALL_REQUEST: +- cid = &pptpReq.ocreq->callID; +- +- /* save original call ID in nat_info */ +- nat_pptp_info->pns_call_id = ct_pptp_info->pns_call_id; +- +- new_callid = tcph->source; +- /* save new call ID in ct info */ +- ct_pptp_info->pns_call_id = ntohs(new_callid); +- break; +- case PPTP_IN_CALL_REPLY: +- cid = &pptpReq.icreq->callID; +- break; +- case PPTP_CALL_CLEAR_REQUEST: +- cid = &pptpReq.clrreq->callID; +- break; +- case PPTP_CALL_DISCONNECT_NOTIFY: +- cid = &pptpReq.disc->callID; +- break; +- +- default: +- DEBUGP("unknown outbound packet 0x%04x:%s\n", msg, +- (msg <= PPTP_MSG_MAX)? strMName[msg]:strMName[0]); +- /* fall through */ +- +- case PPTP_SET_LINK_INFO: +- /* only need to NAT in case PAC is behind NAT box */ +- case PPTP_START_SESSION_REQUEST: +- case PPTP_START_SESSION_REPLY: +- case PPTP_STOP_SESSION_REQUEST: +- case PPTP_STOP_SESSION_REPLY: +- case PPTP_ECHO_REQUEST: +- case PPTP_ECHO_REPLY: +- /* no need to alter packet */ +- return NF_ACCEPT; +- } +- +- IP_NF_ASSERT(cid); +- +- DEBUGP("altering call id from 0x%04x to 0x%04x\n", +- ntohs(*cid), ntohs(new_callid)); +- /* mangle packet */ +- tcph->check = ip_nat_cheat_check(*cid^0xFFFF, +- new_callid, tcph->check); +- *cid = new_callid; +- +- return NF_ACCEPT; +-} +- +-/* inbound packets == from PAC to PNS */ +-static inline unsigned int +-pptp_inbound_pkt(struct tcphdr *tcph, struct pptp_pkt_hdr *pptph, +- size_t datalen, +- struct ip_conntrack *ct, +- enum ip_conntrack_info ctinfo, +- struct ip_conntrack_expect *oldexp) +-{ +- struct PptpControlHeader *ctlh; +- union pptp_ctrl_union pptpReq; +- struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info; +- struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info; +- +- u_int16_t msg, new_cid = 0, new_pcid, *pcid = NULL, *cid = NULL; +- u_int32_t old_dst_ip; +- +- struct ip_conntrack_tuple t; +- +- ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph)); +- pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh)); +- +- new_pcid = htons(nat_pptp_info->pns_call_id); +- +- switch (msg = ntohs(ctlh->messageType)) { +- case PPTP_OUT_CALL_REPLY: +- pcid = &pptpReq.ocack->peersCallID; +- cid = &pptpReq.ocack->callID; +- if (!oldexp) { +- DEBUGP("outcall but no expectation\n"); +- break; +- } +- old_dst_ip = oldexp->tuple.dst.ip; +- t = oldexp->tuple; +- +- /* save original PAC call ID in nat_info */ +- nat_pptp_info->pac_call_id = ct_pptp_info->pac_call_id; +- +- /* store new callID in ct_info, so conntrack works */ +- //ct_pptp_info->pac_call_id = ntohs(tcph->source); +- //new_cid = htons(ct_pptp_info->pac_call_id); +- +- /* alter expectation */ +- if (t.dst.ip == ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip) { +- /* expectation for PNS->PAC direction */ +- t.dst.u.gre.key = htonl(ct_pptp_info->pac_call_id); +- t.src.u.gre.key = htonl(nat_pptp_info->pns_call_id); +- } else { +- /* expectation for PAC->PNS direction */ +- t.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; +- DEBUGP("EXPECTATION IN WRONG DIRECTION!!!\n"); +- } +- +- if (!ip_conntrack_change_expect(oldexp, &t)) { +- DEBUGP("successfully changed expect\n"); +- } else { +- DEBUGP("can't change expect\n"); +- } +- ip_ct_gre_keymap_change(oldexp->proto.gre.keymap_orig, &t); +- /* reply keymap */ +- t.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; +- t.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; +- t.src.u.gre.key = htonl(nat_pptp_info->pac_call_id); +- t.dst.u.gre.key = htonl(ct_pptp_info->pns_call_id); +- ip_ct_gre_keymap_change(oldexp->proto.gre.keymap_reply, &t); +- +- break; +- case PPTP_IN_CALL_CONNECT: +- pcid = &pptpReq.iccon->peersCallID; +- if (!oldexp) +- break; +- old_dst_ip = oldexp->tuple.dst.ip; +- t = oldexp->tuple; +- +- /* alter expectation, no need for callID */ +- if (t.dst.ip == ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip) { +- /* expectation for PNS->PAC direction */ +- t.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; +- } else { +- /* expectation for PAC->PNS direction */ +- t.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; +- } +- +- if (!ip_conntrack_change_expect(oldexp, &t)) { +- DEBUGP("successfully changed expect\n"); +- } else { +- DEBUGP("can't change expect\n"); +- } +- break; +- case PPTP_IN_CALL_REQUEST: +- /* only need to nat in case PAC is behind NAT box */ +- break; +- case PPTP_WAN_ERROR_NOTIFY: +- pcid = &pptpReq.wanerr->peersCallID; +- break; +- default: +- DEBUGP("unknown inbound packet %s\n", +- (msg <= PPTP_MSG_MAX)? strMName[msg]:strMName[0]); +- /* fall through */ +- +- case PPTP_START_SESSION_REQUEST: +- case PPTP_START_SESSION_REPLY: +- case PPTP_STOP_SESSION_REQUEST: +- case PPTP_ECHO_REQUEST: +- case PPTP_ECHO_REPLY: +- /* no need to alter packet */ +- return NF_ACCEPT; +- } +- +- /* mangle packet */ +- IP_NF_ASSERT(pcid); +- DEBUGP("altering peer call id from 0x%04x to 0x%04x\n", +- ntohs(*pcid), ntohs(new_pcid)); +- tcph->check = ip_nat_cheat_check(*pcid^0xFFFF, +- new_pcid, tcph->check); +- *pcid = new_pcid; +- +- if (new_cid) { +- IP_NF_ASSERT(cid); +- DEBUGP("altering call id from 0x%04x to 0x%04x\n", +- ntohs(*cid), ntohs(new_cid)); +- tcph->check = ip_nat_cheat_check(*cid^0xFFFF, +- new_cid, tcph->check); +- *cid = new_cid; +- } +- +- /* great, at least we don't need to resize packets */ +- return NF_ACCEPT; +-} +- +- +-static unsigned int tcp_help(struct ip_conntrack *ct, +- struct ip_conntrack_expect *exp, +- struct ip_nat_info *info, +- enum ip_conntrack_info ctinfo, +- unsigned int hooknum, struct sk_buff **pskb) +-{ +- struct iphdr *iph = (*pskb)->nh.iph; +- struct tcphdr *tcph = (void *) iph + iph->ihl*4; +- unsigned int datalen = (*pskb)->len - iph->ihl*4 - tcph->doff*4; +- struct pptp_pkt_hdr *pptph; +- void *datalimit; +- +- int dir; +- +- DEBUGP("entering\n"); +- +- /* Only mangle things once: original direction in POST_ROUTING +- and reply direction on PRE_ROUTING. */ +- dir = CTINFO2DIR(ctinfo); +- if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL) +- || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) { +- DEBUGP("Not touching dir %s at hook %s\n", +- dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", +- hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" +- : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" +- : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???"); +- return NF_ACCEPT; +- } +- +- /* if packet is too small, just skip it */ +- if (datalen < sizeof(struct pptp_pkt_hdr)+ +- sizeof(struct PptpControlHeader)) { +- DEBUGP("pptp packet too short\n"); +- return NF_ACCEPT; +- } +- +- +- pptph = (struct pptp_pkt_hdr *) ((void *)tcph + tcph->doff*4); +- datalimit = (void *) pptph + datalen; +- +- LOCK_BH(&ip_pptp_lock); +- +- if (dir == IP_CT_DIR_ORIGINAL) { +- /* reuqests sent by client to server (PNS->PAC) */ +- pptp_outbound_pkt(tcph, pptph, datalen, ct, ctinfo, exp); +- } else { +- /* response from the server to the client (PAC->PNS) */ +- pptp_inbound_pkt(tcph, pptph, datalen, ct, ctinfo, exp); +- } +- +- UNLOCK_BH(&ip_pptp_lock); +- +- return NF_ACCEPT; +-} +- +-/* nat helper struct for control connection */ +-static struct ip_nat_helper pptp_tcp_helper = { +- { NULL, NULL }, +- "pptp", IP_NAT_HELPER_F_ALWAYS, THIS_MODULE, +- { { 0, { tcp: { port: __constant_htons(PPTP_CONTROL_PORT) } } }, +- { 0, { 0 }, IPPROTO_TCP } }, +- { { 0, { tcp: { port: 0xFFFF } } }, +- { 0, { 0 }, 0xFFFF } }, +- tcp_help, pptp_nat_expected }; +- +- +-static int __init init(void) +-{ +- DEBUGP("init_module\n" ); +- +- if (ip_nat_helper_register(&pptp_tcp_helper)) +- return -EIO; +- +- return 0; +-} +- +-static void __exit fini(void) +-{ +- DEBUGP("cleanup_module\n" ); +- ip_nat_helper_unregister(&pptp_tcp_helper); +-} +- +-module_init(init); +-module_exit(fini); +diff -Nurb src/linux/linux/net/ipv4/netfilter/ip_nat_proto_gre.c src/linux/linux.stock/net/ipv4/netfilter/ip_nat_proto_gre.c +--- src/linux/linux/net/ipv4/netfilter/ip_nat_proto_gre.c 2003-07-04 04:12:31.000000000 -0400 ++++ src/linux/linux.stock/net/ipv4/netfilter/ip_nat_proto_gre.c 1969-12-31 19:00:00.000000000 -0500 +@@ -1,212 +0,0 @@ +-/* +- * ip_nat_proto_gre.c - Version 1.11 +- * +- * NAT protocol helper module for GRE. +- * +- * GRE is a generic encapsulation protocol, which is generally not very +- * suited for NAT, as it has no protocol-specific part as port numbers. +- * +- * It has an optional key field, which may help us distinguishing two +- * connections between the same two hosts. +- * +- * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784 +- * +- * PPTP is built on top of a modified version of GRE, and has a mandatory +- * field called "CallID", which serves us for the same purpose as the key +- * field in plain GRE. +- * +- * Documentation about PPTP can be found in RFC 2637 +- * +- * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org> +- * +- * Development of this code funded by Astaro AG (http://www.astaro.com/) +- * +- */ +- +-#include <linux/config.h> +-#include <linux/module.h> +-#include <linux/ip.h> +-#include <linux/netfilter_ipv4/ip_nat.h> +-#include <linux/netfilter_ipv4/ip_nat_rule.h> +-#include <linux/netfilter_ipv4/ip_nat_protocol.h> +-#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h> +- +-MODULE_LICENSE("GPL"); +-MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); +-MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE"); +- +-#define DEBUGP(x, args...) +- +-/* is key in given range between min and max */ +-static int +-gre_in_range(const struct ip_conntrack_tuple *tuple, +- enum ip_nat_manip_type maniptype, +- const union ip_conntrack_manip_proto *min, +- const union ip_conntrack_manip_proto *max) +-{ +- return ntohl(tuple->src.u.gre.key) >= ntohl(min->gre.key) +- && ntohl(tuple->src.u.gre.key) <= ntohl(max->gre.key); +-} +- +-/* generate unique tuple ... */ +-static int +-gre_unique_tuple(struct ip_conntrack_tuple *tuple, +- const struct ip_nat_range *range, +- enum ip_nat_manip_type maniptype, +- const struct ip_conntrack *conntrack) +-{ +- u_int32_t min, i, range_size; +- u_int32_t key = 0, *keyptr; +- +- if (maniptype == IP_NAT_MANIP_SRC) +- keyptr = &tuple->src.u.gre.key; +- else +- keyptr = &tuple->dst.u.gre.key; +- +- if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { +- +- switch (tuple->dst.u.gre.version) { +- case 0: +- DEBUGP("NATing GRE version 0 (ct=%p)\n", +- conntrack); +- min = 1; +- range_size = 0xffffffff; +- break; +- case GRE_VERSION_PPTP: +- DEBUGP("%p: NATing GRE PPTP\n", +- conntrack); +- min = 1; +- range_size = 0xffff; +- break; +- default: +- printk(KERN_WARNING "nat_gre: unknown GRE version\n"); +- return 0; +- break; +- } +- +- } else { +- min = ntohl(range->min.gre.key); +- range_size = ntohl(range->max.gre.key) - min + 1; +- } +- +- DEBUGP("min = %u, range_size = %u\n", min, range_size); +- +- for (i = 0; i < range_size; i++, key++) { +- *keyptr = htonl(min + key % range_size); +- if (!ip_nat_used_tuple(tuple, conntrack)) +- return 1; +- } +- +- DEBUGP("%p: no NAT mapping\n", conntrack); +- +- return 0; +-} +- +-/* manipulate a GRE packet according to maniptype */ +-static void +-gre_manip_pkt(struct iphdr *iph, size_t len, +- const struct ip_conntrack_manip *manip, +- enum ip_nat_manip_type maniptype) +-{ +- struct gre_hdr *greh = (struct gre_hdr *)((u_int32_t *)iph+iph->ihl); +- struct gre_hdr_pptp *pgreh = (struct gre_hdr_pptp *) greh; +- +- /* we only have destination manip of a packet, since 'source key' +- * is not present in the packet itself */ +- if (maniptype == IP_NAT_MANIP_DST) { +- /* key manipulation is always dest */ +- switch (greh->version) { +- case 0: +- if (!greh->key) { +- DEBUGP("can't nat GRE w/o key\n"); +- break; +- } +- if (greh->csum) { +- *(gre_csum(greh)) = +- ip_nat_cheat_check(~*(gre_key(greh)), +- manip->u.gre.key, +- *(gre_csum(greh))); +- } +- *(gre_key(greh)) = manip->u.gre.key; +- break; +- case GRE_VERSION_PPTP: +- DEBUGP("call_id -> 0x%04x\n", +- ntohl(manip->u.gre.key)); +- pgreh->call_id = htons(ntohl(manip->u.gre.key)); +- break; +- default: +- DEBUGP("can't nat unknown GRE version\n"); +- break; +- } +- } +-} +- +-/* print out a nat tuple */ +-static unsigned int +-gre_print(char *buffer, +- const struct ip_conntrack_tuple *match, +- const struct ip_conntrack_tuple *mask) +-{ +- unsigned int len = 0; +- +- if (mask->dst.u.gre.version) +- len += sprintf(buffer + len, "version=%d ", +- ntohs(match->dst.u.gre.version)); +- +- if (mask->dst.u.gre.protocol) +- len += sprintf(buffer + len, "protocol=0x%x ", +- ntohs(match->dst.u.gre.protocol)); +- +- if (mask->src.u.gre.key) +- len += sprintf(buffer + len, "srckey=0x%x ", +- ntohl(match->src.u.gre.key)); +- +- if (mask->dst.u.gre.key) +- len += sprintf(buffer + len, "dstkey=0x%x ", +- ntohl(match->src.u.gre.key)); +- +- return len; +-} +- +-/* print a range of keys */ +-static unsigned int +-gre_print_range(char *buffer, const struct ip_nat_range *range) +-{ +- if (range->min.gre.key != 0 +- || range->max.gre.key != 0xFFFF) { +- if (range->min.gre.key == range->max.gre.key) +- return sprintf(buffer, "key 0x%x ", +- ntohl(range->min.gre.key)); +- else +- return sprintf(buffer, "keys 0x%u-0x%u ", +- ntohl(range->min.gre.key), +- ntohl(range->max.gre.key)); +- } else +- return 0; +-} +- +-/* nat helper struct */ +-static struct ip_nat_protocol gre = +- { { NULL, NULL }, "GRE", IPPROTO_GRE, +- gre_manip_pkt, +- gre_in_range, +- gre_unique_tuple, +- gre_print, +- gre_print_range +- }; +- +-static int __init init(void) +-{ +- if (ip_nat_protocol_register(&gre)) +- return -EIO; +- +- return 0; +-} +- +-static void __exit fini(void) +-{ +- ip_nat_protocol_unregister(&gre); +-} +- +-module_init(init); +-module_exit(fini); +diff -Nurb src/linux/linux/net/ipv4/netfilter/ip_nat_standalone.c src/linux/linux.stock/net/ipv4/netfilter/ip_nat_standalone.c +--- src/linux/linux/net/ipv4/netfilter/ip_nat_standalone.c 2003-07-04 04:12:31.000000000 -0400 ++++ src/linux/linux.stock/net/ipv4/netfilter/ip_nat_standalone.c 2004-05-09 04:13:03.000000000 -0400 +@@ -37,7 +37,11 @@ + #include <linux/netfilter_ipv4/ip_conntrack_core.h> + #include <linux/netfilter_ipv4/listhelp.h> + ++#if 0 ++#define DEBUGP printk ++#else + #define DEBUGP(format, args...) ++#endif + + #define HOOKNAME(hooknum) ((hooknum) == NF_IP_POST_ROUTING ? "POST_ROUTING" \ + : ((hooknum) == NF_IP_PRE_ROUTING ? "PRE_ROUTING" \ +@@ -354,6 +358,5 @@ + EXPORT_SYMBOL(ip_nat_helper_unregister); + EXPORT_SYMBOL(ip_nat_cheat_check); + EXPORT_SYMBOL(ip_nat_mangle_tcp_packet); +-EXPORT_SYMBOL(ip_nat_mangle_udp_packet); + EXPORT_SYMBOL(ip_nat_used_tuple); + MODULE_LICENSE("GPL"); +diff -Nurb src/linux/linux/net/ipv4/netfilter/ip_nat_tftp.c src/linux/linux.stock/net/ipv4/netfilter/ip_nat_tftp.c +--- src/linux/linux/net/ipv4/netfilter/ip_nat_tftp.c 2003-07-04 04:12:31.000000000 -0400 ++++ src/linux/linux.stock/net/ipv4/netfilter/ip_nat_tftp.c 1969-12-31 19:00:00.000000000 -0500 +@@ -1,186 +0,0 @@ +-/* +- * Licensed under GNU GPL version 2 Copyright Magnus Boden <mb@ozaba.mine.nu> +- * Version: 0.0.7 +- * +- * Thu 21 Mar 2002 Harald Welte <laforge@gnumonks.org> +- * - Port to newnat API +- * +- * This module currently supports DNAT: +- * iptables -t nat -A PREROUTING -d x.x.x.x -j DNAT --to-dest x.x.x.y +- * +- * and SNAT: +- * iptables -t nat -A POSTROUTING { -j MASQUERADE , -j SNAT --to-source x.x.x.x } +- * +- * It has not been tested with +- * -j SNAT --to-source x.x.x.x-x.x.x.y since I only have one external ip +- * If you do test this please let me know if it works or not. +- * +- */ +- +-#include <linux/module.h> +-#include <linux/netfilter_ipv4.h> +-#include <linux/ip.h> +-#include <linux/udp.h> +- +-#include <linux/netfilter.h> +-#include <linux/netfilter_ipv4/ip_tables.h> +-#include <linux/netfilter_ipv4/ip_conntrack_helper.h> +-#include <linux/netfilter_ipv4/ip_conntrack_tftp.h> +-#include <linux/netfilter_ipv4/ip_nat_helper.h> +-#include <linux/netfilter_ipv4/ip_nat_rule.h> +- +-MODULE_AUTHOR("Magnus Boden <mb@ozaba.mine.nu>"); +-MODULE_DESCRIPTION("Netfilter NAT helper for tftp"); +-MODULE_LICENSE("GPL"); +- +-#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"); +-MODULE_PARM_DESC(ports, "port numbers of tftp servers"); +-#endif +- +-#define DEBUGP(format, args...) +-static unsigned int +-tftp_nat_help(struct ip_conntrack *ct, +- struct ip_conntrack_expect *exp, +- struct ip_nat_info *info, +- enum ip_conntrack_info ctinfo, +- unsigned int hooknum, +- struct sk_buff **pskb) +-{ +- int dir = CTINFO2DIR(ctinfo); +- struct iphdr *iph = (*pskb)->nh.iph; +- struct udphdr *udph = (void *)iph + iph->ihl * 4; +- struct tftphdr *tftph = (void *)udph + 8; +- struct ip_conntrack_tuple repl; +- +- if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL) +- || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) +- return NF_ACCEPT; +- +- if (!exp) { +- DEBUGP("no conntrack expectation to modify\n"); +- return NF_ACCEPT; +- } +- +- switch (ntohs(tftph->opcode)) { +- /* RRQ and WRQ works the same way */ +- case TFTP_OPCODE_READ: +- case TFTP_OPCODE_WRITE: +- repl = ct->tuplehash[IP_CT_DIR_REPLY].tuple; +- DEBUGP(""); +- DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); +- DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); +- DEBUGP("expecting: "); +- DUMP_TUPLE_RAW(&repl); +- DUMP_TUPLE_RAW(&exp->mask); +- ip_conntrack_change_expect(exp, &repl); +- break; +- default: +- DEBUGP("Unknown opcode\n"); +- } +- +- return NF_ACCEPT; +-} +- +-static unsigned int +-tftp_nat_expected(struct sk_buff **pskb, +- unsigned int hooknum, +- struct ip_conntrack *ct, +- struct ip_nat_info *info) +-{ +- const struct ip_conntrack *master = ct->master->expectant; +- const struct ip_conntrack_tuple *orig = +- &master->tuplehash[IP_CT_DIR_ORIGINAL].tuple; +- struct ip_nat_multi_range mr; +- +- IP_NF_ASSERT(info); +- IP_NF_ASSERT(master); +- IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum)))); +- +- mr.rangesize = 1; +- mr.range[0].flags = IP_NAT_RANGE_MAP_IPS; +- +- if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) { +- mr.range[0].min_ip = mr.range[0].max_ip = orig->dst.ip; +- DEBUGP("orig: %u.%u.%u.%u:%u <-> %u.%u.%u.%u:%u " +- "newsrc: %u.%u.%u.%u\n", +- NIPQUAD((*pskb)->nh.iph->saddr), ntohs(udph->source), +- NIPQUAD((*pskb)->nh.iph->daddr), ntohs(udph->dest), +- NIPQUAD(orig->dst.ip)); +- } else { +- mr.range[0].min_ip = mr.range[0].max_ip = orig->src.ip; +- mr.range[0].min.udp.port = mr.range[0].max.udp.port = +- orig->src.u.udp.port; +- mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED; +- +- DEBUGP("orig: %u.%u.%u.%u:%u <-> %u.%u.%u.%u:%u " +- "newdst: %u.%u.%u.%u:%u\n", +- NIPQUAD((*pskb)->nh.iph->saddr), ntohs(udph->source), +- NIPQUAD((*pskb)->nh.iph->daddr), ntohs(udph->dest), +- NIPQUAD(orig->src.ip), ntohs(orig->src.u.udp.port)); +- } +- +- return ip_nat_setup_info(ct,&mr,hooknum); +-} +- +-static struct ip_nat_helper tftp[MAX_PORTS]; +-static char tftp_names[MAX_PORTS][10]; +- +-static void fini(void) +-{ +- int i; +- +- for (i = 0 ; i < ports_c; i++) { +- DEBUGP("unregistering helper for port %d\n", ports[i]); +- ip_nat_helper_unregister(&tftp[i]); +- } +-} +- +-static int __init init(void) +-{ +- int i, ret; +- char *tmpname; +- +- if (!ports[0]) +- ports[0] = TFTP_PORT; +- +- for (i = 0 ; (i < MAX_PORTS) && ports[i] ; i++) { +- memset(&tftp[i], 0, sizeof(struct ip_nat_helper)); +- +- tftp[i].tuple.dst.protonum = IPPROTO_UDP; +- tftp[i].tuple.src.u.udp.port = htons(ports[i]); +- tftp[i].mask.dst.protonum = 0xFFFF; +- tftp[i].mask.src.u.udp.port = 0xFFFF; +- tftp[i].help = tftp_nat_help; +- tftp[i].flags = 0; +- tftp[i].me = THIS_MODULE; +- tftp[i].expect = tftp_nat_expected; +- +- tmpname = &tftp_names[i][0]; +- if (ports[i] == TFTP_PORT) +- sprintf(tmpname, "tftp"); +- else +- sprintf(tmpname, "tftp-%d", i); +- tftp[i].name = tmpname; +- +- DEBUGP("ip_nat_tftp: registering for port %d: name %s\n", +- ports[i], tftp[i].name); +- ret = ip_nat_helper_register(&tftp[i]); +- +- if (ret) { +- printk("ip_nat_tftp: unable to register for port %d\n", +- ports[i]); +- fini(); +- return ret; +- } +- ports_c++; +- } +- return ret; +-} +- +-module_init(init); +-module_exit(fini); +diff -Nurb src/linux/linux/net/ipv4/netfilter/ip_pool.c src/linux/linux.stock/net/ipv4/netfilter/ip_pool.c +--- src/linux/linux/net/ipv4/netfilter/ip_pool.c 2003-07-04 04:12:31.000000000 -0400 ++++ src/linux/linux.stock/net/ipv4/netfilter/ip_pool.c 1969-12-31 19:00:00.000000000 -0500 +@@ -1,328 +0,0 @@ +-/* Kernel module for IP pool management */ +- +-#include <linux/module.h> +-#include <linux/ip.h> +-#include <linux/skbuff.h> +-#include <linux/netfilter_ipv4/ip_tables.h> +-#include <linux/netfilter_ipv4/ip_pool.h> +-#include <linux/errno.h> +-#include <asm/uaccess.h> +-#include <asm/bitops.h> +-#include <linux/interrupt.h> +-#include <linux/spinlock.h> +- +-#define DP(format, args...) +- +-MODULE_LICENSE("GPL"); +- +-#define NR_POOL 16 +-static int nr_pool = NR_POOL;/* overwrite this when loading module */ +- +-struct ip_pool { +- u_int32_t first_ip; /* host byte order, included in range */ +- u_int32_t last_ip; /* host byte order, included in range */ +- void *members; /* the bitmap proper */ +- int nr_use; /* total nr. of tests through this */ +- int nr_match; /* total nr. of matches through this */ +- rwlock_t lock; +-}; +- +-static struct ip_pool *POOL; +- +-static inline struct ip_pool *lookup(ip_pool_t index) +-{ +- if (index < 0 || index >= nr_pool) { +- DP("ip_pool:lookup: bad index %d\n", index); +- return 0; +- } +- return POOL+index; +-} +- +-int ip_pool_match(ip_pool_t index, u_int32_t addr) +-{ +- struct ip_pool *pool = lookup(index); +- int res = 0; +- +- if (!pool || !pool->members) +- return 0; +- read_lock_bh(&pool->lock); +- if (pool->members) { +- if (addr >= pool->first_ip && addr <= pool->last_ip) { +- addr -= pool->first_ip; +- if (test_bit(addr, pool->members)) { +- res = 1; +-#ifdef CONFIG_IP_POOL_STATISTICS +- pool->nr_match++; +-#endif +- } +- } +-#ifdef CONFIG_IP_POOL_STATISTICS +- pool->nr_use++; +-#endif +- } +- read_unlock_bh(&pool->lock); +- return res; +-} +- +-static int pool_change(ip_pool_t index, u_int32_t addr, int isdel) +-{ +- struct ip_pool *pool; +- int res = -1; +- +- pool = lookup(index); +- if ( !pool || !pool->members +- || addr < pool->first_ip || addr > pool->last_ip) +- return -1; +- read_lock_bh(&pool->lock); +- if (pool->members && addr >= pool->first_ip && addr <= pool->last_ip) { +- addr -= pool->first_ip; +- res = isdel +- ? (0 != test_and_clear_bit(addr, pool->members)) +- : (0 != test_and_set_bit(addr, pool->members)); +- } +- read_unlock_bh(&pool->lock); +- return res; +-} +- +-int ip_pool_mod(ip_pool_t index, u_int32_t addr, int isdel) +-{ +- int res = pool_change(index,addr,isdel); +- +- if (!isdel) res = !res; +- return res; +-} +- +-static inline int bitmap_bytes(u_int32_t a, u_int32_t b) +-{ +- return 4*((((b-a+8)/8)+3)/4); +-} +- +-static inline int poolbytes(ip_pool_t index) +-{ +- struct ip_pool *pool = lookup(index); +- +- return pool ? bitmap_bytes(pool->first_ip, pool->last_ip) : 0; +-} +- +-static int setpool( +- struct sock *sk, +- int optval, +- void *user, +- unsigned int len +-) { +- struct ip_pool_request req; +- +- DP("ip_pool:setpool: optval=%d, user=%p, len=%d\n", optval, user, len); +- if (!capable(CAP_NET_ADMIN)) +- return -EPERM; +- if (optval != SO_IP_POOL) +- return -EBADF; +- if (len != sizeof(req)) +- return -EINVAL; +- if (copy_from_user(&req, user, sizeof(req)) != 0) +- return -EFAULT; +- printk("obsolete op - upgrade your ippool(8) utility.\n"); +- return -EINVAL; +-} +- +-static int getpool( +- struct sock *sk, +- int optval, +- void *user, +- int *len +-) { +- struct ip_pool_request req; +- struct ip_pool *pool; +- ip_pool_t i; +- int newbytes; +- void *newmembers; +- int res; +- +- DP("ip_pool:getpool: optval=%d, user=%p\n", optval, user); +- if (!capable(CAP_NET_ADMIN)) +- return -EINVAL; +- if (optval != SO_IP_POOL) +- return -EINVAL; +- if (*len != sizeof(req)) { +- return -EFAULT; +- } +- if (copy_from_user(&req, user, sizeof(req)) != 0) +- return -EFAULT; +- DP("ip_pool:getpool op=%d, index=%d\n", req.op, req.index); +- if (req.op < IP_POOL_BAD001) { +- printk("obsolete op - upgrade your ippool(8) utility.\n"); +- return -EFAULT; +- } +- switch(req.op) { +- case IP_POOL_HIGH_NR: +- DP("ip_pool HIGH_NR\n"); +- req.index = IP_POOL_NONE; +- for (i=0; i<nr_pool; i++) +- if (POOL[i].members) +- req.index = i; +- return copy_to_user(user, &req, sizeof(req)); +- case IP_POOL_LOOKUP: +- DP("ip_pool LOOKUP\n"); +- pool = lookup(req.index); +- if (!pool) +- return -EINVAL; +- if (!pool->members) +- return -EBADF; +- req.addr = htonl(pool->first_ip); +- req.addr2 = htonl(pool->last_ip); +- return copy_to_user(user, &req, sizeof(req)); +- case IP_POOL_USAGE: +- DP("ip_pool USE\n"); +- pool = lookup(req.index); +- if (!pool) +- return -EINVAL; +- if (!pool->members) +- return -EBADF; +- req.addr = pool->nr_use; +- req.addr2 = pool->nr_match; +- return copy_to_user(user, &req, sizeof(req)); +- case IP_POOL_TEST_ADDR: +- DP("ip_pool TEST 0x%08x\n", req.addr); +- pool = lookup(req.index); +- if (!pool) +- return -EINVAL; +- res = 0; +- read_lock_bh(&pool->lock); +- if (!pool->members) { +- DP("ip_pool TEST_ADDR no members in pool\n"); +- res = -EBADF; +- goto unlock_and_return_res; +- } +- req.addr = ntohl(req.addr); +- if (req.addr < pool->first_ip) { +- DP("ip_pool TEST_ADDR address < pool bounds\n"); +- res = -ERANGE; +- goto unlock_and_return_res; +- } +- if (req.addr > pool->last_ip) { +- DP("ip_pool TEST_ADDR address > pool bounds\n"); +- res = -ERANGE; +- goto unlock_and_return_res; +- } +- req.addr = (0 != test_bit((req.addr - pool->first_ip), +- pool->members)); +- read_unlock_bh(&pool->lock); +- return copy_to_user(user, &req, sizeof(req)); +- case IP_POOL_FLUSH: +- DP("ip_pool FLUSH not yet implemented.\n"); +- return -EBUSY; +- case IP_POOL_DESTROY: +- DP("ip_pool DESTROY not yet implemented.\n"); +- return -EBUSY; +- case IP_POOL_INIT: +- DP("ip_pool INIT 0x%08x-0x%08x\n", req.addr, req.addr2); +- pool = lookup(req.index); +- if (!pool) +- return -EINVAL; +- req.addr = ntohl(req.addr); +- req.addr2 = ntohl(req.addr2); +- if (req.addr > req.addr2) { +- DP("ip_pool INIT bad ip range\n"); +- return -EINVAL; +- } +- newbytes = bitmap_bytes(req.addr, req.addr2); +- newmembers = kmalloc(newbytes, GFP_KERNEL); +- if (!newmembers) { +- DP("ip_pool INIT out of mem for %d bytes\n", newbytes); +- return -ENOMEM; +- } +- memset(newmembers, 0, newbytes); +- write_lock_bh(&pool->lock); +- if (pool->members) { +- DP("ip_pool INIT pool %d exists\n", req.index); +- kfree(newmembers); +- res = -EBUSY; +- goto unlock_and_return_res; +- } +- pool->first_ip = req.addr; +- pool->last_ip = req.addr2; +- pool->nr_use = 0; +- pool->nr_match = 0; +- pool->members = newmembers; +- write_unlock_bh(&pool->lock); +- return 0; +- case IP_POOL_ADD_ADDR: +- DP("ip_pool ADD_ADDR 0x%08x\n", req.addr); +- req.addr = pool_change(req.index, ntohl(req.addr), 0); +- return copy_to_user(user, &req, sizeof(req)); +- case IP_POOL_DEL_ADDR: +- DP("ip_pool DEL_ADDR 0x%08x\n", req.addr); +- req.addr = pool_change(req.index, ntohl(req.addr), 1); +- return copy_to_user(user, &req, sizeof(req)); +- default: +- DP("ip_pool:getpool bad op %d\n", req.op); +- return -EINVAL; +- } +- return -EINVAL; +- +-unlock_and_return_res: +- if (pool) +- read_unlock_bh(&pool->lock); +- return res; +-} +- +-static struct nf_sockopt_ops so_pool +-= { { NULL, NULL }, PF_INET, +- SO_IP_POOL, SO_IP_POOL+1, &setpool, +- SO_IP_POOL, SO_IP_POOL+1, &getpool, +- 0, NULL }; +- +-MODULE_PARM(nr_pool, "i"); +- +-static int __init init(void) +-{ +- ip_pool_t i; +- int res; +- +- if (nr_pool < 1) { +- printk("ip_pool module init: bad nr_pool %d\n", nr_pool); +- return -EINVAL; +- } +- POOL = kmalloc(nr_pool * sizeof(*POOL), GFP_KERNEL); +- if (!POOL) { +- printk("ip_pool module init: out of memory for nr_pool %d\n", +- nr_pool); +- return -ENOMEM; +- } +- for (i=0; i<nr_pool; i++) { +- POOL[i].first_ip = 0; +- POOL[i].last_ip = 0; +- POOL[i].members = 0; +- POOL[i].nr_use = 0; +- POOL[i].nr_match = 0; +- POOL[i].lock = RW_LOCK_UNLOCKED; +- } +- res = nf_register_sockopt(&so_pool); +- DP("ip_pool:init %d pools, result %d\n", nr_pool, res); +- if (res != 0) { +- kfree(POOL); +- POOL = 0; +- } +- return res; +-} +- +-static void __exit fini(void) +-{ +- ip_pool_t i; +- +- DP("ip_pool:fini BYEBYE\n"); +- nf_unregister_sockopt(&so_pool); +- for (i=0; i<nr_pool; i++) { +- if (POOL[i].members) { +- kfree(POOL[i].members); +- POOL[i].members = 0; +- } +- } +- kfree(POOL); +- POOL = 0; +- DP("ip_pool:fini these are the famous last words\n"); +- return; +-} +- +-module_init(init); +-module_exit(fini); +diff -Nurb src/linux/linux/net/ipv4/netfilter/ip_tables.c src/linux/linux.stock/net/ipv4/netfilter/ip_tables.c +--- src/linux/linux/net/ipv4/netfilter/ip_tables.c 2003-07-04 04:12:31.000000000 -0400 ++++ src/linux/linux.stock/net/ipv4/netfilter/ip_tables.c 2004-05-09 04:13:03.000000000 -0400 +@@ -62,6 +62,11 @@ + #include <linux/netfilter_ipv4/lockhelp.h> + #include <linux/netfilter_ipv4/listhelp.h> + ++#if 0 ++/* All the better to debug you with... */ ++#define static ++#define inline ++#endif + + /* Locking is simple: we assume at worst case there will be one packet + in user context and one from bottom halves (or soft irq if Alexey's +@@ -83,6 +88,7 @@ + { + /* Size per table */ + unsigned int size; ++ /* Number of entries: FIXME. --RR */ + unsigned int number; + /* Initial number of entries. Needed for module usage count */ + unsigned int initial_entries; +@@ -106,6 +112,11 @@ + #define TABLE_OFFSET(t,p) 0 + #endif + ++#if 0 ++#define down(x) do { printk("DOWN:%u:" #x "\n", __LINE__); down(x); } while(0) ++#define down_interruptible(x) ({ int __r; printk("DOWNi:%u:" #x "\n", __LINE__); __r = down_interruptible(x); if (__r != 0) printk("ABORT-DOWNi:%u\n", __LINE__); __r; }) ++#define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0) ++#endif + + /* Returns whether matches rule or not. */ + static inline int +@@ -408,6 +419,12 @@ + { + void *ret; + ++#if 0 ++ duprintf("find_inlist: searching for `%s' in %s.\n", ++ name, head == &ipt_target ? "ipt_target" ++ : head == &ipt_match ? "ipt_match" ++ : head == &ipt_tables ? "ipt_tables" : "UNKNOWN"); ++#endif + + *error = down_interruptible(mutex); + if (*error != 0) +@@ -745,6 +762,8 @@ + newinfo->underflow[h] = underflows[h]; + } + ++ /* FIXME: underflows must be unconditional, standard verdicts ++ < 0 (not IPT_RETURN). --RR */ + + /* Clear counters and comefrom */ + e->counters = ((struct ipt_counters) { 0, 0 }); +@@ -957,6 +976,7 @@ + goto free_counters; + } + ++ /* FIXME: use iterator macros --RR */ + /* ... then go back and fix counters and names */ + for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){ + unsigned int i; +@@ -1134,6 +1154,14 @@ + const struct ipt_counters addme[], + unsigned int *i) + { ++#if 0 ++ duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n", ++ *i, ++ (long unsigned int)e->counters.pcnt, ++ (long unsigned int)e->counters.bcnt, ++ (long unsigned int)addme[*i].pcnt, ++ (long unsigned int)addme[*i].bcnt); ++#endif + + ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt); + +@@ -1495,6 +1523,7 @@ + return 0; + } + ++ /* FIXME: Try tcp doff >> packet len against various stacks --RR */ + + #define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg)) + +@@ -1670,15 +1699,14 @@ + = { { NULL, NULL }, "icmp", &icmp_match, &icmp_checkentry, NULL }; + + #ifdef CONFIG_PROC_FS +-static inline int print_name(const char *i, ++static inline int print_name(const struct ipt_table *t, + off_t start_offset, char *buffer, int length, + off_t *pos, unsigned int *count) + { + if ((*count)++ >= start_offset) { + unsigned int namelen; + +- namelen = sprintf(buffer + *pos, "%s\n", +- i + sizeof(struct list_head)); ++ namelen = sprintf(buffer + *pos, "%s\n", t->name); + if (*pos + namelen > length) { + /* Stop iterating */ + return 1; +@@ -1696,7 +1724,7 @@ + if (down_interruptible(&ipt_mutex) != 0) + return 0; + +- LIST_FIND(&ipt_tables, print_name, void *, ++ LIST_FIND(&ipt_tables, print_name, struct ipt_table *, + offset, buffer, length, &pos, &count); + + up(&ipt_mutex); +@@ -1705,46 +1733,6 @@ + *start=(char *)((unsigned long)count-offset); + return pos; + } +- +-static int ipt_get_targets(char *buffer, char **start, off_t offset, int length) +-{ +- off_t pos = 0; +- unsigned int count = 0; +- +- if (down_interruptible(&ipt_mutex) != 0) +- return 0; +- +- LIST_FIND(&ipt_target, print_name, void *, +- offset, buffer, length, &pos, &count); +- +- up(&ipt_mutex); +- +- *start = (char *)((unsigned long)count - offset); +- return pos; +-} +- +-static int ipt_get_matches(char *buffer, char **start, off_t offset, int length) +-{ +- off_t pos = 0; +- unsigned int count = 0; +- +- if (down_interruptible(&ipt_mutex) != 0) +- return 0; +- +- LIST_FIND(&ipt_match, print_name, void *, +- offset, buffer, length, &pos, &count); +- +- up(&ipt_mutex); +- +- *start = (char *)((unsigned long)count - offset); +- return pos; +-} +- +-static struct { char *name; get_info_t *get_info; } ipt_proc_entry[] = +-{ { "ip_tables_names", ipt_get_tables }, +- { "ip_tables_targets", ipt_get_targets }, +- { "ip_tables_matches", ipt_get_matches }, +- { NULL, NULL} }; + #endif /*CONFIG_PROC_FS*/ + + static int __init init(void) +@@ -1770,20 +1758,14 @@ + #ifdef CONFIG_PROC_FS + { + struct proc_dir_entry *proc; +- int i; + +- for (i = 0; ipt_proc_entry[i].name; i++) { +- proc = proc_net_create(ipt_proc_entry[i].name, 0, +- ipt_proc_entry[i].get_info); ++ proc = proc_net_create("ip_tables_names", 0, ipt_get_tables); + if (!proc) { +- while (--i >= 0) +- proc_net_remove(ipt_proc_entry[i].name); + nf_unregister_sockopt(&ipt_sockopts); + return -ENOMEM; + } + proc->owner = THIS_MODULE; + } +- } + #endif + + printk("ip_tables: (C) 2000-2002 Netfilter core team\n"); +@@ -1794,11 +1776,7 @@ + { + nf_unregister_sockopt(&ipt_sockopts); + #ifdef CONFIG_PROC_FS +- { +- int i; +- for (i = 0; ipt_proc_entry[i].name; i++) +- proc_net_remove(ipt_proc_entry[i].name); +- } ++ proc_net_remove("ip_tables_names"); + #endif + } + +diff -Nurb src/linux/linux/net/ipv4/netfilter/ipchains_core.c src/linux/linux.stock/net/ipv4/netfilter/ipchains_core.c +--- src/linux/linux/net/ipv4/netfilter/ipchains_core.c 2003-07-04 04:12:31.000000000 -0400 ++++ src/linux/linux.stock/net/ipv4/netfilter/ipchains_core.c 2004-05-09 04:13:03.000000000 -0400 +@@ -977,10 +977,17 @@ + || ftmp->ipfw.fw_dst.s_addr!=frwl->ipfw.fw_dst.s_addr + || ftmp->ipfw.fw_smsk.s_addr!=frwl->ipfw.fw_smsk.s_addr + || ftmp->ipfw.fw_dmsk.s_addr!=frwl->ipfw.fw_dmsk.s_addr ++#if 0 ++ || ftmp->ipfw.fw_flg!=frwl->ipfw.fw_flg ++#else + || ((ftmp->ipfw.fw_flg & ~IP_FW_F_MARKABS) + != (frwl->ipfw.fw_flg & ~IP_FW_F_MARKABS)) ++#endif + || ftmp->ipfw.fw_invflg!=frwl->ipfw.fw_invflg + || ftmp->ipfw.fw_proto!=frwl->ipfw.fw_proto ++#if 0 ++ || ftmp->ipfw.fw_mark!=frwl->ipfw.fw_mark ++#endif + || ftmp->ipfw.fw_redirpt!=frwl->ipfw.fw_redirpt + || ftmp->ipfw.fw_spts[0]!=frwl->ipfw.fw_spts[0] + || ftmp->ipfw.fw_spts[1]!=frwl->ipfw.fw_spts[1] +@@ -1566,6 +1573,7 @@ + ) + { + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,29) ++ /* FIXME: No more `atomic' read and reset. Wonderful 8-( --RR */ + int reset = 0; + #endif + struct ip_chain *i; +diff -Nurb src/linux/linux/net/ipv4/netfilter/ipfwadm_core.c src/linux/linux.stock/net/ipv4/netfilter/ipfwadm_core.c +--- src/linux/linux/net/ipv4/netfilter/ipfwadm_core.c 2003-10-14 04:09:33.000000000 -0400 ++++ src/linux/linux.stock/net/ipv4/netfilter/ipfwadm_core.c 2004-05-09 04:13:03.000000000 -0400 +@@ -20,7 +20,7 @@ + * license in recognition of the original copyright. + * -- Alan Cox. + * +- * $Id: ipfwadm_core.c,v 1.1.1.4 2003/10/14 08:09:33 sparq Exp $ ++ * $Id: ipfwadm_core.c,v 1.9.2.2 2002/01/24 15:50:42 davem Exp $ + * + * Ported from BSD to Linux, + * Alan Cox 22/Nov/1994. +@@ -1205,6 +1205,7 @@ + ) + { + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,29) ++ /* FIXME: No more `atomic' read and reset. Wonderful 8-( --RR */ + int reset = 0; + #endif + return ip_chain_procinfo(IP_FW_ACCT, buffer,start, offset,length, +@@ -1223,6 +1224,7 @@ + ) + { + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,29) ++ /* FIXME: No more `atomic' read and reset. Wonderful 8-( --RR */ + int reset = 0; + #endif + return ip_chain_procinfo(IP_FW_IN, buffer,start,offset,length, +@@ -1237,6 +1239,7 @@ + ) + { + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,29) ++ /* FIXME: No more `atomic' read and reset. Wonderful 8-( --RR */ + int reset = 0; + #endif + return ip_chain_procinfo(IP_FW_OUT, buffer,start,offset,length, +@@ -1251,6 +1254,7 @@ + ) + { + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,29) ++ /* FIXME: No more `atomic' read and reset. Wonderful 8-( --RR */ + int reset = 0; + #endif + return ip_chain_procinfo(IP_FW_FWD, buffer,start,offset,length, +diff -Nurb src/linux/linux/net/ipv4/netfilter/ipt_ECN.c src/linux/linux.stock/net/ipv4/netfilter/ipt_ECN.c +--- src/linux/linux/net/ipv4/netfilter/ipt_ECN.c 2003-10-14 04:02:57.000000000 -0400 ++++ src/linux/linux.stock/net/ipv4/netfilter/ipt_ECN.c 2004-05-09 04:13:03.000000000 -0400 +@@ -87,8 +87,8 @@ + } + + if (diffs[0] != *tcpflags) { +- diffs[0] = diffs[0] ^ 0xFFFF; +- diffs[1] = *tcpflags; ++ diffs[0] = htons(diffs[0]) ^ 0xFFFF; ++ diffs[1] = htons(*tcpflags); + tcph->check = csum_fold(csum_partial((char *)diffs, + sizeof(diffs), + tcph->check^0xFFFF)); +diff -Nurb src/linux/linux/net/ipv4/netfilter/ipt_LOG.c src/linux/linux.stock/net/ipv4/netfilter/ipt_LOG.c +--- src/linux/linux/net/ipv4/netfilter/ipt_LOG.c 2003-07-04 04:12:31.000000000 -0400 ++++ src/linux/linux.stock/net/ipv4/netfilter/ipt_LOG.c 2004-05-09 04:13:03.000000000 -0400 +@@ -14,11 +14,15 @@ + #include <net/route.h> + #include <linux/netfilter_ipv4/ipt_LOG.h> + ++#if 0 ++#define DEBUGP printk ++#else + #define DEBUGP(format, args...) ++#endif + + struct esphdr { + __u32 spi; +-}; ++}; /* FIXME evil kludge */ + + /* Use lock to serialize, so printks don't overlap */ + static spinlock_t log_lock = SPIN_LOCK_UNLOCKED; +diff -Nurb src/linux/linux/net/ipv4/netfilter/ipt_REJECT.c src/linux/linux.stock/net/ipv4/netfilter/ipt_REJECT.c +--- src/linux/linux/net/ipv4/netfilter/ipt_REJECT.c 2003-07-04 04:12:31.000000000 -0400 ++++ src/linux/linux.stock/net/ipv4/netfilter/ipt_REJECT.c 2004-05-09 04:13:03.000000000 -0400 +@@ -6,8 +6,6 @@ + #include <linux/module.h> + #include <linux/skbuff.h> + #include <linux/ip.h> +-#include <linux/udp.h> +-#include <linux/icmp.h> + #include <net/icmp.h> + #include <net/ip.h> + #include <net/tcp.h> +@@ -16,7 +14,11 @@ + #include <linux/netfilter_ipv4/ip_tables.h> + #include <linux/netfilter_ipv4/ipt_REJECT.h> + ++#if 0 ++#define DEBUGP printk ++#else + #define DEBUGP(format, args...) ++#endif + + /* If the original packet is part of a connection, but the connection + is not confirmed, our manufactured reply will not be associated +@@ -155,7 +157,6 @@ + static void send_unreach(struct sk_buff *skb_in, int code) + { + struct iphdr *iph; +- struct udphdr *udph; + struct icmphdr *icmph; + struct sk_buff *nskb; + u32 saddr; +@@ -167,6 +168,7 @@ + if (!rt) + return; + ++ /* FIXME: Use sysctl number. --RR */ + if (!xrlim_allow(&rt->u.dst, 1*HZ)) + return; + +@@ -184,19 +186,6 @@ + if (iph->frag_off&htons(IP_OFFSET)) + return; + +- /* if UDP checksum is set, verify it's correct */ +- if (iph->protocol == IPPROTO_UDP +- && skb_in->tail-(u8*)iph >= sizeof(struct udphdr)) { +- int datalen = skb_in->len - (iph->ihl<<2); +- udph = (struct udphdr *)((char *)iph + (iph->ihl<<2)); +- if (udph->check +- && csum_tcpudp_magic(iph->saddr, iph->daddr, +- datalen, IPPROTO_UDP, +- csum_partial((char *)udph, datalen, +- 0)) != 0) +- return; +- } +- + /* If we send an ICMP error to an ICMP error a mess would result.. */ + if (iph->protocol == IPPROTO_ICMP + && skb_in->tail-(u8*)iph >= sizeof(struct icmphdr)) { +@@ -271,6 +260,7 @@ + /* Copy as much of original packet as will fit */ + data = skb_put(nskb, + length - sizeof(struct iphdr) - sizeof(struct icmphdr)); ++ /* FIXME: won't work with nonlinear skbs --RR */ + memcpy(data, skb_in->nh.iph, + length - sizeof(struct iphdr) - sizeof(struct icmphdr)); + icmph->checksum = ip_compute_csum((unsigned char *)icmph, +diff -Nurb src/linux/linux/net/ipv4/netfilter/ipt_ULOG.c src/linux/linux.stock/net/ipv4/netfilter/ipt_ULOG.c +--- src/linux/linux/net/ipv4/netfilter/ipt_ULOG.c 2003-07-04 04:12:32.000000000 -0400 ++++ src/linux/linux.stock/net/ipv4/netfilter/ipt_ULOG.c 2004-05-09 04:13:03.000000000 -0400 +@@ -12,7 +12,6 @@ + * 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> + * + * Released under the terms of the GPL + * +@@ -32,7 +31,7 @@ + * Specify, after how many clock ticks (intel: 100 per second) the queue + * should be flushed even if it is not full yet. + * +- * ipt_ULOG.c,v 1.22 2002/10/30 09:07:31 laforge Exp ++ * ipt_ULOG.c,v 1.21 2002/08/29 10:54:34 laforge Exp + */ + + #include <linux/module.h> +@@ -60,7 +59,12 @@ + #define ULOG_NL_EVENT 111 /* Harald's favorite number */ + #define ULOG_MAXNLGROUPS 32 /* numer of nlgroups */ + ++#if 0 ++#define DEBUGP(format, args...) printk(__FILE__ ":" __FUNCTION__ ":" \ ++ format, ## args) ++#else + #define DEBUGP(format, args...) ++#endif + + #define PRINTR(format, args...) do { if (net_ratelimit()) printk(format, ## args); } while (0) + +@@ -220,8 +224,7 @@ + && in->hard_header_len <= ULOG_MAC_LEN) { + memcpy(pm->mac, (*pskb)->mac.raw, in->hard_header_len); + pm->mac_len = in->hard_header_len; +- } else +- pm->mac_len = 0; ++ } + + if (in) + strncpy(pm->indev_name, in->name, sizeof(pm->indev_name)); +diff -Nurb src/linux/linux/net/ipv4/netfilter/ipt_multiport.c src/linux/linux.stock/net/ipv4/netfilter/ipt_multiport.c +--- src/linux/linux/net/ipv4/netfilter/ipt_multiport.c 2003-07-04 04:12:32.000000000 -0400 ++++ src/linux/linux.stock/net/ipv4/netfilter/ipt_multiport.c 2004-05-09 04:13:03.000000000 -0400 +@@ -8,7 +8,11 @@ + #include <linux/netfilter_ipv4/ipt_multiport.h> + #include <linux/netfilter_ipv4/ip_tables.h> + ++#if 0 ++#define duprintf(format, args...) printk(format , ## args) ++#else + #define duprintf(format, args...) ++#endif + + /* Returns 1 if the port is matched by the test, 0 otherwise. */ + static inline int +@@ -74,7 +78,7 @@ + + /* Must specify proto == TCP/UDP, no unknown flags or bad count */ + return (ip->proto == IPPROTO_TCP || ip->proto == IPPROTO_UDP) +- && !(ip->invflags & IPT_INV_PROTO) ++ && !(ip->flags & IPT_INV_PROTO) + && matchsize == IPT_ALIGN(sizeof(struct ipt_multiport)) + && (multiinfo->flags == IPT_MULTIPORT_SOURCE + || multiinfo->flags == IPT_MULTIPORT_DESTINATION +diff -Nurb src/linux/linux/net/ipv4/netfilter/ipt_pool.c src/linux/linux.stock/net/ipv4/netfilter/ipt_pool.c +--- src/linux/linux/net/ipv4/netfilter/ipt_pool.c 2003-07-04 04:12:32.000000000 -0400 ++++ src/linux/linux.stock/net/ipv4/netfilter/ipt_pool.c 1969-12-31 19:00:00.000000000 -0500 +@@ -1,71 +0,0 @@ +-/* Kernel module to match an IP address pool. */ +- +-#include <linux/module.h> +-#include <linux/ip.h> +-#include <linux/skbuff.h> +- +-#include <linux/netfilter_ipv4/ip_tables.h> +-#include <linux/netfilter_ipv4/ip_pool.h> +-#include <linux/netfilter_ipv4/ipt_pool.h> +- +-static inline int match_pool( +- ip_pool_t index, +- __u32 addr, +- int inv +-) { +- if (ip_pool_match(index, ntohl(addr))) +- 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, +- const void *hdr, +- u_int16_t datalen, +- int *hotdrop +-) { +- const struct ipt_pool_info *info = matchinfo; +- const struct iphdr *iph = skb->nh.iph; +- +- if (info->src != IP_POOL_NONE && !match_pool(info->src, iph->saddr, +- info->flags&IPT_POOL_INV_SRC)) +- return 0; +- +- if (info->dst != IP_POOL_NONE && !match_pool(info->dst, iph->daddr, +- info->flags&IPT_POOL_INV_DST)) +- return 0; +- +- return 1; +-} +- +-static int checkentry( +- const char *tablename, +- const struct ipt_ip *ip, +- void *matchinfo, +- unsigned int matchsize, +- unsigned int hook_mask +-) { +- if (matchsize != IPT_ALIGN(sizeof(struct ipt_pool_info))) +- return 0; +- return 1; +-} +- +-static struct ipt_match pool_match +-= { { NULL, NULL }, "pool", &match, &checkentry, NULL, THIS_MODULE }; +- +-static int __init init(void) +-{ +- return ipt_register_match(&pool_match); +-} +- +-static void __exit fini(void) +-{ +- ipt_unregister_match(&pool_match); +-} +- +-module_init(init); +-module_exit(fini); +diff -Nurb src/linux/linux/net/ipv6/mcast.c src/linux/linux.stock/net/ipv6/mcast.c +--- src/linux/linux/net/ipv6/mcast.c 2003-10-14 04:09:34.000000000 -0400 ++++ src/linux/linux.stock/net/ipv6/mcast.c 2004-05-09 04:13:22.000000000 -0400 +@@ -5,7 +5,7 @@ + * Authors: + * Pedro Roque <roque@di.fc.ul.pt> + * +- * $Id: mcast.c,v 1.1.1.4 2003/10/14 08:09:34 sparq Exp $ ++ * $Id: mcast.c,v 1.38 2001/08/15 07:36:31 davem Exp $ + * + * Based on linux/ipv4/igmp.c and linux/ipv4/ip_sockglue.c + * diff --git a/obsolete-buildroot/sources/openwrt/kernel/patches/110-sch_htb.patch b/obsolete-buildroot/sources/openwrt/kernel/patches/110-sch_htb.patch new file mode 100644 index 0000000000..f74168aeea --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/kernel/patches/110-sch_htb.patch @@ -0,0 +1,570 @@ +--- src/linux/linux/net/sched/sch_htb.c 2003-10-14 01:09:35.000000000 -0700 ++++ src/linux/linux.2.4.26/net/sched/sch_htb.c 2004-05-10 00:05:51.000000000 -0700 +@@ -9,6 +9,8 @@ + * Authors: Martin Devera, <devik@cdi.cz> + * + * Credits (in time order) for older HTB versions: ++ * Stef Coene <stef.coene@docum.org> ++ * HTB support at LARTC mailing list + * Ondrej Kraus, <krauso@barr.cz> + * found missing INIT_QDISC(htb) + * Vladimir Smelhaus, Aamer Akhter, Bert Hubert +@@ -17,9 +19,13 @@ + * code review and helpful comments on shaping + * Tomasz Wrona, <tw@eter.tym.pl> + * created test case so that I was able to fix nasty bug ++ * Wilfried Weissmann ++ * spotted bug in dequeue code and helped with fix ++ * Jiri Fojtasek ++ * fixed requeue routine + * and many others. thanks. + * +- * $Id: sch_htb.c,v 1.1.1.4 2003/10/14 08:09:35 sparq Exp $ ++ * $Id: sch_htb.c,v 1.25 2003/12/07 11:08:25 devik Exp devik $ + */ + #include <linux/config.h> + #include <linux/module.h> +@@ -71,16 +77,12 @@ + #define HTB_HYSTERESIS 1/* whether to use mode hysteresis for speedup */ + #define HTB_QLOCK(S) spin_lock_bh(&(S)->dev->queue_lock) + #define HTB_QUNLOCK(S) spin_unlock_bh(&(S)->dev->queue_lock) +-#define HTB_VER 0x30007 /* major must be matched with number suplied by TC as version */ ++#define HTB_VER 0x30010 /* major must be matched with number suplied by TC as version */ + + #if HTB_VER >> 16 != TC_HTB_PROTOVER + #error "Mismatched sch_htb.c and pkt_sch.h" + #endif + +-/* temporary debug defines to be removed after beta stage */ +-#define DEVIK_MEND(N) +-#define DEVIK_MSTART(N) +- + /* debugging support; S is subsystem, these are defined: + 0 - netlink messages + 1 - enqueue +@@ -100,13 +102,16 @@ + from LSB + */ + #ifdef HTB_DEBUG +-#define HTB_DBG(S,L,FMT,ARG...) if (((q->debug>>(2*S))&3) >= L) \ ++#define HTB_DBG_COND(S,L) (((q->debug>>(2*S))&3) >= L) ++#define HTB_DBG(S,L,FMT,ARG...) if (HTB_DBG_COND(S,L)) \ + printk(KERN_DEBUG FMT,##ARG) + #define HTB_CHCL(cl) BUG_TRAP((cl)->magic == HTB_CMAGIC) + #define HTB_PASSQ q, + #define HTB_ARGQ struct htb_sched *q, + #define static ++#undef __inline__ + #define __inline__ ++#undef inline + #define inline + #define HTB_CMAGIC 0xFEFAFEF1 + #define htb_safe_rb_erase(N,R) do { BUG_TRAP((N)->rb_color != -1); \ +@@ -114,6 +119,7 @@ + rb_erase(N,R); \ + (N)->rb_color = -1; } while (0) + #else ++#define HTB_DBG_COND(S,L) (0) + #define HTB_DBG(S,L,FMT,ARG...) + #define HTB_PASSQ + #define HTB_ARGQ +@@ -219,6 +225,9 @@ + /* time of nearest event per level (row) */ + unsigned long near_ev_cache[TC_HTB_MAXDEPTH]; + ++ /* cached value of jiffies in dequeue */ ++ unsigned long jiffies; ++ + /* whether we hit non-work conserving class during this dequeue; we use */ + int nwc_hit; /* this to disable mindelay complaint in dequeue */ + +@@ -297,7 +306,7 @@ + rules in it */ + if (skb->priority == sch->handle) + return HTB_DIRECT; /* X:0 (direct flow) selected */ +- if ((cl = htb_find(skb->priority,sch)) != NULL) ++ if ((cl = htb_find(skb->priority,sch)) != NULL && cl->level == 0) + return cl; + + tcf = q->filter_list; +@@ -338,7 +347,7 @@ + static void htb_debug_dump (struct htb_sched *q) + { + int i,p; +- printk(KERN_DEBUG "htb*g j=%lu\n",jiffies); ++ printk(KERN_DEBUG "htb*g j=%lu lj=%lu\n",jiffies,q->jiffies); + /* rows */ + for (i=TC_HTB_MAXDEPTH-1;i>=0;i--) { + printk(KERN_DEBUG "htb*r%d m=%x",i,q->row_mask[i]); +@@ -421,26 +430,24 @@ + if ((delay <= 0 || delay > cl->mbuffer) && net_ratelimit()) + printk(KERN_ERR "HTB: suspicious delay in wait_tree d=%ld cl=%X h=%d\n",delay,cl->classid,debug_hint); + #endif +- DEVIK_MSTART(9); +- cl->pq_key = jiffies + PSCHED_US2JIFFIE(delay); +- if (cl->pq_key == jiffies) ++ cl->pq_key = q->jiffies + PSCHED_US2JIFFIE(delay); ++ if (cl->pq_key == q->jiffies) + cl->pq_key++; + + /* update the nearest event cache */ +- if (q->near_ev_cache[cl->level] - cl->pq_key < 0x80000000) ++ if (time_after(q->near_ev_cache[cl->level], cl->pq_key)) + q->near_ev_cache[cl->level] = cl->pq_key; + + while (*p) { + struct htb_class *c; parent = *p; + c = rb_entry(parent, struct htb_class, pq_node); +- if (cl->pq_key - c->pq_key < 0x80000000) ++ if (time_after_eq(cl->pq_key, c->pq_key)) + p = &parent->rb_right; + else + p = &parent->rb_left; + } + rb_link_node(&cl->pq_node, parent, p); + rb_insert_color(&cl->pq_node, &q->wait_pq[cl->level]); +- DEVIK_MEND(9); + } + + /** +@@ -453,12 +460,14 @@ + { + rb_node_t *p; + if ((*n)->rb_right) { ++ /* child at right. use it or its leftmost ancestor */ + *n = (*n)->rb_right; + while ((*n)->rb_left) + *n = (*n)->rb_left; + return; + } + while ((p = (*n)->rb_parent) != NULL) { ++ /* if we've arrived from left child then we have next node */ + if (p->rb_left == *n) break; + *n = p; + } +@@ -602,7 +611,7 @@ + long toks; + + if ((toks = (cl->ctokens + *diff)) < ( +-#ifdef HTB_HYSTERESIS ++#if HTB_HYSTERESIS + cl->cmode != HTB_CANT_SEND ? -cl->cbuffer : + #endif + 0)) { +@@ -610,7 +619,7 @@ + return HTB_CANT_SEND; + } + if ((toks = (cl->tokens + *diff)) >= ( +-#ifdef HTB_HYSTERESIS ++#if HTB_HYSTERESIS + cl->cmode == HTB_CAN_SEND ? -cl->buffer : + #endif + 0)) +@@ -689,7 +698,6 @@ + struct htb_sched *q = (struct htb_sched *)sch->data; + struct htb_class *cl = htb_classify(skb,sch); + +- DEVIK_MSTART(0); + if (cl == HTB_DIRECT || !cl) { + /* enqueue to helper queue */ + if (q->direct_queue.qlen < q->direct_qlen && cl) { +@@ -698,25 +706,20 @@ + } else { + kfree_skb (skb); + sch->stats.drops++; +- DEVIK_MEND(0); + return NET_XMIT_DROP; + } + } else if (cl->un.leaf.q->enqueue(skb, cl->un.leaf.q) != NET_XMIT_SUCCESS) { + sch->stats.drops++; + cl->stats.drops++; +- DEVIK_MEND(0); + return NET_XMIT_DROP; + } else { + cl->stats.packets++; cl->stats.bytes += skb->len; +- DEVIK_MSTART(1); + htb_activate (q,cl); +- DEVIK_MEND(1); + } + + sch->q.qlen++; + sch->stats.packets++; sch->stats.bytes += skb->len; +- HTB_DBG(1,1,"htb_enq_ok cl=%X skb=%p\n",cl?cl->classid:0,skb); +- DEVIK_MEND(0); ++ HTB_DBG(1,1,"htb_enq_ok cl=%X skb=%p\n",(cl && cl != HTB_DIRECT)?cl->classid:0,skb); + return NET_XMIT_SUCCESS; + } + +@@ -725,16 +728,18 @@ + { + struct htb_sched *q = (struct htb_sched *)sch->data; + struct htb_class *cl = htb_classify(skb,sch); ++ struct sk_buff *tskb; + + if (cl == HTB_DIRECT || !cl) { + /* enqueue to helper queue */ + if (q->direct_queue.qlen < q->direct_qlen && cl) { +- __skb_queue_tail(&q->direct_queue, skb); +- q->direct_pkts++; ++ __skb_queue_head(&q->direct_queue, skb); + } else { +- kfree_skb (skb); +- sch->stats.drops++; +- return NET_XMIT_DROP; ++ __skb_queue_head(&q->direct_queue, skb); ++ tskb = __skb_dequeue_tail(&q->direct_queue); ++ kfree_skb (tskb); ++ sch->stats.drops++; ++ return NET_XMIT_CN; + } + } else if (cl->un.leaf.q->ops->requeue(skb, cl->un.leaf.q) != NET_XMIT_SUCCESS) { + sch->stats.drops++; +@@ -744,7 +749,7 @@ + htb_activate (q,cl); + + sch->q.qlen++; +- HTB_DBG(1,1,"htb_req_ok cl=%X skb=%p\n",cl?cl->classid:0,skb); ++ HTB_DBG(1,1,"htb_req_ok cl=%X skb=%p\n",(cl && cl != HTB_DIRECT)?cl->classid:0,skb); + return NET_XMIT_SUCCESS; + } + +@@ -819,7 +824,7 @@ + cl->classid, diff, + (unsigned long long) q->now, + (unsigned long long) cl->t_c, +- jiffies); ++ q->jiffies); + diff = 1000; + } + #endif +@@ -862,6 +867,7 @@ + * + * Scans event queue for pending events and applies them. Returns jiffies to + * next pending event (0 for no event in pq). ++ * Note: Aplied are events whose have cl->pq_key <= jiffies. + */ + static long htb_do_events(struct htb_sched *q,int level) + { +@@ -876,9 +882,9 @@ + while (p->rb_left) p = p->rb_left; + + cl = rb_entry(p, struct htb_class, pq_node); +- if (cl->pq_key - (jiffies+1) < 0x80000000) { +- HTB_DBG(8,3,"htb_do_ev_ret delay=%ld\n",cl->pq_key - jiffies); +- return cl->pq_key - jiffies; ++ if (time_after(cl->pq_key, q->jiffies)) { ++ HTB_DBG(8,3,"htb_do_ev_ret delay=%ld\n",cl->pq_key - q->jiffies); ++ return cl->pq_key - q->jiffies; + } + htb_safe_rb_erase(p,q->wait_pq+level); + diff = PSCHED_TDIFF_SAFE(q->now, cl->t_c, (u32)cl->mbuffer, 0); +@@ -889,7 +895,7 @@ + cl->classid, diff, + (unsigned long long) q->now, + (unsigned long long) cl->t_c, +- jiffies); ++ q->jiffies); + diff = 1000; + } + #endif +@@ -916,6 +922,7 @@ + rb_node_t **pptr; + } stk[TC_HTB_MAXDEPTH],*sp = stk; + ++ BUG_TRAP(tree->rb_node); + sp->root = tree->rb_node; + sp->pptr = pptr; + +@@ -949,16 +956,36 @@ + htb_dequeue_tree(struct htb_sched *q,int prio,int level) + { + struct sk_buff *skb = NULL; +- //struct htb_sched *q = (struct htb_sched *)sch->data; + struct htb_class *cl,*start; + /* look initial class up in the row */ +- DEVIK_MSTART(6); + start = cl = htb_lookup_leaf (q->row[level]+prio,prio,q->ptr[level]+prio); + + do { +- BUG_TRAP(cl && cl->un.leaf.q->q.qlen); if (!cl) return NULL; ++next: ++ BUG_TRAP(cl); ++ if (!cl) return NULL; + HTB_DBG(4,1,"htb_deq_tr prio=%d lev=%d cl=%X defic=%d\n", + prio,level,cl->classid,cl->un.leaf.deficit[level]); ++ ++ /* class can be empty - it is unlikely but can be true if leaf ++ qdisc drops packets in enqueue routine or if someone used ++ graft operation on the leaf since last dequeue; ++ simply deactivate and skip such class */ ++ if (unlikely(cl->un.leaf.q->q.qlen == 0)) { ++ struct htb_class *next; ++ htb_deactivate(q,cl); ++ ++ /* row/level might become empty */ ++ if ((q->row_mask[level] & (1 << prio)) == 0) ++ return NULL; ++ ++ next = htb_lookup_leaf (q->row[level]+prio, ++ prio,q->ptr[level]+prio); ++ if (cl == start) /* fix start if we just deleted it */ ++ start = next; ++ cl = next; ++ goto next; ++ } + + if (likely((skb = cl->un.leaf.q->dequeue(cl->un.leaf.q)) != NULL)) + break; +@@ -971,8 +998,6 @@ + cl = htb_lookup_leaf (q->row[level]+prio,prio,q->ptr[level]+prio); + } while (cl != start); + +- DEVIK_MEND(6); +- DEVIK_MSTART(7); + if (likely(skb != NULL)) { + if ((cl->un.leaf.deficit[level] -= skb->len) < 0) { + HTB_DBG(4,2,"htb_next_cl oldptr=%p quant_add=%d\n", +@@ -984,11 +1009,8 @@ + gives us slightly better performance */ + if (!cl->un.leaf.q->q.qlen) + htb_deactivate (q,cl); +- DEVIK_MSTART(8); + htb_charge_class (q,cl,level,skb->len); +- DEVIK_MEND(8); + } +- DEVIK_MEND(7); + return skb; + } + +@@ -1002,9 +1024,8 @@ + printk(KERN_INFO "HTB delay %ld > 5sec\n", delay); + delay = 5*HZ; + } +- del_timer(&q->timer); +- q->timer.expires = jiffies + delay; +- add_timer(&q->timer); ++ /* why don't use jiffies here ? because expires can be in past */ ++ mod_timer(&q->timer, q->jiffies + delay); + sch->flags |= TCQ_F_THROTTLED; + sch->stats.overlimits++; + HTB_DBG(3,1,"htb_deq t_delay=%ld\n",delay); +@@ -1016,7 +1037,11 @@ + struct htb_sched *q = (struct htb_sched *)sch->data; + int level; + long min_delay; ++#ifdef HTB_DEBUG ++ int evs_used = 0; ++#endif + ++ q->jiffies = jiffies; + HTB_DBG(3,1,"htb_deq dircnt=%d qlen=%d\n",skb_queue_len(&q->direct_queue), + sch->q.qlen); + +@@ -1027,27 +1052,26 @@ + return skb; + } + +- DEVIK_MSTART(2); + if (!sch->q.qlen) goto fin; + PSCHED_GET_TIME(q->now); + +- min_delay = HZ*5; ++ min_delay = LONG_MAX; + q->nwc_hit = 0; + for (level = 0; level < TC_HTB_MAXDEPTH; level++) { + /* common case optimization - skip event handler quickly */ + int m; + long delay; +- DEVIK_MSTART(3); +- if (jiffies - q->near_ev_cache[level] < 0x80000000 || 0) { ++ if (time_after_eq(q->jiffies, q->near_ev_cache[level])) { + delay = htb_do_events(q,level); +- q->near_ev_cache[level] += delay ? delay : HZ; ++ q->near_ev_cache[level] = q->jiffies + (delay ? delay : HZ); ++#ifdef HTB_DEBUG ++ evs_used++; ++#endif + } else +- delay = q->near_ev_cache[level] - jiffies; ++ delay = q->near_ev_cache[level] - q->jiffies; + + if (delay && min_delay > delay) + min_delay = delay; +- DEVIK_MEND(3); +- DEVIK_MSTART(5); + m = ~q->row_mask[level]; + while (m != (int)(-1)) { + int prio = ffz (m); +@@ -1056,29 +1080,29 @@ + if (likely(skb != NULL)) { + sch->q.qlen--; + sch->flags &= ~TCQ_F_THROTTLED; +- DEVIK_MEND(5); + goto fin; + } + } +- DEVIK_MEND(5); + } +- DEVIK_MSTART(4); + #ifdef HTB_DEBUG +- if (!q->nwc_hit && min_delay >= 5*HZ && net_ratelimit()) { +- printk(KERN_ERR "HTB: mindelay=%ld, report it please !\n",min_delay); +- htb_debug_dump(q); ++ if (!q->nwc_hit && min_delay >= 10*HZ && net_ratelimit()) { ++ if (min_delay == LONG_MAX) { ++ printk(KERN_ERR "HTB: dequeue bug (%d,%lu,%lu), report it please !\n", ++ evs_used,q->jiffies,jiffies); ++ htb_debug_dump(q); ++ } else ++ printk(KERN_WARNING "HTB: mindelay=%ld, some class has " ++ "too small rate\n",min_delay); + } + #endif +- htb_delay_by (sch,min_delay); +- DEVIK_MEND(4); ++ htb_delay_by (sch,min_delay > 5*HZ ? 5*HZ : min_delay); + fin: +- HTB_DBG(3,1,"htb_deq_end %s j=%lu skb=%p\n",sch->dev->name,jiffies,skb); +- DEVIK_MEND(2); ++ HTB_DBG(3,1,"htb_deq_end %s j=%lu skb=%p\n",sch->dev->name,q->jiffies,skb); + return skb; + } + + /* try to drop from each class (by prio) until one succeed */ +-static int htb_drop(struct Qdisc* sch) ++static unsigned int htb_drop(struct Qdisc* sch) + { + struct htb_sched *q = (struct htb_sched *)sch->data; + int prio; +@@ -1086,14 +1110,15 @@ + for (prio = TC_HTB_NUMPRIO - 1; prio >= 0; prio--) { + struct list_head *p; + list_for_each (p,q->drops+prio) { +- struct htb_class *cl = list_entry(p,struct htb_class, +- un.leaf.drop_list); ++ struct htb_class *cl = list_entry(p, struct htb_class, ++ un.leaf.drop_list); ++ unsigned int len; + if (cl->un.leaf.q->ops->drop && +- cl->un.leaf.q->ops->drop(cl->un.leaf.q)) { ++ (len = cl->un.leaf.q->ops->drop(cl->un.leaf.q))) { + sch->q.qlen--; + if (!cl->un.leaf.q->q.qlen) + htb_deactivate (q,cl); +- return 1; ++ return len; + } + } + } +@@ -1208,7 +1233,8 @@ + gopt.direct_pkts = q->direct_pkts; + + #ifdef HTB_DEBUG +- htb_debug_dump(q); ++ if (HTB_DBG_COND(0,2)) ++ htb_debug_dump(q); + #endif + gopt.version = HTB_VER; + gopt.rate2quantum = q->rate2quantum; +@@ -1289,6 +1315,9 @@ + return -ENOBUFS; + sch_tree_lock(sch); + if ((*old = xchg(&cl->un.leaf.q, new)) != NULL) { ++ if (cl->prio_activity) ++ htb_deactivate ((struct htb_sched*)sch->data,cl); ++ + /* TODO: is it correct ? Why CBQ doesn't do it ? */ + sch->q.qlen -= (*old)->q.qlen; + qdisc_reset(*old); +@@ -1323,7 +1352,7 @@ + + while ((tp = *fl) != NULL) { + *fl = tp->next; +- tp->ops->destroy(tp); ++ tcf_destroy(tp); + } + } + +@@ -1371,11 +1400,16 @@ + #ifdef HTB_RATECM + del_timer_sync (&q->rttim); + #endif ++ /* This line used to be after htb_destroy_class call below ++ and surprisingly it worked in 2.4. But it must precede it ++ because filter need its target class alive to be able to call ++ unbind_filter on it (without Oops). */ ++ htb_destroy_filters(&q->filter_list); ++ + while (!list_empty(&q->root)) + htb_destroy_class (sch,list_entry(q->root.next, + struct htb_class,sibling)); + +- htb_destroy_filters(&q->filter_list); + __skb_queue_purge(&q->direct_queue); + MOD_DEC_USE_COUNT; + } +@@ -1438,12 +1472,13 @@ + parent = parentid == TC_H_ROOT ? NULL : htb_find (parentid,sch); + + hopt = RTA_DATA(tb[TCA_HTB_PARMS-1]); +- HTB_DBG(0,1,"htb_chg cl=%p, clid=%X, opt/prio=%d, rate=%u, buff=%d, quant=%d\n", cl,cl?cl->classid:0,(int)hopt->prio,hopt->rate.rate,hopt->buffer,hopt->quantum); ++ HTB_DBG(0,1,"htb_chg cl=%p(%X), clid=%X, parid=%X, opt/prio=%d, rate=%u, buff=%d, quant=%d\n", cl,cl?cl->classid:0,classid,parentid,(int)hopt->prio,hopt->rate.rate,hopt->buffer,hopt->quantum); + rtab = qdisc_get_rtab(&hopt->rate, tb[TCA_HTB_RTAB-1]); + ctab = qdisc_get_rtab(&hopt->ceil, tb[TCA_HTB_CTAB-1]); + if (!rtab || !ctab) goto failure; + + if (!cl) { /* new class */ ++ struct Qdisc *new_q; + /* check for valid classid */ + if (!classid || TC_H_MAJ(classid^sch->handle) || htb_find(classid,sch)) + goto failure; +@@ -1467,6 +1502,10 @@ + cl->magic = HTB_CMAGIC; + #endif + ++ /* create leaf qdisc early because it uses kmalloc(GFP_KERNEL) ++ so that can't be used inside of sch_tree_lock ++ -- thanks to Karlis Peisenieks */ ++ new_q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops); + sch_tree_lock(sch); + if (parent && !parent->level) { + /* turn parent into inner node */ +@@ -1485,8 +1524,7 @@ + memset (&parent->un.inner,0,sizeof(parent->un.inner)); + } + /* leaf (we) needs elementary qdisc */ +- if (!(cl->un.leaf.q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops))) +- cl->un.leaf.q = &noop_qdisc; ++ cl->un.leaf.q = new_q ? new_q : &noop_qdisc; + + cl->classid = classid; cl->parent = parent; + +@@ -1514,11 +1552,11 @@ + if (!cl->level) { + cl->un.leaf.quantum = rtab->rate.rate / q->rate2quantum; + if (!hopt->quantum && cl->un.leaf.quantum < 1000) { +- printk(KERN_WARNING "HTB: quantum of class %X is small. Consider r2q change.", cl->classid); ++ printk(KERN_WARNING "HTB: quantum of class %X is small. Consider r2q change.\n", cl->classid); + cl->un.leaf.quantum = 1000; + } + if (!hopt->quantum && cl->un.leaf.quantum > 200000) { +- printk(KERN_WARNING "HTB: quantum of class %X is big. Consider r2q change.", cl->classid); ++ printk(KERN_WARNING "HTB: quantum of class %X is big. Consider r2q change.\n", cl->classid); + cl->un.leaf.quantum = 200000; + } + if (hopt->quantum) +--- src/linux/linux/include/net/pkt_cls.h 2003-07-04 01:12:28.000000000 -0700 ++++ src/linux/linux.2.4.26/include/net/pkt_cls.h 2004-05-10 22:21:40.000000000 -0700 +@@ -77,7 +77,11 @@ + return -1; + } + +- ++static inline void tcf_destroy(struct tcf_proto *tp) ++{ ++ tp->ops->destroy(tp); ++ kfree(tp); ++} + + extern int register_tcf_proto_ops(struct tcf_proto_ops *ops); + extern int unregister_tcf_proto_ops(struct tcf_proto_ops *ops); diff --git a/obsolete-buildroot/sources/openwrt/kernel/patches/120-openwrt.patch b/obsolete-buildroot/sources/openwrt/kernel/patches/120-openwrt.patch new file mode 100644 index 0000000000..37c1dd34fd --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/kernel/patches/120-openwrt.patch @@ -0,0 +1,2521 @@ +diff -Nurb src/linux/linux.orig/Makefile src/linux/linux/Makefile +--- src/linux/linux.orig/Makefile 2003-10-14 04:00:10.000000000 -0400 ++++ src/linux/linux/Makefile 2004-05-25 21:12:24.000000000 -0400 +@@ -17,7 +17,7 @@ + FINDHPATH = $(HPATH)/asm $(HPATH)/linux $(HPATH)/scsi $(HPATH)/net $(HPATH)/math-emu + + HOSTCC = gcc +-HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer ++HOSTCFLAGS = -Wall -Wstrict-prototypes -Os -fomit-frame-pointer + + CROSS_COMPILE = + +@@ -88,7 +88,7 @@ + + CPPFLAGS := -D__KERNEL__ -I$(HPATH) + +-CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -O2 \ ++CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -Os \ + -fno-strict-aliasing -fno-common + + # Turn on -pg to instrument the kernel with calls to mcount(). +diff -Nurb src/linux/linux.orig/arch/mips/brcm-boards/bcm947xx/setup.c src/linux/linux/arch/mips/brcm-boards/bcm947xx/setup.c +--- src/linux/linux.orig/arch/mips/brcm-boards/bcm947xx/setup.c 2003-11-11 09:08:46.000000000 -0500 ++++ src/linux/linux/arch/mips/brcm-boards/bcm947xx/setup.c 2004-05-25 21:12:24.000000000 -0400 +@@ -27,6 +27,7 @@ + #include <linux/ext2_fs.h> + #include <linux/romfs_fs.h> + #include <linux/cramfs_fs.h> ++#include <linux/squashfs_fs.h> + #endif + + #include <typedefs.h> +@@ -160,37 +161,38 @@ + #ifdef CONFIG_MTD_PARTITIONS + + static struct mtd_partition bcm947xx_parts[] = { +- { name: "pmon", offset: 0, size: 0, /*mask_flags: MTD_WRITEABLE,*/ }, ++ { name: "pmon", offset: 0, size: 0, mask_flags: MTD_WRITEABLE, }, + { name: "linux", offset: 0, size: 0, }, + { name: "rootfs", offset: 0, size: 0, /*mask_flags: MTD_WRITEABLE,*/ }, + { name: "nvram", offset: 0, size: 0, }, ++ { name: "OpenWrt", offset: 0, size: 0, }, + { name: NULL, }, + }; + +-struct mtd_partition * __init +-init_mtd_partitions(struct mtd_info *mtd, size_t size) ++ ++static int __init ++find_root(struct mtd_info *mtd, size_t size, struct mtd_partition *part) + { +- struct minix_super_block *minixsb; +- struct ext2_super_block *ext2sb; +- struct romfs_super_block *romfsb; + struct cramfs_super *cramfsb; ++ struct squashfs_super_block *squashfsb; + struct trx_header *trx; ++ + unsigned char buf[512]; + int off; + size_t len; + +- minixsb = (struct minix_super_block *) buf; +- ext2sb = (struct ext2_super_block *) buf; +- romfsb = (struct romfs_super_block *) buf; + cramfsb = (struct cramfs_super *) buf; ++ squashfsb = (struct squashfs_super_block *) buf; + trx = (struct trx_header *) buf; + +- /* Look at every 64 KB boundary */ +- for (off = 0; off < size; off += (64 * 1024)) { ++ part->offset = 0; ++ part->size = 0; ++ ++ for (off = 0; off < size; off += mtd->erasesize) { + memset(buf, 0xe5, sizeof(buf)); + + /* +- * Read block 0 to test for romfs and cramfs superblock ++ * Read block 0 to test for cramfs superblock + */ + if (MTD_READ(mtd, off, sizeof(buf), &len, buf) || + len != sizeof(buf)) +@@ -198,75 +200,105 @@ + + /* Try looking at TRX header for rootfs offset */ + if (le32_to_cpu(trx->magic) == TRX_MAGIC) { +- bcm947xx_parts[1].offset = off; + if (le32_to_cpu(trx->offsets[1]) > off) + off = le32_to_cpu(trx->offsets[1]); + continue; + } + +- /* romfs is at block zero too */ +- if (romfsb->word0 == ROMSB_WORD0 && +- romfsb->word1 == ROMSB_WORD1) { +- printk(KERN_NOTICE +- "%s: romfs filesystem found at block %d\n", +- mtd->name, off / BLOCK_SIZE); +- goto done; +- } +- +- /* so is cramfs */ ++ /* need to find cramfs */ + if (cramfsb->magic == CRAMFS_MAGIC) { + printk(KERN_NOTICE + "%s: cramfs filesystem found at block %d\n", + mtd->name, off / BLOCK_SIZE); +- goto done; +- } + +- /* +- * Read block 1 to test for minix and ext2 superblock +- */ +- if (MTD_READ(mtd, off + BLOCK_SIZE, sizeof(buf), &len, buf) || +- len != sizeof(buf)) +- continue; +- +- /* Try minix */ +- if (minixsb->s_magic == MINIX_SUPER_MAGIC || +- minixsb->s_magic == MINIX_SUPER_MAGIC2) { +- printk(KERN_NOTICE +- "%s: Minix filesystem found at block %d\n", +- mtd->name, off / BLOCK_SIZE); ++ part->size = cramfsb->size; + goto done; + } + +- /* Try ext2 */ +- if (ext2sb->s_magic == cpu_to_le16(EXT2_SUPER_MAGIC)) { ++ /* or squashfs */ ++ if (squashfsb->s_magic == SQUASHFS_MAGIC) { + printk(KERN_NOTICE +- "%s: ext2 filesystem found at block %d\n", ++ "%s: squashfs filesystem found at block %d\n", + mtd->name, off / BLOCK_SIZE); ++ part->size = squashfsb->bytes_used+2048; + goto done; + } +- } + ++ } + printk(KERN_NOTICE +- "%s: Couldn't find valid ROM disk image\n", ++ "%s: Couldn't find valid cramfs image\n", + mtd->name); ++ return -1; ++ ++done: ++ part->offset = off; ++ return 0; ++} ++ ++ ++struct mtd_partition * __init ++init_mtd_partitions(struct mtd_info *mtd, size_t size) ++{ ++ ++ bcm947xx_parts[0].offset=0; ++ bcm947xx_parts[0].size=256*1024; + +- done: + /* Find and size nvram */ + bcm947xx_parts[3].offset = size - ROUNDUP(NVRAM_SPACE, mtd->erasesize); + bcm947xx_parts[3].size = size - bcm947xx_parts[3].offset; + + /* Find and size rootfs */ +- if (off < size) { +- bcm947xx_parts[2].offset = off; +- bcm947xx_parts[2].size = bcm947xx_parts[3].offset - bcm947xx_parts[2].offset; +- } ++ //if (off < size) { ++ // bcm947xx_parts[2].offset = off; ++ // bcm947xx_parts[2].size = bcm947xx_parts[3].offset - bcm947xx_parts[2].offset; ++ //} ++ ++ /* Find and size rootfs */ ++ find_root(mtd,size,&bcm947xx_parts[2]); ++ ++ + + /* Size linux (kernel and rootfs) */ ++ bcm947xx_parts[1].offset = bcm947xx_parts[0].size; + bcm947xx_parts[1].size = bcm947xx_parts[3].offset - bcm947xx_parts[1].offset; + ++ ++ ++ /* calculate leftover flash, and assign it to the jffs partition */ ++ size_t spot; ++ size_t len; ++ size_t mask; ++ // get the offset to the end of the root_fs ++ spot=bcm947xx_parts[2].offset+bcm947xx_parts[2].size; ++ // round it up to an erase size boundary ++ spot+=mtd->erasesize-1; ++ // mask the number to the boundary ++ mask=mtd->erasesize; ++ mask=mask-1; ++ mask=mask^0xffffffff; ++ spot&=mask; ++ // length = flashsize - start position - nvram size ++ len=size-spot; ++ len=len-bcm947xx_parts[3].size; ++ ++ ++ bcm947xx_parts[4].offset = spot; ++ bcm947xx_parts[4].size = len; ++ ++ ++ ++ + /* Size pmon */ + bcm947xx_parts[0].size = bcm947xx_parts[1].offset - bcm947xx_parts[0].offset; + ++ //int x; ++ //for(x=0; x<5; x++) { ++ // printk(KERN_NOTICE ++ // "Partition %d mask_flags %08x\n", ++ // x,bcm947xx_parts[x].mask_flags); ++ //} ++ ++ + return bcm947xx_parts; + } + +diff -Nurb src/linux/linux.orig/drivers/mtd/maps/bcm947xx-flash.c src/linux/linux/drivers/mtd/maps/bcm947xx-flash.c +--- src/linux/linux.orig/drivers/mtd/maps/bcm947xx-flash.c 2003-11-08 04:35:52.000000000 -0500 ++++ src/linux/linux/drivers/mtd/maps/bcm947xx-flash.c 2004-05-25 21:12:24.000000000 -0400 +@@ -82,7 +82,21 @@ + + void bcm947xx_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) + { ++ //memcpy_fromio(to, map->map_priv_1 + from, len); ++ if (len==1) { + memcpy_fromio(to, map->map_priv_1 + from, len); ++ } else { ++ int i; ++ u16 *dest = (u16 *) to; ++ u16 *src = (u16 *) (map->map_priv_1 + from); ++ ++ for (i = 0; i < (len / 2); i++) { ++ dest[i] = src[i]; ++ } ++ ++ if (len & 1) ++ *((u8 *)dest+len-1) = src[i] & 0xff; ++ } + } + + void bcm947xx_map_write8(struct map_info *map, __u8 d, unsigned long adr) +diff -Nurb src/linux/linux.orig/drivers/net/Makefile src/linux/linux/drivers/net/Makefile +--- src/linux/linux.orig/drivers/net/Makefile 2004-02-12 21:35:15.000000000 -0500 ++++ src/linux/linux/drivers/net/Makefile 2004-05-25 21:12:24.000000000 -0400 +@@ -25,7 +25,7 @@ + list-multi := rcpci.o + rcpci-objs := rcpci45.o rclanmtl.o + +-subdir-m += mac ++# subdir-m += mac + subdir-m += diag + + ifeq ($(CONFIG_HW_QOS),y) +diff -Nurb src/linux/linux.orig/fs/Config.in src/linux/linux/fs/Config.in +--- src/linux/linux.orig/fs/Config.in 2003-07-04 04:12:05.000000000 -0400 ++++ src/linux/linux/fs/Config.in 2004-05-25 21:13:03.000000000 -0400 +@@ -47,6 +47,7 @@ + int 'JFFS2 debugging verbosity (0 = quiet, 2 = noisy)' CONFIG_JFFS2_FS_DEBUG 0 + fi + tristate 'Compressed ROM file system support' CONFIG_CRAMFS ++tristate 'Squashed file system support' CONFIG_SQUASHFS + bool 'Virtual memory file system support (former shm fs)' CONFIG_TMPFS + define_bool CONFIG_RAMFS y + +diff -Nurb src/linux/linux.orig/fs/Makefile src/linux/linux/fs/Makefile +--- src/linux/linux.orig/fs/Makefile 2003-07-04 04:12:05.000000000 -0400 ++++ src/linux/linux/fs/Makefile 2004-05-25 21:13:03.000000000 -0400 +@@ -68,6 +68,7 @@ + subdir-$(CONFIG_SUN_OPENPROMFS) += openpromfs + subdir-$(CONFIG_BEFS_FS) += befs + subdir-$(CONFIG_JFS_FS) += jfs ++subdir-$(CONFIG_SQUASHFS) += squashfs + + + obj-$(CONFIG_BINFMT_AOUT) += binfmt_aout.o +diff -Nurb src/linux/linux.orig/fs/squashfs/Makefile src/linux/linux/fs/squashfs/Makefile +--- src/linux/linux.orig/fs/squashfs/Makefile 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/fs/squashfs/Makefile 2004-05-25 21:13:03.000000000 -0400 +@@ -0,0 +1,11 @@ ++# ++# Makefile for the linux squashfs routines. ++# ++ ++O_TARGET := squashfs.o ++ ++obj-y := inode.o ++ ++obj-m := $(O_TARGET) ++ ++include $(TOPDIR)/Rules.make +diff -Nurb src/linux/linux.orig/fs/squashfs/inode.c src/linux/linux/fs/squashfs/inode.c +--- src/linux/linux.orig/fs/squashfs/inode.c 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/fs/squashfs/inode.c 2004-05-25 21:13:03.000000000 -0400 +@@ -0,0 +1,1515 @@ ++/* ++ * Squashfs - a compressed read only filesystem for Linux ++ * ++ * Copyright (c) 2002, 2003, 2004 Phillip Lougher <plougher@users.sourceforge.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, ++ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * Squashfs - a compressed read only filesystem for Linux ++ * ++ * inode.c ++ */ ++ ++#define SQUASHFS_1_0_COMPATIBILITY ++ ++#include <linux/types.h> ++#include <linux/squashfs_fs.h> ++#include <linux/module.h> ++#include <linux/errno.h> ++#include <linux/slab.h> ++#include <linux/fs.h> ++#include <linux/locks.h> ++#include <linux/init.h> ++#include <linux/dcache.h> ++#include <asm/uaccess.h> ++#include <linux/wait.h> ++#include <asm/semaphore.h> ++#include <linux/zlib.h> ++#include <linux/blkdev.h> ++#include <linux/vmalloc.h> ++ ++#ifdef SQUASHFS_TRACE ++#define TRACE(s, args...) printk(KERN_NOTICE "SQUASHFS: "s, ## args) ++#else ++#define TRACE(s, args...) {} ++#endif ++ ++#define ERROR(s, args...) printk(KERN_ERR "SQUASHFS error: "s, ## args) ++ ++#define SERROR(s, args...) if(!silent) printk(KERN_ERR "SQUASHFS error: "s, ## args) ++#define WARNING(s, args...) printk(KERN_WARNING "SQUASHFS: "s, ## args) ++ ++static struct super_block *squashfs_read_super(struct super_block *, void *, int); ++static void squashfs_put_super(struct super_block *); ++static int squashfs_statfs(struct super_block *, struct statfs *); ++static int squashfs_symlink_readpage(struct file *file, struct page *page); ++static int squashfs_readpage(struct file *file, struct page *page); ++static int squashfs_readpage4K(struct file *file, struct page *page); ++static int squashfs_readdir(struct file *, void *, filldir_t); ++static struct dentry *squashfs_lookup(struct inode *, struct dentry *); ++static unsigned int read_data(struct super_block *s, char *buffer, ++ unsigned int index, unsigned int length, int, unsigned int *next_index); ++static int squashfs_get_cached_block(struct super_block *s, char *buffer, ++ unsigned int block, unsigned int offset, int length, ++ unsigned int *next_block, unsigned int *next_offset); ++static struct inode *squashfs_iget(struct super_block *s, squashfs_inode inode); ++static unsigned int read_blocklist(struct inode *inode, int index, int readahead_blks, ++ char *block_list, char **block_p, unsigned int *bsize); ++static void squashfs_put_super(struct super_block *s); ++ ++#ifdef SQUASHFS_1_0_COMPATIBILITY ++static int squashfs_readpage_lessthan4K(struct file *file, struct page *page); ++static struct inode *squashfs_iget_1(struct super_block *s, squashfs_inode inode); ++static unsigned int read_blocklist_1(struct inode *inode, int index, int readahead_blks, ++ char *block_list, char **block_p, unsigned int *bsize); ++#endif ++ ++DECLARE_MUTEX(read_data_mutex); ++ ++static z_stream stream; ++ ++static DECLARE_FSTYPE_DEV(squashfs_fs_type, "squashfs", squashfs_read_super); ++ ++static unsigned char squashfs_filetype_table[] = { ++ DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK ++}; ++ ++static struct super_operations squashfs_ops = { ++ statfs: squashfs_statfs, ++ put_super: squashfs_put_super, ++}; ++ ++static struct address_space_operations squashfs_symlink_aops = { ++ readpage: squashfs_symlink_readpage ++}; ++ ++static struct address_space_operations squashfs_aops = { ++ readpage: squashfs_readpage ++}; ++ ++static struct address_space_operations squashfs_aops_4K = { ++ readpage: squashfs_readpage4K ++}; ++ ++#ifdef SQUASHFS_1_0_COMPATIBILITY ++static struct address_space_operations squashfs_aops_lessthan4K = { ++ readpage: squashfs_readpage_lessthan4K ++}; ++#endif ++ ++static struct file_operations squashfs_dir_ops = { ++ read: generic_read_dir, ++ readdir: squashfs_readdir ++}; ++ ++static struct inode_operations squashfs_dir_inode_ops = { ++ lookup: squashfs_lookup ++}; ++ ++ ++static unsigned int read_data(struct super_block *s, char *buffer, ++ unsigned int index, unsigned int length, int datablock, unsigned int *next_index) ++{ ++ squashfs_sb_info *msBlk = &s->u.squashfs_sb; ++ struct buffer_head *bh[((SQUASHFS_FILE_MAX_SIZE - 1) >> msBlk->devblksize_log2) + 2]; ++ unsigned int offset = index & ((1 << msBlk->devblksize_log2) - 1); ++ unsigned int cur_index = index >> msBlk->devblksize_log2; ++ int bytes, avail_bytes, b, k; ++ char *c_buffer; ++ unsigned int compressed; ++ unsigned int c_byte = length; ++ ++ if(c_byte) { ++ bytes = msBlk->devblksize - offset; ++ if(datablock) { ++ c_buffer = (compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte)) ? msBlk->read_data : buffer; ++ c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte); ++ } else { ++ c_buffer = (compressed = SQUASHFS_COMPRESSED(c_byte)) ? msBlk->read_data : buffer; ++ c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte); ++ } ++ ++ TRACE("Block @ 0x%x, %scompressed size %d\n", index, compressed ? "" : "un", (unsigned int) c_byte); ++ ++ if(!(bh[0] = sb_getblk(s, cur_index))) ++ goto block_release; ++ for(b = 1; bytes < c_byte; b++) { ++ if(!(bh[b] = sb_getblk(s, ++cur_index))) ++ goto block_release; ++ bytes += msBlk->devblksize; ++ } ++ ll_rw_block(READ, b, bh); ++ } else { ++ unsigned short temp; ++ if(!(bh[0] = sb_bread(s, cur_index))) ++ goto read_failure; ++ ++ if(msBlk->devblksize - offset == 1) { ++ if(msBlk->swap) ++ ((unsigned char *) &temp)[1] = *((unsigned char *) (bh[0]->b_data + offset)); ++ else ++ ((unsigned char *) &temp)[0] = *((unsigned char *) (bh[0]->b_data + offset)); ++ brelse(bh[0]); ++ if(!(bh[0] = sb_bread(s, ++cur_index))) ++ goto read_failure; ++ if(msBlk->swap) ++ ((unsigned char *) &temp)[0] = *((unsigned char *) bh[0]->b_data); ++ else ++ ((unsigned char *) &temp)[1] = *((unsigned char *) bh[0]->b_data); ++ c_byte = temp; ++ offset = 1; ++ } ++ else { ++ if(msBlk->swap) { ++ unsigned short temp; ++ ((unsigned char *) &temp)[1] = *((unsigned char *) (bh[0]->b_data + offset)); ++ ((unsigned char *) &temp)[0] = *((unsigned char *) (bh[0]->b_data + offset + 1)); ++ c_byte = temp; ++ } else ++ c_byte = *((unsigned short *) (bh[0]->b_data + offset)); ++ offset += 2; ++ } ++ if(SQUASHFS_CHECK_DATA(msBlk->sBlk.flags)) { ++ if(offset == msBlk->devblksize) { ++ brelse(bh[0]); ++ if(!(bh[0] = sb_bread(s, ++cur_index))) ++ goto read_failure; ++ offset = 0; ++ } ++ if(*((unsigned char *) (bh[0]->b_data + offset)) != SQUASHFS_MARKER_BYTE) { ++ ERROR("Metadata block marker corrupt @ %x\n", index); ++ brelse(bh[0]); ++ return 0; ++ } ++ offset ++; ++ } ++ ++ bytes = msBlk->devblksize - offset; ++ if(datablock) { ++ c_buffer = (compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte)) ? msBlk->read_data : buffer; ++ c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte); ++ } else { ++ c_buffer = (compressed = SQUASHFS_COMPRESSED(c_byte)) ? msBlk->read_data : buffer; ++ c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte); ++ } ++ ++ TRACE("Block @ 0x%x, %scompressed size %d\n", index, compressed ? "" : "un", (unsigned int) c_byte); ++ ++ for(b = 1; bytes < c_byte; b++) { ++ if(!(bh[b] = sb_getblk(s, ++cur_index))) ++ goto block_release; ++ bytes += msBlk->devblksize; ++ } ++ ll_rw_block(READ, b - 1, bh + 1); ++ } ++ ++ if(compressed) ++ down(&read_data_mutex); ++ ++ for(bytes = 0, k = 0; k < b; k++) { ++ avail_bytes = (c_byte - bytes) > (msBlk->devblksize - offset) ? msBlk->devblksize - offset : c_byte - bytes; ++ wait_on_buffer(bh[k]); ++ memcpy(c_buffer + bytes, bh[k]->b_data + offset, avail_bytes); ++ bytes += avail_bytes; ++ offset = 0; ++ brelse(bh[k]); ++ } ++ ++ /* ++ * uncompress block ++ */ ++ if(compressed) { ++ int zlib_err; ++ ++ stream.next_in = c_buffer; ++ stream.avail_in = c_byte; ++ stream.next_out = buffer; ++ stream.avail_out = msBlk->read_size; ++ if(((zlib_err = zlib_inflateInit(&stream)) != Z_OK) || ++ ((zlib_err = zlib_inflate(&stream, Z_FINISH)) != Z_STREAM_END) || ++ ((zlib_err = zlib_inflateEnd(&stream)) != Z_OK)) { ++ ERROR("zlib_fs returned unexpected result 0x%x\n", zlib_err); ++ bytes = 0; ++ } else ++ bytes = stream.total_out; ++ up(&read_data_mutex); ++ } ++ ++ if(next_index) ++ *next_index = index + c_byte + (length ? 0 : (SQUASHFS_CHECK_DATA(msBlk->sBlk.flags) ? 3 : 2)); ++ ++ return bytes; ++ ++block_release: ++ while(--b >= 0) brelse(bh[b]); ++ ++read_failure: ++ ERROR("sb_bread failed reading block 0x%x\n", cur_index); ++ return 0; ++} ++ ++ ++static int squashfs_get_cached_block(struct super_block *s, char *buffer, ++ unsigned int block, unsigned int offset, int length, ++ unsigned int *next_block, unsigned int *next_offset) ++{ ++ squashfs_sb_info *msBlk = &s->u.squashfs_sb; ++ int n, i, bytes, return_length = length; ++ unsigned int next_index; ++ ++ TRACE("Entered squashfs_get_cached_block [%x:%x]\n", block, offset); ++ ++ for(;;) { ++ for(i = 0; i < SQUASHFS_CACHED_BLKS; i++) ++ if(msBlk->block_cache[i].block == block) ++ break; ++ ++ down(&msBlk->block_cache_mutex); ++ if(i == SQUASHFS_CACHED_BLKS) { ++ /* read inode header block */ ++ for(i = msBlk->next_cache, n = SQUASHFS_CACHED_BLKS; n ; n --, i = (i + 1) % SQUASHFS_CACHED_BLKS) ++ if(msBlk->block_cache[i].block != SQUASHFS_USED_BLK) ++ break; ++ if(n == 0) { ++ up(&msBlk->block_cache_mutex); ++ sleep_on(&msBlk->waitq); ++ continue; ++ } ++ msBlk->next_cache = (i + 1) % SQUASHFS_CACHED_BLKS; ++ ++ if(msBlk->block_cache[i].block == SQUASHFS_INVALID_BLK) { ++ if(!(msBlk->block_cache[i].data = (unsigned char *) ++ kmalloc(SQUASHFS_METADATA_SIZE, GFP_KERNEL))) { ++ ERROR("Failed to allocate cache block\n"); ++ up(&msBlk->block_cache_mutex); ++ return 0; ++ } ++ } ++ ++ msBlk->block_cache[i].block = SQUASHFS_USED_BLK; ++ up(&msBlk->block_cache_mutex); ++ if(!(msBlk->block_cache[i].length = read_data(s, msBlk->block_cache[i].data, block, 0, 0, ++ &next_index))) { ++ ERROR("Unable to read cache block [%x:%x]\n", block, offset); ++ return 0; ++ } ++ down(&msBlk->block_cache_mutex); ++ wake_up(&msBlk->waitq); ++ msBlk->block_cache[i].block = block; ++ msBlk->block_cache[i].next_index = next_index; ++ TRACE("Read cache block [%x:%x]\n", block, offset); ++ } ++ ++ if(msBlk->block_cache[i].block != block) { ++ up(&msBlk->block_cache_mutex); ++ continue; ++ } ++ ++ if((bytes = msBlk->block_cache[i].length - offset) >= length) { ++ if(buffer) ++ memcpy(buffer, msBlk->block_cache[i].data + offset, length); ++ if(msBlk->block_cache[i].length - offset == length) { ++ *next_block = msBlk->block_cache[i].next_index; ++ *next_offset = 0; ++ } else { ++ *next_block = block; ++ *next_offset = offset + length; ++ } ++ ++ up(&msBlk->block_cache_mutex); ++ return return_length; ++ } else { ++ if(buffer) { ++ memcpy(buffer, msBlk->block_cache[i].data + offset, bytes); ++ buffer += bytes; ++ } ++ block = msBlk->block_cache[i].next_index; ++ up(&msBlk->block_cache_mutex); ++ length -= bytes; ++ offset = 0; ++ } ++ } ++} ++ ++ ++static int get_fragment_location(struct super_block *s, unsigned int fragment, unsigned int *fragment_start_block, unsigned int *fragment_size) ++{ ++ squashfs_sb_info *msBlk = &s->u.squashfs_sb; ++ unsigned int start_block = msBlk->fragment_index[SQUASHFS_FRAGMENT_INDEX(fragment)]; ++ int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment); ++ squashfs_fragment_entry fragment_entry; ++ ++ if(msBlk->swap) { ++ squashfs_fragment_entry sfragment_entry; ++ ++ if(!squashfs_get_cached_block(s, (char *) &sfragment_entry, start_block, offset, ++ sizeof(sfragment_entry), &start_block, &offset)) ++ return 0; ++ SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_entry, &sfragment_entry); ++ } else ++ if(!squashfs_get_cached_block(s, (char *) &fragment_entry, start_block, offset, ++ sizeof(fragment_entry), &start_block, &offset)) ++ return 0; ++ ++ *fragment_start_block = fragment_entry.start_block; ++ *fragment_size = fragment_entry.size; ++ ++ return 1; ++} ++ ++ ++void release_cached_fragment(squashfs_sb_info *msBlk, struct squashfs_fragment_cache *fragment) ++{ ++ down(&msBlk->fragment_mutex); ++ fragment->locked --; ++ wake_up(&msBlk->fragment_wait_queue); ++ up(&msBlk->fragment_mutex); ++} ++ ++ ++struct squashfs_fragment_cache *get_cached_fragment(struct super_block *s, unsigned int start_block, int length) ++{ ++ int i, n; ++ squashfs_sb_info *msBlk = &s->u.squashfs_sb; ++ ++ for(;;) { ++ down(&msBlk->fragment_mutex); ++ for(i = 0; i < SQUASHFS_CACHED_FRAGMENTS && msBlk->fragment[i].block != start_block; i++); ++ if(i == SQUASHFS_CACHED_FRAGMENTS) { ++ for(i = msBlk->next_fragment, n = SQUASHFS_CACHED_FRAGMENTS; ++ n && msBlk->fragment[i].locked; n--, i = (i + 1) % SQUASHFS_CACHED_FRAGMENTS); ++ ++ if(n == 0) { ++ up(&msBlk->fragment_mutex); ++ sleep_on(&msBlk->fragment_wait_queue); ++ continue; ++ } ++ msBlk->next_fragment = (msBlk->next_fragment + 1) % SQUASHFS_CACHED_FRAGMENTS; ++ ++ if(msBlk->fragment[i].data == NULL) ++ if(!(msBlk->fragment[i].data = (unsigned char *) ++ kmalloc(SQUASHFS_FILE_MAX_SIZE, GFP_KERNEL))) { ++ ERROR("Failed to allocate fragment cache block\n"); ++ up(&msBlk->fragment_mutex); ++ return NULL; ++ } ++ ++ msBlk->fragment[i].block = SQUASHFS_INVALID_BLK; ++ msBlk->fragment[i].locked = 1; ++ up(&msBlk->fragment_mutex); ++ if(!(msBlk->fragment[i].length = read_data(s, msBlk->fragment[i].data, start_block, length, ++ 1, NULL))) { ++ ERROR("Unable to read fragment cache block [%x]\n", start_block); ++ msBlk->fragment[i].locked = 0; ++ return NULL; ++ } ++ msBlk->fragment[i].block = start_block; ++ TRACE("New fragment %d, start block %d, locked %d\n", i, msBlk->fragment[i].block, msBlk->fragment[i].locked); ++ return &msBlk->fragment[i]; ++ } ++ ++ msBlk->fragment[i].locked ++; ++ up(&msBlk->fragment_mutex); ++ ++ TRACE("Got fragment %d, start block %d, locked %d\n", i, msBlk->fragment[i].block, msBlk->fragment[i].locked); ++ return &msBlk->fragment[i]; ++ } ++} ++ ++ ++#ifdef SQUASHFS_1_0_COMPATIBILITY ++static struct inode *squashfs_iget_1(struct super_block *s, squashfs_inode inode) ++{ ++ struct inode *i = new_inode(s); ++ squashfs_sb_info *msBlk = &s->u.squashfs_sb; ++ squashfs_super_block *sBlk = &msBlk->sBlk; ++ unsigned int block = SQUASHFS_INODE_BLK(inode) + sBlk->inode_table_start; ++ unsigned int offset = SQUASHFS_INODE_OFFSET(inode); ++ unsigned int next_block, next_offset; ++ squashfs_base_inode_header_1 inodeb; ++ ++ TRACE("Entered squashfs_iget_1\n"); ++ ++ if(msBlk->swap) { ++ squashfs_base_inode_header_1 sinodeb; ++ ++ if(!squashfs_get_cached_block(s, (char *) &sinodeb, block, offset, ++ sizeof(sinodeb), &next_block, &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_BASE_INODE_HEADER_1(&inodeb, &sinodeb, sizeof(sinodeb)); ++ } else ++ if(!squashfs_get_cached_block(s, (char *) &inodeb, block, offset, ++ sizeof(inodeb), &next_block, &next_offset)) ++ goto failed_read; ++ ++ i->i_nlink = 1; ++ ++ i->i_mtime = sBlk->mkfs_time; ++ i->i_atime = sBlk->mkfs_time; ++ i->i_ctime = sBlk->mkfs_time; ++ ++ if(inodeb.inode_type != SQUASHFS_IPC_TYPE) ++ i->i_uid = msBlk->uid[((inodeb.inode_type - 1) / SQUASHFS_TYPES) * 16 + inodeb.uid]; ++ i->i_ino = SQUASHFS_MK_VFS_INODE(block - sBlk->inode_table_start, offset); ++ ++ i->i_mode = inodeb.mode; ++ ++ switch(inodeb.inode_type == SQUASHFS_IPC_TYPE ? SQUASHFS_IPC_TYPE : (inodeb.inode_type - 1) % SQUASHFS_TYPES + 1) { ++ case SQUASHFS_FILE_TYPE: { ++ squashfs_reg_inode_header_1 inodep; ++ ++ if(msBlk->swap) { ++ squashfs_reg_inode_header_1 sinodep; ++ ++ if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), ++ &next_block, &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_REG_INODE_HEADER_1(&inodep, &sinodep); ++ } else ++ if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ i->i_size = inodep.file_size; ++ i->i_fop = &generic_ro_fops; ++ if(sBlk->block_size > 4096) ++ i->i_data.a_ops = &squashfs_aops; ++ else if(sBlk->block_size == 4096) ++ i->i_data.a_ops = &squashfs_aops_4K; ++ else ++ i->i_data.a_ops = &squashfs_aops_lessthan4K; ++ i->i_mode |= S_IFREG; ++ i->i_mtime = inodep.mtime; ++ i->i_atime = inodep.mtime; ++ i->i_ctime = inodep.mtime; ++ i->i_blocks = ((i->i_size - 1) >> 9) + 1; ++ i->i_blksize = PAGE_CACHE_SIZE; ++ i->u.squashfs_i.fragment_start_block = SQUASHFS_INVALID_BLK; ++ i->u.squashfs_i.fragment_offset = 0; ++ i->u.squashfs_i.start_block = inodep.start_block; ++ i->u.squashfs_i.block_list_start = next_block; ++ i->u.squashfs_i.offset = next_offset; ++ TRACE("File inode %x:%x, start_block %x, block_list_start %x, offset %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, inodep.start_block, next_block, next_offset); ++ break; ++ } ++ case SQUASHFS_DIR_TYPE: { ++ squashfs_dir_inode_header_1 inodep; ++ ++ if(msBlk->swap) { ++ squashfs_dir_inode_header_1 sinodep; ++ ++ if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), ++ &next_block, &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_DIR_INODE_HEADER_1(&inodep, &sinodep); ++ } else ++ if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ i->i_size = inodep.file_size; ++ i->i_op = &squashfs_dir_inode_ops; ++ i->i_fop = &squashfs_dir_ops; ++ i->i_mode |= S_IFDIR; ++ i->i_mtime = inodep.mtime; ++ i->i_atime = inodep.mtime; ++ i->i_ctime = inodep.mtime; ++ i->u.squashfs_i.start_block = inodep.start_block; ++ i->u.squashfs_i.offset = inodep.offset; ++ TRACE("Directory inode %x:%x, start_block %x, offset %x\n", SQUASHFS_INODE_BLK(inode), offset, ++ inodep.start_block, inodep.offset); ++ break; ++ } ++ case SQUASHFS_SYMLINK_TYPE: { ++ squashfs_symlink_inode_header_1 inodep; ++ ++ if(msBlk->swap) { ++ squashfs_symlink_inode_header_1 sinodep; ++ ++ if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), ++ &next_block, &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(&inodep, &sinodep); ++ } else ++ if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ i->i_size = inodep.symlink_size; ++ i->i_op = &page_symlink_inode_operations; ++ i->i_data.a_ops = &squashfs_symlink_aops; ++ i->i_mode |= S_IFLNK; ++ i->u.squashfs_i.start_block = next_block; ++ i->u.squashfs_i.offset = next_offset; ++ TRACE("Symbolic link inode %x:%x, start_block %x, offset %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, next_block, next_offset); ++ break; ++ } ++ case SQUASHFS_BLKDEV_TYPE: ++ case SQUASHFS_CHRDEV_TYPE: { ++ squashfs_dev_inode_header_1 inodep; ++ ++ if(msBlk->swap) { ++ squashfs_dev_inode_header_1 sinodep; ++ ++ if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), ++ &next_block, &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_DEV_INODE_HEADER_1(&inodep, &sinodep); ++ } else ++ if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ i->i_size = 0; ++ i->i_mode |= (inodeb.inode_type == SQUASHFS_CHRDEV_TYPE) ? S_IFCHR : S_IFBLK; ++ init_special_inode(i, i->i_mode, inodep.rdev); ++ TRACE("Device inode %x:%x, rdev %x\n", SQUASHFS_INODE_BLK(inode), offset, inodep.rdev); ++ break; ++ } ++ case SQUASHFS_IPC_TYPE: { ++ squashfs_ipc_inode_header_1 inodep; ++ ++ if(msBlk->swap) { ++ squashfs_ipc_inode_header_1 sinodep; ++ ++ if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), ++ &next_block, &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_IPC_INODE_HEADER_1(&inodep, &sinodep); ++ } else ++ if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ i->i_size = 0; ++ i->i_mode |= (inodep.type == SQUASHFS_FIFO_TYPE) ? S_IFIFO : S_IFSOCK; ++ i->i_uid = msBlk->uid[inodep.offset * 16 + inodeb.uid]; ++ init_special_inode(i, i->i_mode, 0); ++ break; ++ } ++ default: ++ ERROR("Unknown inode type %d in squashfs_iget!\n", inodeb.inode_type); ++ goto failed_read1; ++ } ++ ++ if(inodeb.guid == SQUASHFS_GUIDS) ++ i->i_gid = i->i_uid; ++ else ++ i->i_gid = msBlk->guid[inodeb.guid]; ++ ++ return i; ++ ++failed_read: ++ ERROR("Unable to read inode [%x:%x]\n", block, offset); ++ ++failed_read1: ++ return NULL; ++} ++#endif ++ ++ ++static struct inode *squashfs_iget(struct super_block *s, squashfs_inode inode) ++{ ++ struct inode *i = new_inode(s); ++ squashfs_sb_info *msBlk = &s->u.squashfs_sb; ++ squashfs_super_block *sBlk = &msBlk->sBlk; ++ unsigned int block = SQUASHFS_INODE_BLK(inode) + sBlk->inode_table_start; ++ unsigned int offset = SQUASHFS_INODE_OFFSET(inode); ++ unsigned int next_block, next_offset; ++ squashfs_base_inode_header inodeb; ++ ++ TRACE("Entered squashfs_iget\n"); ++ ++ if(msBlk->swap) { ++ squashfs_base_inode_header sinodeb; ++ ++ if(!squashfs_get_cached_block(s, (char *) &sinodeb, block, offset, ++ sizeof(sinodeb), &next_block, &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_BASE_INODE_HEADER(&inodeb, &sinodeb, sizeof(sinodeb)); ++ } else ++ if(!squashfs_get_cached_block(s, (char *) &inodeb, block, offset, ++ sizeof(inodeb), &next_block, &next_offset)) ++ goto failed_read; ++ ++ i->i_nlink = 1; ++ ++ i->i_mtime = sBlk->mkfs_time; ++ i->i_atime = sBlk->mkfs_time; ++ i->i_ctime = sBlk->mkfs_time; ++ ++ if(inodeb.inode_type != SQUASHFS_IPC_TYPE) ++ i->i_uid = msBlk->uid[((inodeb.inode_type - 1) / SQUASHFS_TYPES) * 16 + inodeb.uid]; ++ i->i_ino = SQUASHFS_MK_VFS_INODE(block - sBlk->inode_table_start, offset); ++ ++ i->i_mode = inodeb.mode; ++ ++ switch(inodeb.inode_type) { ++ case SQUASHFS_FILE_TYPE: { ++ squashfs_reg_inode_header inodep; ++ ++ if(msBlk->swap) { ++ squashfs_reg_inode_header sinodep; ++ ++ if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), ++ &next_block, &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_REG_INODE_HEADER(&inodep, &sinodep); ++ } else ++ if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ i->u.squashfs_i.fragment_start_block = SQUASHFS_INVALID_BLK; ++ if(inodep.fragment != SQUASHFS_INVALID_BLK && !get_fragment_location(s, inodep.fragment, ++ &i->u.squashfs_i.fragment_start_block, &i->u.squashfs_i.fragment_size)) ++ goto failed_read; ++ ++ i->u.squashfs_i.fragment_offset = inodep.offset; ++ i->i_size = inodep.file_size; ++ i->i_fop = &generic_ro_fops; ++ if(sBlk->block_size > 4096) ++ i->i_data.a_ops = &squashfs_aops; ++ else ++ i->i_data.a_ops = &squashfs_aops_4K; ++ i->i_mode |= S_IFREG; ++ i->i_mtime = inodep.mtime; ++ i->i_atime = inodep.mtime; ++ i->i_ctime = inodep.mtime; ++ i->i_blocks = ((i->i_size - 1) >> 9) + 1; ++ i->i_blksize = PAGE_CACHE_SIZE; ++ i->u.squashfs_i.start_block = inodep.start_block; ++ i->u.squashfs_i.block_list_start = next_block; ++ i->u.squashfs_i.offset = next_offset; ++ TRACE("File inode %x:%x, start_block %x, block_list_start %x, offset %x fragment_index %x fragment_offset %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, inodep.start_block, next_block, next_offset, inodep.fragment, inodep.offset); ++ break; ++ } ++ case SQUASHFS_DIR_TYPE: { ++ squashfs_dir_inode_header inodep; ++ ++ if(msBlk->swap) { ++ squashfs_dir_inode_header sinodep; ++ ++ if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), ++ &next_block, &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_DIR_INODE_HEADER(&inodep, &sinodep); ++ } else ++ if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ i->i_size = inodep.file_size; ++ i->i_op = &squashfs_dir_inode_ops; ++ i->i_fop = &squashfs_dir_ops; ++ i->i_mode |= S_IFDIR; ++ i->i_mtime = inodep.mtime; ++ i->i_atime = inodep.mtime; ++ i->i_ctime = inodep.mtime; ++ i->u.squashfs_i.start_block = inodep.start_block; ++ i->u.squashfs_i.offset = inodep.offset; ++ TRACE("Directory inode %x:%x, start_block %x, offset %x\n", SQUASHFS_INODE_BLK(inode), offset, ++ inodep.start_block, inodep.offset); ++ break; ++ } ++ case SQUASHFS_SYMLINK_TYPE: { ++ squashfs_symlink_inode_header inodep; ++ ++ if(msBlk->swap) { ++ squashfs_symlink_inode_header sinodep; ++ ++ if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), ++ &next_block, &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_SYMLINK_INODE_HEADER(&inodep, &sinodep); ++ } else ++ if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ i->i_size = inodep.symlink_size; ++ i->i_op = &page_symlink_inode_operations; ++ i->i_data.a_ops = &squashfs_symlink_aops; ++ i->i_mode |= S_IFLNK; ++ i->u.squashfs_i.start_block = next_block; ++ i->u.squashfs_i.offset = next_offset; ++ TRACE("Symbolic link inode %x:%x, start_block %x, offset %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, next_block, next_offset); ++ break; ++ } ++ case SQUASHFS_BLKDEV_TYPE: ++ case SQUASHFS_CHRDEV_TYPE: { ++ squashfs_dev_inode_header inodep; ++ ++ if(msBlk->swap) { ++ squashfs_dev_inode_header sinodep; ++ ++ if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), ++ &next_block, &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_DEV_INODE_HEADER(&inodep, &sinodep); ++ } else ++ if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ i->i_size = 0; ++ i->i_mode |= (inodeb.inode_type == SQUASHFS_CHRDEV_TYPE) ? S_IFCHR : S_IFBLK; ++ init_special_inode(i, i->i_mode, inodep.rdev); ++ TRACE("Device inode %x:%x, rdev %x\n", SQUASHFS_INODE_BLK(inode), offset, inodep.rdev); ++ break; ++ } ++ case SQUASHFS_FIFO_TYPE: ++ case SQUASHFS_SOCKET_TYPE: { ++ i->i_size = 0; ++ i->i_mode |= (inodeb.inode_type == SQUASHFS_FIFO_TYPE) ? S_IFIFO : S_IFSOCK; ++ init_special_inode(i, i->i_mode, 0); ++ break; ++ } ++ default: ++ ERROR("Unknown inode type %d in squashfs_iget!\n", inodeb.inode_type); ++ goto failed_read1; ++ } ++ ++ if(inodeb.guid == SQUASHFS_GUIDS) ++ i->i_gid = i->i_uid; ++ else ++ i->i_gid = msBlk->guid[inodeb.guid]; ++ ++ return i; ++ ++failed_read: ++ ERROR("Unable to read inode [%x:%x]\n", block, offset); ++ ++failed_read1: ++ return NULL; ++} ++ ++ ++static struct super_block *squashfs_read_super(struct super_block *s, ++ void *data, int silent) ++{ ++ kdev_t dev = s->s_dev; ++ squashfs_sb_info *msBlk = &s->u.squashfs_sb; ++ squashfs_super_block *sBlk = &msBlk->sBlk; ++ int i; ++ ++ TRACE("Entered squashfs_read_superblock\n"); ++ ++ msBlk->devblksize = get_hardsect_size(dev); ++ if(msBlk->devblksize < BLOCK_SIZE) ++ msBlk->devblksize = BLOCK_SIZE; ++ msBlk->devblksize_log2 = ffz(~msBlk->devblksize); ++ set_blocksize(dev, msBlk->devblksize); ++ s->s_blocksize = msBlk->devblksize; ++ s->s_blocksize_bits = msBlk->devblksize_log2; ++ ++ init_MUTEX(&msBlk->read_page_mutex); ++ init_MUTEX(&msBlk->block_cache_mutex); ++ init_MUTEX(&msBlk->fragment_mutex); ++ ++ init_waitqueue_head(&msBlk->waitq); ++ init_waitqueue_head(&msBlk->fragment_wait_queue); ++ ++ if(!read_data(s, (char *) sBlk, SQUASHFS_START, sizeof(squashfs_super_block) | SQUASHFS_COMPRESSED_BIT, 0, NULL)) { ++ SERROR("unable to read superblock\n"); ++ goto failed_mount; ++ } ++ ++ /* Check it is a SQUASHFS superblock */ ++ msBlk->swap = 0; ++ if((s->s_magic = sBlk->s_magic) != SQUASHFS_MAGIC) { ++ if(sBlk->s_magic == SQUASHFS_MAGIC_SWAP) { ++ squashfs_super_block sblk; ++ WARNING("Mounting a different endian SQUASHFS filesystem on %s\n", bdevname(dev)); ++ SQUASHFS_SWAP_SUPER_BLOCK(&sblk, sBlk); ++ memcpy(sBlk, &sblk, sizeof(squashfs_super_block)); ++ msBlk->swap = 1; ++ } else { ++ SERROR("Can't find a SQUASHFS superblock on %s\n", bdevname(dev)); ++ goto failed_mount; ++ } ++ } ++ ++ /* Check the MAJOR & MINOR versions */ ++#ifdef SQUASHFS_1_0_COMPATIBILITY ++ if((sBlk->s_major != 1) && (sBlk->s_major != 2 || sBlk->s_minor > SQUASHFS_MINOR)) { ++ SERROR("Major/Minor mismatch, filesystem is (%d:%d), I support (1 : x) or (2 : <= %d)\n", ++ sBlk->s_major, sBlk->s_minor, SQUASHFS_MINOR); ++ goto failed_mount; ++ } ++ if(sBlk->s_major == 1) ++ sBlk->block_size = sBlk->block_size_1; ++#else ++ if(sBlk->s_major != SQUASHFS_MAJOR || sBlk->s_minor > SQUASHFS_MINOR) { ++ SERROR("Major/Minor mismatch, filesystem is (%d:%d), I support (%d: <= %d)\n", ++ sBlk->s_major, sBlk->s_minor, SQUASHFS_MAJOR, SQUASHFS_MINOR); ++ goto failed_mount; ++ } ++#endif ++ ++ TRACE("Found valid superblock on %s\n", bdevname(dev)); ++ TRACE("Inodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(sBlk->flags) ? "un" : ""); ++ TRACE("Data is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(sBlk->flags) ? "un" : ""); ++ TRACE("Check data is %s present in the filesystem\n", SQUASHFS_CHECK_DATA(sBlk->flags) ? "" : "not"); ++ TRACE("Filesystem size %d bytes\n", sBlk->bytes_used); ++ TRACE("Block size %d\n", sBlk->block_size); ++ TRACE("Number of inodes %d\n", sBlk->inodes); ++ if(sBlk->s_major > 1) ++ TRACE("Number of fragments %d\n", sBlk->fragments); ++ TRACE("Number of uids %d\n", sBlk->no_uids); ++ TRACE("Number of gids %d\n", sBlk->no_guids); ++ TRACE("sBlk->inode_table_start %x\n", sBlk->inode_table_start); ++ TRACE("sBlk->directory_table_start %x\n", sBlk->directory_table_start); ++ if(sBlk->s_major > 1) ++ TRACE("sBlk->fragment_table_start %x\n", sBlk->fragment_table_start); ++ TRACE("sBlk->uid_start %x\n", sBlk->uid_start); ++ ++ s->s_flags |= MS_RDONLY; ++ s->s_op = &squashfs_ops; ++ ++ /* Init inode_table block pointer array */ ++ if(!(msBlk->block_cache = (squashfs_cache *) kmalloc(sizeof(squashfs_cache) * SQUASHFS_CACHED_BLKS, GFP_KERNEL))) { ++ ERROR("Failed to allocate block cache\n"); ++ goto failed_mount; ++ } ++ ++ for(i = 0; i < SQUASHFS_CACHED_BLKS; i++) ++ msBlk->block_cache[i].block = SQUASHFS_INVALID_BLK; ++ ++ msBlk->next_cache = 0; ++ ++ /* Allocate read_data block */ ++ msBlk->read_size = (sBlk->block_size < SQUASHFS_METADATA_SIZE) ? SQUASHFS_METADATA_SIZE : sBlk->block_size; ++ if(!(msBlk->read_data = (char *) kmalloc(msBlk->read_size, GFP_KERNEL))) { ++ ERROR("Failed to allocate read_data block\n"); ++ goto failed_mount1; ++ } ++ ++ /* Allocate read_page block */ ++ if(sBlk->block_size > PAGE_CACHE_SIZE && ++ !(msBlk->read_page = (char *) kmalloc(sBlk->block_size, GFP_KERNEL))) { ++ ERROR("Failed to allocate read_page block\n"); ++ goto failed_mount2; ++ } ++ ++ /* Allocate uid and gid tables */ ++ if(!(msBlk->uid = (squashfs_uid *) kmalloc((sBlk->no_uids + ++ sBlk->no_guids) * sizeof(squashfs_uid), GFP_KERNEL))) { ++ ERROR("Failed to allocate uid/gid table\n"); ++ goto failed_mount3; ++ } ++ msBlk->guid = msBlk->uid + sBlk->no_uids; ++ ++ if(msBlk->swap) { ++ squashfs_uid suid[sBlk->no_uids + sBlk->no_guids]; ++ ++ if(!read_data(s, (char *) &suid, sBlk->uid_start, ((sBlk->no_uids + sBlk->no_guids) * ++ sizeof(squashfs_uid)) | SQUASHFS_COMPRESSED_BIT, 0, NULL)) { ++ SERROR("unable to read uid/gid table\n"); ++ goto failed_mount4; ++ } ++ SQUASHFS_SWAP_DATA(msBlk->uid, suid, (sBlk->no_uids + sBlk->no_guids), (sizeof(squashfs_uid) * 8)); ++ } else ++ if(!read_data(s, (char *) msBlk->uid, sBlk->uid_start, ((sBlk->no_uids + sBlk->no_guids) * ++ sizeof(squashfs_uid)) | SQUASHFS_COMPRESSED_BIT, 0, NULL)) { ++ SERROR("unable to read uid/gid table\n"); ++ goto failed_mount4; ++ } ++ ++ ++#ifdef SQUASHFS_1_0_COMPATIBILITY ++ if(sBlk->s_major == 1) { ++ msBlk->iget = squashfs_iget_1; ++ msBlk->read_blocklist = read_blocklist_1; ++ msBlk->fragment = (struct squashfs_fragment_cache *) msBlk->fragment_index = NULL; ++ goto allocate_root; ++ } ++#endif ++ msBlk->iget = squashfs_iget; ++ msBlk->read_blocklist = read_blocklist; ++ ++ if(!(msBlk->fragment = (struct squashfs_fragment_cache *) kmalloc(sizeof(struct squashfs_fragment_cache) * SQUASHFS_CACHED_FRAGMENTS, GFP_KERNEL))) { ++ ERROR("Failed to allocate fragment block cache\n"); ++ goto failed_mount4; ++ } ++ ++ for(i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) { ++ msBlk->fragment[i].locked = 0; ++ msBlk->fragment[i].block = SQUASHFS_INVALID_BLK; ++ msBlk->fragment[i].data = NULL; ++ } ++ ++ msBlk->next_fragment = 0; ++ ++ /* Allocate fragment index table */ ++ if(!(msBlk->fragment_index = (squashfs_fragment_index *) kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments), GFP_KERNEL))) { ++ ERROR("Failed to allocate uid/gid table\n"); ++ goto failed_mount5; ++ } ++ ++ if(SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments) && ++ !read_data(s, (char *) msBlk->fragment_index, sBlk->fragment_table_start, ++ SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments) | SQUASHFS_COMPRESSED_BIT, 0, NULL)) { ++ SERROR("unable to read fragment index table\n"); ++ goto failed_mount6; ++ } ++ ++ if(msBlk->swap) { ++ int i; ++ squashfs_fragment_index fragment; ++ ++ for(i = 0; i < SQUASHFS_FRAGMENT_INDEXES(sBlk->fragments); i++) { ++ SQUASHFS_SWAP_FRAGMENT_INDEXES((&fragment), &msBlk->fragment_index[i], 1); ++ msBlk->fragment_index[i] = fragment; ++ } ++ } ++ ++#ifdef SQUASHFS_1_0_COMPATIBILITY ++allocate_root: ++#endif ++ if(!(s->s_root = d_alloc_root((msBlk->iget)(s, sBlk->root_inode)))) { ++ ERROR("Root inode create failed\n"); ++ goto failed_mount5; ++ } ++ ++ TRACE("Leaving squashfs_read_super\n"); ++ return s; ++ ++failed_mount6: ++ kfree(msBlk->fragment_index); ++failed_mount5: ++ kfree(msBlk->fragment); ++failed_mount4: ++ kfree(msBlk->uid); ++failed_mount3: ++ kfree(msBlk->read_page); ++failed_mount2: ++ kfree(msBlk->read_data); ++failed_mount1: ++ kfree(msBlk->block_cache); ++failed_mount: ++ return NULL; ++} ++ ++ ++static int squashfs_statfs(struct super_block *s, struct statfs *buf) ++{ ++ squashfs_super_block *sBlk = &s->u.squashfs_sb.sBlk; ++ ++ TRACE("Entered squashfs_statfs\n"); ++ buf->f_type = SQUASHFS_MAGIC; ++ buf->f_bsize = sBlk->block_size; ++ buf->f_blocks = ((sBlk->bytes_used - 1) >> sBlk->block_log) + 1; ++ buf->f_bfree = buf->f_bavail = 0; ++ buf->f_files = sBlk->inodes; ++ buf->f_ffree = 0; ++ buf->f_namelen = SQUASHFS_NAME_LEN; ++ return 0; ++} ++ ++ ++static int squashfs_symlink_readpage(struct file *file, struct page *page) ++{ ++ struct inode *inode = page->mapping->host; ++ int index = page->index << PAGE_CACHE_SHIFT, length, bytes; ++ int block = inode->u.squashfs_i.start_block; ++ int offset = inode->u.squashfs_i.offset; ++ void *pageaddr = kmap(page); ++ ++ TRACE("Entered squashfs_symlink_readpage, page index %x, start block %x, offset %x\n", ++ (unsigned int) page->index, inode->u.squashfs_i.start_block, inode->u.squashfs_i.offset); ++ ++ for(length = 0; length < index; length += bytes) { ++ if(!(bytes = squashfs_get_cached_block(inode->i_sb, NULL, block, offset, ++ PAGE_CACHE_SIZE, &block, &offset))) { ++ ERROR("Unable to read symbolic link [%x:%x]\n", block, offset); ++ goto skip_read; ++ } ++ } ++ ++ if(length != index) { ++ ERROR("(squashfs_symlink_readpage) length != index\n"); ++ bytes = 0; ++ goto skip_read; ++ } ++ ++ bytes = (inode->i_size - length) > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE : inode->i_size - length; ++ if(!(bytes = squashfs_get_cached_block(inode->i_sb, pageaddr, block, offset, bytes, &block, &offset))) ++ ERROR("Unable to read symbolic link [%x:%x]\n", block, offset); ++ ++skip_read: ++ memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes); ++ kunmap(page); ++ flush_dcache_page(page); ++ SetPageUptodate(page); ++ UnlockPage(page); ++ ++ return 0; ++} ++ ++ ++#define SIZE 256 ++ ++#ifdef SQUASHFS_1_0_COMPATIBILITY ++static unsigned int read_blocklist_1(struct inode *inode, int index, int readahead_blks, ++ char *block_list, char **block_p, unsigned int *bsize) ++{ ++ squashfs_sb_info *msBlk = &inode->i_sb->u.squashfs_sb; ++ unsigned short *block_listp; ++ int i = 0; ++ int block_ptr = inode->u.squashfs_i.block_list_start; ++ int offset = inode->u.squashfs_i.offset; ++ int block = inode->u.squashfs_i.start_block; ++ ++ for(;;) { ++ int blocks = (index + readahead_blks - i); ++ if(blocks > (SIZE >> 1)) { ++ if((index - i) <= (SIZE >> 1)) ++ blocks = index - i; ++ else ++ blocks = SIZE >> 1; ++ } ++ ++ if(msBlk->swap) { ++ unsigned char sblock_list[SIZE]; ++ if(!squashfs_get_cached_block(inode->i_sb, (char *) sblock_list, block_ptr, offset, blocks << 1, &block_ptr, &offset)) { ++ ERROR("Unable to read block list [%d:%x]\n", block_ptr, offset); ++ return 0; ++ } ++ SQUASHFS_SWAP_SHORTS(((unsigned short *)block_list), ((unsigned short *)sblock_list), blocks); ++ } else ++ if(!squashfs_get_cached_block(inode->i_sb, (char *) block_list, block_ptr, offset, blocks << 1, &block_ptr, &offset)) { ++ ERROR("Unable to read block list [%d:%x]\n", block_ptr, offset); ++ return 0; ++ } ++ for(block_listp = (unsigned short *) block_list; i < index && blocks; i ++, block_listp ++, blocks --) ++ block += SQUASHFS_COMPRESSED_SIZE(*block_listp); ++ if(blocks >= readahead_blks) ++ break; ++ } ++ ++ if(bsize) ++ *bsize = SQUASHFS_COMPRESSED_SIZE(*block_listp) | (!SQUASHFS_COMPRESSED(*block_listp) ? SQUASHFS_COMPRESSED_BIT_BLOCK : 0); ++ else ++ (unsigned short *) *block_p = block_listp; ++ return block; ++} ++#endif ++ ++ ++ ++static unsigned int read_blocklist(struct inode *inode, int index, int readahead_blks, ++ char *block_list, char **block_p, unsigned int *bsize) ++{ ++ squashfs_sb_info *msBlk = &inode->i_sb->u.squashfs_sb; ++ unsigned int *block_listp; ++ int i = 0; ++ int block_ptr = inode->u.squashfs_i.block_list_start; ++ int offset = inode->u.squashfs_i.offset; ++ int block = inode->u.squashfs_i.start_block; ++ ++ for(;;) { ++ int blocks = (index + readahead_blks - i); ++ if(blocks > (SIZE >> 2)) { ++ if((index - i) <= (SIZE >> 2)) ++ blocks = index - i; ++ else ++ blocks = SIZE >> 2; ++ } ++ ++ if(msBlk->swap) { ++ unsigned char sblock_list[SIZE]; ++ if(!squashfs_get_cached_block(inode->i_sb, (char *) sblock_list, block_ptr, offset, blocks << 2, &block_ptr, &offset)) { ++ ERROR("Unable to read block list [%d:%x]\n", block_ptr, offset); ++ return 0; ++ } ++ SQUASHFS_SWAP_INTS(((unsigned int *)block_list), ((unsigned int *)sblock_list), blocks); ++ } else ++ if(!squashfs_get_cached_block(inode->i_sb, (char *) block_list, block_ptr, offset, blocks << 2, &block_ptr, &offset)) { ++ ERROR("Unable to read block list [%d:%x]\n", block_ptr, offset); ++ return 0; ++ } ++ for(block_listp = (unsigned int *) block_list; i < index && blocks; i ++, block_listp ++, blocks --) ++ block += SQUASHFS_COMPRESSED_SIZE_BLOCK(*block_listp); ++ if(blocks >= readahead_blks) ++ break; ++ } ++ ++ *bsize = *block_listp; ++ return block; ++} ++ ++ ++static int squashfs_readpage(struct file *file, struct page *page) ++{ ++ struct inode *inode = page->mapping->host; ++ squashfs_sb_info *msBlk = &inode->i_sb->u.squashfs_sb; ++ squashfs_super_block *sBlk = &msBlk->sBlk; ++ unsigned char block_list[SIZE]; ++ unsigned int bsize, block, i = 0, bytes = 0, byte_offset = 0; ++ int index = page->index >> (sBlk->block_log - PAGE_CACHE_SHIFT); ++ void *pageaddr = kmap(page); ++ struct squashfs_fragment_cache *fragment; ++ char *data_ptr = msBlk->read_page; ++ ++ int mask = (1 << (sBlk->block_log - PAGE_CACHE_SHIFT)) - 1; ++ int start_index = page->index & ~mask; ++ int end_index = start_index | mask; ++ ++ TRACE("Entered squashfs_readpage, page index %x, start block %x\n", (unsigned int) page->index, ++ inode->u.squashfs_i.start_block); ++ ++ if(inode->u.squashfs_i.fragment_start_block == SQUASHFS_INVALID_BLK || index < (inode->i_size >> sBlk->block_log)) { ++ if((block = (msBlk->read_blocklist)(inode, index, 1, block_list, NULL, &bsize)) == 0) ++ goto skip_read; ++ ++ down(&msBlk->read_page_mutex); ++ if(!(bytes = read_data(inode->i_sb, msBlk->read_page, block, bsize, 1, NULL))) { ++ ERROR("Unable to read page, block %x, size %x\n", block, bsize); ++ up(&msBlk->read_page_mutex); ++ goto skip_read; ++ } ++ } else { ++ if((fragment = get_cached_fragment(inode->i_sb, inode->u.squashfs_i.fragment_start_block, inode->u.squashfs_i.fragment_size)) == NULL) { ++ ERROR("Unable to read page, block %x, size %x\n", inode->u.squashfs_i.fragment_start_block, (int) inode->u.squashfs_i.fragment_size); ++ goto skip_read; ++ } ++ bytes = inode->u.squashfs_i.fragment_offset + (inode->i_size & (sBlk->block_size - 1)); ++ byte_offset = inode->u.squashfs_i.fragment_offset; ++ data_ptr = fragment->data; ++ } ++ ++ for(i = start_index; i <= end_index && byte_offset < bytes; i++, byte_offset += PAGE_CACHE_SIZE) { ++ struct page *push_page; ++ int available_bytes = (bytes - byte_offset) > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE : bytes - byte_offset; ++ ++ TRACE("bytes %d, i %d, byte_offset %d, available_bytes %d\n", bytes, i, byte_offset, available_bytes); ++ ++ if(i == page->index) { ++ memcpy(pageaddr, data_ptr + byte_offset, available_bytes); ++ memset(pageaddr + available_bytes, 0, PAGE_CACHE_SIZE - available_bytes); ++ kunmap(page); ++ flush_dcache_page(page); ++ SetPageUptodate(page); ++ UnlockPage(page); ++ } else if((push_page = grab_cache_page_nowait(page->mapping, i))) { ++ void *pageaddr = kmap(push_page); ++ memcpy(pageaddr, data_ptr + byte_offset, available_bytes); ++ memset(pageaddr + available_bytes, 0, PAGE_CACHE_SIZE - available_bytes); ++ kunmap(push_page); ++ flush_dcache_page(push_page); ++ SetPageUptodate(push_page); ++ UnlockPage(push_page); ++ page_cache_release(push_page); ++ } ++ } ++ ++ if(inode->u.squashfs_i.fragment_start_block == SQUASHFS_INVALID_BLK || index < (inode->i_size >> sBlk->block_log)) ++ up(&msBlk->read_page_mutex); ++ else ++ release_cached_fragment(msBlk, fragment); ++ ++ return 0; ++ ++skip_read: ++ memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes); ++ kunmap(page); ++ flush_dcache_page(page); ++ SetPageUptodate(page); ++ UnlockPage(page); ++ ++ return 0; ++} ++ ++ ++static int squashfs_readpage4K(struct file *file, struct page *page) ++{ ++ struct inode *inode = page->mapping->host; ++ squashfs_sb_info *msBlk = &inode->i_sb->u.squashfs_sb; ++ squashfs_super_block *sBlk = &msBlk->sBlk; ++ unsigned char block_list[SIZE]; ++ unsigned int bsize, block, bytes = 0; ++ void *pageaddr = kmap(page); ++ ++ TRACE("Entered squashfs_readpage4K, page index %x, start block %x\n", (unsigned int) page->index, ++ inode->u.squashfs_i.start_block); ++ ++ if(page->index < (inode->i_size >> sBlk->block_log)) { ++ block = (msBlk->read_blocklist)(inode, page->index, 1, block_list, NULL, &bsize); ++ ++ if(!(bytes = read_data(inode->i_sb, pageaddr, block, bsize, 1, NULL))) ++ ERROR("Unable to read page, block %x, size %x\n", block, bsize); ++ } else { ++ struct squashfs_fragment_cache *fragment; ++ ++ if((fragment = get_cached_fragment(inode->i_sb, inode->u.squashfs_i.fragment_start_block, inode->u.squashfs_i.fragment_size)) == NULL) ++ ERROR("Unable to read page, block %x, size %x\n", inode->u.squashfs_i.fragment_start_block, (int) inode->u.squashfs_i.fragment_size); ++ else { ++ bytes = inode->i_size & (sBlk->block_size - 1); ++ memcpy(pageaddr, fragment->data + inode->u.squashfs_i.fragment_offset, bytes); ++ release_cached_fragment(msBlk, fragment); ++ } ++ } ++ ++ memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes); ++ kunmap(page); ++ flush_dcache_page(page); ++ SetPageUptodate(page); ++ UnlockPage(page); ++ ++ return 0; ++} ++ ++ ++#ifdef SQUASHFS_1_0_COMPATIBILITY ++static int squashfs_readpage_lessthan4K(struct file *file, struct page *page) ++{ ++ struct inode *inode = page->mapping->host; ++ squashfs_sb_info *msBlk = &inode->i_sb->u.squashfs_sb; ++ squashfs_super_block *sBlk = &msBlk->sBlk; ++ unsigned char block_list[SIZE]; ++ unsigned short *block_listp, block, bytes = 0; ++ int index = page->index << (PAGE_CACHE_SHIFT - sBlk->block_log); ++ int file_blocks = ((inode->i_size - 1) >> sBlk->block_log) + 1; ++ int readahead_blks = 1 << (PAGE_CACHE_SHIFT - sBlk->block_log); ++ void *pageaddr = kmap(page); ++ ++ int i_end = index + (1 << (PAGE_CACHE_SHIFT - sBlk->block_log)); ++ int byte; ++ ++ TRACE("Entered squashfs_readpage_lessthan4K, page index %x, start block %x\n", (unsigned int) page->index, ++ inode->u.squashfs_i.start_block); ++ ++ block = read_blocklist_1(inode, index, readahead_blks, block_list, (char **) &block_listp, NULL); ++ ++ if(i_end > file_blocks) ++ i_end = file_blocks; ++ ++ while(index < i_end) { ++ if(!(byte = read_data(inode->i_sb, pageaddr, block, *block_listp, 0, NULL))) { ++ ERROR("Unable to read page, block %x, size %x\n", block, *block_listp); ++ goto skip_read; ++ } ++ block += SQUASHFS_COMPRESSED_SIZE(*block_listp); ++ pageaddr += byte; ++ bytes += byte; ++ index ++; ++ block_listp ++; ++ } ++ ++skip_read: ++ memset(pageaddr, 0, PAGE_CACHE_SIZE - bytes); ++ kunmap(page); ++ flush_dcache_page(page); ++ SetPageUptodate(page); ++ UnlockPage(page); ++ ++ return 0; ++} ++#endif ++ ++ ++static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir) ++{ ++ struct inode *i = file->f_dentry->d_inode; ++ squashfs_sb_info *msBlk = &i->i_sb->u.squashfs_sb; ++ squashfs_super_block *sBlk = &msBlk->sBlk; ++ int next_block = i->u.squashfs_i.start_block + sBlk->directory_table_start, next_offset = ++ i->u.squashfs_i.offset, length = 0, dirs_read = 0, dir_count; ++ squashfs_dir_header dirh; ++ char buffer[sizeof(squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1]; ++ squashfs_dir_entry *dire = (squashfs_dir_entry *) buffer; ++ ++ TRACE("Entered squashfs_readdir [%x:%x]\n", next_block, next_offset); ++ ++ while(length < i->i_size) { ++ /* read directory header */ ++ if(msBlk->swap) { ++ squashfs_dir_header sdirh; ++ if(!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, next_block, ++ next_offset, sizeof(sdirh), &next_block, &next_offset)) ++ goto failed_read; ++ length += sizeof(sdirh); ++ SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh); ++ } else { ++ if(!squashfs_get_cached_block(i->i_sb, (char *) &dirh, next_block, ++ next_offset, sizeof(dirh), &next_block, &next_offset)) ++ goto failed_read; ++ length += sizeof(dirh); ++ } ++ ++ dir_count = dirh.count + 1; ++ while(dir_count--) { ++ if(msBlk->swap) { ++ squashfs_dir_entry sdire; ++ if(!squashfs_get_cached_block(i->i_sb, (char *) &sdire, next_block, ++ next_offset, sizeof(sdire), &next_block, &next_offset)) ++ goto failed_read; ++ length += sizeof(sdire); ++ SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire); ++ } else { ++ if(!squashfs_get_cached_block(i->i_sb, (char *) dire, next_block, ++ next_offset, sizeof(*dire), &next_block, &next_offset)) ++ goto failed_read; ++ length += sizeof(*dire); ++ } ++ ++ if(!squashfs_get_cached_block(i->i_sb, dire->name, next_block, ++ next_offset, dire->size + 1, &next_block, &next_offset)) ++ goto failed_read; ++ length += dire->size + 1; ++ ++ if(file->f_pos >= length) ++ continue; ++ ++ dire->name[dire->size + 1] = '\0'; ++ ++ TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d)\n", (unsigned int) dirent, ++ dire->name, dire->size + 1, (int) file->f_pos, ++ dirh.start_block, dire->offset, squashfs_filetype_table[dire->type]); ++ ++ if(filldir(dirent, dire->name, dire->size + 1, file->f_pos, SQUASHFS_MK_VFS_INODE(dirh.start_block, ++ dire->offset), squashfs_filetype_table[dire->type]) < 0) { ++ TRACE("Filldir returned less than 0\n"); ++ return dirs_read; ++ } ++ ++ file->f_pos = length; ++ dirs_read ++; ++ } ++ } ++ ++ return dirs_read; ++ ++failed_read: ++ ERROR("Unable to read directory block [%x:%x]\n", next_block, next_offset); ++ return 0; ++} ++ ++ ++static struct dentry *squashfs_lookup(struct inode *i, struct dentry *dentry) ++{ ++ const char *name =dentry->d_name.name; ++ int len = dentry->d_name.len; ++ struct inode *inode = NULL; ++ squashfs_sb_info *msBlk = &i->i_sb->u.squashfs_sb; ++ squashfs_super_block *sBlk = &msBlk->sBlk; ++ int next_block = i->u.squashfs_i.start_block + sBlk->directory_table_start, next_offset = ++ i->u.squashfs_i.offset, length = 0, dir_count; ++ squashfs_dir_header dirh; ++ char buffer[sizeof(squashfs_dir_entry) + SQUASHFS_NAME_LEN]; ++ squashfs_dir_entry *dire = (squashfs_dir_entry *) buffer; ++ ++ TRACE("Entered squashfs_lookup [%x:%x]\n", next_block, next_offset); ++ ++ while(length < i->i_size) { ++ /* read directory header */ ++ if(msBlk->swap) { ++ squashfs_dir_header sdirh; ++ if(!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, next_block, next_offset, ++ sizeof(sdirh), &next_block, &next_offset)) ++ goto failed_read; ++ length += sizeof(sdirh); ++ SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh); ++ } else { ++ if(!squashfs_get_cached_block(i->i_sb, (char *) &dirh, next_block, next_offset, ++ sizeof(dirh), &next_block, &next_offset)) ++ goto failed_read; ++ length += sizeof(dirh); ++ } ++ ++ dir_count = dirh.count + 1; ++ while(dir_count--) { ++ if(msBlk->swap) { ++ squashfs_dir_entry sdire; ++ if(!squashfs_get_cached_block(i->i_sb, (char *) &sdire, ++ next_block,next_offset, sizeof(sdire), &next_block, &next_offset)) ++ goto failed_read; ++ length += sizeof(sdire); ++ SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire); ++ } else { ++ if(!squashfs_get_cached_block(i->i_sb, (char *) dire, ++ next_block,next_offset, sizeof(*dire), &next_block, &next_offset)) ++ goto failed_read; ++ length += sizeof(*dire); ++ } ++ ++ if(!squashfs_get_cached_block(i->i_sb, dire->name, ++ next_block, next_offset, dire->size + 1, &next_block, &next_offset)) ++ goto failed_read; ++ length += dire->size + 1; ++ ++ if((len == dire->size + 1) && !strncmp(name, dire->name, len)) { ++ squashfs_inode ino = SQUASHFS_MKINODE(dirh.start_block, dire->offset); ++ ++ TRACE("calling squashfs_iget for directory entry %s, inode %x:%x\n", ++ name, dirh.start_block, dire->offset); ++ ++ inode = (msBlk->iget)(i->i_sb, ino); ++ ++ goto exit_loop; ++ } ++ } ++ } ++ ++exit_loop: ++ d_add(dentry, inode); ++ return ERR_PTR(0); ++ ++failed_read: ++ ERROR("Unable to read directory block [%x:%x]\n", next_block, next_offset); ++ goto exit_loop; ++} ++ ++ ++static void squashfs_put_super(struct super_block *s) ++{ ++ if(s->u.squashfs_sb.block_cache) kfree(s->u.squashfs_sb.block_cache); ++ if(s->u.squashfs_sb.read_data) kfree(s->u.squashfs_sb.read_data); ++ if(s->u.squashfs_sb.read_page) kfree(s->u.squashfs_sb.read_page); ++ if(s->u.squashfs_sb.uid) kfree(s->u.squashfs_sb.uid); ++ s->u.squashfs_sb.block_cache = (void *) s->u.squashfs_sb.uid = ++ s->u.squashfs_sb.read_data = s->u.squashfs_sb.read_page = NULL; ++} ++ ++ ++static int __init init_squashfs_fs(void) ++{ ++ ++ if(!(stream.workspace = (char *) vmalloc(zlib_inflate_workspacesize()))) { ++ ERROR("Failed to allocate zlib workspace\n"); ++ return -ENOMEM; ++ } ++ return register_filesystem(&squashfs_fs_type); ++} ++ ++ ++static void __exit exit_squashfs_fs(void) ++{ ++ vfree(stream.workspace); ++ unregister_filesystem(&squashfs_fs_type); ++} ++ ++ ++EXPORT_NO_SYMBOLS; ++ ++module_init(init_squashfs_fs); ++module_exit(exit_squashfs_fs); ++MODULE_DESCRIPTION("squashfs, a compressed read-only filesystem"); ++MODULE_AUTHOR("Phillip Lougher <plougher@users.sourceforge.net>"); ++MODULE_LICENSE("GPL"); +diff -Nurb src/linux/linux.orig/include/linux/fs.h src/linux/linux/include/linux/fs.h +--- src/linux/linux.orig/include/linux/fs.h 2003-07-04 04:12:25.000000000 -0400 ++++ src/linux/linux/include/linux/fs.h 2004-05-25 21:13:03.000000000 -0400 +@@ -313,6 +313,7 @@ + #include <linux/usbdev_fs_i.h> + #include <linux/jffs2_fs_i.h> + #include <linux/cramfs_fs_sb.h> ++#include <linux/squashfs_fs_i.h> + + /* + * Attribute flags. These should be or-ed together to figure out what +@@ -503,6 +504,7 @@ + struct socket socket_i; + struct usbdev_inode_info usbdev_i; + struct jffs2_inode_info jffs2_i; ++ struct squashfs_inode_info squashfs_i; + void *generic_ip; + } u; + }; +@@ -697,6 +699,7 @@ + #include <linux/usbdev_fs_sb.h> + #include <linux/cramfs_fs_sb.h> + #include <linux/jffs2_fs_sb.h> ++#include <linux/squashfs_fs_sb.h> + + extern struct list_head super_blocks; + extern spinlock_t sb_lock; +@@ -755,6 +758,7 @@ + struct usbdev_sb_info usbdevfs_sb; + struct jffs2_sb_info jffs2_sb; + struct cramfs_sb_info cramfs_sb; ++ struct squashfs_sb_info squashfs_sb; + void *generic_sbp; + } u; + /* +diff -Nurb src/linux/linux.orig/include/linux/squashfs_fs.h src/linux/linux/include/linux/squashfs_fs.h +--- src/linux/linux.orig/include/linux/squashfs_fs.h 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/include/linux/squashfs_fs.h 2004-05-25 21:13:03.000000000 -0400 +@@ -0,0 +1,474 @@ ++#ifndef SQUASHFS_FS ++#define SQUASHFS_FS ++/* ++ * Squashfs ++ * ++ * Copyright (c) 2002, 2003, 2004 Phillip Lougher <plougher@users.sourceforge.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, ++ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * squashfs_fs.h ++ */ ++ ++#define SQUASHFS_MAJOR 2 ++#define SQUASHFS_MINOR 0 ++#define SQUASHFS_MAGIC 0x73717368 ++#define SQUASHFS_MAGIC_SWAP 0x68737173 ++#define SQUASHFS_START 0 ++ ++/* size of metadata (inode and directory) blocks */ ++#define SQUASHFS_METADATA_SIZE 8192 ++#define SQUASHFS_METADATA_LOG 13 ++ ++/* default size of data blocks */ ++#define SQUASHFS_FILE_SIZE 65536 ++#define SQUASHFS_FILE_LOG 16 ++ ++#define SQUASHFS_FILE_MAX_SIZE 65536 ++ ++/* Max number of uids and gids */ ++#define SQUASHFS_UIDS 256 ++#define SQUASHFS_GUIDS 255 ++ ++/* Max length of filename (not 255) */ ++#define SQUASHFS_NAME_LEN 256 ++ ++#define SQUASHFS_INVALID ((long long) 0xffffffffffff) ++#define SQUASHFS_INVALID_BLK ((long long) 0xffffffff) ++#define SQUASHFS_USED_BLK ((long long) 0xfffffffe) ++ ++/* Filesystem flags */ ++#define SQUASHFS_NOI 0 ++#define SQUASHFS_NOD 1 ++#define SQUASHFS_CHECK 2 ++#define SQUASHFS_NOF 3 ++#define SQUASHFS_NO_FRAG 4 ++#define SQUASHFS_ALWAYS_FRAG 5 ++#define SQUASHFS_DUPLICATE 6 ++#define SQUASHFS_BIT(flag, bit) ((flag >> bit) & 1) ++#define SQUASHFS_UNCOMPRESSED_INODES(flags) SQUASHFS_BIT(flags, SQUASHFS_NOI) ++#define SQUASHFS_UNCOMPRESSED_DATA(flags) SQUASHFS_BIT(flags, SQUASHFS_NOD) ++#define SQUASHFS_UNCOMPRESSED_FRAGMENTS(flags) SQUASHFS_BIT(flags, SQUASHFS_NOF) ++#define SQUASHFS_NO_FRAGMENTS(flags) SQUASHFS_BIT(flags, SQUASHFS_NO_FRAG) ++#define SQUASHFS_ALWAYS_FRAGMENTS(flags) SQUASHFS_BIT(flags, SQUASHFS_ALWAYS_FRAG) ++#define SQUASHFS_DUPLICATES(flags) SQUASHFS_BIT(flags, SQUASHFS_DUPLICATE) ++#define SQUASHFS_CHECK_DATA(flags) SQUASHFS_BIT(flags, SQUASHFS_CHECK) ++#define SQUASHFS_MKFLAGS(noi, nod, check_data, nof, no_frag, always_frag, duplicate_checking) (noi | (nod << 1) | (check_data << 2) | (nof << 3) | (no_frag << 4) | (always_frag << 5) | (duplicate_checking << 6)) ++ ++/* Max number of types and file types */ ++#define SQUASHFS_DIR_TYPE 1 ++#define SQUASHFS_FILE_TYPE 2 ++#define SQUASHFS_SYMLINK_TYPE 3 ++#define SQUASHFS_BLKDEV_TYPE 4 ++#define SQUASHFS_CHRDEV_TYPE 5 ++#define SQUASHFS_FIFO_TYPE 6 ++#define SQUASHFS_SOCKET_TYPE 7 ++ ++/* 1.0 filesystem type definitions */ ++#define SQUASHFS_TYPES 5 ++#define SQUASHFS_IPC_TYPE 0 ++ ++/* Flag whether block is compressed or uncompressed, bit is set if block is uncompressed */ ++#define SQUASHFS_COMPRESSED_BIT (1 << 15) ++#define SQUASHFS_COMPRESSED_SIZE(B) (((B) & ~SQUASHFS_COMPRESSED_BIT) ? \ ++ (B) & ~SQUASHFS_COMPRESSED_BIT : SQUASHFS_COMPRESSED_BIT) ++ ++#define SQUASHFS_COMPRESSED(B) (!((B) & SQUASHFS_COMPRESSED_BIT)) ++ ++#define SQUASHFS_COMPRESSED_BIT_BLOCK (1 << 24) ++#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B) (((B) & ~SQUASHFS_COMPRESSED_BIT_BLOCK) ? \ ++ (B) & ~SQUASHFS_COMPRESSED_BIT_BLOCK : SQUASHFS_COMPRESSED_BIT_BLOCK) ++ ++#define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK)) ++ ++/* ++ * Inode number ops. Inodes consist of a compressed block number, and an uncompressed ++ * offset within that block ++ */ ++#define SQUASHFS_INODE_BLK(a) ((unsigned int) ((a) >> 16)) ++#define SQUASHFS_INODE_OFFSET(a) ((unsigned int) ((a) & 0xffff)) ++#define SQUASHFS_MKINODE(A, B) ((squashfs_inode)(((squashfs_inode) (A) << 16)\ ++ + (B))) ++ ++/* Compute 32 bit VFS inode number from squashfs inode number */ ++#define SQUASHFS_MK_VFS_INODE(a, b) ((unsigned int) (((a) << 8) + ((b) >> 2) + 1)) ++ ++/* Translate between VFS mode and squashfs mode */ ++#define SQUASHFS_MODE(a) ((a) & 0xfff) ++ ++/* fragment and fragment table defines */ ++typedef unsigned int squashfs_fragment_index; ++#define SQUASHFS_FRAGMENT_BYTES(A) (A * sizeof(squashfs_fragment_entry)) ++#define SQUASHFS_FRAGMENT_INDEX(A) (SQUASHFS_FRAGMENT_BYTES(A) / SQUASHFS_METADATA_SIZE) ++#define SQUASHFS_FRAGMENT_INDEX_OFFSET(A) (SQUASHFS_FRAGMENT_BYTES(A) % SQUASHFS_METADATA_SIZE) ++#define SQUASHFS_FRAGMENT_INDEXES(A) ((SQUASHFS_FRAGMENT_BYTES(A) + SQUASHFS_METADATA_SIZE - 1) / SQUASHFS_METADATA_SIZE) ++#define SQUASHFS_FRAGMENT_INDEX_BYTES(A) (SQUASHFS_FRAGMENT_INDEXES(A) * sizeof(squashfs_fragment_index)) ++#define SQUASHFS_CACHED_FRAGMENTS 3 ++ ++/* cached data constants for filesystem */ ++#define SQUASHFS_CACHED_BLKS 8 ++ ++#define SQUASHFS_MAX_FILE_SIZE_LOG 32 ++#define SQUASHFS_MAX_FILE_SIZE ((long long) 1 << (SQUASHFS_MAX_FILE_SIZE_LOG - 1)) ++ ++#define SQUASHFS_MARKER_BYTE 0xff ++ ++/* ++ * definitions for structures on disk ++ */ ++ ++typedef unsigned int squashfs_block; ++typedef long long squashfs_inode; ++ ++typedef unsigned int squashfs_uid; ++ ++typedef struct squashfs_super_block { ++ unsigned int s_magic; ++ unsigned int inodes; ++ unsigned int bytes_used; ++ unsigned int uid_start; ++ unsigned int guid_start; ++ unsigned int inode_table_start; ++ unsigned int directory_table_start; ++ unsigned int s_major:16; ++ unsigned int s_minor:16; ++ unsigned int block_size_1:16; ++ unsigned int block_log:16; ++ unsigned int flags:8; ++ unsigned int no_uids:8; ++ unsigned int no_guids:8; ++ time_t mkfs_time /* time of filesystem creation */; ++ squashfs_inode root_inode; ++ unsigned int block_size; ++ unsigned int fragments; ++ unsigned int fragment_table_start; ++} __attribute__ ((packed)) squashfs_super_block; ++ ++typedef struct { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:8; /* index into uid table */ ++ unsigned int guid:8; /* index into guid table */ ++} __attribute__ ((packed)) squashfs_base_inode_header; ++ ++typedef squashfs_base_inode_header squashfs_ipc_inode_header; ++ ++typedef struct { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:8; /* index into uid table */ ++ unsigned int guid:8; /* index into guid table */ ++ unsigned short rdev; ++} __attribute__ ((packed)) squashfs_dev_inode_header; ++ ++typedef struct { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:8; /* index into uid table */ ++ unsigned int guid:8; /* index into guid table */ ++ unsigned short symlink_size; ++ char symlink[0]; ++} __attribute__ ((packed)) squashfs_symlink_inode_header; ++ ++typedef struct { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:8; /* index into uid table */ ++ unsigned int guid:8; /* index into guid table */ ++ time_t mtime; ++ squashfs_block start_block; ++ unsigned int fragment; ++ unsigned int offset; ++ unsigned int file_size:SQUASHFS_MAX_FILE_SIZE_LOG; ++ unsigned short block_list[0]; ++} __attribute__ ((packed)) squashfs_reg_inode_header; ++ ++typedef struct { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:8; /* index into uid table */ ++ unsigned int guid:8; /* index into guid table */ ++ unsigned int file_size:19; ++ unsigned int offset:13; ++ time_t mtime; ++ unsigned int start_block:24; ++} __attribute__ ((packed)) squashfs_dir_inode_header; ++ ++typedef union { ++ squashfs_base_inode_header base; ++ squashfs_dev_inode_header dev; ++ squashfs_symlink_inode_header symlink; ++ squashfs_reg_inode_header reg; ++ squashfs_dir_inode_header dir; ++ squashfs_ipc_inode_header ipc; ++} squashfs_inode_header; ++ ++typedef struct { ++ unsigned int offset:13; ++ unsigned int type:3; ++ unsigned int size:8; ++ char name[0]; ++} __attribute__ ((packed)) squashfs_dir_entry; ++ ++typedef struct { ++ unsigned int count:8; ++ unsigned int start_block:24; ++} __attribute__ ((packed)) squashfs_dir_header; ++ ++ ++typedef struct { ++ unsigned int start_block; ++ unsigned int size; ++} __attribute__ ((packed)) squashfs_fragment_entry; ++ ++extern int squashfs_uncompress_block(void *d, int dstlen, void *s, int srclen); ++extern int squashfs_uncompress_init(void); ++extern int squashfs_uncompress_exit(void); ++ ++/* ++ * macros to convert each packed bitfield structure from little endian to big ++ * endian and vice versa. These are needed when creating or using a filesystem on a ++ * machine with different byte ordering to the target architecture. ++ * ++ */ ++ ++#define SQUASHFS_SWAP_SUPER_BLOCK(s, d) {\ ++ SQUASHFS_MEMSET(s, d, sizeof(squashfs_super_block));\ ++ SQUASHFS_SWAP((s)->s_magic, d, 0, 32);\ ++ SQUASHFS_SWAP((s)->inodes, d, 32, 32);\ ++ SQUASHFS_SWAP((s)->bytes_used, d, 64, 32);\ ++ SQUASHFS_SWAP((s)->uid_start, d, 96, 32);\ ++ SQUASHFS_SWAP((s)->guid_start, d, 128, 32);\ ++ SQUASHFS_SWAP((s)->inode_table_start, d, 160, 32);\ ++ SQUASHFS_SWAP((s)->directory_table_start, d, 192, 32);\ ++ SQUASHFS_SWAP((s)->s_major, d, 224, 16);\ ++ SQUASHFS_SWAP((s)->s_minor, d, 240, 16);\ ++ SQUASHFS_SWAP((s)->block_size_1, d, 256, 16);\ ++ SQUASHFS_SWAP((s)->block_log, d, 272, 16);\ ++ SQUASHFS_SWAP((s)->flags, d, 288, 8);\ ++ SQUASHFS_SWAP((s)->no_uids, d, 296, 8);\ ++ SQUASHFS_SWAP((s)->no_guids, d, 304, 8);\ ++ SQUASHFS_SWAP((s)->mkfs_time, d, 312, 32);\ ++ SQUASHFS_SWAP((s)->root_inode, d, 344, 64);\ ++ SQUASHFS_SWAP((s)->block_size, d, 408, 32);\ ++ SQUASHFS_SWAP((s)->fragments, d, 440, 32);\ ++ SQUASHFS_SWAP((s)->fragment_table_start, d, 472, 32);\ ++} ++ ++#define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, n) {\ ++ SQUASHFS_MEMSET(s, d, n);\ ++ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\ ++ SQUASHFS_SWAP((s)->mode, d, 4, 12);\ ++ SQUASHFS_SWAP((s)->uid, d, 16, 8);\ ++ SQUASHFS_SWAP((s)->guid, d, 24, 8);\ ++} ++ ++#define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_ipc_inode_header)) ++ ++#define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) {\ ++ SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_dev_inode_header));\ ++ SQUASHFS_SWAP((s)->rdev, d, 32, 16);\ ++} ++ ++#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) {\ ++ SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_symlink_inode_header));\ ++ SQUASHFS_SWAP((s)->symlink_size, d, 32, 16);\ ++} ++ ++#define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) {\ ++ SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_reg_inode_header));\ ++ SQUASHFS_SWAP((s)->mtime, d, 32, 32);\ ++ SQUASHFS_SWAP((s)->start_block, d, 64, 32);\ ++ SQUASHFS_SWAP((s)->fragment, d, 96, 32);\ ++ SQUASHFS_SWAP((s)->offset, d, 128, 32);\ ++ SQUASHFS_SWAP((s)->file_size, d, 160, SQUASHFS_MAX_FILE_SIZE_LOG);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_INODE_HEADER(s, d) {\ ++ SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_dir_inode_header));\ ++ SQUASHFS_SWAP((s)->file_size, d, 32, 19);\ ++ SQUASHFS_SWAP((s)->offset, d, 51, 13);\ ++ SQUASHFS_SWAP((s)->mtime, d, 64, 32);\ ++ SQUASHFS_SWAP((s)->start_block, d, 96, 24);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_HEADER(s, d) {\ ++ SQUASHFS_MEMSET(s, d, sizeof(squashfs_dir_header));\ ++ SQUASHFS_SWAP((s)->count, d, 0, 8);\ ++ SQUASHFS_SWAP((s)->start_block, d, 8, 24);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_ENTRY(s, d) {\ ++ SQUASHFS_MEMSET(s, d, sizeof(squashfs_dir_entry));\ ++ SQUASHFS_SWAP((s)->offset, d, 0, 13);\ ++ SQUASHFS_SWAP((s)->type, d, 13, 3);\ ++ SQUASHFS_SWAP((s)->size, d, 16, 8);\ ++} ++ ++#define SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d) {\ ++ SQUASHFS_MEMSET(s, d, sizeof(squashfs_fragment_entry));\ ++ SQUASHFS_SWAP((s)->start_block, d, 0, 32);\ ++ SQUASHFS_SWAP((s)->size, d, 32, 32);\ ++} ++ ++#define SQUASHFS_SWAP_SHORTS(s, d, n) {\ ++ int entry;\ ++ int bit_position;\ ++ SQUASHFS_MEMSET(s, d, n * 2);\ ++ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += 16)\ ++ SQUASHFS_SWAP(s[entry], d, bit_position, 16);\ ++} ++ ++#define SQUASHFS_SWAP_INTS(s, d, n) {\ ++ int entry;\ ++ int bit_position;\ ++ SQUASHFS_MEMSET(s, d, n * 4);\ ++ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += 32)\ ++ SQUASHFS_SWAP(s[entry], d, bit_position, 32);\ ++} ++ ++#define SQUASHFS_SWAP_DATA(s, d, n, bits) {\ ++ int entry;\ ++ int bit_position;\ ++ SQUASHFS_MEMSET(s, d, n * bits / 8);\ ++ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += bits)\ ++ SQUASHFS_SWAP(s[entry], d, bit_position, bits);\ ++} ++ ++#define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) SQUASHFS_SWAP_INTS(s, d, n) ++ ++#ifdef SQUASHFS_1_0_COMPATIBILITY ++typedef struct { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:4; /* index into uid table */ ++ unsigned int guid:4; /* index into guid table */ ++} __attribute__ ((packed)) squashfs_base_inode_header_1; ++ ++typedef struct { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:4; /* index into uid table */ ++ unsigned int guid:4; /* index into guid table */ ++ unsigned int type:4; ++ unsigned int offset:4; ++} __attribute__ ((packed)) squashfs_ipc_inode_header_1; ++ ++typedef struct { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:4; /* index into uid table */ ++ unsigned int guid:4; /* index into guid table */ ++ unsigned short rdev; ++} __attribute__ ((packed)) squashfs_dev_inode_header_1; ++ ++typedef struct { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:4; /* index into uid table */ ++ unsigned int guid:4; /* index into guid table */ ++ unsigned short symlink_size; ++ char symlink[0]; ++} __attribute__ ((packed)) squashfs_symlink_inode_header_1; ++ ++typedef struct { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:4; /* index into uid table */ ++ unsigned int guid:4; /* index into guid table */ ++ time_t mtime; ++ squashfs_block start_block; ++ unsigned int file_size:SQUASHFS_MAX_FILE_SIZE_LOG; ++ unsigned short block_list[0]; ++} __attribute__ ((packed)) squashfs_reg_inode_header_1; ++ ++typedef struct { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:4; /* index into uid table */ ++ unsigned int guid:4; /* index into guid table */ ++ unsigned int file_size:19; ++ unsigned int offset:13; ++ time_t mtime; ++ unsigned int start_block:24; ++} __attribute__ ((packed)) squashfs_dir_inode_header_1; ++ ++#define SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, n) {\ ++ SQUASHFS_MEMSET(s, d, n);\ ++ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\ ++ SQUASHFS_SWAP((s)->mode, d, 4, 12);\ ++ SQUASHFS_SWAP((s)->uid, d, 16, 4);\ ++ SQUASHFS_SWAP((s)->guid, d, 20, 4);\ ++} ++ ++#define SQUASHFS_SWAP_IPC_INODE_HEADER_1(s, d) {\ ++ SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, sizeof(squashfs_ipc_inode_header_1));\ ++ SQUASHFS_SWAP((s)->type, d, 24, 4);\ ++ SQUASHFS_SWAP((s)->offset, d, 28, 4);\ ++} ++ ++#define SQUASHFS_SWAP_DEV_INODE_HEADER_1(s, d) {\ ++ SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, sizeof(squashfs_dev_inode_header_1));\ ++ SQUASHFS_SWAP((s)->rdev, d, 24, 16);\ ++} ++ ++#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(s, d) {\ ++ SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_symlink_inode_header_1));\ ++ SQUASHFS_SWAP((s)->symlink_size, d, 24, 16);\ ++} ++ ++#define SQUASHFS_SWAP_REG_INODE_HEADER_1(s, d) {\ ++ SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_reg_inode_header_1));\ ++ SQUASHFS_SWAP((s)->mtime, d, 24, 32);\ ++ SQUASHFS_SWAP((s)->start_block, d, 56, 32);\ ++ SQUASHFS_SWAP((s)->file_size, d, 88, SQUASHFS_MAX_FILE_SIZE_LOG);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_INODE_HEADER_1(s, d) {\ ++ SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_dir_inode_header_1));\ ++ SQUASHFS_SWAP((s)->file_size, d, 24, 19);\ ++ SQUASHFS_SWAP((s)->offset, d, 43, 13);\ ++ SQUASHFS_SWAP((s)->mtime, d, 56, 32);\ ++ SQUASHFS_SWAP((s)->start_block, d, 88, 24);\ ++} ++#endif ++ ++#ifdef __KERNEL__ ++/* ++ * macros used to swap each structure entry, taking into account ++ * bitfields and different bitfield placing conventions on differing architectures ++ */ ++#include <asm/byteorder.h> ++#ifdef __BIG_ENDIAN ++ /* convert from little endian to big endian */ ++#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, tbits, b_pos) ++#else ++ /* convert from big endian to little endian */ ++#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, tbits, 64 - tbits - b_pos) ++#endif ++ ++#define _SQUASHFS_SWAP(value, p, pos, tbits, SHIFT) {\ ++ int bits;\ ++ int b_pos = pos % 8;\ ++ unsigned long long val = 0;\ ++ unsigned char *s = (unsigned char *)p + (pos / 8);\ ++ unsigned char *d = ((unsigned char *) &val) + 7;\ ++ for(bits = 0; bits < (tbits + b_pos); bits += 8) \ ++ *d-- = *s++;\ ++ value = (val >> (SHIFT))/* & ((1 << tbits) - 1)*/;\ ++} ++#define SQUASHFS_MEMSET(s, d, n) memset(s, 0, n); ++#endif ++#endif +diff -Nurb src/linux/linux.orig/include/linux/squashfs_fs_i.h src/linux/linux/include/linux/squashfs_fs_i.h +--- src/linux/linux.orig/include/linux/squashfs_fs_i.h 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/include/linux/squashfs_fs_i.h 2004-05-25 21:13:03.000000000 -0400 +@@ -0,0 +1,33 @@ ++#ifndef SQUASHFS_FS_I ++#define SQUASHFS_FS_I ++/* ++ * Squashfs ++ * ++ * Copyright (c) 2002, 2003, 2004 Phillip Lougher <plougher@users.sourceforge.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, ++ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * squashfs_fs_i.h ++ */ ++ ++typedef struct squashfs_inode_info { ++ unsigned int start_block; ++ unsigned int block_list_start; ++ unsigned int offset; ++ unsigned int fragment_start_block; ++ unsigned int fragment_size; ++ unsigned int fragment_offset; ++ } squashfs_inode_info; ++#endif +diff -Nurb src/linux/linux.orig/include/linux/squashfs_fs_sb.h src/linux/linux/include/linux/squashfs_fs_sb.h +--- src/linux/linux.orig/include/linux/squashfs_fs_sb.h 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/include/linux/squashfs_fs_sb.h 2004-05-25 21:13:03.000000000 -0400 +@@ -0,0 +1,65 @@ ++#ifndef SQUASHFS_FS_SB ++#define SQUASHFS_FS_SB ++/* ++ * Squashfs ++ * ++ * Copyright (c) 2002, 2003, 2004 Phillip Lougher <plougher@users.sourceforge.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, ++ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * squashfs_fs_sb.h ++ */ ++ ++#include <linux/squashfs_fs.h> ++ ++typedef struct { ++ unsigned int block; ++ int length; ++ unsigned int next_index; ++ char *data; ++ } squashfs_cache; ++ ++struct squashfs_fragment_cache { ++ unsigned int block; ++ int length; ++ unsigned int locked; ++ char *data; ++ }; ++ ++typedef struct squashfs_sb_info { ++ squashfs_super_block sBlk; ++ int devblksize; ++ int devblksize_log2; ++ int swap; ++ squashfs_cache *block_cache; ++ struct squashfs_fragment_cache *fragment; ++ int next_cache; ++ int next_fragment; ++ squashfs_uid *uid; ++ squashfs_uid *guid; ++ squashfs_fragment_index *fragment_index; ++ unsigned int read_size; ++ char *read_data; ++ char *read_page; ++ struct semaphore read_page_mutex; ++ struct semaphore block_cache_mutex; ++ struct semaphore fragment_mutex; ++ wait_queue_head_t waitq; ++ wait_queue_head_t fragment_wait_queue; ++ struct inode *(*iget)(struct super_block *s, squashfs_inode inode); ++ unsigned int (*read_blocklist)(struct inode *inode, int index, int readahead_blks, ++ char *block_list, char **block_p, unsigned int *bsize); ++ } squashfs_sb_info; ++#endif +diff -Nurb src/linux/linux.orig/init/do_mounts.c src/linux/linux/init/do_mounts.c +--- src/linux/linux.orig/init/do_mounts.c 2003-11-08 03:13:20.000000000 -0500 ++++ src/linux/linux/init/do_mounts.c 2004-05-25 21:13:03.000000000 -0400 +@@ -16,6 +16,7 @@ + #include <linux/ext2_fs.h> + #include <linux/romfs_fs.h> + #include <linux/cramfs_fs.h> ++#include <linux/squashfs_fs.h> + + #undef BUILD_CRAMDISK + +@@ -470,6 +471,7 @@ + * ext2 + * romfs + * gzip ++ * squashfs + */ + static int __init + identify_ramdisk_image(int fd, int start_block) +@@ -479,6 +481,7 @@ + struct ext2_super_block *ext2sb; + struct romfs_super_block *romfsb; + struct cramfs_super *cramfsb; ++ struct squashfs_super_block *squashfsb; + int nblocks = -1; + unsigned char *buf; + +@@ -490,6 +493,7 @@ + ext2sb = (struct ext2_super_block *) buf; + romfsb = (struct romfs_super_block *) buf; + cramfsb = (struct cramfs_super *) buf; ++ squashfsb = (struct squashfs_super_block *) buf; + memset(buf, 0xe5, size); + + /* +@@ -536,6 +540,15 @@ + goto done; + } + ++ /* squashfs is at block zero too */ ++ if (squashfsb->s_magic == SQUASHFS_MAGIC) { ++ printk(KERN_NOTICE ++ "RAMDISK: squashfs filesystem found at block %d\n", ++ start_block); ++ nblocks = (squashfsb->bytes_used+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS; ++ goto done; ++ } ++ + /* + * Read block 1 to test for minix and ext2 superblock + */ +diff -Nurb src/linux/linux.orig/kernel/ksyms.c src/linux/linux/kernel/ksyms.c +--- src/linux/linux.orig/kernel/ksyms.c 2003-07-04 04:12:28.000000000 -0400 ++++ src/linux/linux/kernel/ksyms.c 2004-05-25 21:12:24.000000000 -0400 +@@ -482,9 +482,9 @@ + EXPORT_SYMBOL(simple_strtoull); + EXPORT_SYMBOL(system_utsname); /* UTS data */ + EXPORT_SYMBOL(uts_sem); /* UTS semaphore */ +-#ifndef __mips__ ++//#ifndef __mips__ //bite me. -mbm. + EXPORT_SYMBOL(sys_call_table); +-#endif ++//#endif + EXPORT_SYMBOL(machine_restart); + EXPORT_SYMBOL(machine_halt); + EXPORT_SYMBOL(machine_power_off); +diff -Nurb src/linux/linux.orig/lib/Config.in src/linux/linux/lib/Config.in +--- src/linux/linux.orig/lib/Config.in 2003-07-04 04:12:29.000000000 -0400 ++++ src/linux/linux/lib/Config.in 2004-05-25 21:13:03.000000000 -0400 +@@ -8,12 +8,14 @@ + # Do we need the compression support? + # + if [ "$CONFIG_CRAMFS" = "y" -o \ ++ "$CONFIG_SQUASHFS" = "y" -o \ + "$CONFIG_PPP_DEFLATE" = "y" -o \ + "$CONFIG_JFFS2_FS" = "y" -o \ + "$CONFIG_ZISOFS_FS" = "y" ]; then + define_tristate CONFIG_ZLIB_INFLATE y + else + if [ "$CONFIG_CRAMFS" = "m" -o \ ++ "$CONFIG_SQUASHFS" = "m" -o \ + "$CONFIG_PPP_DEFLATE" = "m" -o \ + "$CONFIG_JFFS2_FS" = "m" -o \ + "$CONFIG_ZISOFS_FS" = "m" ]; then diff --git a/obsolete-buildroot/sources/openwrt/kernel/patches/130-nfsswap.patch b/obsolete-buildroot/sources/openwrt/kernel/patches/130-nfsswap.patch new file mode 100644 index 0000000000..bf848c129a --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/kernel/patches/130-nfsswap.patch @@ -0,0 +1,2362 @@ +diff -Nurb src/linux/linux.orig/Documentation/netswap.txt src/linux/linux/Documentation/netswap.txt +--- src/linux/linux.orig/Documentation/netswap.txt 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/Documentation/netswap.txt 2004-05-31 02:18:03.000000000 -0400 +@@ -0,0 +1,51 @@ ++ Swapping over network ++ ++Support for this is enabled via the CONFIG_NETSWAP option, which is ++automatically enabled when enabling swap files located on NFS volumes ++(CONFIG_SWAP_VIA_NFS). ++ ++When swapping to files located on a network file system like NFS or ++CODA or others or to nbd (network block device, see `nbd.txt') ++partitions there is the problem that this requires additional memory, ++besides the page which is currently swapped in or out, probably at ++least two more pages for each page in question. ++ ++This means that not only there needs to be free space left in the swap ++file or the swap partition, but in addition there must be enough free ++memory left in the system to perform the swap out of pages. ++ ++This is particularly painful as receiving data over the network itself ++consumes memory, and this memory is allocated from an interrupt ++context (i.e. in the interrupt handler of the network card). That ++means that on a congested network there are chances that the machine ++runs out of memory, simply because the network device's interrupt ++routines allocate memory faster that it is freed by swapping via ++network. ++ ++To cope with this problem, there is a new socket option `SO_SWAPPING' ++which has to be set on the `SOL_SOCKET' level with setsockopt() (see ++setsockopt(2)). When this option is set on any network socket, then ++the system will start to drop network packets it receives on any other ++socket when the number of free pages falls below a certain threshold. ++ ++This threshold initially is 4 pages less than `freepages.min' (see ++`Documentation/sysctl/vm.txt') but can be tuned using the sysctl ++interface by writing to the file `/proc/sys/net/swapping/threshold' ++ ++There are two other files: ++ ++`/proc/sys/net/swapping/dropped': ++ how many network packets have been dropped so far. This file is ++ writable, writing to it simply sets the counter to the given value ++ (useful for resetting the counter). ++ ++`/proc/sys/net/swapping/sock_count': ++ How many network sockets have the `SO_SWAPPING' option set (read ++ only, of course). ++ ++When using swap-files on NFS volumes, then the `SO_SWAPPING' option is ++set or cleared by swapon/swapoff system calls, so the user need not ++care about it. ++ ++Swapping over the network is insecure unless the data would be ++encrypted, which is not the case with NFS. It is also very slow. +diff -Nurb src/linux/linux.orig/Documentation/nfsswap.txt src/linux/linux/Documentation/nfsswap.txt +--- src/linux/linux.orig/Documentation/nfsswap.txt 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/Documentation/nfsswap.txt 2004-05-31 02:18:03.000000000 -0400 +@@ -0,0 +1,41 @@ ++ Swapping to files on NFS volumes ++ ++To do this you have to say `Y' or `M' to the CONFIG_SWAP_VIA_NFS ++configuration option. When compling support for this as a module you ++should read `Documentation/modules.txt'. For auto-loading of the ++module during the `swapon' system call you have to place a line like ++ ++alias swapfile-mod nfsswap ++ ++in `/etc/modules.conf' (or `/etc/conf.modules', depending on your ++setup). NFS volumes holding swapfile should be mounted with `rsize' ++and `wsize' set to something less than the size of a page, otherwise ++deadlocks caused by memory fragmentation can happen, i.e. mount the ++volume which is to hold the swapfiles with ++ ++mount -t nfs -o rsize=2048,wsize=2048 NFS_SERVER_IP:/server_volume /mount_point ++ ++or set the option in `/etc/fstab'. Read `Documentation/nfsroot.txt' to ++learn how to set mount options for the root file system, if your swap ++files are to be located on the root file system. ++ ++Setting the `rsize' and `wsize' to anything less than PAGE_SIZE is a ++performance hit, so you probably want to have at least two volumes ++mounted, one for the swapfiles, one for the rest. ++ ++You may want to read `Documentation/netswap.txt' as well. ++ ++Swapfiles on NFS volumes can be treated like any other swapfile, ++i.e. ++ ++dd if=/dev/zero of=/swapfiles/SWAPFILE bs=1k count=20480 ++mkswap /swapfiles/SWAPFILE ++swapon /swapfiles/SWAPFILE ++ ++will create a 20M swapfile and tell the system to use it. Actually, ++one could use lseek(2) to create an empty swapfile. This is different ++from swapfiles located on local harddisk. ++ ++Swapping over the network is insecure unless the data would be ++encrypted, which is not the case with NFS. It is also very slow. ++ +diff -Nurb src/linux/linux.orig/drivers/block/blkpg.c src/linux/linux/drivers/block/blkpg.c +--- src/linux/linux.orig/drivers/block/blkpg.c 2003-07-04 04:11:31.000000000 -0400 ++++ src/linux/linux/drivers/block/blkpg.c 2004-05-31 02:18:03.000000000 -0400 +@@ -34,7 +34,7 @@ + #include <linux/blk.h> /* for set_device_ro() */ + #include <linux/blkpg.h> + #include <linux/genhd.h> +-#include <linux/swap.h> /* for is_swap_partition() */ ++#include <linux/swap.h> /* for swap_run_test() */ + #include <linux/module.h> /* for EXPORT_SYMBOL */ + + #include <asm/uaccess.h> +@@ -114,6 +114,29 @@ + return 0; + } + ++/* swap_run_test() applies this hook to all swapfiles until it returns ++ * "1". If it never returns "1", the result of swap_run_test() is "0", ++ * otherwise "1". ++ */ ++static int is_swap_partition_hook(unsigned int flags, struct file *swap_file, ++ void *testdata) ++{ ++ kdev_t swap_dev = S_ISBLK(swap_file->f_dentry->d_inode->i_mode) ++ ? swap_file->f_dentry->d_inode->i_rdev : 0; ++ kdev_t dev = *((kdev_t *)testdata); ++ ++ if (flags & SWP_USED && dev == swap_dev) { ++ return 1; ++ } else { ++ return 0; ++ } ++} ++ ++static inline int is_swap_partition(kdev_t dev) ++{ ++ return swap_run_test(is_swap_partition_hook, &dev); ++} ++ + /* + * Delete a partition given by partition number + * +diff -Nurb src/linux/linux.orig/fs/Config.in src/linux/linux/fs/Config.in +--- src/linux/linux.orig/fs/Config.in 2004-05-31 02:02:43.000000000 -0400 ++++ src/linux/linux/fs/Config.in 2004-05-31 02:18:03.000000000 -0400 +@@ -4,6 +4,12 @@ + mainmenu_option next_comment + comment 'File systems' + ++if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then ++ tristate 'Swapping to block devices' CONFIG_BLKDEV_SWAP ++else ++ define_bool CONFIG_BLKDEV_SWAP y ++fi ++ + bool 'Quota support' CONFIG_QUOTA + tristate 'Kernel automounter support' CONFIG_AUTOFS_FS + tristate 'Kernel automounter version 4 support (also supports v3)' CONFIG_AUTOFS4_FS +@@ -110,6 +116,12 @@ + dep_tristate 'NFS file system support' CONFIG_NFS_FS $CONFIG_INET + dep_mbool ' Provide NFSv3 client support' CONFIG_NFS_V3 $CONFIG_NFS_FS + dep_bool ' Root file system on NFS' CONFIG_ROOT_NFS $CONFIG_NFS_FS $CONFIG_IP_PNP ++ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then ++ dep_tristate ' Swapping via NFS (EXPERIMENTAL)' CONFIG_SWAP_VIA_NFS $CONFIG_NFS_FS ++ if [ "$CONFIG_SWAP_VIA_NFS" = "y" -o "$CONFIG_SWAP_VIA_NFS" = "m" ]; then ++ define_bool CONFIG_NETSWAP y ++ fi ++ fi + + dep_tristate 'NFS server support' CONFIG_NFSD $CONFIG_INET + dep_mbool ' Provide NFSv3 server support' CONFIG_NFSD_V3 $CONFIG_NFSD +diff -Nurb src/linux/linux.orig/fs/Makefile src/linux/linux/fs/Makefile +--- src/linux/linux.orig/fs/Makefile 2004-05-31 02:02:42.000000000 -0400 ++++ src/linux/linux/fs/Makefile 2004-05-31 02:18:03.000000000 -0400 +@@ -8,7 +8,7 @@ + O_TARGET := fs.o + + export-objs := filesystems.o open.o dcache.o buffer.o +-mod-subdirs := nls ++mod-subdirs := nls nfs + + obj-y := open.o read_write.o devices.o file_table.o buffer.o \ + super.o block_dev.o char_dev.o stat.o exec.o pipe.o namei.o \ +@@ -70,6 +70,7 @@ + subdir-$(CONFIG_JFS_FS) += jfs + subdir-$(CONFIG_SQUASHFS) += squashfs + ++obj-$(CONFIG_BLKDEV_SWAP) += blkdev_swap.o + + obj-$(CONFIG_BINFMT_AOUT) += binfmt_aout.o + obj-$(CONFIG_BINFMT_EM86) += binfmt_em86.o +diff -Nurb src/linux/linux.orig/fs/blkdev_swap.c src/linux/linux/fs/blkdev_swap.c +--- src/linux/linux.orig/fs/blkdev_swap.c 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/fs/blkdev_swap.c 2004-05-31 02:18:03.000000000 -0400 +@@ -0,0 +1,309 @@ ++/* ++ * Swapping to partitions or files located on partitions. ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/slab.h> ++#include <linux/locks.h> ++#include <linux/blkdev.h> ++#include <linux/pagemap.h> ++#include <linux/swap.h> ++#include <linux/fs.h> ++ ++#ifdef DEBUG_BLKDEV_SWAP ++# define dprintk(fmt...) printk(##fmt) ++#else ++# define dprintk(fmt...) do { /* */ } while (0) ++#endif ++ ++#define BLKDEV_SWAP_ID "blkdev" ++#define BLKDEV_FILE_SWAP_ID "blkdev file" ++ ++/* ++ * Helper function, copied here from buffer.c ++ */ ++ ++/* ++ * Start I/O on a page. ++ * This function expects the page to be locked and may return ++ * before I/O is complete. You then have to check page->locked ++ * and page->uptodate. ++ * ++ * brw_page() is SMP-safe, although it's being called with the ++ * kernel lock held - but the code is ready. ++ * ++ * FIXME: we need a swapper_inode->get_block function to remove ++ * some of the bmap kludges and interface ugliness here. ++ */ ++int brw_page(int rw, struct page *page, kdev_t dev, int b[], int size) ++{ ++ struct buffer_head *head, *bh; ++ ++ if (!PageLocked(page)) ++ panic("brw_page: page not locked for I/O"); ++ ++ if (!page->buffers) ++ create_empty_buffers(page, dev, size); ++ head = bh = page->buffers; ++ ++ /* Stage 1: lock all the buffers */ ++ do { ++ lock_buffer(bh); ++ bh->b_blocknr = *(b++); ++ set_bit(BH_Mapped, &bh->b_state); ++ set_buffer_async_io(bh); ++ bh = bh->b_this_page; ++ } while (bh != head); ++ ++ /* Stage 2: start the IO */ ++ do { ++ struct buffer_head *next = bh->b_this_page; ++ submit_bh(rw, bh); ++ bh = next; ++ } while (bh != head); ++ return 0; ++} ++ ++/* ++ * We implement to methods: swapping to partitions, and swapping to files ++ * located on partitions. ++ */ ++ ++struct blkdev_swap_data { ++ kdev_t dev; ++}; ++ ++struct test_data { ++ struct file * filp; ++ kdev_t dev; ++}; ++ ++static int is_blkdev_swapping(unsigned int flags, ++ struct file * swapf, ++ void *data) ++{ ++ struct test_data *testdata = (struct test_data *) data; ++ struct file * filp = testdata->filp; ++ kdev_t dev = testdata->dev; ++ ++ /* Only check filp's that don't match the one already opened ++ * for us by sys_swapon(). Otherwise, we will always flag a ++ * busy swap file. ++ */ ++ ++ if (swapf != filp) { ++ if (dev == swapf->f_dentry->d_inode->i_rdev) ++ return 1; ++ } ++ return 0; ++} ++ ++static int blkdev_swap_open(struct file * filp, void **dptr) ++{ ++ int swapfilesize; ++ kdev_t dev; ++ struct blkdev_swap_data *data; ++ int error; ++ struct test_data testdata; ++ ++ MOD_INC_USE_COUNT; ++ ++ if (!S_ISBLK(filp->f_dentry->d_inode->i_mode)) { ++ dprintk(__FUNCTION__": can't handle this swap file: %s\n", ++ swapf->d_name.name); ++ error = 0; /* not for us */ ++ goto bad_swap; ++ } ++ ++ dev = filp->f_dentry->d_inode->i_rdev; ++ set_blocksize(dev, PAGE_SIZE); ++ error = -ENODEV; ++ if (!dev || ++ (blk_size[MAJOR(dev)] && !blk_size[MAJOR(dev)][MINOR(dev)])) { ++ printk("blkdev_swap_open: blkdev weirdness for %s\n", ++ filp->f_dentry->d_name.name); ++ goto bad_swap; ++ } ++ ++ /* Check to make sure that we aren't already swapping. */ ++ error = -EBUSY; ++ testdata.filp = filp; ++ testdata.dev = dev; ++ if (swap_run_test(is_blkdev_swapping, &testdata)) { ++ printk("blkdev_swap_open: already swapping to %s\n", ++ filp->f_dentry->d_name.name); ++ goto bad_swap; ++ } ++ ++ swapfilesize = 0; ++ if (blk_size[MAJOR(dev)]) ++ swapfilesize = blk_size[MAJOR(dev)][MINOR(dev)] ++ >> (PAGE_SHIFT - 10); ++ ++ if ((data = kmalloc(sizeof(*data), GFP_KERNEL)) == NULL) { ++ printk("blkdev_swap_open: can't allocate data for %s\n", ++ filp->f_dentry->d_name.name); ++ error = -ENOMEM; ++ goto bad_swap; ++ } ++ data->dev = dev; ++ *dptr = data; ++ ++ dprintk("blkdev_swap_open: returning %d\n", swapfilesize); ++ return swapfilesize; ++ ++ bad_swap: ++ MOD_DEC_USE_COUNT; ++ return error; /* this swap thing is not for us */ ++} ++ ++static int blkdev_swap_release(struct file * filp, void *data) ++{ ++ dprintk("blkdev_swap_release: releasing swap device %s\n", ++ filp->f_dentry->d_name.name); ++ kfree(data); ++ MOD_DEC_USE_COUNT; ++ return 0; ++} ++ ++static int blkdev_rw_page(int rw, struct page *page, unsigned long offset, ++ void *ptr) ++{ ++ struct blkdev_swap_data *data = (struct blkdev_swap_data *)ptr; ++ brw_page(rw, page, data->dev, (int *)&offset, PAGE_SIZE); ++ return 1; ++} ++ ++static struct swap_ops blkdev_swap_ops = { ++ blkdev_swap_open, ++ blkdev_swap_release, ++ blkdev_rw_page ++}; ++ ++struct blkdevfile_swap_data { ++ struct inode *swapf; ++}; ++ ++static int is_blkdevfile_swapping(unsigned int flags, ++ struct file * swapf, ++ void * data) ++{ ++ struct file * filp = (struct file *) data; ++ ++ /* Only check filp's that don't match the one already opened ++ * for us by sys_swapon(). Otherwise, we will always flag a ++ * busy swap file. ++ */ ++ ++ if (swapf != filp) { ++ if (filp->f_dentry->d_inode == swapf->f_dentry->d_inode) ++ return 1; ++ } ++ return 0; ++} ++ ++static int blkdevfile_swap_open(struct file *swapf, void **dptr) ++{ ++ int error = 0; ++ int swapfilesize; ++ struct blkdevfile_swap_data *data; ++ ++ MOD_INC_USE_COUNT; ++ ++ /* first check whether this is a regular file located on a local ++ * hard disk ++ */ ++ if (!S_ISREG(swapf->f_dentry->d_inode->i_mode)) { ++ dprintk("blkdevfile_swap_open: " ++ "can't handle this swap file: %s\n", ++ swapf->d_name.name); ++ error = 0; /* not for us */ ++ goto bad_swap; ++ } ++ if (!swapf->f_dentry->d_inode->i_mapping->a_ops->bmap) { ++ dprintk("blkdevfile_swap_open: no bmap for file: %s\n", ++ swapf->d_name.name); ++ error = 0; /* not for us */ ++ goto bad_swap; ++ } ++ ++ if (swap_run_test(is_blkdevfile_swapping, swapf)) { ++ dprintk("blkdevfile_swap_open: already swapping to %s\n", ++ swapf->d_name.name); ++ error = -EBUSY; ++ goto bad_swap; ++ } ++ swapfilesize = swapf->f_dentry->d_inode->i_size >> PAGE_SHIFT; ++ if ((data = kmalloc(sizeof(*data), GFP_KERNEL)) == NULL) { ++ error = -ENOMEM; ++ goto bad_swap; ++ } ++ data->swapf = swapf->f_dentry->d_inode; ++ *dptr = data; ++ return swapfilesize; ++ ++ bad_swap: ++ MOD_DEC_USE_COUNT; ++ return error; ++} ++ ++static int blkdevfile_swap_release(struct file *swapf, void *data) ++{ ++ kfree(data); ++ MOD_DEC_USE_COUNT; ++ return 0; ++} ++ ++static int blkdevfile_rw_page(int rw, struct page *page, unsigned long offset, ++ void *ptr) ++{ ++ struct blkdevfile_swap_data *data = (struct blkdevfile_swap_data *)ptr; ++ struct inode * swapf = data->swapf; ++ int i, j; ++ unsigned int block = offset ++ << (PAGE_SHIFT - swapf->i_sb->s_blocksize_bits); ++ kdev_t dev = swapf->i_dev; ++ int block_size; ++ int zones[PAGE_SIZE/512]; ++ int zones_used; ++ ++ block_size = swapf->i_sb->s_blocksize; ++ for (i=0, j=0; j< PAGE_SIZE ; i++, j += block_size) ++ if (!(zones[i] = bmap(swapf,block++))) { ++ printk("blkdevfile_rw_page: bad swap file\n"); ++ return 0; ++ } ++ zones_used = i; ++ ++ /* block_size == PAGE_SIZE/zones_used */ ++ brw_page(rw, page, dev, zones, block_size); ++ return 1; ++} ++ ++static struct swap_ops blkdevfile_swap_ops = { ++ blkdevfile_swap_open, ++ blkdevfile_swap_release, ++ blkdevfile_rw_page ++ }; ++ ++int __init blkdev_swap_init(void) ++{ ++ (void)register_swap_method(BLKDEV_SWAP_ID, &blkdev_swap_ops); ++ (void)register_swap_method(BLKDEV_FILE_SWAP_ID, &blkdevfile_swap_ops); ++ return 0; ++} ++ ++void __exit blkdev_swap_exit(void) ++{ ++ unregister_swap_method(BLKDEV_SWAP_ID); ++ unregister_swap_method(BLKDEV_FILE_SWAP_ID); ++} ++ ++module_init(blkdev_swap_init) ++module_exit(blkdev_swap_exit) ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Many. Stuffed into a module by cH (Claus-Justus Heine)"); ++MODULE_DESCRIPTION("Swapping to partitions and files on local hard-disks"); +diff -Nurb src/linux/linux.orig/fs/buffer.c src/linux/linux/fs/buffer.c +--- src/linux/linux.orig/fs/buffer.c 2003-07-04 04:12:05.000000000 -0400 ++++ src/linux/linux/fs/buffer.c 2004-05-31 02:21:05.000000000 -0400 +@@ -743,7 +743,7 @@ + bh->b_private = private; + } + +-static void end_buffer_io_async(struct buffer_head * bh, int uptodate) ++void end_buffer_io_async(struct buffer_head * bh, int uptodate) + { + static spinlock_t page_uptodate_lock = SPIN_LOCK_UNLOCKED; + unsigned long flags; +@@ -2344,35 +2344,6 @@ + return err; + } + +-int brw_page(int rw, struct page *page, kdev_t dev, int b[], int size) +-{ +- struct buffer_head *head, *bh; +- +- if (!PageLocked(page)) +- panic("brw_page: page not locked for I/O"); +- +- if (!page->buffers) +- create_empty_buffers(page, dev, size); +- head = bh = page->buffers; +- +- /* Stage 1: lock all the buffers */ +- do { +- lock_buffer(bh); +- bh->b_blocknr = *(b++); +- set_bit(BH_Mapped, &bh->b_state); +- set_buffer_async_io(bh); +- bh = bh->b_this_page; +- } while (bh != head); +- +- /* Stage 2: start the IO */ +- do { +- struct buffer_head *next = bh->b_this_page; +- submit_bh(rw, bh); +- bh = next; +- } while (bh != head); +- return 0; +-} +- + int block_symlink(struct inode *inode, const char *symname, int len) + { + struct address_space *mapping = inode->i_mapping; +diff -Nurb src/linux/linux.orig/fs/nfs/Makefile src/linux/linux/fs/nfs/Makefile +--- src/linux/linux.orig/fs/nfs/Makefile 2003-07-04 04:12:07.000000000 -0400 ++++ src/linux/linux/fs/nfs/Makefile 2004-05-31 02:18:03.000000000 -0400 +@@ -15,6 +15,14 @@ + obj-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o + obj-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o + +-obj-m := $(O_TARGET) ++obj-$(CONFIG_SWAP_VIA_NFS) += nfsswap.o ++ifeq ($(CONFIG_SWAP_VIA_NFS),m) ++export-objs := nfs_syms.o ++obj-y += nfs_syms.o ++endif ++ ++ifeq ($(CONFIG_NFS_FS),m) ++obj-m += $(O_TARGET) ++endif + + include $(TOPDIR)/Rules.make +diff -Nurb src/linux/linux.orig/fs/nfs/file.c src/linux/linux/fs/nfs/file.c +--- src/linux/linux.orig/fs/nfs/file.c 2003-07-04 04:12:07.000000000 -0400 ++++ src/linux/linux/fs/nfs/file.c 2004-05-31 02:18:03.000000000 -0400 +@@ -58,11 +58,6 @@ + setattr: nfs_notify_change, + }; + +-/* Hack for future NFS swap support */ +-#ifndef IS_SWAPFILE +-# define IS_SWAPFILE(inode) (0) +-#endif +- + /* + * Flush all dirty pages, and check for write errors. + * +@@ -217,8 +212,6 @@ + inode->i_ino, (unsigned long) count, (unsigned long) *ppos); + + result = -EBUSY; +- if (IS_SWAPFILE(inode)) +- goto out_swapfile; + result = nfs_revalidate_inode(NFS_SERVER(inode), inode); + if (result) + goto out; +@@ -230,10 +223,6 @@ + result = generic_file_write(file, buf, count, ppos); + out: + return result; +- +-out_swapfile: +- printk(KERN_INFO "NFS: attempt to write to active swap file!\n"); +- goto out; + } + + /* +diff -Nurb src/linux/linux.orig/fs/nfs/nfs_syms.c src/linux/linux/fs/nfs/nfs_syms.c +--- src/linux/linux.orig/fs/nfs/nfs_syms.c 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/fs/nfs/nfs_syms.c 2004-05-31 02:18:03.000000000 -0400 +@@ -0,0 +1,10 @@ ++#include <linux/config.h> ++#define __NO_VERSION__ ++#include <linux/module.h> ++#include <linux/types.h> ++#include <linux/sunrpc/clnt.h> ++#include <linux/nfs_fs.h> ++ ++EXPORT_SYMBOL(__nfs_refresh_inode); ++EXPORT_SYMBOL(nfs_write_attributes); ++ +diff -Nurb src/linux/linux.orig/fs/nfs/nfsswap.c src/linux/linux/fs/nfs/nfsswap.c +--- src/linux/linux.orig/fs/nfs/nfsswap.c 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/fs/nfs/nfsswap.c 2004-05-31 02:18:03.000000000 -0400 +@@ -0,0 +1,350 @@ ++/* ++ * Swapping to files located on NFS mounted volumes ++ * Copyright (c) 2000 Claus-Justus Heine ++ * ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/types.h> ++#include <linux/slab.h> ++#include <linux/swap.h> ++#include <linux/pagemap.h> ++#include <linux/file.h> ++#include <linux/fs.h> ++#include <linux/socket.h> ++#include <linux/smp_lock.h> ++#include <net/netswapping.h> ++#include <net/sock.h> ++ ++#include <linux/sunrpc/clnt.h> ++#include <linux/nfs_fs.h> ++#include <linux/nfs_fs_sb.h> ++#include <asm/uaccess.h> ++ ++#define NFSDBG_FACILITY NFSDBG_SWAP ++ ++#define NFS_SWAP_ID "nfs file" ++ ++/* we cache some values here. In principle, we only need the file. ++ */ ++struct nfs_swap_data { ++ struct file *file; ++ struct inode *inode; ++ struct nfs_server *server; ++ struct socket *socket; ++}; ++ ++/* Nearly a clone of nfs_readpage_sync() in read.c, but "struct page" does not ++ * contain information about the file offset when swapping. So. ++ */ ++static int nfs_read_swap_page(struct page *page, ++ struct nfs_server *server, ++ struct inode *inode, ++ struct file *file) ++{ ++ unsigned int rsize = server->rsize; ++ unsigned int count = PAGE_SIZE; ++ unsigned int offset = 0; /* always at start of page */ ++ int result, eof; ++ struct rpc_cred *cred; ++ struct nfs_fattr fattr; ++ ++ cred = nfs_file_cred(file); ++ ++ do { ++ if (count < rsize) ++ rsize = count; ++ ++ lock_kernel(); ++ result = NFS_PROTO(inode)->read(inode, cred, ++ &fattr, ++ NFS_RPC_SWAPFLAGS, ++ offset, rsize, page, &eof); ++ nfs_refresh_inode(inode, &fattr); ++ unlock_kernel(); ++ ++ /* ++ * Even if we had a partial success we can't mark the page ++ * cache valid. ++ */ ++ if (result < 0) { ++ if (result == -EISDIR) ++ result = -EINVAL; ++ goto io_error; ++ } ++ count -= result; ++ offset += result; ++ if (result < rsize) /* NFSv2ism */ ++ break; ++ } while (count); ++ ++ if (count) { ++ char *kaddr = kmap(page); ++ memset(kaddr + offset, 0, count); ++ kunmap(page); ++ } ++ flush_dcache_page(page); ++ result = 0; ++ ++io_error: ++ return result; ++} ++ ++/* Like nfs_writepage_sync(), but when swapping page->index does not encode ++ * the offset in the swap file alone. ++ * ++ */ ++static int nfs_write_swap_page(struct page *page, ++ struct nfs_server *server, ++ struct inode *inode, ++ struct file *file) ++{ ++ struct rpc_cred *cred; ++ unsigned int wsize = server->wsize; ++ unsigned int count = PAGE_SIZE; ++ unsigned int offset = 0; ++ int result; ++ struct nfs_writeverf verf; ++ struct nfs_fattr fattr; ++ ++ cred = nfs_file_cred(file); ++ ++ do { ++ if (count < wsize) ++ wsize = count; ++ ++ lock_kernel(); ++ result = NFS_PROTO(inode)->write(inode, cred, &fattr, ++ NFS_RW_SWAP|NFS_RW_SYNC, ++ offset, wsize, page, &verf); ++ nfs_write_attributes(inode, &fattr); ++ unlock_kernel(); ++ ++ if (result < 0) { ++ goto io_error; ++ } ++ if (result != wsize) ++ printk("NFS: short write, wsize=%u, result=%d\n", ++ wsize, result); ++ offset += wsize; ++ count -= wsize; ++ /* ++ * If we've extended the file, update the inode ++ * now so we don't invalidate the cache. ++ */ ++ if (offset > inode->i_size) ++ inode->i_size = offset; ++ } while (count); ++ ++ result = 0; ++ ++io_error: ++ ++ return result; ++} ++ ++/* Unluckily (for us) form 2.4.19 -> 2.4.20 the nfs-proc's where ++ * changed and expect now a proper file-mapping page, where index ++ * encodes the offset alone. ++ * ++ * What we do: we save the original value of page->index, initialize ++ * page->index to what the NFS/sun-rpc subsystem expects and restore ++ * the index later. ++ */ ++static int nfs_rw_swap_page(int rw, struct page *page, ++ unsigned long offset, void *dptr) ++{ ++ int error; ++ struct nfs_swap_data *data = dptr; ++ unsigned long alloc_flag = current->flags & PF_MEMALLOC; ++ unsigned long page_index; ++ ++ if (!PageLocked(page)) ++ panic("nfs_rw_swap_page: page not locked for I/O"); ++ ++ /* prevent memory deadlocks */ ++ if (!(current->flags & PF_MEMALLOC)) { ++ dprintk("nfs_rw_swap_page: Setting PF_MEMALLOC\n"); ++ } ++ current->flags |= PF_MEMALLOC; ++ ++ /* now tweak the page->index field ... */ ++ page_index = page->index; ++ page->index = ((loff_t)offset*(loff_t)PAGE_SIZE) >> PAGE_CACHE_SHIFT; ++ ++ if (rw == WRITE) { ++ error = nfs_write_swap_page(page, ++ data->server, ++ data->inode, ++ data->file); ++ } else { ++ error = nfs_read_swap_page(page, ++ data->server, ++ data->inode, ++ data->file); ++ } ++ ++ if (!alloc_flag) { ++ current->flags &= ~PF_MEMALLOC; ++ } ++ ++ /* now restore the page->index field ... */ ++ page->index = page_index; ++ ++ if (error) { ++ /* Must mark the page invalid after I/O error */ ++ SetPageError(page); ++ ClearPageUptodate(page); ++ } else { ++ ClearPageError(page); ++ SetPageUptodate(page); ++ } ++ ++ if (!error) { /* in case of an error rw_swap_page() likes to unlock ++ * itself. ++ */ ++ UnlockPage(page); ++ } ++ ++ return error < 0 ? 0 : 1; ++} ++ ++static int is_nfsfile_swapping(unsigned int flags, ++ struct file * swapf, ++ void * data) ++{ ++ struct file * filp = (struct file *) data; ++ ++ /* Only check filp's that don't match the one already opened ++ * for us by sys_swapon(). Otherwise, we will always flag a ++ * busy swap file. ++ */ ++ ++ if (swapf != filp) { ++ if (filp->f_dentry->d_inode == swapf->f_dentry->d_inode) ++ return 1; ++ } ++ return 0; ++} ++ ++static int nfs_swap_open(struct file *swapf, void **dptr) ++{ ++ int error = 0; ++ int swapfilesize; ++ struct nfs_swap_data *data; ++ int on = 1; ++ mm_segment_t fs; ++ struct inode *inode = swapf->f_dentry->d_inode; ++ ++ MOD_INC_USE_COUNT; ++ ++ if (!S_ISREG(inode->i_mode)) { ++ dprintk("nfs_swap_open: can't handle this swap file: %s\n", ++ swapf->f_dentry->d_name.name); ++ error = 0; /* not for us */ ++ goto bad_swap; ++ } ++ /* determine whether this file really is located on an NFS mounted ++ * volume ++ */ ++ if (!inode->i_sb || inode->i_sb->s_magic != NFS_SUPER_MAGIC) { ++ dprintk("nfs_swap_open: %s is not an NFS file.\n", ++ swapf->f_dentry->d_name.name); ++ error = 0; /* not for us */ ++ goto bad_swap; ++ } ++ ++ if (swap_run_test(is_nfsfile_swapping, swapf)) { ++ dprintk("nfs_swap_open: already swapping to %s\n", ++ swapf->f_dentry->d_name.name); ++ error = -EBUSY; ++ goto bad_swap; ++ } ++ swapfilesize = inode->i_size >> PAGE_SHIFT; ++ if ((data = kmalloc(sizeof(*data), GFP_KERNEL)) == NULL) { ++ error = -ENOMEM; ++ goto bad_swap; ++ } ++ data->file = swapf; ++ data->inode = inode; ++ data->server = NFS_SERVER(inode); ++ data->socket = data->server->client->cl_xprt->sock; ++ ++ /* set socket option SO_SWAPPING */ ++ fs = get_fs(); ++ set_fs(KERNEL_DS); ++ error = sock_setsockopt(data->socket, SOL_SOCKET, SO_SWAPPING, ++ (char *)&on, sizeof(on)); ++ set_fs(fs); ++ if (error) { ++ dprintk("nfs_swap_open: error setting SO_SWAPPING\n"); ++ goto bad_swap_2; ++ } ++ ++ *dptr = data; ++ return swapfilesize; ++ ++ bad_swap_2: ++ kfree(data); ++ bad_swap: ++ MOD_DEC_USE_COUNT; ++ return error; ++} ++ ++static int nfs_swap_release(struct file *swapf, void *dptr) ++{ ++ struct nfs_swap_data *data = (struct nfs_swap_data *)dptr; ++ int off = 0; ++ mm_segment_t fs; ++ int error; ++ ++#if 1 ++ if (swapf != data->file || ++ swapf->f_dentry->d_inode != data->inode || ++ !swapf->f_dentry->d_inode->i_sb || ++ swapf->f_dentry->d_inode->i_sb->s_magic != NFS_SUPER_MAGIC || ++ NFS_SERVER(swapf->f_dentry->d_inode) != data->server || ++ data->socket != data->server->client->cl_xprt->sock) { ++ panic("nfs_swap_release: nfs swap data messed up"); ++ } ++#endif ++ ++ /* remove socket option SO_SWAPPING */ ++ fs = get_fs(); ++ set_fs(KERNEL_DS); ++ error = sock_setsockopt(data->socket, SOL_SOCKET, SO_SWAPPING, ++ (char *)&off, sizeof(off)); ++ set_fs(fs); ++ if (error) { ++ dprintk("nfs_swap_open: error clearing SO_SWAPPING\n"); ++ } ++ kfree(data); ++ MOD_DEC_USE_COUNT; ++ return error; ++} ++ ++static struct swap_ops nfs_swap_ops = { ++ open: nfs_swap_open, ++ release: nfs_swap_release, ++ rw_page: nfs_rw_swap_page ++}; ++ ++int __init nfs_swap_init(void) ++{ ++ (void)register_swap_method(NFS_SWAP_ID, &nfs_swap_ops); ++ return 0; ++} ++ ++void __exit nfs_swap_exit(void) ++{ ++ unregister_swap_method(NFS_SWAP_ID); ++} ++ ++module_init(nfs_swap_init) ++module_exit(nfs_swap_exit) ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("(c) 1996-2002 cH (Claus-Justus Heine)"); ++MODULE_DESCRIPTION("Swapping to files located on volumes mounted via NFS"); +diff -Nurb src/linux/linux.orig/fs/nfs/read.c src/linux/linux/fs/nfs/read.c +--- src/linux/linux.orig/fs/nfs/read.c 2003-07-04 04:12:08.000000000 -0400 ++++ src/linux/linux/fs/nfs/read.c 2004-05-31 02:18:03.000000000 -0400 +@@ -50,11 +50,6 @@ + */ + static void nfs_readpage_result(struct rpc_task *task); + +-/* Hack for future NFS swap support */ +-#ifndef IS_SWAPFILE +-# define IS_SWAPFILE(inode) (0) +-#endif +- + static kmem_cache_t *nfs_rdata_cachep; + + static __inline__ struct nfs_read_data *nfs_readdata_alloc(void) +@@ -92,7 +87,6 @@ + int rsize = NFS_SERVER(inode)->rsize; + int result; + int count = PAGE_CACHE_SIZE; +- int flags = IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0; + int eof; + + dprintk("NFS: nfs_readpage_sync(%p)\n", page); +@@ -114,7 +108,7 @@ + offset, rsize, page); + + lock_kernel(); +- result = NFS_PROTO(inode)->read(inode, cred, &fattr, flags, ++ result = NFS_PROTO(inode)->read(inode, cred, &fattr, 0, + offset, rsize, page, &eof); + nfs_refresh_inode(inode, &fattr); + unlock_kernel(); +@@ -246,7 +240,7 @@ + task = &data->task; + + /* N.B. Do we need to test? Never called for swapfile inode */ +- flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); ++ flags = RPC_TASK_ASYNC; + + nfs_read_rpcsetup(head, data); + +@@ -476,8 +470,6 @@ + } + + error = nfs_readpage_sync(file, inode, page); +- if (error < 0 && IS_SWAPFILE(inode)) +- printk("Aiee.. nfs swap-in of page failed!\n"); + out: + return error; + +diff -Nurb src/linux/linux.orig/fs/nfs/write.c src/linux/linux/fs/nfs/write.c +--- src/linux/linux.orig/fs/nfs/write.c 2003-07-04 04:12:08.000000000 -0400 ++++ src/linux/linux/fs/nfs/write.c 2004-05-31 02:20:47.000000000 -0400 +@@ -3,7 +3,6 @@ + #include <linux/config.h> + #include <linux/types.h> + #include <linux/slab.h> +-#include <linux/swap.h> + #include <linux/pagemap.h> + #include <linux/file.h> + +@@ -46,11 +45,6 @@ + static void nfs_commit_done(struct rpc_task *); + #endif + +-/* Hack for future NFS swap support */ +-#ifndef IS_SWAPFILE +-# define IS_SWAPFILE(inode) (0) +-#endif +- + static kmem_cache_t *nfs_wdata_cachep; + + static __inline__ struct nfs_write_data *nfs_writedata_alloc(void) +@@ -82,7 +76,7 @@ + * For the moment, we just call nfs_refresh_inode(). + */ + static __inline__ int +-nfs_write_attributes(struct inode *inode, struct nfs_fattr *fattr) ++__nfs_write_attributes(struct inode *inode, struct nfs_fattr *fattr) + { + if ((fattr->valid & NFS_ATTR_FATTR) && !(fattr->valid & NFS_ATTR_WCC)) { + fattr->pre_size = NFS_CACHE_ISIZE(inode); +@@ -93,6 +87,11 @@ + return nfs_refresh_inode(inode, fattr); + } + ++int nfs_write_attributes(struct inode *inode, struct nfs_fattr *fattr) ++{ ++ return __nfs_write_attributes(inode, fattr); ++} ++ + /* + * Write a page synchronously. + * Offset is the data offset within the page. +@@ -104,8 +103,7 @@ + struct rpc_cred *cred = NULL; + loff_t base; + unsigned int wsize = NFS_SERVER(inode)->wsize; +- int result, refresh = 0, written = 0, flags; +- u8 *buffer; ++ int result, refresh = 0, written = 0; + struct nfs_fattr fattr; + struct nfs_writeverf verf; + +@@ -121,15 +119,14 @@ + + base = page_offset(page) + offset; + +- flags = ((IS_SWAPFILE(inode)) ? NFS_RW_SWAP : 0) | NFS_RW_SYNC; +- + do { +- if (count < wsize && !IS_SWAPFILE(inode)) ++ if (count < wsize) + wsize = count; + +- result = NFS_PROTO(inode)->write(inode, cred, &fattr, flags, ++ result = NFS_PROTO(inode)->write(inode, cred, &fattr, ++ NFS_RW_SYNC, + offset, wsize, page, &verf); +- nfs_write_attributes(inode, &fattr); ++ __nfs_write_attributes(inode, &fattr); + + if (result < 0) { + /* Must mark the page invalid after I/O error */ +@@ -140,7 +137,6 @@ + printk("NFS: short write, wsize=%u, result=%d\n", + wsize, result); + refresh = 1; +- buffer += wsize; + base += wsize; + offset += wsize; + written += wsize; +@@ -979,7 +975,7 @@ + } + #endif + +- nfs_write_attributes(inode, resp->fattr); ++ __nfs_write_attributes(inode, resp->fattr); + while (!list_empty(&data->pages)) { + req = nfs_list_entry(data->pages.next); + nfs_list_remove_request(req); +@@ -1133,7 +1129,7 @@ + if (nfs_async_handle_jukebox(task)) + return; + +- nfs_write_attributes(inode, resp->fattr); ++ __nfs_write_attributes(inode, resp->fattr); + while (!list_empty(&data->pages)) { + req = nfs_list_entry(data->pages.next); + nfs_list_remove_request(req); +diff -Nurb src/linux/linux.orig/include/linux/fs.h src/linux/linux/include/linux/fs.h +--- src/linux/linux.orig/include/linux/fs.h 2004-05-31 02:06:19.000000000 -0400 ++++ src/linux/linux/include/linux/fs.h 2004-05-31 02:18:03.000000000 -0400 +@@ -1500,6 +1500,10 @@ + extern int inode_change_ok(struct inode *, struct iattr *); + extern int inode_setattr(struct inode *, struct iattr *); + ++/* for swapping to block devices */ ++void create_empty_buffers(struct page *page, kdev_t dev, unsigned long blocksize); ++void end_buffer_io_async(struct buffer_head * bh, int uptodate); ++ + /* + * Common dentry functions for inclusion in the VFS + * or in other stackable file systems. Some of these +diff -Nurb src/linux/linux.orig/include/linux/nfs_fs.h src/linux/linux/include/linux/nfs_fs.h +--- src/linux/linux.orig/include/linux/nfs_fs.h 2004-05-31 02:06:28.000000000 -0400 ++++ src/linux/linux/include/linux/nfs_fs.h 2004-05-31 02:18:03.000000000 -0400 +@@ -40,8 +40,8 @@ + */ + #define NFS_MAX_DIRCACHE 16 + +-#define NFS_MAX_FILE_IO_BUFFER_SIZE 32768 +-#define NFS_DEF_FILE_IO_BUFFER_SIZE 4096 ++#define NFS_MAX_FILE_IO_BUFFER_SIZE (8*PAGE_SIZE) ++#define NFS_DEF_FILE_IO_BUFFER_SIZE PAGE_SIZE + + /* + * The upper limit on timeouts for the exponential backoff algorithm. +@@ -205,6 +205,8 @@ + extern int nfs_writepage(struct page *); + extern int nfs_flush_incompatible(struct file *file, struct page *page); + extern int nfs_updatepage(struct file *, struct page *, unsigned int, unsigned int); ++extern int nfs_write_attributes(struct inode *inode, struct nfs_fattr *fattr); ++ + /* + * Try to write back everything synchronously (but check the + * return value!) +@@ -375,6 +377,7 @@ + #define NFSDBG_XDR 0x0020 + #define NFSDBG_FILE 0x0040 + #define NFSDBG_ROOT 0x0080 ++#define NFSDBG_SWAP 0x0100 + #define NFSDBG_ALL 0xFFFF + + #ifdef __KERNEL__ +diff -Nurb src/linux/linux.orig/include/linux/slab.h src/linux/linux/include/linux/slab.h +--- src/linux/linux.orig/include/linux/slab.h 2004-05-31 02:06:19.000000000 -0400 ++++ src/linux/linux/include/linux/slab.h 2004-05-31 02:18:03.000000000 -0400 +@@ -39,6 +39,7 @@ + #define SLAB_HWCACHE_ALIGN 0x00002000UL /* align objs on a h/w cache lines */ + #define SLAB_CACHE_DMA 0x00004000UL /* use GFP_DMA memory */ + #define SLAB_MUST_HWCACHE_ALIGN 0x00008000UL /* force alignment */ ++#define SLAB_LOW_GFP_ORDER 0x00010000UL /* use as low a gfp order as possible */ + + /* flags passed to a constructor func */ + #define SLAB_CTOR_CONSTRUCTOR 0x001UL /* if not set, then deconstructor */ +diff -Nurb src/linux/linux.orig/include/linux/swap.h src/linux/linux/include/linux/swap.h +--- src/linux/linux.orig/include/linux/swap.h 2004-05-31 02:06:19.000000000 -0400 ++++ src/linux/linux/include/linux/swap.h 2004-05-31 02:18:03.000000000 -0400 +@@ -58,15 +58,29 @@ + #define SWAP_MAP_MAX 0x7fff + #define SWAP_MAP_BAD 0x8000 + ++struct swap_ops { ++ int (*open)(struct file *swapf, void **data); ++ int (*release)(struct file *swapf, void *data); ++ int (*rw_page)(int rw, ++ struct page *page, unsigned long offset, void *data); ++}; ++ ++struct swap_method { ++ struct swap_method *next; ++ char * name; ++ struct swap_ops *ops; ++ int use_count; ++}; ++ + /* + * The in-memory structure used to track swap areas. + */ + struct swap_info_struct { + unsigned int flags; +- kdev_t swap_device; ++ struct file *swap_file; ++ struct swap_method *method; ++ void *data; + spinlock_t sdev_lock; +- struct dentry * swap_file; +- struct vfsmount *swap_vfsmnt; + unsigned short * swap_map; + unsigned int lowest_bit; + unsigned int highest_bit; +@@ -141,11 +155,15 @@ + extern int total_swap_pages; + extern unsigned int nr_swapfiles; + extern struct swap_info_struct swap_info[]; +-extern int is_swap_partition(kdev_t); ++extern int register_swap_method(char *name, struct swap_ops *ops); ++extern int unregister_swap_method(char *name); ++extern int swap_run_test(int (*test_fct)(unsigned int flags, ++ struct file *swap_file, ++ void *testdata), void *testdata); + extern void si_swapinfo(struct sysinfo *); + extern swp_entry_t get_swap_page(void); +-extern void get_swaphandle_info(swp_entry_t, unsigned long *, kdev_t *, +- struct inode **); ++struct swap_method *get_swaphandle_info(swp_entry_t entry, ++ unsigned long *offset, void **data); + extern int swap_duplicate(swp_entry_t); + extern int swap_count(struct page *); + extern int valid_swaphandles(swp_entry_t, unsigned long *); +diff -Nurb src/linux/linux.orig/include/net/netswapping.h src/linux/linux/include/net/netswapping.h +--- src/linux/linux.orig/include/net/netswapping.h 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/include/net/netswapping.h 2004-05-31 02:18:03.000000000 -0400 +@@ -0,0 +1,47 @@ ++#ifndef _LINUX_NETSWAPPING_H ++#define _LINUX_NETSWAPPING_H ++ ++#include <linux/swap.h> ++#include <linux/init.h> ++ ++/* It is a mess. Socket options are defined in asm-ARCH/socket.h */ ++ ++#define SO_SWAPPING 0x00100000 /* hopefully not used by anybody else */ ++ ++#ifdef __KERNEL__ ++ ++#define CTL_NETSWAP 0x00100000 ++ ++enum { ++ NET_SWAP_DROPPED = 1, ++ NET_SWAP_DROP_THRESHOLD = 2, ++ NET_SWAP_SOCK_COUNT = 3 ++}; ++ ++extern unsigned int netswap_free_pages_min; ++extern int netswap_sock_count; ++extern unsigned int netswap_dropped; ++ ++/* this is "#defined" and not inline because sock.h includes us, but we need ++ * the "struct sock" definition. ++ */ ++#define netswap_low_memory(sk, skb) \ ++({ \ ++ int _ret = 0; \ ++ \ ++ if (netswap_sock_count > 0 && /* anybody swapping via network? */ \ ++ !(sk)->swapping && /* but we are not needed for swapping */ \ ++ nr_free_pages() < netswap_free_pages_min) { /* so drop us */ \ ++ printk("netswap_low_memory: " \ ++ "dropping skb 0x%p@0x%p\n", skb, sk); \ ++ netswap_dropped ++; \ ++ _ret = 1; \ ++ } \ ++ _ret; \ ++}) ++ ++extern int __init netswap_init(void); ++ ++#endif ++ ++#endif +diff -Nurb src/linux/linux.orig/include/net/sock.h src/linux/linux/include/net/sock.h +--- src/linux/linux.orig/include/net/sock.h 2004-05-31 02:07:17.000000000 -0400 ++++ src/linux/linux/include/net/sock.h 2004-05-31 02:18:03.000000000 -0400 +@@ -103,6 +103,10 @@ + #include <linux/filter.h> + #endif + ++#ifdef CONFIG_NETSWAP ++#include <net/netswapping.h> ++#endif ++ + #include <asm/atomic.h> + #include <net/dst.h> + +@@ -536,6 +540,12 @@ + no_check, + broadcast, + bsdism; ++#ifdef CONFIG_NETSWAP ++ /* Increased by SO_SWAPPING with arg != 0, decreased by ++ * SO_SWAPPING with arg 0 ++ */ ++ int swapping; ++#endif + unsigned char debug; + unsigned char rcvtstamp; + unsigned char use_write_queue; +@@ -1165,6 +1175,11 @@ + return err; /* Toss packet */ + } + #endif /* CONFIG_FILTER */ ++#ifdef CONFIG_NETSWAP ++ /* an inline function defined in net/netswapping.h */ ++ if (netswap_low_memory(sk, skb)) ++ return -ENOMEM; ++#endif /* CONFIG_NETSWAP */ + + skb->dev = NULL; + skb_set_owner_r(skb, sk); +diff -Nurb src/linux/linux.orig/kernel/ksyms.c src/linux/linux/kernel/ksyms.c +--- src/linux/linux.orig/kernel/ksyms.c 2004-05-31 02:02:43.000000000 -0400 ++++ src/linux/linux/kernel/ksyms.c 2004-05-31 02:18:03.000000000 -0400 +@@ -41,6 +41,7 @@ + #include <linux/mm.h> + #include <linux/capability.h> + #include <linux/highuid.h> ++#include <linux/swapctl.h> + #include <linux/brlock.h> + #include <linux/fs.h> + #include <linux/tty.h> +@@ -127,6 +128,11 @@ + EXPORT_SYMBOL(kmap_prot); + EXPORT_SYMBOL(kmap_pte); + #endif ++EXPORT_SYMBOL(nr_free_pages); ++/* EXPORT_SYMBOL(freepages); */ ++EXPORT_SYMBOL(register_swap_method); ++EXPORT_SYMBOL(unregister_swap_method); ++EXPORT_SYMBOL(swap_run_test); + + /* filesystem internal functions */ + EXPORT_SYMBOL(def_blk_fops); +@@ -531,7 +537,7 @@ + EXPORT_SYMBOL(make_bad_inode); + EXPORT_SYMBOL(is_bad_inode); + EXPORT_SYMBOL(event); +-EXPORT_SYMBOL(brw_page); ++EXPORT_SYMBOL(end_buffer_io_async); + EXPORT_SYMBOL(__inode_dir_notify); + + #ifdef CONFIG_UID16 +diff -Nurb src/linux/linux.orig/mm/page_io.c src/linux/linux/mm/page_io.c +--- src/linux/linux.orig/mm/page_io.c 2003-07-04 04:12:29.000000000 -0400 ++++ src/linux/linux/mm/page_io.c 2004-05-31 02:18:03.000000000 -0400 +@@ -36,11 +36,8 @@ + static int rw_swap_page_base(int rw, swp_entry_t entry, struct page *page) + { + unsigned long offset; +- int zones[PAGE_SIZE/512]; +- int zones_used; +- kdev_t dev = 0; +- int block_size; +- struct inode *swapf = 0; ++ struct swap_method *method; ++ void *data; + + if (rw == READ) { + ClearPageUptodate(page); +@@ -48,30 +45,11 @@ + } else + kstat.pswpout++; + +- get_swaphandle_info(entry, &offset, &dev, &swapf); +- if (dev) { +- zones[0] = offset; +- zones_used = 1; +- block_size = PAGE_SIZE; +- } else if (swapf) { +- int i, j; +- unsigned int block = offset +- << (PAGE_SHIFT - swapf->i_sb->s_blocksize_bits); +- +- block_size = swapf->i_sb->s_blocksize; +- for (i=0, j=0; j< PAGE_SIZE ; i++, j += block_size) +- if (!(zones[i] = bmap(swapf,block++))) { +- printk("rw_swap_page: bad swap file\n"); +- return 0; +- } +- zones_used = i; +- dev = swapf->i_dev; +- } else { ++ method = get_swaphandle_info(entry, &offset, &data); ++ if (!method || !method->ops->rw_page(rw, page, offset, data)) { + return 0; + } + +- /* block_size == PAGE_SIZE/zones_used */ +- brw_page(rw, page, dev, zones, block_size); + return 1; + } + +diff -Nurb src/linux/linux.orig/mm/slab.c src/linux/linux/mm/slab.c +--- src/linux/linux.orig/mm/slab.c 2003-07-04 04:12:29.000000000 -0400 ++++ src/linux/linux/mm/slab.c 2004-05-31 02:18:03.000000000 -0400 +@@ -111,10 +111,12 @@ + # define CREATE_MASK (SLAB_DEBUG_INITIAL | SLAB_RED_ZONE | \ + SLAB_POISON | SLAB_HWCACHE_ALIGN | \ + SLAB_NO_REAP | SLAB_CACHE_DMA | \ +- SLAB_MUST_HWCACHE_ALIGN) ++ SLAB_MUST_HWCACHE_ALIGN | \ ++ SLAB_LOW_GFP_ORDER) + #else + # define CREATE_MASK (SLAB_HWCACHE_ALIGN | SLAB_NO_REAP | \ +- SLAB_CACHE_DMA | SLAB_MUST_HWCACHE_ALIGN) ++ SLAB_CACHE_DMA | SLAB_MUST_HWCACHE_ALIGN | \ ++ SLAB_LOW_GFP_ORDER) + #endif + + /* +@@ -247,8 +249,13 @@ + }; + + /* internal c_flags */ +-#define CFLGS_OFF_SLAB 0x010000UL /* slab management in own cache */ +-#define CFLGS_OPTIMIZE 0x020000UL /* optimized slab lookup */ ++#define CFLGS_OFF_SLAB 0x020000UL /* slab management in own cache */ ++#define CFLGS_OPTIMIZE 0x040000UL /* optimized slab lookup */ ++#define CFLGS_MASK (CFLGS_OFF_SLAB | CFLGS_OPTIMIZE) ++ ++#if (CFLGS_MASK & CREATE_MASK) ++# error BUG: internal and external SLAB flags overlap ++#endif + + /* c_dflags (dynamic flags). Need to hold the spinlock to access this member */ + #define DFLGS_GROWN 0x000001UL /* don't reap a recently grown */ +@@ -452,7 +459,12 @@ + snprintf(name, sizeof(name), "size-%Zd",sizes->cs_size); + if (!(sizes->cs_cachep = + kmem_cache_create(name, sizes->cs_size, +- 0, SLAB_HWCACHE_ALIGN, NULL, NULL))) { ++ 0, ++#if CONFIG_NETSWAP ++ SLAB_LOW_GFP_ORDER| /* sorry */ ++#endif ++ SLAB_HWCACHE_ALIGN, ++ NULL, NULL))) { + BUG(); + } + +@@ -731,6 +743,8 @@ + break; + if (!cachep->num) + goto next; ++ if (cachep->gfporder == 0 && (flags & SLAB_LOW_GFP_ORDER)) ++ break; + if (flags & CFLGS_OFF_SLAB && cachep->num > offslab_limit) { + /* Oops, this num of objs will cause problems. */ + cachep->gfporder--; +diff -Nurb src/linux/linux.orig/mm/swapfile.c src/linux/linux/mm/swapfile.c +--- src/linux/linux.orig/mm/swapfile.c 2003-07-04 04:12:29.000000000 -0400 ++++ src/linux/linux/mm/swapfile.c 2004-05-31 02:18:03.000000000 -0400 +@@ -11,12 +11,17 @@ + #include <linux/swap.h> + #include <linux/swapctl.h> + #include <linux/blkdev.h> /* for blk_size */ ++#include <linux/file.h> + #include <linux/vmalloc.h> + #include <linux/pagemap.h> + #include <linux/shm.h> + + #include <asm/pgtable.h> + ++#ifdef CONFIG_KMOD ++#include <linux/kmod.h> ++#endif ++ + spinlock_t swaplock = SPIN_LOCK_UNLOCKED; + unsigned int nr_swapfiles; + int total_swap_pages; +@@ -31,8 +36,78 @@ + + struct swap_info_struct swap_info[MAX_SWAPFILES]; + ++static struct swap_method *swap_methods = NULL; ++ + #define SWAPFILE_CLUSTER 256 + ++int register_swap_method(char *name, struct swap_ops *ops) ++{ ++ struct swap_method *pos; ++ struct swap_method *new; ++ int result = 0; ++ ++ lock_kernel(); ++ ++ for (pos = swap_methods; pos; pos = pos->next) { ++ if (strcmp(pos->name, name) == 0) { ++ printk(KERN_ERR "register_swap_method: " ++ "method %s already registered\n", name); ++ result = -EBUSY; ++ goto out; ++ } ++ } ++ ++ if (!(new = kmalloc(sizeof(*new), GFP_KERNEL))) { ++ printk(KERN_ERR "register_swap_method: " ++ "no memory for new method \"%s\"\n", name); ++ result = -ENOMEM; ++ goto out; ++ } ++ ++ new->name = name; ++ new->ops = ops; ++ new->use_count = 0; ++ ++ /* ok, insert at top of list */ ++ printk("register_swap_method: method %s\n", name); ++ new->next = swap_methods; ++ swap_methods = new; ++ out: ++ unlock_kernel(); ++ return result; ++} ++ ++int unregister_swap_method(char *name) ++{ ++ struct swap_method **method, *next; ++ int result = 0; ++ ++ lock_kernel(); ++ ++ for (method = &swap_methods; *method; method = &(*method)->next) { ++ if (strcmp((*method)->name, name) == 0) { ++ if ((*method)->use_count > 0) { ++ printk(KERN_ERR "unregister_swap_method: " ++ "method \"%s\" is in use\n", name); ++ result = -EBUSY; ++ goto out; ++ } ++ ++ next = (*method)->next; ++ kfree(*method); ++ *method = next; ++ printk("unregister_swap_method: method %s\n", name); ++ goto out; ++ } ++ } ++ /* not found */ ++ printk("unregister_swap_method: no such method %s\n", name); ++ result = -ENOENT; ++ out: ++ unlock_kernel(); ++ return result; ++} ++ + static inline int scan_swap_map(struct swap_info_struct *si) + { + unsigned long offset; +@@ -711,13 +786,14 @@ + struct nameidata nd; + int i, type, prev; + int err; ++ struct file *swap_file; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + err = user_path_walk(specialfile, &nd); + if (err) +- goto out; ++ return err; + + lock_kernel(); + prev = -1; +@@ -725,15 +801,20 @@ + for (type = swap_list.head; type >= 0; type = swap_info[type].next) { + p = swap_info + type; + if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) { +- if (p->swap_file == nd.dentry) ++ if (p->swap_file && ++ p->swap_file->f_dentry == nd.dentry) + break; + } + prev = type; + } + err = -EINVAL; ++ /* p->swap_file contains all needed info, no need to keep nd, so ++ * release it now. ++ */ ++ path_release(&nd); + if (type < 0) { + swap_list_unlock(); +- goto out_dput; ++ goto out; + } + + if (prev < 0) { +@@ -767,32 +848,30 @@ + total_swap_pages += p->pages; + p->flags = SWP_WRITEOK; + swap_list_unlock(); +- goto out_dput; ++ goto out; + } +- if (p->swap_device) +- blkdev_put(p->swap_file->d_inode->i_bdev, BDEV_SWAP); +- path_release(&nd); + ++ if (p->method->ops->release) ++ p->method->ops->release(p->swap_file, p->data); + swap_list_lock(); + swap_device_lock(p); +- nd.mnt = p->swap_vfsmnt; +- nd.dentry = p->swap_file; +- p->swap_vfsmnt = NULL; ++ p->method->use_count --; ++ p->method = NULL; ++ p->data = NULL; ++ swap_file = p->swap_file; + p->swap_file = NULL; +- p->swap_device = 0; + p->max = 0; + swap_map = p->swap_map; + p->swap_map = NULL; + p->flags = 0; + swap_device_unlock(p); + swap_list_unlock(); ++ filp_close(swap_file, NULL); + vfree(swap_map); + err = 0; + +-out_dput: +- unlock_kernel(); +- path_release(&nd); + out: ++ unlock_kernel(); + return err; + } + +@@ -805,18 +884,17 @@ + if (!page) + return -ENOMEM; + +- len += sprintf(buf, "Filename\t\t\tType\t\tSize\tUsed\tPriority\n"); ++ len += sprintf(buf, "%-32s%-16s%-8s%-8sPriority\n", ++ "Filename", "Type", "Size", "Used"); + for (i = 0 ; i < nr_swapfiles ; i++, ptr++) { + if ((ptr->flags & SWP_USED) && ptr->swap_map) { +- char * path = d_path(ptr->swap_file, ptr->swap_vfsmnt, ++ char * path = d_path(ptr->swap_file->f_dentry, ++ ptr->swap_file->f_vfsmnt, + page, PAGE_SIZE); + + len += sprintf(buf + len, "%-31s ", path); + +- if (!ptr->swap_device) +- len += sprintf(buf + len, "file\t\t"); +- else +- len += sprintf(buf + len, "partition\t"); ++ len += sprintf(buf + len, "%-15s ", ptr->method->name); + + usedswap = 0; + for (j = 0; j < ptr->max; ++j) +@@ -827,7 +905,7 @@ + default: + usedswap++; + } +- len += sprintf(buf + len, "%d\t%d\t%d\n", ptr->pages << (PAGE_SHIFT - 10), ++ len += sprintf(buf + len, "%-8d%-8d%d\n", ptr->pages << (PAGE_SHIFT - 10), + usedswap << (PAGE_SHIFT - 10), ptr->prio); + } + } +@@ -835,18 +913,55 @@ + return len; + } + +-int is_swap_partition(kdev_t dev) { ++/* apply a test function to all active swap objects. E.g. for checking ++ * whether a partition is used for swapping ++ */ ++int swap_run_test(int (*test_fct)(unsigned int flags, ++ struct file * swap_file, ++ void *testdata), void *testdata) ++{ + struct swap_info_struct *ptr = swap_info; + int i; + + for (i = 0 ; i < nr_swapfiles ; i++, ptr++) { +- if (ptr->flags & SWP_USED) +- if (ptr->swap_device == dev) ++ if (ptr->swap_file && ++ test_fct(ptr->flags, ptr->swap_file, testdata)) + return 1; + } + return 0; + } + ++/* Walk through the list of known swap method until somebody wants to ++ * handle this file. Pick the first one which claims to be able to ++ * swap to this kind of file. ++ * ++ * return value: < 0: error, 0: not found, > 0: swapfilesize ++ */ ++int find_swap_method(struct file *swap_file, ++ struct swap_info_struct *p) ++{ ++ int swapfilesize = 0; ++ struct swap_method *method; ++ ++ p->method = NULL; ++ for (method = swap_methods; method; method = method->next) { ++ swapfilesize = method->ops->open(swap_file, &p->data); ++ if (swapfilesize == 0) { ++ continue; ++ } ++ if (swapfilesize > 0) { ++ p->method = method; ++ p->method->use_count ++; ++ p->swap_file = swap_file; ++ break; ++ } ++ if (swapfilesize < 0) { ++ break; ++ } ++ } ++ return swapfilesize; ++} ++ + /* + * Written 01/25/92 by Simmule Turner, heavily changed by Linus. + * +@@ -855,8 +970,6 @@ + asmlinkage long sys_swapon(const char * specialfile, int swap_flags) + { + struct swap_info_struct * p; +- struct nameidata nd; +- struct inode * swap_inode; + unsigned int type; + int i, j, prev; + int error; +@@ -866,8 +979,9 @@ + int nr_good_pages = 0; + unsigned long maxpages = 1; + int swapfilesize; +- struct block_device *bdev = NULL; + unsigned short *swap_map; ++ char * tmp_specialfile; ++ struct file *swap_file; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; +@@ -886,8 +1000,7 @@ + nr_swapfiles = type+1; + p->flags = SWP_USED; + p->swap_file = NULL; +- p->swap_vfsmnt = NULL; +- p->swap_device = 0; ++ p->method = NULL; + p->swap_map = NULL; + p->lowest_bit = 0; + p->highest_bit = 0; +@@ -901,53 +1014,56 @@ + p->prio = --least_priority; + } + swap_list_unlock(); +- error = user_path_walk(specialfile, &nd); +- if (error) ++ ++ /* Open the swap using filp_open. Bail out on any errors. */ ++ tmp_specialfile = getname(specialfile); ++ if (IS_ERR(tmp_specialfile)) { ++ error = PTR_ERR(tmp_specialfile); + goto bad_swap_2; ++ } ++ p->swap_file = filp_open(tmp_specialfile, O_RDWR, 0600); ++ putname(tmp_specialfile); ++ if (IS_ERR(p->swap_file)) { ++ error = PTR_ERR(p->swap_file); ++ goto bad_swap_1; ++ } + +- p->swap_file = nd.dentry; +- p->swap_vfsmnt = nd.mnt; +- swap_inode = nd.dentry->d_inode; + error = -EINVAL; + +- if (S_ISBLK(swap_inode->i_mode)) { +- kdev_t dev = swap_inode->i_rdev; +- struct block_device_operations *bdops; +- devfs_handle_t de; +- +- p->swap_device = dev; +- set_blocksize(dev, PAGE_SIZE); +- +- bd_acquire(swap_inode); +- bdev = swap_inode->i_bdev; +- de = devfs_get_handle_from_inode(swap_inode); +- bdops = devfs_get_ops(de); /* Increments module use count */ +- if (bdops) bdev->bd_op = bdops; +- +- error = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_SWAP); +- devfs_put_ops(de);/*Decrement module use count now we're safe*/ +- if (error) +- goto bad_swap_2; +- set_blocksize(dev, PAGE_SIZE); +- error = -ENODEV; +- if (!dev || (blk_size[MAJOR(dev)] && +- !blk_size[MAJOR(dev)][MINOR(dev)])) +- goto bad_swap; +- swapfilesize = 0; +- if (blk_size[MAJOR(dev)]) +- swapfilesize = blk_size[MAJOR(dev)][MINOR(dev)] +- >> (PAGE_SHIFT - 10); +- } else if (S_ISREG(swap_inode->i_mode)) +- swapfilesize = swap_inode->i_size >> PAGE_SHIFT; +- else +- goto bad_swap; ++ swapfilesize = find_swap_method(p->swap_file, p); ++ if (swapfilesize < 0) { ++ error = swapfilesize; ++ goto bad_swap_1; ++ } ++#ifdef CONFIG_KMOD ++ if (swapfilesize == 0) { ++ (void)request_module("swapfile-mod"); ++ ++ swapfilesize = find_swap_method(p->swap_file, p); ++ if (swapfilesize < 0) { ++ error = swapfilesize; ++ goto bad_swap_1; ++ } ++ } ++#endif ++ if (swapfilesize == 0) { ++ printk("Don't know how to swap to this kind of file\n"); ++ goto bad_swap_1; /* free swap map */ ++ } ++ ++ /* After this point, the swap-file has been opened by the swap ++ * method. We must make sure to use the bad_swap label for any ++ * errors. ++ */ + + error = -EBUSY; + for (i = 0 ; i < nr_swapfiles ; i++) { + struct swap_info_struct *q = &swap_info[i]; + if (i == type || !q->swap_file) + continue; +- if (swap_inode->i_mapping == q->swap_file->d_inode->i_mapping) ++ if (p->swap_file->f_dentry->d_inode->i_mapping ++ == ++ q->swap_file->f_dentry->d_inode->i_mapping) + goto bad_swap; + } + +@@ -1083,17 +1199,27 @@ + swap_list_unlock(); + error = 0; + goto out; ++ + bad_swap: +- if (bdev) +- blkdev_put(bdev, BDEV_SWAP); ++ if (p->method->ops->release) ++ p->method->ops->release(p->swap_file, p->data); ++ swap_list_lock(); ++ p->method->use_count --; ++ p->method = NULL; ++ p->data = NULL; ++ swap_list_unlock(); ++ ++bad_swap_1: ++ swap_list_lock(); ++ swap_file = p->swap_file; ++ p->swap_file = NULL; ++ swap_list_unlock(); ++ filp_close(swap_file, NULL); ++ + bad_swap_2: ++ + swap_list_lock(); + swap_map = p->swap_map; +- nd.mnt = p->swap_vfsmnt; +- nd.dentry = p->swap_file; +- p->swap_device = 0; +- p->swap_file = NULL; +- p->swap_vfsmnt = NULL; + p->swap_map = NULL; + p->flags = 0; + if (!(swap_flags & SWAP_FLAG_PREFER)) +@@ -1101,7 +1227,7 @@ + swap_list_unlock(); + if (swap_map) + vfree(swap_map); +- path_release(&nd); ++ + out: + if (swap_header) + free_page((long) swap_header); +@@ -1217,8 +1343,8 @@ + /* + * Prior swap_duplicate protects against swap device deletion. + */ +-void get_swaphandle_info(swp_entry_t entry, unsigned long *offset, +- kdev_t *dev, struct inode **swapf) ++struct swap_method *get_swaphandle_info(swp_entry_t entry, ++ unsigned long *offset, void **data) + { + unsigned long type; + struct swap_info_struct *p; +@@ -1226,32 +1352,26 @@ + type = SWP_TYPE(entry); + if (type >= nr_swapfiles) { + printk(KERN_ERR "rw_swap_page: %s%08lx\n", Bad_file, entry.val); +- return; ++ return NULL; + } + + p = &swap_info[type]; + *offset = SWP_OFFSET(entry); + if (*offset >= p->max && *offset != 0) { + printk(KERN_ERR "rw_swap_page: %s%08lx\n", Bad_offset, entry.val); +- return; ++ return NULL; + } + if (p->swap_map && !p->swap_map[*offset]) { + printk(KERN_ERR "rw_swap_page: %s%08lx\n", Unused_offset, entry.val); +- return; ++ return NULL; + } + if (!(p->flags & SWP_USED)) { + printk(KERN_ERR "rw_swap_page: %s%08lx\n", Unused_file, entry.val); +- return; ++ return NULL; + } + +- if (p->swap_device) { +- *dev = p->swap_device; +- } else if (p->swap_file) { +- *swapf = p->swap_file->d_inode; +- } else { +- printk(KERN_ERR "rw_swap_page: no swap file or device\n"); +- } +- return; ++ *data = p->data; ++ return p->method; + } + + /* +diff -Nurb src/linux/linux.orig/net/Config.in src/linux/linux/net/Config.in +--- src/linux/linux.orig/net/Config.in 2003-07-04 04:12:29.000000000 -0400 ++++ src/linux/linux/net/Config.in 2004-05-31 02:18:03.000000000 -0400 +@@ -16,6 +16,9 @@ + fi + bool 'Socket Filtering' CONFIG_FILTER + tristate 'Unix domain sockets' CONFIG_UNIX ++if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then ++ bool 'Swapping via network sockets (EXPERIMENTAL)' CONFIG_NETSWAP ++fi + bool 'TCP/IP networking' CONFIG_INET + if [ "$CONFIG_INET" = "y" ]; then + source net/ipv4/Config.in +diff -Nurb src/linux/linux.orig/net/Makefile src/linux/linux/net/Makefile +--- src/linux/linux.orig/net/Makefile 2003-07-04 04:12:29.000000000 -0400 ++++ src/linux/linux/net/Makefile 2004-05-31 02:18:03.000000000 -0400 +@@ -51,6 +51,7 @@ + ifeq ($(CONFIG_NET),y) + obj-$(CONFIG_MODULES) += netsyms.o + obj-$(CONFIG_SYSCTL) += sysctl_net.o ++obj-$(CONFIG_NETSWAP) += netswapping.o + endif + + include $(TOPDIR)/Rules.make +diff -Nurb src/linux/linux.orig/net/core/sock.c src/linux/linux/net/core/sock.c +--- src/linux/linux.orig/net/core/sock.c 2003-10-14 04:09:32.000000000 -0400 ++++ src/linux/linux/net/core/sock.c 2004-05-31 02:18:03.000000000 -0400 +@@ -402,6 +402,21 @@ + ret = -ENONET; + break; + #endif ++#ifdef CONFIG_NETSWAP ++ case SO_SWAPPING: ++ if (valbool) { ++ if (!sk->swapping) { ++ netswap_sock_count ++; ++ } ++ sk->swapping ++; ++ } else if (sk->swapping > 0) { ++ sk->swapping --; ++ if (!sk->swapping) { ++ netswap_sock_count --; ++ } ++ } ++ break; ++#endif + /* We implement the SO_SNDLOWAT etc to + not be settable (1003.1g 5.3) */ + default: +@@ -552,6 +567,12 @@ + goto lenout; + } + ++#ifdef CONFIG_NETSWAP ++ case SO_SWAPPING: ++ v.val = sk->swapping; ++ break; ++#endif ++ + /* Dubious BSD thing... Probably nobody even uses it, but + * the UNIX standard wants it for whatever reason... -DaveM + */ +diff -Nurb src/linux/linux.orig/net/ipv4/tcp_ipv4.c src/linux/linux/net/ipv4/tcp_ipv4.c +--- src/linux/linux.orig/net/ipv4/tcp_ipv4.c 2003-10-14 04:09:33.000000000 -0400 ++++ src/linux/linux/net/ipv4/tcp_ipv4.c 2004-05-31 02:18:03.000000000 -0400 +@@ -1657,6 +1657,12 @@ + if (filter && sk_filter(skb, filter)) + goto discard; + #endif /* CONFIG_FILTER */ ++#ifdef CONFIG_NETSWAP ++ /* tcp doesn't use sock_queue_rcv_skb() ... */ ++ /* an inline function defined in net/netswapping.h */ ++ if (netswap_low_memory(sk, skb)) ++ goto discard; ++#endif /* CONFIG_NETSWAP */ + + IP_INC_STATS_BH(IpInDelivers); + +diff -Nurb src/linux/linux.orig/net/ipv6/tcp_ipv6.c src/linux/linux/net/ipv6/tcp_ipv6.c +--- src/linux/linux.orig/net/ipv6/tcp_ipv6.c 2003-10-14 04:09:34.000000000 -0400 ++++ src/linux/linux/net/ipv6/tcp_ipv6.c 2004-05-31 02:18:03.000000000 -0400 +@@ -1424,6 +1424,12 @@ + if (filter && sk_filter(skb, filter)) + goto discard; + #endif /* CONFIG_FILTER */ ++#ifdef CONFIG_NETSWAP ++ /* tcp doesn't use sock_queue_rcv_skb() ... */ ++ /* an inline function defined in net/netswapping.h */ ++ if (netswap_low_memory(sk, skb)) ++ goto discard; ++#endif /* CONFIG_NETSWAP */ + + /* + * socket locking is here for SMP purposes as backlog rcv +diff -Nurb src/linux/linux.orig/net/netswapping.c src/linux/linux/net/netswapping.c +--- src/linux/linux.orig/net/netswapping.c 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/net/netswapping.c 2004-05-31 02:18:03.000000000 -0400 +@@ -0,0 +1,76 @@ ++/* ++ * linux/net/swapping.c ++ * ++ * Support paging over network connections (inet only) ++ * ++ * (c) 2000 Claus-Justus Heine <heine@instmath.rwth-aachen.de> ++ */ ++ ++#include <linux/slab.h> ++#include <linux/swap.h> ++#include <linux/swapctl.h> ++#include <linux/skbuff.h> ++#include <linux/module.h> ++#include <linux/sysctl.h> ++#include <linux/init.h> ++#include <net/netswapping.h> ++#include <net/sock.h> ++#include <asm/uaccess.h> ++ ++unsigned int netswap_dropped; /* statistics */ ++unsigned int netswap_free_pages_min; ++int netswap_sock_count; /* how many sockets have swapping option set */ ++ ++#ifdef CONFIG_SYSCTL ++ ++static ctl_table netswap_table[] = { ++ {NET_SWAP_DROPPED, "dropped", ++ &netswap_dropped, sizeof(int), 0644, NULL, &proc_dointvec }, ++ {NET_SWAP_DROP_THRESHOLD, "threshold", ++ &netswap_free_pages_min, sizeof(int), 0644, NULL, &proc_dointvec }, ++ {NET_SWAP_SOCK_COUNT, "sock_count", ++ &netswap_sock_count, sizeof(int), 0444, NULL, &proc_dointvec }, ++ {0}, ++}; ++ ++static struct ctl_table_header *netswap_sysctl_header; ++ ++static ctl_table netswap_net_table[] = { ++ {CTL_NETSWAP, "swapping", NULL, 0, 0555, netswap_table}, ++ {0} ++}; ++ ++static ctl_table netswap_root_table[] = { ++ {CTL_NET, "net", NULL, 0, 0555, netswap_net_table}, ++ {0} ++}; ++ ++#endif ++ ++int __init netswap_init(void) ++{ ++ /* drop packets when below this threshold */ ++ netswap_free_pages_min = 32 /* freepages.min */; ++#ifdef CONFIG_SYSCTL ++ netswap_sysctl_header = register_sysctl_table(netswap_root_table, 0); ++#endif ++ return 0; ++} ++ ++void __exit netswap_exit(void) ++{ ++#ifdef CONFIG_SYSCTL ++ unregister_sysctl_table(netswap_sysctl_header); ++#endif ++} ++ ++/* linux/init.h -- VERY nice :-) ++ * ++ * On the other hand, we have no control over the order the initcalls ++ * are performed ... ++ * ++ * Actually, we are not compiled as module ... ++ */ ++ ++module_init(netswap_init) ++module_exit(netswap_exit) +diff -Nurb src/linux/linux.orig/net/netsyms.c src/linux/linux/net/netsyms.c +--- src/linux/linux.orig/net/netsyms.c 2004-05-31 02:02:49.000000000 -0400 ++++ src/linux/linux/net/netsyms.c 2004-05-31 02:18:03.000000000 -0400 +@@ -601,4 +601,10 @@ + EXPORT_SYMBOL(wireless_send_event); + #endif /* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */ + ++#ifdef CONFIG_NETSWAP ++EXPORT_SYMBOL(netswap_sock_count); ++EXPORT_SYMBOL(netswap_free_pages_min); ++EXPORT_SYMBOL(netswap_dropped); ++#endif ++ + #endif /* CONFIG_NET */ +diff -Nurb src/linux/linux.orig/net/packet/af_packet.c src/linux/linux/net/packet/af_packet.c +--- src/linux/linux.orig/net/packet/af_packet.c 2003-10-14 04:09:35.000000000 -0400 ++++ src/linux/linux/net/packet/af_packet.c 2004-05-31 02:18:03.000000000 -0400 +@@ -449,6 +449,12 @@ + snaplen = res; + } + #endif /* CONFIG_FILTER */ ++#ifdef CONFIG_NETSWAP ++ /* packet doesn't use sock_queue_rcv_skb() ... */ ++ /* an inline function defined in net/netswapping.h */ ++ if (netswap_low_memory(sk, skb)) ++ goto drop_n_restore; ++#endif /* CONFIG_NETSWAP */ + + if (atomic_read(&sk->rmem_alloc) + skb->truesize >= (unsigned)sk->rcvbuf) + goto drop_n_acct; +@@ -496,7 +502,7 @@ + po->stats.tp_drops++; + spin_unlock(&sk->receive_queue.lock); + +-#ifdef CONFIG_FILTER ++#if defined(CONFIG_FILTER) || defined(CONFIG_NETSWAP) + drop_n_restore: + #endif + if (skb_head != skb->data && skb_shared(skb)) { +@@ -557,6 +563,12 @@ + snaplen = res; + } + #endif ++#ifdef CONFIG_NETSWAP ++ /* packet doesn't use sock_queue_rcv_skb() ... */ ++ /* an inline function defined in net/netswapping.h */ ++ if (netswap_low_memory(sk, skb)) ++ goto drop_n_restore; ++#endif /* CONFIG_NETSWAP */ + + if (sk->type == SOCK_DGRAM) { + macoff = netoff = TPACKET_ALIGN(TPACKET_HDRLEN) + 16; +diff -Nurb src/linux/linux.orig/net/sunrpc/sched.c src/linux/linux/net/sunrpc/sched.c +--- src/linux/linux.orig/net/sunrpc/sched.c 2003-07-04 04:12:33.000000000 -0400 ++++ src/linux/linux/net/sunrpc/sched.c 2004-05-31 02:18:03.000000000 -0400 +@@ -79,10 +79,11 @@ + */ + static spinlock_t rpc_sched_lock = SPIN_LOCK_UNLOCKED; + ++#if CONFIG_SWAP_VIA_NFS || CONFIG_SWAP_VIA_NFS_MODULE + /* + * This is the last-ditch buffer for NFS swap requests + */ +-static u32 swap_buffer[PAGE_SIZE >> 2]; ++static u32 swap_buffer[2*PAGE_SIZE >> 2]; + static long swap_buffer_used; + + /* +@@ -96,6 +97,7 @@ + { + clear_bit(1, &swap_buffer_used); + } ++#endif + + /* + * Disable the timer for a given RPC task. Should be called with +@@ -501,6 +503,7 @@ + __rpc_execute(struct rpc_task *task) + { + int status = 0; ++ unsigned long alloc_flag = current->flags & PF_MEMALLOC; + + dprintk("RPC: %4d rpc_execute flgs %x\n", + task->tk_pid, task->tk_flags); +@@ -510,6 +513,13 @@ + return 0; + } + ++ if (task->tk_flags & RPC_TASK_SWAPPER) { ++ if (!current->flags & PF_MEMALLOC) { ++ dprintk("__rpc_execute: Setting PF_MEMALLOC\n"); ++ } ++ current->flags |= PF_MEMALLOC; ++ } ++ + restarted: + while (1) { + /* +@@ -554,7 +564,8 @@ + rpc_set_sleeping(task); + if (RPC_IS_ASYNC(task)) { + spin_unlock_bh(&rpc_queue_lock); +- return 0; ++ status = 0; ++ goto out; + } + } + spin_unlock_bh(&rpc_queue_lock); +@@ -563,7 +574,12 @@ + /* sync task: sleep here */ + dprintk("RPC: %4d sync task going to sleep\n", + task->tk_pid); +- if (current->pid == rpciod_pid) ++ /* it's ok to wait for rpciod when swapping, ++ * because this means it needed memory and is ++ * doing the swap-out itself. ++ */ ++ if (current->pid == rpciod_pid && ++ !(task->tk_flags & RPC_TASK_SWAPPER)) + printk(KERN_ERR "RPC: rpciod waiting on sync task!\n"); + + __wait_event(task->tk_wait, !RPC_IS_SLEEPING(task)); +@@ -608,6 +624,10 @@ + /* Release all resources associated with the task */ + rpc_release_task(task); + ++ out: ++ if (!alloc_flag) { ++ current->flags &= ~PF_MEMALLOC; ++ } + return status; + } + +@@ -699,10 +719,16 @@ + { + u32 *buffer; + int gfp; ++ unsigned long alloc_flag = current->flags & PF_MEMALLOC; ++ void *ret = NULL; + +- if (flags & RPC_TASK_SWAPPER) ++ if (flags & RPC_TASK_SWAPPER) { + gfp = GFP_ATOMIC; +- else if (flags & RPC_TASK_ASYNC) ++ if (!(current->flags & PF_MEMALLOC)) { ++ dprintk("rpc_allocate: Setting PF_MEMALLOC\n"); ++ } ++ current->flags |= PF_MEMALLOC; ++ } else if (flags & RPC_TASK_ASYNC) + gfp = GFP_RPC; + else + gfp = GFP_KERNEL; +@@ -710,29 +736,44 @@ + do { + if ((buffer = (u32 *) kmalloc(size, gfp)) != NULL) { + dprintk("RPC: allocated buffer %p\n", buffer); +- return buffer; ++ ret = buffer; ++ goto out; + } ++#if CONFIG_SWAP_VIA_NFS || CONFIG_SWAP_VIA_NFS_MODULE + if ((flags & RPC_TASK_SWAPPER) && size <= sizeof(swap_buffer) + && rpc_lock_swapbuf()) { + dprintk("RPC: used last-ditch swap buffer\n"); +- return swap_buffer; ++ ret = swap_buffer; ++ goto out; ++#endif ++ } ++ if (flags & RPC_TASK_ASYNC) { ++ ret = NULL; ++ goto out; + } +- if (flags & RPC_TASK_ASYNC) +- return NULL; + yield(); + } while (!signalled()); + +- return NULL; ++ out: ++ if (!alloc_flag) { ++ current->flags &= ~PF_MEMALLOC; ++ } ++ return ret; + } + + void + rpc_free(void *buffer) + { ++#if CONFIG_SWAP_VIA_NFS || CONFIG_SWAP_VIA_NFS_MODULE + if (buffer != swap_buffer) { ++#endif + kfree(buffer); + return; ++#if CONFIG_SWAP_VIA_NFS || CONFIG_SWAP_VIA_NFS_MODULE + } + rpc_unlock_swapbuf(); ++ printk("RPC: Released swap buffer\n"); ++#endif + } + + /* +diff -Nurb src/linux/linux.orig/net/sunrpc/xprt.c src/linux/linux/net/sunrpc/xprt.c +--- src/linux/linux.orig/net/sunrpc/xprt.c 2003-07-04 04:12:33.000000000 -0400 ++++ src/linux/linux/net/sunrpc/xprt.c 2004-05-31 02:18:03.000000000 -0400 +@@ -139,7 +139,7 @@ + __xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task) + { + if (!xprt->snd_task) { +- if (xprt->nocong || __xprt_get_cong(xprt, task)) ++ if (__xprt_get_cong(xprt, task)) + xprt->snd_task = task; + } + if (xprt->snd_task != task) { +@@ -179,7 +179,7 @@ + if (!task) + return; + } +- if (xprt->nocong || __xprt_get_cong(xprt, task)) ++ if (__xprt_get_cong(xprt, task)) + xprt->snd_task = task; + } + +@@ -276,6 +276,9 @@ + { + struct rpc_rqst *req = task->tk_rqstp; + ++ if (xprt->nocong || RPC_IS_SWAPPER(task)) ++ return 1; ++ + if (req->rq_cong) + return 1; + dprintk("RPC: %4d xprt_cwnd_limited cong = %ld cwnd = %ld\n", diff --git a/obsolete-buildroot/sources/openwrt/kernel/patches/140-ebtables-brnf-5.patch b/obsolete-buildroot/sources/openwrt/kernel/patches/140-ebtables-brnf-5.patch new file mode 100644 index 0000000000..707919e2bd --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/kernel/patches/140-ebtables-brnf-5.patch @@ -0,0 +1,6336 @@ +diff -Nurb src/linux/linux.stock/include/linux/if_bridge.h src/linux/linux/include/linux/if_bridge.h +--- src/linux/linux.stock/include/linux/if_bridge.h 2003-10-14 04:09:25.000000000 -0400 ++++ src/linux/linux/include/linux/if_bridge.h 2004-07-10 23:46:39.000000000 -0400 +@@ -102,7 +102,8 @@ + struct net_bridge_port; + + extern int (*br_ioctl_hook)(unsigned long arg); +-extern void (*br_handle_frame_hook)(struct sk_buff *skb); ++extern int (*br_handle_frame_hook)(struct sk_buff *skb); ++extern int (*br_should_route_hook)(struct sk_buff **pskb); + + #endif + +diff -Nurb src/linux/linux.stock/include/linux/netfilter.h src/linux/linux/include/linux/netfilter.h +--- src/linux/linux.stock/include/linux/netfilter.h 2004-07-10 23:30:09.000000000 -0400 ++++ src/linux/linux/include/linux/netfilter.h 2004-07-10 23:46:39.000000000 -0400 +@@ -119,17 +119,23 @@ + /* This is gross, but inline doesn't cut it for avoiding the function + call in fast path: gcc doesn't inline (needs value tracking?). --RR */ + #ifdef CONFIG_NETFILTER_DEBUG +-#define NF_HOOK nf_hook_slow ++#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) \ ++nf_hook_slow((pf), (hook), (skb), (indev), (outdev), (okfn), INT_MIN) ++#define NF_HOOK_THRESH nf_hook_slow + #else + #define NF_HOOK(pf, hook, skb, indev, outdev, okfn) \ + (list_empty(&nf_hooks[(pf)][(hook)]) \ + ? (okfn)(skb) \ +- : nf_hook_slow((pf), (hook), (skb), (indev), (outdev), (okfn))) ++ : nf_hook_slow((pf), (hook), (skb), (indev), (outdev), (okfn), INT_MIN)) ++#define NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, thresh) \ ++(list_empty(&nf_hooks[(pf)][(hook)]) \ ++ ? (okfn)(skb) \ ++ : nf_hook_slow((pf), (hook), (skb), (indev), (outdev), (okfn), (thresh))) + #endif + + int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb, + struct net_device *indev, struct net_device *outdev, +- int (*okfn)(struct sk_buff *)); ++ int (*okfn)(struct sk_buff *), int thresh); + + /* Call setsockopt() */ + int nf_setsockopt(struct sock *sk, int pf, int optval, char *opt, +diff -Nurb src/linux/linux.stock/include/linux/netfilter_bridge/ebt_802_3.h src/linux/linux/include/linux/netfilter_bridge/ebt_802_3.h +--- src/linux/linux.stock/include/linux/netfilter_bridge/ebt_802_3.h 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/include/linux/netfilter_bridge/ebt_802_3.h 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,60 @@ ++#ifndef __LINUX_BRIDGE_EBT_802_3_H ++#define __LINUX_BRIDGE_EBT_802_3_H ++ ++#define EBT_802_3_SAP 0x01 ++#define EBT_802_3_TYPE 0x02 ++ ++#define EBT_802_3_MATCH "802_3" ++ ++/* ++ * If frame has DSAP/SSAP value 0xaa you must check the SNAP type ++ * to discover what kind of packet we're carrying. ++ */ ++#define CHECK_TYPE 0xaa ++ ++/* ++ * Control field may be one or two bytes. If the first byte has ++ * the value 0x03 then the entire length is one byte, otherwise it is two. ++ * One byte controls are used in Unnumbered Information frames. ++ * Two byte controls are used in Numbered Information frames. ++ */ ++#define IS_UI 0x03 ++ ++#define EBT_802_3_MASK (EBT_802_3_SAP | EBT_802_3_TYPE | EBT_802_3) ++ ++/* ui has one byte ctrl, ni has two */ ++struct hdr_ui { ++ uint8_t dsap; ++ uint8_t ssap; ++ uint8_t ctrl; ++ uint8_t orig[3]; ++ uint16_t type; ++}; ++ ++struct hdr_ni { ++ uint8_t dsap; ++ uint8_t ssap; ++ uint16_t ctrl; ++ uint8_t orig[3]; ++ uint16_t type; ++}; ++ ++struct ebt_802_3_hdr { ++ uint8_t daddr[6]; ++ uint8_t saddr[6]; ++ uint16_t len; ++ union { ++ struct hdr_ui ui; ++ struct hdr_ni ni; ++ } llc; ++}; ++ ++struct ebt_802_3_info ++{ ++ uint8_t sap; ++ uint16_t type; ++ uint8_t bitmask; ++ uint8_t invflags; ++}; ++ ++#endif +diff -Nurb src/linux/linux.stock/include/linux/netfilter_bridge/ebt_among.h src/linux/linux/include/linux/netfilter_bridge/ebt_among.h +--- src/linux/linux.stock/include/linux/netfilter_bridge/ebt_among.h 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/include/linux/netfilter_bridge/ebt_among.h 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,65 @@ ++#ifndef __LINUX_BRIDGE_EBT_AMONG_H ++#define __LINUX_BRIDGE_EBT_AMONG_H ++ ++#define EBT_AMONG_DST 0x01 ++#define EBT_AMONG_SRC 0x02 ++ ++/* Grzegorz Borowiak <grzes@gnu.univ.gda.pl> 2003 ++ * ++ * Write-once-read-many hash table, used for checking if a given ++ * MAC address belongs to a set or not and possibly for checking ++ * if it is related with a given IPv4 address. ++ * ++ * The hash value of an address is its last byte. ++ * ++ * In real-world ethernet addresses, values of the last byte are ++ * evenly distributed and there is no need to consider other bytes. ++ * It would only slow the routines down. ++ * ++ * For MAC address comparison speedup reasons, we introduce a trick. ++ * MAC address is mapped onto an array of two 32-bit integers. ++ * This pair of integers is compared with MAC addresses in the ++ * hash table, which are stored also in form of pairs of integers ++ * (in `cmp' array). This is quick as it requires only two elementary ++ * number comparisons in worst case. Further, we take advantage of ++ * fact that entropy of 3 last bytes of address is larger than entropy ++ * of 3 first bytes. So first we compare 4 last bytes of addresses and ++ * if they are the same we compare 2 first. ++ * ++ * Yes, it is a memory overhead, but in 2003 AD, who cares? ++ */ ++ ++struct ebt_mac_wormhash_tuple ++{ ++ uint32_t cmp[2]; ++ uint32_t ip; ++}; ++ ++struct ebt_mac_wormhash ++{ ++ int table[257]; ++ int poolsize; ++ struct ebt_mac_wormhash_tuple pool[0]; ++}; ++ ++#define ebt_mac_wormhash_size(x) ((x) ? sizeof(struct ebt_mac_wormhash) \ ++ + (x)->poolsize * sizeof(struct ebt_mac_wormhash_tuple) : 0) ++ ++struct ebt_among_info ++{ ++ int wh_dst_ofs; ++ int wh_src_ofs; ++ int bitmask; ++}; ++ ++#define EBT_AMONG_DST_NEG 0x1 ++#define EBT_AMONG_SRC_NEG 0x2 ++ ++#define ebt_among_wh_dst(x) ((x)->wh_dst_ofs ? \ ++ (struct ebt_mac_wormhash*)((char*)(x) + (x)->wh_dst_ofs) : NULL) ++#define ebt_among_wh_src(x) ((x)->wh_src_ofs ? \ ++ (struct ebt_mac_wormhash*)((char*)(x) + (x)->wh_src_ofs) : NULL) ++ ++#define EBT_AMONG_MATCH "among" ++ ++#endif +diff -Nurb src/linux/linux.stock/include/linux/netfilter_bridge/ebt_arp.h src/linux/linux/include/linux/netfilter_bridge/ebt_arp.h +--- src/linux/linux.stock/include/linux/netfilter_bridge/ebt_arp.h 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/include/linux/netfilter_bridge/ebt_arp.h 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,32 @@ ++#ifndef __LINUX_BRIDGE_EBT_ARP_H ++#define __LINUX_BRIDGE_EBT_ARP_H ++ ++#define EBT_ARP_OPCODE 0x01 ++#define EBT_ARP_HTYPE 0x02 ++#define EBT_ARP_PTYPE 0x04 ++#define EBT_ARP_SRC_IP 0x08 ++#define EBT_ARP_DST_IP 0x10 ++#define EBT_ARP_SRC_MAC 0x20 ++#define EBT_ARP_DST_MAC 0x40 ++#define EBT_ARP_MASK (EBT_ARP_OPCODE | EBT_ARP_HTYPE | EBT_ARP_PTYPE | \ ++ EBT_ARP_SRC_IP | EBT_ARP_DST_IP | EBT_ARP_SRC_MAC | EBT_ARP_DST_MAC) ++#define EBT_ARP_MATCH "arp" ++ ++struct ebt_arp_info ++{ ++ uint16_t htype; ++ uint16_t ptype; ++ uint16_t opcode; ++ uint32_t saddr; ++ uint32_t smsk; ++ uint32_t daddr; ++ uint32_t dmsk; ++ unsigned char smaddr[ETH_ALEN]; ++ unsigned char smmsk[ETH_ALEN]; ++ unsigned char dmaddr[ETH_ALEN]; ++ unsigned char dmmsk[ETH_ALEN]; ++ uint8_t bitmask; ++ uint8_t invflags; ++}; ++ ++#endif +diff -Nurb src/linux/linux.stock/include/linux/netfilter_bridge/ebt_arpreply.h src/linux/linux/include/linux/netfilter_bridge/ebt_arpreply.h +--- src/linux/linux.stock/include/linux/netfilter_bridge/ebt_arpreply.h 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/include/linux/netfilter_bridge/ebt_arpreply.h 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,11 @@ ++#ifndef __LINUX_BRIDGE_EBT_ARPREPLY_H ++#define __LINUX_BRIDGE_EBT_ARPREPLY_H ++ ++struct ebt_arpreply_info ++{ ++ unsigned char mac[ETH_ALEN]; ++ int target; ++}; ++#define EBT_ARPREPLY_TARGET "arpreply" ++ ++#endif +diff -Nurb src/linux/linux.stock/include/linux/netfilter_bridge/ebt_ip.h src/linux/linux/include/linux/netfilter_bridge/ebt_ip.h +--- src/linux/linux.stock/include/linux/netfilter_bridge/ebt_ip.h 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/include/linux/netfilter_bridge/ebt_ip.h 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,43 @@ ++/* ++ * ebt_ip ++ * ++ * Authors: ++ * Bart De Schuymer <bart.de.schuymer@pandora.be> ++ * ++ * April, 2002 ++ * ++ * Changes: ++ * added ip-sport and ip-dport ++ * Innominate Security Technologies AG <mhopf@innominate.com> ++ * September, 2002 ++ */ ++ ++#ifndef __LINUX_BRIDGE_EBT_IP_H ++#define __LINUX_BRIDGE_EBT_IP_H ++ ++#define EBT_IP_SOURCE 0x01 ++#define EBT_IP_DEST 0x02 ++#define EBT_IP_TOS 0x04 ++#define EBT_IP_PROTO 0x08 ++#define EBT_IP_SPORT 0x10 ++#define EBT_IP_DPORT 0x20 ++#define EBT_IP_MASK (EBT_IP_SOURCE | EBT_IP_DEST | EBT_IP_TOS | EBT_IP_PROTO |\ ++ EBT_IP_SPORT | EBT_IP_DPORT ) ++#define EBT_IP_MATCH "ip" ++ ++// the same values are used for the invflags ++struct ebt_ip_info ++{ ++ uint32_t saddr; ++ uint32_t daddr; ++ uint32_t smsk; ++ uint32_t dmsk; ++ uint8_t tos; ++ uint8_t protocol; ++ uint8_t bitmask; ++ uint8_t invflags; ++ uint16_t sport[2]; ++ uint16_t dport[2]; ++}; ++ ++#endif +diff -Nurb src/linux/linux.stock/include/linux/netfilter_bridge/ebt_limit.h src/linux/linux/include/linux/netfilter_bridge/ebt_limit.h +--- src/linux/linux.stock/include/linux/netfilter_bridge/ebt_limit.h 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/include/linux/netfilter_bridge/ebt_limit.h 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,23 @@ ++#ifndef __LINUX_BRIDGE_EBT_LIMIT_H ++#define __LINUX_BRIDGE_EBT_LIMIT_H ++ ++#define EBT_LIMIT_MATCH "limit" ++ ++/* timings are in milliseconds. */ ++#define EBT_LIMIT_SCALE 10000 ++ ++/* 1/10,000 sec period => max of 10,000/sec. Min rate is then 429490 ++ seconds, or one every 59 hours. */ ++ ++struct ebt_limit_info ++{ ++ u_int32_t avg; /* Average secs between packets * scale */ ++ u_int32_t burst; /* Period multiplier for upper limit. */ ++ ++ /* Used internally by the kernel */ ++ unsigned long prev; ++ u_int32_t credit; ++ u_int32_t credit_cap, cost; ++}; ++ ++#endif +diff -Nurb src/linux/linux.stock/include/linux/netfilter_bridge/ebt_log.h src/linux/linux/include/linux/netfilter_bridge/ebt_log.h +--- src/linux/linux.stock/include/linux/netfilter_bridge/ebt_log.h 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/include/linux/netfilter_bridge/ebt_log.h 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,17 @@ ++#ifndef __LINUX_BRIDGE_EBT_LOG_H ++#define __LINUX_BRIDGE_EBT_LOG_H ++ ++#define EBT_LOG_IP 0x01 // if the frame is made by ip, log the ip information ++#define EBT_LOG_ARP 0x02 ++#define EBT_LOG_MASK (EBT_LOG_IP | EBT_LOG_ARP) ++#define EBT_LOG_PREFIX_SIZE 30 ++#define EBT_LOG_WATCHER "log" ++ ++struct ebt_log_info ++{ ++ uint8_t loglevel; ++ uint8_t prefix[EBT_LOG_PREFIX_SIZE]; ++ uint32_t bitmask; ++}; ++ ++#endif +diff -Nurb src/linux/linux.stock/include/linux/netfilter_bridge/ebt_mark_m.h src/linux/linux/include/linux/netfilter_bridge/ebt_mark_m.h +--- src/linux/linux.stock/include/linux/netfilter_bridge/ebt_mark_m.h 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/include/linux/netfilter_bridge/ebt_mark_m.h 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,15 @@ ++#ifndef __LINUX_BRIDGE_EBT_MARK_M_H ++#define __LINUX_BRIDGE_EBT_MARK_M_H ++ ++#define EBT_MARK_AND 0x01 ++#define EBT_MARK_OR 0x02 ++#define EBT_MARK_MASK (EBT_MARK_AND | EBT_MARK_OR) ++struct ebt_mark_m_info ++{ ++ unsigned long mark, mask; ++ uint8_t invert; ++ uint8_t bitmask; ++}; ++#define EBT_MARK_MATCH "mark_m" ++ ++#endif +diff -Nurb src/linux/linux.stock/include/linux/netfilter_bridge/ebt_mark_t.h src/linux/linux/include/linux/netfilter_bridge/ebt_mark_t.h +--- src/linux/linux.stock/include/linux/netfilter_bridge/ebt_mark_t.h 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/include/linux/netfilter_bridge/ebt_mark_t.h 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,12 @@ ++#ifndef __LINUX_BRIDGE_EBT_MARK_T_H ++#define __LINUX_BRIDGE_EBT_MARK_T_H ++ ++struct ebt_mark_t_info ++{ ++ unsigned long mark; ++ // EBT_ACCEPT, EBT_DROP or EBT_CONTINUE or EBT_RETURN ++ int target; ++}; ++#define EBT_MARK_TARGET "mark" ++ ++#endif +diff -Nurb src/linux/linux.stock/include/linux/netfilter_bridge/ebt_nat.h src/linux/linux/include/linux/netfilter_bridge/ebt_nat.h +--- src/linux/linux.stock/include/linux/netfilter_bridge/ebt_nat.h 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/include/linux/netfilter_bridge/ebt_nat.h 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,13 @@ ++#ifndef __LINUX_BRIDGE_EBT_NAT_H ++#define __LINUX_BRIDGE_EBT_NAT_H ++ ++struct ebt_nat_info ++{ ++ unsigned char mac[ETH_ALEN]; ++ // EBT_ACCEPT, EBT_DROP, EBT_CONTINUE or EBT_RETURN ++ int target; ++}; ++#define EBT_SNAT_TARGET "snat" ++#define EBT_DNAT_TARGET "dnat" ++ ++#endif +diff -Nurb src/linux/linux.stock/include/linux/netfilter_bridge/ebt_pkttype.h src/linux/linux/include/linux/netfilter_bridge/ebt_pkttype.h +--- src/linux/linux.stock/include/linux/netfilter_bridge/ebt_pkttype.h 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/include/linux/netfilter_bridge/ebt_pkttype.h 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,11 @@ ++#ifndef __LINUX_BRIDGE_EBT_PKTTYPE_H ++#define __LINUX_BRIDGE_EBT_PKTTYPE_H ++ ++struct ebt_pkttype_info ++{ ++ uint8_t pkt_type; ++ uint8_t invert; ++}; ++#define EBT_PKTTYPE_MATCH "pkttype" ++ ++#endif +diff -Nurb src/linux/linux.stock/include/linux/netfilter_bridge/ebt_redirect.h src/linux/linux/include/linux/netfilter_bridge/ebt_redirect.h +--- src/linux/linux.stock/include/linux/netfilter_bridge/ebt_redirect.h 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/include/linux/netfilter_bridge/ebt_redirect.h 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,11 @@ ++#ifndef __LINUX_BRIDGE_EBT_REDIRECT_H ++#define __LINUX_BRIDGE_EBT_REDIRECT_H ++ ++struct ebt_redirect_info ++{ ++ // EBT_ACCEPT, EBT_DROP or EBT_CONTINUE or EBT_RETURN ++ int target; ++}; ++#define EBT_REDIRECT_TARGET "redirect" ++ ++#endif +diff -Nurb src/linux/linux.stock/include/linux/netfilter_bridge/ebt_stp.h src/linux/linux/include/linux/netfilter_bridge/ebt_stp.h +--- src/linux/linux.stock/include/linux/netfilter_bridge/ebt_stp.h 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/include/linux/netfilter_bridge/ebt_stp.h 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,46 @@ ++#ifndef __LINUX_BRIDGE_EBT_STP_H ++#define __LINUX_BRIDGE_EBT_STP_H ++ ++#define EBT_STP_TYPE 0x0001 ++ ++#define EBT_STP_FLAGS 0x0002 ++#define EBT_STP_ROOTPRIO 0x0004 ++#define EBT_STP_ROOTADDR 0x0008 ++#define EBT_STP_ROOTCOST 0x0010 ++#define EBT_STP_SENDERPRIO 0x0020 ++#define EBT_STP_SENDERADDR 0x0040 ++#define EBT_STP_PORT 0x0080 ++#define EBT_STP_MSGAGE 0x0100 ++#define EBT_STP_MAXAGE 0x0200 ++#define EBT_STP_HELLOTIME 0x0400 ++#define EBT_STP_FWDD 0x0800 ++ ++#define EBT_STP_MASK 0x0fff ++#define EBT_STP_CONFIG_MASK 0x0ffe ++ ++#define EBT_STP_MATCH "stp" ++ ++struct ebt_stp_config_info ++{ ++ uint8_t flags; ++ uint16_t root_priol, root_priou; ++ char root_addr[6], root_addrmsk[6]; ++ uint32_t root_costl, root_costu; ++ uint16_t sender_priol, sender_priou; ++ char sender_addr[6], sender_addrmsk[6]; ++ uint16_t portl, portu; ++ uint16_t msg_agel, msg_ageu; ++ uint16_t max_agel, max_ageu; ++ uint16_t hello_timel, hello_timeu; ++ uint16_t forward_delayl, forward_delayu; ++}; ++ ++struct ebt_stp_info ++{ ++ uint8_t type; ++ struct ebt_stp_config_info config; ++ uint16_t bitmask; ++ uint16_t invflags; ++}; ++ ++#endif +diff -Nurb src/linux/linux.stock/include/linux/netfilter_bridge/ebt_vlan.h src/linux/linux/include/linux/netfilter_bridge/ebt_vlan.h +--- src/linux/linux.stock/include/linux/netfilter_bridge/ebt_vlan.h 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/include/linux/netfilter_bridge/ebt_vlan.h 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,20 @@ ++#ifndef __LINUX_BRIDGE_EBT_VLAN_H ++#define __LINUX_BRIDGE_EBT_VLAN_H ++ ++#define EBT_VLAN_ID 0x01 ++#define EBT_VLAN_PRIO 0x02 ++#define EBT_VLAN_ENCAP 0x04 ++#define EBT_VLAN_MASK (EBT_VLAN_ID | EBT_VLAN_PRIO | EBT_VLAN_ENCAP) ++#define EBT_VLAN_MATCH "vlan" ++ ++struct ebt_vlan_info { ++ uint16_t id; /* VLAN ID {1-4095} */ ++ uint8_t prio; /* VLAN User Priority {0-7} */ ++ uint16_t encap; /* VLAN Encapsulated frame code {0-65535} */ ++ uint8_t bitmask; /* Args bitmask bit 1=1 - ID arg, ++ bit 2=1 User-Priority arg, bit 3=1 encap*/ ++ uint8_t invflags; /* Inverse bitmask bit 1=1 - inversed ID arg, ++ bit 2=1 - inversed Pirority arg */ ++}; ++ ++#endif +diff -Nurb src/linux/linux.stock/include/linux/netfilter_bridge/ebtables.h src/linux/linux/include/linux/netfilter_bridge/ebtables.h +--- src/linux/linux.stock/include/linux/netfilter_bridge/ebtables.h 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/include/linux/netfilter_bridge/ebtables.h 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,361 @@ ++/* ++ * ebtables ++ * ++ * Authors: ++ * Bart De Schuymer <bart.de.schuymer@pandora.be> ++ * ++ * ebtables.c,v 2.0, September, 2002 ++ * ++ * This code is stongly inspired on the iptables code which is ++ * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling ++ */ ++ ++#ifndef __LINUX_BRIDGE_EFF_H ++#define __LINUX_BRIDGE_EFF_H ++#include <linux/if.h> ++#include <linux/netfilter_bridge.h> ++#include <linux/if_ether.h> ++ ++#define EBT_TABLE_MAXNAMELEN 32 ++#define EBT_CHAIN_MAXNAMELEN EBT_TABLE_MAXNAMELEN ++#define EBT_FUNCTION_MAXNAMELEN EBT_TABLE_MAXNAMELEN ++ ++// verdicts >0 are "branches" ++#define EBT_ACCEPT -1 ++#define EBT_DROP -2 ++#define EBT_CONTINUE -3 ++#define EBT_RETURN -4 ++#define NUM_STANDARD_TARGETS 4 ++ ++struct ebt_counter ++{ ++ uint64_t pcnt; ++ uint64_t bcnt; ++}; ++ ++struct ebt_entries { ++ // this field is always set to zero ++ // See EBT_ENTRY_OR_ENTRIES. ++ // Must be same size as ebt_entry.bitmask ++ unsigned int distinguisher; ++ // the chain name ++ char name[EBT_CHAIN_MAXNAMELEN]; ++ // counter offset for this chain ++ unsigned int counter_offset; ++ // one standard (accept, drop, return) per hook ++ int policy; ++ // nr. of entries ++ unsigned int nentries; ++ // entry list ++ char data[0]; ++}; ++ ++// used for the bitmask of struct ebt_entry ++ ++// This is a hack to make a difference between an ebt_entry struct and an ++// ebt_entries struct when traversing the entries from start to end. ++// Using this simplifies the code alot, while still being able to use ++// ebt_entries. ++// Contrary, iptables doesn't use something like ebt_entries and therefore uses ++// different techniques for naming the policy and such. So, iptables doesn't ++// need a hack like this. ++#define EBT_ENTRY_OR_ENTRIES 0x01 ++// these are the normal masks ++#define EBT_NOPROTO 0x02 ++#define EBT_802_3 0x04 ++#define EBT_SOURCEMAC 0x08 ++#define EBT_DESTMAC 0x10 ++#define EBT_F_MASK (EBT_NOPROTO | EBT_802_3 | EBT_SOURCEMAC | EBT_DESTMAC \ ++ | EBT_ENTRY_OR_ENTRIES) ++ ++#define EBT_IPROTO 0x01 ++#define EBT_IIN 0x02 ++#define EBT_IOUT 0x04 ++#define EBT_ISOURCE 0x8 ++#define EBT_IDEST 0x10 ++#define EBT_ILOGICALIN 0x20 ++#define EBT_ILOGICALOUT 0x40 ++#define EBT_INV_MASK (EBT_IPROTO | EBT_IIN | EBT_IOUT | EBT_ILOGICALIN \ ++ | EBT_ILOGICALOUT | EBT_ISOURCE | EBT_IDEST) ++ ++struct ebt_entry_match ++{ ++ union { ++ char name[EBT_FUNCTION_MAXNAMELEN]; ++ struct ebt_match *match; ++ } u; ++ // size of data ++ unsigned int match_size; ++ unsigned char data[0]; ++}; ++ ++struct ebt_entry_watcher ++{ ++ union { ++ char name[EBT_FUNCTION_MAXNAMELEN]; ++ struct ebt_watcher *watcher; ++ } u; ++ // size of data ++ unsigned int watcher_size; ++ unsigned char data[0]; ++}; ++ ++struct ebt_entry_target ++{ ++ union { ++ char name[EBT_FUNCTION_MAXNAMELEN]; ++ struct ebt_target *target; ++ } u; ++ // size of data ++ unsigned int target_size; ++ unsigned char data[0]; ++}; ++ ++#define EBT_STANDARD_TARGET "standard" ++struct ebt_standard_target ++{ ++ struct ebt_entry_target target; ++ int verdict; ++}; ++ ++// one entry ++struct ebt_entry { ++ // this needs to be the first field ++ unsigned int bitmask; ++ unsigned int invflags; ++ uint16_t ethproto; ++ // the physical in-dev ++ char in[IFNAMSIZ]; ++ // the logical in-dev ++ char logical_in[IFNAMSIZ]; ++ // the physical out-dev ++ char out[IFNAMSIZ]; ++ // the logical out-dev ++ char logical_out[IFNAMSIZ]; ++ unsigned char sourcemac[ETH_ALEN]; ++ unsigned char sourcemsk[ETH_ALEN]; ++ unsigned char destmac[ETH_ALEN]; ++ unsigned char destmsk[ETH_ALEN]; ++ // sizeof ebt_entry + matches ++ unsigned int watchers_offset; ++ // sizeof ebt_entry + matches + watchers ++ unsigned int target_offset; ++ // sizeof ebt_entry + matches + watchers + target ++ unsigned int next_offset; ++ unsigned char elems[0]; ++}; ++ ++struct ebt_replace ++{ ++ char name[EBT_TABLE_MAXNAMELEN]; ++ unsigned int valid_hooks; ++ // nr of rules in the table ++ unsigned int nentries; ++ // total size of the entries ++ unsigned int entries_size; ++ // start of the chains ++ struct ebt_entries *hook_entry[NF_BR_NUMHOOKS]; ++ // nr of counters userspace expects back ++ unsigned int num_counters; ++ // where the kernel will put the old counters ++ struct ebt_counter *counters; ++ char *entries; ++}; ++ ++// [gs]etsockopt numbers ++#define EBT_BASE_CTL 128 ++ ++#define EBT_SO_SET_ENTRIES (EBT_BASE_CTL) ++#define EBT_SO_SET_COUNTERS (EBT_SO_SET_ENTRIES+1) ++#define EBT_SO_SET_MAX (EBT_SO_SET_COUNTERS+1) ++ ++#define EBT_SO_GET_INFO (EBT_BASE_CTL) ++#define EBT_SO_GET_ENTRIES (EBT_SO_GET_INFO+1) ++#define EBT_SO_GET_INIT_INFO (EBT_SO_GET_ENTRIES+1) ++#define EBT_SO_GET_INIT_ENTRIES (EBT_SO_GET_INIT_INFO+1) ++#define EBT_SO_GET_MAX (EBT_SO_GET_INIT_ENTRIES+1) ++ ++#ifdef __KERNEL__ ++ ++// return values for match() functions ++#define EBT_MATCH 0 ++#define EBT_NOMATCH 1 ++ ++struct ebt_match ++{ ++ struct list_head list; ++ const char name[EBT_FUNCTION_MAXNAMELEN]; ++ // 0 == it matches ++ int (*match)(const struct sk_buff *skb, const struct net_device *in, ++ const struct net_device *out, const void *matchdata, ++ unsigned int datalen); ++ // 0 == let it in ++ int (*check)(const char *tablename, unsigned int hookmask, ++ const struct ebt_entry *e, void *matchdata, unsigned int datalen); ++ void (*destroy)(void *matchdata, unsigned int datalen); ++ struct module *me; ++}; ++ ++struct ebt_watcher ++{ ++ struct list_head list; ++ const char name[EBT_FUNCTION_MAXNAMELEN]; ++ void (*watcher)(const struct sk_buff *skb, const struct net_device *in, ++ const struct net_device *out, const void *watcherdata, ++ unsigned int datalen); ++ // 0 == let it in ++ int (*check)(const char *tablename, unsigned int hookmask, ++ const struct ebt_entry *e, void *watcherdata, unsigned int datalen); ++ void (*destroy)(void *watcherdata, unsigned int datalen); ++ struct module *me; ++}; ++ ++struct ebt_target ++{ ++ struct list_head list; ++ const char name[EBT_FUNCTION_MAXNAMELEN]; ++ // returns one of the standard verdicts ++ int (*target)(struct sk_buff **pskb, unsigned int hooknr, ++ const struct net_device *in, const struct net_device *out, ++ const void *targetdata, unsigned int datalen); ++ // 0 == let it in ++ int (*check)(const char *tablename, unsigned int hookmask, ++ const struct ebt_entry *e, void *targetdata, unsigned int datalen); ++ void (*destroy)(void *targetdata, unsigned int datalen); ++ struct module *me; ++}; ++ ++// used for jumping from and into user defined chains (udc) ++struct ebt_chainstack ++{ ++ struct ebt_entries *chaininfo; // pointer to chain data ++ struct ebt_entry *e; // pointer to entry data ++ unsigned int n; // n'th entry ++}; ++ ++struct ebt_table_info ++{ ++ // total size of the entries ++ unsigned int entries_size; ++ unsigned int nentries; ++ // pointers to the start of the chains ++ struct ebt_entries *hook_entry[NF_BR_NUMHOOKS]; ++ // room to maintain the stack used for jumping from and into udc ++ struct ebt_chainstack **chainstack; ++ char *entries; ++ struct ebt_counter counters[0] ____cacheline_aligned; ++}; ++ ++struct ebt_table ++{ ++ struct list_head list; ++ char name[EBT_TABLE_MAXNAMELEN]; ++ struct ebt_replace *table; ++ unsigned int valid_hooks; ++ rwlock_t lock; ++ // e.g. could be the table explicitly only allows certain ++ // matches, targets, ... 0 == let it in ++ int (*check)(const struct ebt_table_info *info, ++ unsigned int valid_hooks); ++ // the data used by the kernel ++ struct ebt_table_info *private; ++}; ++ ++#define EBT_ALIGN(s) (((s) + (__alignof__(struct ebt_entry_target)-1)) & \ ++ ~(__alignof__(struct ebt_entry_target)-1)) ++extern int ebt_register_table(struct ebt_table *table); ++extern void ebt_unregister_table(struct ebt_table *table); ++extern int ebt_register_match(struct ebt_match *match); ++extern void ebt_unregister_match(struct ebt_match *match); ++extern int ebt_register_watcher(struct ebt_watcher *watcher); ++extern void ebt_unregister_watcher(struct ebt_watcher *watcher); ++extern int ebt_register_target(struct ebt_target *target); ++extern void ebt_unregister_target(struct ebt_target *target); ++extern unsigned int ebt_do_table(unsigned int hook, struct sk_buff **pskb, ++ const struct net_device *in, const struct net_device *out, ++ struct ebt_table *table); ++ ++ // Used in the kernel match() functions ++#define FWINV(bool,invflg) ((bool) ^ !!(info->invflags & invflg)) ++// True if the hook mask denotes that the rule is in a base chain, ++// used in the check() functions ++#define BASE_CHAIN (hookmask & (1 << NF_BR_NUMHOOKS)) ++// Clear the bit in the hook mask that tells if the rule is on a base chain ++#define CLEAR_BASE_CHAIN_BIT (hookmask &= ~(1 << NF_BR_NUMHOOKS)) ++// True if the target is not a standard target ++#define INVALID_TARGET (info->target < -NUM_STANDARD_TARGETS || info->target >= 0) ++ ++#endif /* __KERNEL__ */ ++ ++// blatently stolen from ip_tables.h ++// fn returns 0 to continue iteration ++#define EBT_MATCH_ITERATE(e, fn, args...) \ ++({ \ ++ unsigned int __i; \ ++ int __ret = 0; \ ++ struct ebt_entry_match *__match; \ ++ \ ++ for (__i = sizeof(struct ebt_entry); \ ++ __i < (e)->watchers_offset; \ ++ __i += __match->match_size + \ ++ sizeof(struct ebt_entry_match)) { \ ++ __match = (void *)(e) + __i; \ ++ \ ++ __ret = fn(__match , ## args); \ ++ if (__ret != 0) \ ++ break; \ ++ } \ ++ if (__ret == 0) { \ ++ if (__i != (e)->watchers_offset) \ ++ __ret = -EINVAL; \ ++ } \ ++ __ret; \ ++}) ++ ++#define EBT_WATCHER_ITERATE(e, fn, args...) \ ++({ \ ++ unsigned int __i; \ ++ int __ret = 0; \ ++ struct ebt_entry_watcher *__watcher; \ ++ \ ++ for (__i = e->watchers_offset; \ ++ __i < (e)->target_offset; \ ++ __i += __watcher->watcher_size + \ ++ sizeof(struct ebt_entry_watcher)) { \ ++ __watcher = (void *)(e) + __i; \ ++ \ ++ __ret = fn(__watcher , ## args); \ ++ if (__ret != 0) \ ++ break; \ ++ } \ ++ if (__ret == 0) { \ ++ if (__i != (e)->target_offset) \ ++ __ret = -EINVAL; \ ++ } \ ++ __ret; \ ++}) ++ ++#define EBT_ENTRY_ITERATE(entries, size, fn, args...) \ ++({ \ ++ unsigned int __i; \ ++ int __ret = 0; \ ++ struct ebt_entry *__entry; \ ++ \ ++ for (__i = 0; __i < (size);) { \ ++ __entry = (void *)(entries) + __i; \ ++ __ret = fn(__entry , ## args); \ ++ if (__ret != 0) \ ++ break; \ ++ if (__entry->bitmask != 0) \ ++ __i += __entry->next_offset; \ ++ else \ ++ __i += sizeof(struct ebt_entries); \ ++ } \ ++ if (__ret == 0) { \ ++ if (__i != (size)) \ ++ __ret = -EINVAL; \ ++ } \ ++ __ret; \ ++}) ++ ++#endif +diff -Nurb src/linux/linux.stock/include/linux/netfilter_bridge.h src/linux/linux/include/linux/netfilter_bridge.h +--- src/linux/linux.stock/include/linux/netfilter_bridge.h 2003-07-04 04:12:26.000000000 -0400 ++++ src/linux/linux/include/linux/netfilter_bridge.h 2004-07-10 23:46:39.000000000 -0400 +@@ -6,6 +6,10 @@ + + #include <linux/config.h> + #include <linux/netfilter.h> ++#if defined(__KERNEL__) && defined(CONFIG_NETFILTER) ++#include <asm/atomic.h> ++#include <linux/if_ether.h> ++#endif + + /* Bridge Hooks */ + /* After promisc drops, checksum checks. */ +@@ -18,7 +22,76 @@ + #define NF_BR_LOCAL_OUT 3 + /* Packets about to hit the wire. */ + #define NF_BR_POST_ROUTING 4 +-#define NF_BR_NUMHOOKS 5 ++/* Not really a hook, but used for the ebtables broute table */ ++#define NF_BR_BROUTING 5 ++#define NF_BR_NUMHOOKS 6 ++ ++#ifdef __KERNEL__ ++ ++#define BRNF_PKT_TYPE 0x01 ++#define BRNF_BRIDGED_DNAT 0x02 ++#define BRNF_DONT_TAKE_PARENT 0x04 ++#define BRNF_BRIDGED 0x08 ++#define BRNF_NF_BRIDGE_PREROUTING 0x10 ++ ++enum nf_br_hook_priorities { ++ NF_BR_PRI_FIRST = INT_MIN, ++ NF_BR_PRI_NAT_DST_BRIDGED = -300, ++ NF_BR_PRI_FILTER_BRIDGED = -200, ++ NF_BR_PRI_BRNF = 0, ++ NF_BR_PRI_NAT_DST_OTHER = 100, ++ NF_BR_PRI_FILTER_OTHER = 200, ++ NF_BR_PRI_NAT_SRC = 300, ++ NF_BR_PRI_LAST = INT_MAX, ++}; ++ ++#ifdef CONFIG_NETFILTER ++static inline ++struct nf_bridge_info *nf_bridge_alloc(struct sk_buff *skb) ++{ ++ struct nf_bridge_info **nf_bridge = &(skb->nf_bridge); ++ ++ if ((*nf_bridge = kmalloc(sizeof(**nf_bridge), GFP_ATOMIC)) != NULL) { ++ atomic_set(&(*nf_bridge)->use, 1); ++ (*nf_bridge)->mask = 0; ++ (*nf_bridge)->physindev = (*nf_bridge)->physoutdev = NULL; ++#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) ++ (*nf_bridge)->netoutdev = NULL; ++#endif ++ } ++ ++ return *nf_bridge; ++} ++ ++/* Only used in br_forward.c */ ++static inline ++void nf_bridge_maybe_copy_header(struct sk_buff *skb) ++{ ++ if (skb->nf_bridge) { ++ if (skb->protocol == __constant_htons(ETH_P_8021Q)) { ++ memcpy(skb->data - 18, skb->nf_bridge->data, 18); ++ skb_push(skb, 4); ++ } else ++ memcpy(skb->data - 16, skb->nf_bridge->data, 16); ++ } ++} ++ ++static inline ++void nf_bridge_save_header(struct sk_buff *skb) ++{ ++ int header_size = 16; ++ ++ if (skb->protocol == __constant_htons(ETH_P_8021Q)) ++ header_size = 18; ++ memcpy(skb->nf_bridge->data, skb->data - header_size, header_size); ++} + ++struct bridge_skb_cb { ++ union { ++ __u32 ipv4; ++ } daddr; ++}; ++#endif /* CONFIG_NETFILTER */ + ++#endif /* __KERNEL__ */ + #endif +diff -Nurb src/linux/linux.stock/include/linux/netfilter_ipv4/ipt_physdev.h src/linux/linux/include/linux/netfilter_ipv4/ipt_physdev.h +--- src/linux/linux.stock/include/linux/netfilter_ipv4/ipt_physdev.h 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/include/linux/netfilter_ipv4/ipt_physdev.h 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,24 @@ ++#ifndef _IPT_PHYSDEV_H ++#define _IPT_PHYSDEV_H ++ ++#ifdef __KERNEL__ ++#include <linux/if.h> ++#endif ++ ++#define IPT_PHYSDEV_OP_IN 0x01 ++#define IPT_PHYSDEV_OP_OUT 0x02 ++#define IPT_PHYSDEV_OP_BRIDGED 0x04 ++#define IPT_PHYSDEV_OP_ISIN 0x08 ++#define IPT_PHYSDEV_OP_ISOUT 0x10 ++#define IPT_PHYSDEV_OP_MASK (0x20 - 1) ++ ++struct ipt_physdev_info { ++ char physindev[IFNAMSIZ]; ++ char in_mask[IFNAMSIZ]; ++ char physoutdev[IFNAMSIZ]; ++ char out_mask[IFNAMSIZ]; ++ u_int8_t invert; ++ u_int8_t bitmask; ++}; ++ ++#endif /*_IPT_PHYSDEV_H*/ +diff -Nurb src/linux/linux.stock/include/linux/netfilter_ipv4.h src/linux/linux/include/linux/netfilter_ipv4.h +--- src/linux/linux.stock/include/linux/netfilter_ipv4.h 2004-07-10 23:30:09.000000000 -0400 ++++ src/linux/linux/include/linux/netfilter_ipv4.h 2004-07-10 23:46:39.000000000 -0400 +@@ -54,8 +54,10 @@ + NF_IP_PRI_CONNTRACK_DEFRAG = -400, + NF_IP_PRI_RAW = -300, + NF_IP_PRI_CONNTRACK = -200, ++ NF_IP_PRI_BRIDGE_SABOTAGE_FORWARD = -175, + NF_IP_PRI_MANGLE = -150, + NF_IP_PRI_NAT_DST = -100, ++ NF_IP_PRI_BRIDGE_SABOTAGE_LOCAL_OUT = -50, + NF_IP_PRI_FILTER = 0, + NF_IP_PRI_NAT_SRC = 100, + NF_IP_PRI_LAST = INT_MAX, +diff -Nurb src/linux/linux.stock/include/linux/skbuff.h src/linux/linux/include/linux/skbuff.h +--- src/linux/linux.stock/include/linux/skbuff.h 2003-07-04 04:12:26.000000000 -0400 ++++ src/linux/linux/include/linux/skbuff.h 2004-07-10 23:46:39.000000000 -0400 +@@ -92,6 +92,20 @@ + struct nf_ct_info { + struct nf_conntrack *master; + }; ++ ++#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) ++struct nf_bridge_info { ++ atomic_t use; ++ struct net_device *physindev; ++ struct net_device *physoutdev; ++#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) ++ struct net_device *netoutdev; ++#endif ++ unsigned int mask; ++ unsigned long data[32 / sizeof(unsigned long)]; ++}; ++#endif ++ + #endif + + struct sk_buff_head { +@@ -204,6 +218,9 @@ + #ifdef CONFIG_NETFILTER_DEBUG + unsigned int nf_debug; + #endif ++#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) ++ struct nf_bridge_info *nf_bridge; /* Saved data about a bridged frame - see br_netfilter.c */ ++#endif + #endif /*CONFIG_NETFILTER*/ + + #if defined(CONFIG_HIPPI) +@@ -1143,6 +1160,20 @@ + if (nfct) + atomic_inc(&nfct->master->use); + } ++ ++#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) ++static inline void nf_bridge_put(struct nf_bridge_info *nf_bridge) ++{ ++ if (nf_bridge && atomic_dec_and_test(&nf_bridge->use)) ++ kfree(nf_bridge); ++} ++static inline void nf_bridge_get(struct nf_bridge_info *nf_bridge) ++{ ++ if (nf_bridge) ++ atomic_inc(&nf_bridge->use); ++} ++#endif ++ + #endif + + #endif /* __KERNEL__ */ +diff -Nurb src/linux/linux.stock/include/linux/sysctl.h src/linux/linux/include/linux/sysctl.h +--- src/linux/linux.stock/include/linux/sysctl.h 2004-07-10 23:29:55.000000000 -0400 ++++ src/linux/linux/include/linux/sysctl.h 2004-07-10 23:46:39.000000000 -0400 +@@ -547,6 +547,15 @@ + NET_DECNET_CONF_DEV_STATE = 7 + }; + ++/* /proc/sys/net/bridge */ ++enum { ++ NET_BRIDGE_NF_CALL_ARPTABLES = 1, ++ NET_BRIDGE_NF_CALL_IPTABLES = 2, ++ NET_BRIDGE_NF_CALL_IP6TABLES = 3, ++ NET_BRIDGE_NF_FILTER_VLAN_TAGGED = 4, ++}; ++ ++ + /* CTL_PROC names: */ + + /* CTL_FS names: */ +diff -Nurb src/linux/linux.stock/net/8021q/vlan_dev.c src/linux/linux/net/8021q/vlan_dev.c +--- src/linux/linux.stock/net/8021q/vlan_dev.c 2003-07-04 04:12:29.000000000 -0400 ++++ src/linux/linux/net/8021q/vlan_dev.c 2004-07-10 23:46:39.000000000 -0400 +@@ -503,6 +503,10 @@ + stats->tx_packets++; /* for statics only */ + stats->tx_bytes += skb->len; + ++ skb->protocol = __constant_htons(ETH_P_8021Q); ++ skb->mac.raw -= VLAN_HLEN; ++ skb->nh.raw -= VLAN_HLEN; ++ + dev_queue_xmit(skb); + + return 0; +diff -Nurb src/linux/linux.stock/net/Config.in src/linux/linux/net/Config.in +--- src/linux/linux.stock/net/Config.in 2004-07-10 23:29:49.000000000 -0400 ++++ src/linux/linux/net/Config.in 2004-07-10 23:46:39.000000000 -0400 +@@ -68,6 +68,9 @@ + source net/decnet/Config.in + fi + dep_tristate '802.1d Ethernet Bridging' CONFIG_BRIDGE $CONFIG_INET ++if [ "$CONFIG_BRIDGE" != "n" -a "$CONFIG_NETFILTER" != "n" ]; then ++ source net/bridge/netfilter/Config.in ++fi + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'CCITT X.25 Packet Layer (EXPERIMENTAL)' CONFIG_X25 + tristate 'LAPB Data Link Driver (EXPERIMENTAL)' CONFIG_LAPB +diff -Nurb src/linux/linux.stock/net/Makefile src/linux/linux/net/Makefile +--- src/linux/linux.stock/net/Makefile 2004-07-10 23:29:49.000000000 -0400 ++++ src/linux/linux/net/Makefile 2004-07-10 23:49:10.000000000 -0400 +@@ -26,6 +26,12 @@ + endif + endif + ++ifneq ($(CONFIG_BRIDGE),n) ++ifneq ($(CONFIG_BRIDGE),) ++subdir-$(CONFIG_BRIDGE) += bridge/netfilter ++endif ++endif ++ + subdir-$(CONFIG_KHTTPD) += khttpd + subdir-$(CONFIG_PACKET) += packet + subdir-$(CONFIG_NET_SCHED) += sched +diff -Nurb src/linux/linux.stock/net/bridge/Makefile src/linux/linux/net/bridge/Makefile +--- src/linux/linux.stock/net/bridge/Makefile 2003-07-04 04:12:30.000000000 -0400 ++++ src/linux/linux/net/bridge/Makefile 2004-07-10 23:46:39.000000000 -0400 +@@ -7,10 +7,17 @@ + # + # Note 2! The CFLAGS definition is now in the main makefile... + ++export-objs := br.o ++ + O_TARGET := bridge.o + obj-y := br.o br_device.o br_fdb.o br_forward.o br_if.o br_input.o \ + br_ioctl.o br_notify.o br_stp.o br_stp_bpdu.o \ + br_stp_if.o br_stp_timer.o ++ ++ifeq ($(CONFIG_NETFILTER),y) ++obj-y += br_netfilter.o ++endif ++ + obj-m := $(O_TARGET) + + include $(TOPDIR)/Rules.make +diff -Nurb src/linux/linux.stock/net/bridge/br.c src/linux/linux/net/bridge/br.c +--- src/linux/linux.stock/net/bridge/br.c 2003-10-14 04:09:32.000000000 -0400 ++++ src/linux/linux/net/bridge/br.c 2004-07-10 23:46:39.000000000 -0400 +@@ -29,6 +29,8 @@ + #include "../atm/lec.h" + #endif + ++int (*br_should_route_hook) (struct sk_buff **pskb) = NULL; ++ + void br_dec_use_count() + { + MOD_DEC_USE_COUNT; +@@ -43,6 +45,10 @@ + { + printk(KERN_INFO "NET4: Ethernet Bridge 008 for NET4.0\n"); + ++#ifdef CONFIG_NETFILTER ++ if (br_netfilter_init()) ++ return 1; ++#endif + br_handle_frame_hook = br_handle_frame; + br_ioctl_hook = br_ioctl_deviceless_stub; + #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) +@@ -61,6 +67,9 @@ + + static void __exit br_deinit(void) + { ++#ifdef CONFIG_NETFILTER ++ br_netfilter_fini(); ++#endif + unregister_netdevice_notifier(&br_device_notifier); + br_call_ioctl_atomic(__br_clear_ioctl_hook); + +@@ -74,7 +83,7 @@ + #endif + } + +-EXPORT_NO_SYMBOLS; ++EXPORT_SYMBOL(br_should_route_hook); + + module_init(br_init) + module_exit(br_deinit) +diff -Nurb src/linux/linux.stock/net/bridge/br_forward.c src/linux/linux/net/bridge/br_forward.c +--- src/linux/linux.stock/net/bridge/br_forward.c 2003-10-14 04:09:32.000000000 -0400 ++++ src/linux/linux/net/bridge/br_forward.c 2004-07-10 23:46:39.000000000 -0400 +@@ -30,18 +30,21 @@ + return 1; + } + +-static int __dev_queue_push_xmit(struct sk_buff *skb) ++int br_dev_queue_push_xmit(struct sk_buff *skb) + { ++#ifdef CONFIG_NETFILTER ++ nf_bridge_maybe_copy_header(skb); ++#endif + skb_push(skb, ETH_HLEN); + dev_queue_xmit(skb); + + return 0; + } + +-static int __br_forward_finish(struct sk_buff *skb) ++int br_forward_finish(struct sk_buff *skb) + { + NF_HOOK(PF_BRIDGE, NF_BR_POST_ROUTING, skb, NULL, skb->dev, +- __dev_queue_push_xmit); ++ br_dev_queue_push_xmit); + + return 0; + } +@@ -49,8 +52,11 @@ + static void __br_deliver(struct net_bridge_port *to, struct sk_buff *skb) + { + skb->dev = to->dev; ++#ifdef CONFIG_NETFILTER_DEBUG ++ skb->nf_debug = 0; ++#endif + NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, +- __br_forward_finish); ++ br_forward_finish); + } + + static void __br_forward(struct net_bridge_port *to, struct sk_buff *skb) +@@ -61,7 +67,7 @@ + skb->dev = to->dev; + + NF_HOOK(PF_BRIDGE, NF_BR_FORWARD, skb, indev, skb->dev, +- __br_forward_finish); ++ br_forward_finish); + } + + /* called under bridge lock */ +diff -Nurb src/linux/linux.stock/net/bridge/br_input.c src/linux/linux/net/bridge/br_input.c +--- src/linux/linux.stock/net/bridge/br_input.c 2003-10-14 04:09:32.000000000 -0400 ++++ src/linux/linux/net/bridge/br_input.c 2004-07-10 23:48:36.000000000 -0400 +@@ -24,6 +24,9 @@ + + static int br_pass_frame_up_finish(struct sk_buff *skb) + { ++#ifdef CONFIG_NETFILTER_DEBUG ++ skb->nf_debug = 0; ++#endif + netif_rx(skb); + + return 0; +@@ -46,7 +49,7 @@ + br_pass_frame_up_finish); + } + +-static int br_handle_frame_finish(struct sk_buff *skb) ++int br_handle_frame_finish(struct sk_buff *skb) + { + struct net_bridge *br; + unsigned char *dest; +@@ -112,7 +115,7 @@ + return 0; + } + +-void br_handle_frame(struct sk_buff *skb) ++int br_handle_frame(struct sk_buff *skb) + { + struct net_bridge *br; + unsigned char *dest; +@@ -146,25 +149,34 @@ + goto handle_special_frame; + + if (p->state == BR_STATE_FORWARDING) { ++ if (br_should_route_hook && br_should_route_hook(&skb)) { ++ read_unlock(&br->lock); ++ return -1; ++ } ++ ++ if (!memcmp(p->br->dev.dev_addr, dest, ETH_ALEN)) ++ skb->pkt_type = PACKET_HOST; ++ + NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, + br_handle_frame_finish); + read_unlock(&br->lock); +- return; ++ return 0; + } + + err: + read_unlock(&br->lock); + err_nolock: + kfree_skb(skb); +- return; ++ return 0; + + handle_special_frame: + if (!dest[5]) { + br_stp_handle_bpdu(skb); + read_unlock(&br->lock); +- return; ++ return 0; + } + + read_unlock(&br->lock); + kfree_skb(skb); ++ return 0; + } +diff -Nurb src/linux/linux.stock/net/bridge/br_netfilter.c src/linux/linux/net/bridge/br_netfilter.c +--- src/linux/linux.stock/net/bridge/br_netfilter.c 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/net/bridge/br_netfilter.c 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,896 @@ ++/* ++ * Handle firewalling ++ * Linux ethernet bridge ++ * ++ * Authors: ++ * Lennert Buytenhek <buytenh@gnu.org> ++ * Bart De Schuymer (maintainer) <bdschuym@pandora.be> ++ * ++ * Changes: ++ * Apr 29 2003: physdev module support (bdschuym) ++ * Jun 19 2003: let arptables see bridged ARP traffic (bdschuym) ++ * Oct 06 2003: filter encapsulated IP/ARP VLAN traffic on untagged bridge ++ * (bdschuym) ++ * ++ * 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. ++ * ++ * Lennert dedicates this file to Kerstin Wurdinger. ++ */ ++ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/ip.h> ++#include <linux/netdevice.h> ++#include <linux/skbuff.h> ++#include <linux/if_ether.h> ++#include <linux/if_vlan.h> ++#include <linux/netfilter_bridge.h> ++#include <linux/netfilter_ipv4.h> ++#include <linux/in_route.h> ++#include <net/ip.h> ++#include <asm/uaccess.h> ++#include <asm/checksum.h> ++#include "br_private.h" ++#ifdef CONFIG_SYSCTL ++#include <linux/sysctl.h> ++#endif ++ ++ ++#define skb_origaddr(skb) (((struct bridge_skb_cb *) \ ++ (skb->nf_bridge->data))->daddr.ipv4) ++#define store_orig_dstaddr(skb) (skb_origaddr(skb) = (skb)->nh.iph->daddr) ++#define dnat_took_place(skb) (skb_origaddr(skb) != (skb)->nh.iph->daddr) ++ ++#define has_bridge_parent(device) ((device)->br_port != NULL) ++#define bridge_parent(device) (&((device)->br_port->br->dev)) ++ ++#ifdef CONFIG_SYSCTL ++static struct ctl_table_header *brnf_sysctl_header; ++static int brnf_call_iptables = 1; ++static int brnf_call_arptables = 1; ++static int brnf_filter_vlan_tagged = 1; ++#else ++#define brnf_filter_vlan_tagged 1 ++#endif ++ ++#define IS_VLAN_IP (skb->protocol == __constant_htons(ETH_P_8021Q) && \ ++ hdr->h_vlan_encapsulated_proto == __constant_htons(ETH_P_IP) && \ ++ brnf_filter_vlan_tagged) ++/* ++#define IS_VLAN_ARP (skb->protocol == __constant_htons(ETH_P_8021Q) && \ ++ hdr->h_vlan_encapsulated_proto == __constant_htons(ETH_P_ARP) && \ ++ brnf_filter_vlan_tagged) ++*/ ++ ++/* We need these fake structures to make netfilter happy -- ++ * lots of places assume that skb->dst != NULL, which isn't ++ * all that unreasonable. ++ * ++ * Currently, we fill in the PMTU entry because netfilter ++ * refragmentation needs it, and the rt_flags entry because ++ * ipt_REJECT needs it. Future netfilter modules might ++ * require us to fill additional fields. ++ */ ++static struct net_device __fake_net_device = { ++ .hard_header_len = ETH_HLEN ++}; ++ ++static struct rtable __fake_rtable = { ++ u: { ++ dst: { ++ __refcnt: ATOMIC_INIT(1), ++ dev: &__fake_net_device, ++ pmtu: 1500 ++ } ++ }, ++ ++ rt_flags: 0 ++}; ++ ++ ++/* PF_BRIDGE/PRE_ROUTING *********************************************/ ++static void __br_dnat_complain(void) ++{ ++ static unsigned long last_complaint; ++ ++ if (jiffies - last_complaint >= 5 * HZ) { ++ printk(KERN_WARNING "Performing cross-bridge DNAT requires IP " ++ "forwarding to be enabled\n"); ++ last_complaint = jiffies; ++ } ++} ++ ++ ++/* This requires some explaining. If DNAT has taken place, ++ * we will need to fix up the destination Ethernet address, ++ * and this is a tricky process. ++ * ++ * There are two cases to consider: ++ * 1. The packet was DNAT'ed to a device in the same bridge ++ * port group as it was received on. We can still bridge ++ * the packet. ++ * 2. The packet was DNAT'ed to a different device, either ++ * a non-bridged device or another bridge port group. ++ * The packet will need to be routed. ++ * ++ * The correct way of distinguishing between these two cases is to ++ * call ip_route_input() and to look at skb->dst->dev, which is ++ * changed to the destination device if ip_route_input() succeeds. ++ * ++ * Let us first consider the case that ip_route_input() succeeds: ++ * ++ * If skb->dst->dev equals the logical bridge device the packet ++ * came in on, we can consider this bridging. We then call ++ * skb->dst->output() which will make the packet enter br_nf_local_out() ++ * not much later. In that function it is assured that the iptables ++ * FORWARD chain is traversed for the packet. ++ * ++ * Otherwise, the packet is considered to be routed and we just ++ * change the destination MAC address so that the packet will ++ * later be passed up to the IP stack to be routed. ++ * ++ * Let us now consider the case that ip_route_input() fails: ++ * ++ * After a "echo '0' > /proc/sys/net/ipv4/ip_forward" ip_route_input() ++ * will fail, while __ip_route_output_key() will return success. The source ++ * address for __ip_route_output_key() is set to zero, so __ip_route_output_key ++ * thinks we're handling a locally generated packet and won't care ++ * if IP forwarding is allowed. We send a warning message to the users's ++ * log telling her to put IP forwarding on. ++ * ++ * ip_route_input() will also fail if there is no route available. ++ * In that case we just drop the packet. ++ * ++ * --Lennert, 20020411 ++ * --Bart, 20020416 (updated) ++ * --Bart, 20021007 (updated) ++ */ ++ ++static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb) ++{ ++#ifdef CONFIG_NETFILTER_DEBUG ++ skb->nf_debug |= (1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_FORWARD); ++#endif ++ ++ if (skb->pkt_type == PACKET_OTHERHOST) { ++ skb->pkt_type = PACKET_HOST; ++ skb->nf_bridge->mask |= BRNF_PKT_TYPE; ++ } ++ skb->nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING; ++ ++ skb->dev = bridge_parent(skb->dev); ++ if (skb->protocol == __constant_htons(ETH_P_8021Q)) { ++ skb_pull(skb, VLAN_HLEN); ++ skb->nh.raw += VLAN_HLEN; ++ } ++ skb->dst->output(skb); ++ return 0; ++} ++ ++static int br_nf_pre_routing_finish(struct sk_buff *skb) ++{ ++ struct net_device *dev = skb->dev; ++ struct iphdr *iph = skb->nh.iph; ++ struct nf_bridge_info *nf_bridge = skb->nf_bridge; ++ ++#ifdef CONFIG_NETFILTER_DEBUG ++ skb->nf_debug ^= (1 << NF_BR_PRE_ROUTING); ++#endif ++ ++ if (nf_bridge->mask & BRNF_PKT_TYPE) { ++ skb->pkt_type = PACKET_OTHERHOST; ++ nf_bridge->mask ^= BRNF_PKT_TYPE; ++ } ++ nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING; ++ ++ if (dnat_took_place(skb)) { ++ if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, ++ dev)) { ++ struct rtable *rt; ++ ++ if (!ip_route_output(&rt, iph->daddr, 0, iph->tos, 0)) { ++ /* Bridged-and-DNAT'ed traffic doesn't ++ * require ip_forwarding. ++ */ ++ if (((struct dst_entry *)rt)->dev == dev) { ++ skb->dst = (struct dst_entry *)rt; ++ goto bridged_dnat; ++ } ++ __br_dnat_complain(); ++ dst_release((struct dst_entry *)rt); ++ } ++ kfree_skb(skb); ++ return 0; ++ } else { ++ if (skb->dst->dev == dev) { ++bridged_dnat: ++ /* Tell br_nf_local_out this is a ++ * bridged frame ++ */ ++ nf_bridge->mask |= BRNF_BRIDGED_DNAT; ++ skb->dev = nf_bridge->physindev; ++ if (skb->protocol == ++ __constant_htons(ETH_P_8021Q)) { ++ skb_push(skb, VLAN_HLEN); ++ skb->nh.raw -= VLAN_HLEN; ++ } ++ NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING, ++ skb, skb->dev, NULL, ++ br_nf_pre_routing_finish_bridge, ++ 1); ++ return 0; ++ } ++ memcpy(skb->mac.ethernet->h_dest, dev->dev_addr, ++ ETH_ALEN); ++ skb->pkt_type = PACKET_HOST; ++ } ++ } else { ++ skb->dst = (struct dst_entry *)&__fake_rtable; ++ dst_hold(skb->dst); ++ } ++ ++ skb->dev = nf_bridge->physindev; ++ if (skb->protocol == __constant_htons(ETH_P_8021Q)) { ++ skb_push(skb, VLAN_HLEN); ++ skb->nh.raw -= VLAN_HLEN; ++ } ++ NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, ++ br_handle_frame_finish, 1); ++ ++ return 0; ++} ++ ++/* Replicate the checks that IPv4 does on packet reception. ++ * Set skb->dev to the bridge device (i.e. parent of the ++ * receiving device) to make netfilter happy, the REDIRECT ++ * target in particular. Save the original destination IP ++ * address to be able to detect DNAT afterwards. ++ */ ++static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff **pskb, ++ const struct net_device *in, const struct net_device *out, ++ int (*okfn)(struct sk_buff *)) ++{ ++ struct iphdr *iph; ++ __u32 len; ++ struct sk_buff *skb = *pskb; ++ struct nf_bridge_info *nf_bridge; ++ ++#ifdef CONFIG_SYSCTL ++ if (!brnf_call_iptables) ++ return NF_ACCEPT; ++#endif ++ ++ if (skb->protocol != __constant_htons(ETH_P_IP)) { ++ struct vlan_ethhdr *hdr = (struct vlan_ethhdr *) ++ ((*pskb)->mac.ethernet); ++ ++ if (!IS_VLAN_IP) ++ return NF_ACCEPT; ++ if ((skb = skb_share_check(*pskb, GFP_ATOMIC)) == NULL) ++ goto out; ++ skb_pull(*pskb, VLAN_HLEN); ++ (*pskb)->nh.raw += VLAN_HLEN; ++ } else if ((skb = skb_share_check(*pskb, GFP_ATOMIC)) == NULL) ++ goto out; ++ ++ if (!pskb_may_pull(skb, sizeof(struct iphdr))) ++ goto inhdr_error; ++ ++ iph = skb->nh.iph; ++ if (iph->ihl < 5 || iph->version != 4) ++ goto inhdr_error; ++ ++ if (!pskb_may_pull(skb, 4*iph->ihl)) ++ goto inhdr_error; ++ ++ iph = skb->nh.iph; ++ if (ip_fast_csum((__u8 *)iph, iph->ihl) != 0) ++ goto inhdr_error; ++ ++ len = ntohs(iph->tot_len); ++ if (skb->len < len || len < 4*iph->ihl) ++ goto inhdr_error; ++ ++ if (skb->len > len) { ++ __pskb_trim(skb, len); ++ if (skb->ip_summed == CHECKSUM_HW) ++ skb->ip_summed = CHECKSUM_NONE; ++ } ++ ++#ifdef CONFIG_NETFILTER_DEBUG ++ skb->nf_debug ^= (1 << NF_IP_PRE_ROUTING); ++#endif ++ if ((nf_bridge = nf_bridge_alloc(skb)) == NULL) ++ return NF_DROP; ++ ++ if (skb->pkt_type == PACKET_OTHERHOST) { ++ skb->pkt_type = PACKET_HOST; ++ nf_bridge->mask |= BRNF_PKT_TYPE; ++ } ++ ++ nf_bridge->mask |= BRNF_NF_BRIDGE_PREROUTING; ++ nf_bridge->physindev = skb->dev; ++ skb->dev = bridge_parent(skb->dev); ++ store_orig_dstaddr(skb); ++ ++ NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, skb->dev, NULL, ++ br_nf_pre_routing_finish); ++ ++ return NF_STOLEN; ++ ++inhdr_error: ++// IP_INC_STATS_BH(IpInHdrErrors); ++out: ++ return NF_DROP; ++} ++ ++ ++/* PF_BRIDGE/LOCAL_IN ************************************************/ ++/* The packet is locally destined, which requires a real ++ * dst_entry, so detach the fake one. On the way up, the ++ * packet would pass through PRE_ROUTING again (which already ++ * took place when the packet entered the bridge), but we ++ * register an IPv4 PRE_ROUTING 'sabotage' hook that will ++ * prevent this from happening. ++ */ ++static unsigned int br_nf_local_in(unsigned int hook, struct sk_buff **pskb, ++ const struct net_device *in, const struct net_device *out, ++ int (*okfn)(struct sk_buff *)) ++{ ++ struct sk_buff *skb = *pskb; ++ ++ if (skb->dst == (struct dst_entry *)&__fake_rtable) { ++ dst_release(skb->dst); ++ skb->dst = NULL; ++ } ++ ++ return NF_ACCEPT; ++} ++ ++/* PF_BRIDGE/FORWARD *************************************************/ ++static int br_nf_forward_finish(struct sk_buff *skb) ++{ ++ struct nf_bridge_info *nf_bridge = skb->nf_bridge; ++ struct net_device *in; ++ struct vlan_ethhdr *hdr = (struct vlan_ethhdr *)(skb->mac.ethernet); ++ ++#ifdef CONFIG_NETFILTER_DEBUG ++ skb->nf_debug ^= (1 << NF_BR_FORWARD); ++#endif ++ ++ if (skb->protocol == __constant_htons(ETH_P_IP) || IS_VLAN_IP) { ++ in = nf_bridge->physindev; ++ if (nf_bridge->mask & BRNF_PKT_TYPE) { ++ skb->pkt_type = PACKET_OTHERHOST; ++ nf_bridge->mask ^= BRNF_PKT_TYPE; ++ } ++ } else { ++ in = *((struct net_device **)(skb->cb)); ++ } ++ if (skb->protocol == __constant_htons(ETH_P_8021Q)) { ++ skb_push(skb, VLAN_HLEN); ++ skb->nh.raw -= VLAN_HLEN; ++ } ++ NF_HOOK_THRESH(PF_BRIDGE, NF_BR_FORWARD, skb, in, ++ skb->dev, br_forward_finish, 1); ++ return 0; ++} ++ ++/* This is the 'purely bridged' case. For IP, we pass the packet to ++ * netfilter with indev and outdev set to the bridge device, ++ * but we are still able to filter on the 'real' indev/outdev ++ * because of the ipt_physdev.c module. For ARP, indev and outdev are the ++ * bridge ports. ++ */ ++static unsigned int br_nf_forward_ip(unsigned int hook, 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 nf_bridge_info *nf_bridge; ++ struct vlan_ethhdr *hdr = (struct vlan_ethhdr *)(skb->mac.ethernet); ++ ++#ifdef CONFIG_SYSCTL ++ if (!skb->nf_bridge) ++ return NF_ACCEPT; ++#endif ++ ++ if (skb->protocol != __constant_htons(ETH_P_IP)) { ++ if (!IS_VLAN_IP) ++ return NF_ACCEPT; ++ skb_pull(*pskb, VLAN_HLEN); ++ (*pskb)->nh.raw += VLAN_HLEN; ++ } ++ ++#ifdef CONFIG_NETFILTER_DEBUG ++ skb->nf_debug ^= (1 << NF_BR_FORWARD); ++#endif ++ nf_bridge = skb->nf_bridge; ++ if (skb->pkt_type == PACKET_OTHERHOST) { ++ skb->pkt_type = PACKET_HOST; ++ nf_bridge->mask |= BRNF_PKT_TYPE; ++ } ++ ++ /* The physdev module checks on this */ ++ nf_bridge->mask |= BRNF_BRIDGED; ++ nf_bridge->physoutdev = skb->dev; ++ ++ NF_HOOK(PF_INET, NF_IP_FORWARD, skb, bridge_parent(in), ++ bridge_parent(out), br_nf_forward_finish); ++ ++ return NF_STOLEN; ++} ++ ++/* ++static unsigned int br_nf_forward_arp(unsigned int hook, 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 vlan_ethhdr *hdr = (struct vlan_ethhdr *)(skb->mac.ethernet); ++ struct net_device **d = (struct net_device **)(skb->cb); ++ ++ if (!brnf_call_arptables) ++ return NF_ACCEPT; ++ ++ if (skb->protocol != __constant_htons(ETH_P_ARP)) { ++ if (!IS_VLAN_ARP) ++ return NF_ACCEPT; ++ skb_pull(*pskb, VLAN_HLEN); ++ (*pskb)->nh.raw += VLAN_HLEN; ++ } ++ ++#ifdef CONFIG_NETFILTER_DEBUG ++ skb->nf_debug ^= (1 << NF_BR_FORWARD); ++#endif ++ ++ if (skb->nh.arph->ar_pln != 4) { ++ if (IS_VLAN_ARP) { ++ skb_push(*pskb, VLAN_HLEN); ++ (*pskb)->nh.raw -= VLAN_HLEN; ++ } ++ return NF_ACCEPT; ++ } ++ *d = (struct net_device *)in; ++ NF_HOOK(NF_ARP, NF_ARP_FORWARD, skb, (struct net_device *)in, ++ (struct net_device *)out, br_nf_forward_finish); ++ ++ return NF_STOLEN; ++} ++*/ ++ ++/* PF_BRIDGE/LOCAL_OUT ***********************************************/ ++static int br_nf_local_out_finish(struct sk_buff *skb) ++{ ++#ifdef CONFIG_NETFILTER_DEBUG ++ skb->nf_debug &= ~(1 << NF_BR_LOCAL_OUT); ++#endif ++ if (skb->protocol == __constant_htons(ETH_P_8021Q)) { ++ skb_push(skb, VLAN_HLEN); ++ skb->nh.raw -= VLAN_HLEN; ++ } ++ ++ NF_HOOK_THRESH(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, ++ br_forward_finish, NF_BR_PRI_FIRST + 1); ++ ++ return 0; ++} ++ ++ ++/* This function sees both locally originated IP packets and forwarded ++ * IP packets (in both cases the destination device is a bridge ++ * device). It also sees bridged-and-DNAT'ed packets. ++ * To be able to filter on the physical bridge devices (with the ipt_physdev.c ++ * module), we steal packets destined to a bridge device away from the ++ * PF_INET/FORWARD and PF_INET/OUTPUT hook functions, and give them back later, ++ * when we have determined the real output device. This is done in here. ++ * ++ * If (nf_bridge->mask & BRNF_BRIDGED_DNAT) then the packet is bridged ++ * and we fake the PF_BRIDGE/FORWARD hook. The function br_nf_forward() ++ * will then fake the PF_INET/FORWARD hook. br_nf_local_out() has priority ++ * NF_BR_PRI_FIRST, so no relevant PF_BRIDGE/INPUT functions have been nor ++ * will be executed. ++ * Otherwise, if nf_bridge->physindev is NULL, the bridge-nf code never touched ++ * this packet before, and so the packet was locally originated. We fake ++ * the PF_INET/LOCAL_OUT hook. ++ * Finally, if nf_bridge->physindev isn't NULL, then the packet was IP routed, ++ * so we fake the PF_INET/FORWARD hook. ipv4_sabotage_out() makes sure ++ * even routed packets that didn't arrive on a bridge interface have their ++ * nf_bridge->physindev set. ++ */ ++ ++static unsigned int br_nf_local_out(unsigned int hook, struct sk_buff **pskb, ++ const struct net_device *in, const struct net_device *out, ++ int (*_okfn)(struct sk_buff *)) ++{ ++ int (*okfn)(struct sk_buff *skb); ++ struct net_device *realindev; ++ struct sk_buff *skb = *pskb; ++ struct nf_bridge_info *nf_bridge; ++ struct vlan_ethhdr *hdr = (struct vlan_ethhdr *)(skb->mac.ethernet); ++ ++#ifdef CONFIG_SYSCTL ++ if (!skb->nf_bridge) ++ return NF_ACCEPT; ++#endif ++ ++ if (skb->protocol != __constant_htons(ETH_P_IP) && !IS_VLAN_IP) ++ return NF_ACCEPT; ++ ++ /* Sometimes we get packets with NULL ->dst here (for example, ++ * running a dhcp client daemon triggers this). ++ */ ++ if (skb->dst == NULL) ++ return NF_ACCEPT; ++ ++ nf_bridge = skb->nf_bridge; ++ nf_bridge->physoutdev = skb->dev; ++ realindev = nf_bridge->physindev; ++ ++ /* Bridged, take PF_BRIDGE/FORWARD. ++ * (see big note in front of br_nf_pre_routing_finish) ++ */ ++ if (nf_bridge->mask & BRNF_BRIDGED_DNAT) { ++ okfn = br_forward_finish; ++ ++ if (nf_bridge->mask & BRNF_PKT_TYPE) { ++ skb->pkt_type = PACKET_OTHERHOST; ++ nf_bridge->mask ^= BRNF_PKT_TYPE; ++ } ++ if (skb->protocol == __constant_htons(ETH_P_8021Q)) { ++ skb_push(skb, VLAN_HLEN); ++ skb->nh.raw -= VLAN_HLEN; ++ } ++ ++ NF_HOOK(PF_BRIDGE, NF_BR_FORWARD, skb, realindev, ++ skb->dev, okfn); ++ } else { ++ struct net_device *realoutdev = bridge_parent(skb->dev); ++ ++#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) ++ /* iptables should match -o br0.x */ ++ if (nf_bridge->netoutdev) ++ realoutdev = nf_bridge->netoutdev; ++#endif ++ okfn = br_nf_local_out_finish; ++ if (skb->protocol == __constant_htons(ETH_P_8021Q)) { ++ skb_pull(skb, VLAN_HLEN); ++ (*pskb)->nh.raw += VLAN_HLEN; ++ } ++ /* IP forwarded traffic has a physindev, locally ++ * generated traffic hasn't. ++ */ ++ if (realindev != NULL) { ++ if (((nf_bridge->mask & BRNF_DONT_TAKE_PARENT) == 0) && ++ has_bridge_parent(realindev)) ++ realindev = bridge_parent(realindev); ++ NF_HOOK_THRESH(PF_INET, NF_IP_FORWARD, skb, realindev, ++ realoutdev, okfn, ++ NF_IP_PRI_BRIDGE_SABOTAGE_FORWARD + 1); ++ } else { ++#ifdef CONFIG_NETFILTER_DEBUG ++ skb->nf_debug ^= (1 << NF_IP_LOCAL_OUT); ++#endif ++ ++ NF_HOOK_THRESH(PF_INET, NF_IP_LOCAL_OUT, skb, realindev, ++ realoutdev, okfn, ++ NF_IP_PRI_BRIDGE_SABOTAGE_LOCAL_OUT + 1); ++ } ++ } ++ ++ return NF_STOLEN; ++} ++ ++ ++/* PF_BRIDGE/POST_ROUTING ********************************************/ ++static unsigned int br_nf_post_routing(unsigned int hook, 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 nf_bridge_info *nf_bridge = (*pskb)->nf_bridge; ++ struct vlan_ethhdr *hdr = (struct vlan_ethhdr *)(skb->mac.ethernet); ++ struct net_device *realoutdev = bridge_parent(skb->dev); ++ ++#ifdef CONFIG_NETFILTER_DEBUG ++ /* Be very paranoid. This probably won't happen anymore, but let's ++ * keep the check just to be sure... */ ++ if (skb->mac.raw < skb->head || skb->mac.raw + ETH_HLEN > skb->data) { ++ printk(KERN_CRIT "br_netfilter: Argh!! br_nf_post_routing: " ++ "bad mac.raw pointer."); ++ goto print_error; ++ } ++#endif ++ ++#ifdef CONFIG_SYSCTL ++ if (!nf_bridge) ++ return NF_ACCEPT; ++#endif ++ ++ if (skb->protocol != __constant_htons(ETH_P_IP) && !IS_VLAN_IP) ++ return NF_ACCEPT; ++ ++ /* Sometimes we get packets with NULL ->dst here (for example, ++ * running a dhcp client daemon triggers this). ++ */ ++ if (skb->dst == NULL) ++ return NF_ACCEPT; ++ ++#ifdef CONFIG_NETFILTER_DEBUG ++ /* Sometimes we get packets with NULL ->dst here (for example, ++ * running a dhcp client daemon triggers this). This should now ++ * be fixed, but let's keep the check around. ++ */ ++ if (skb->dst == NULL) { ++ printk(KERN_CRIT "br_netfilter: skb->dst == NULL."); ++ goto print_error; ++ } ++ ++ skb->nf_debug ^= (1 << NF_IP_POST_ROUTING); ++#endif ++ ++ /* We assume any code from br_dev_queue_push_xmit onwards doesn't care ++ * about the value of skb->pkt_type. ++ */ ++ if (skb->pkt_type == PACKET_OTHERHOST) { ++ skb->pkt_type = PACKET_HOST; ++ nf_bridge->mask |= BRNF_PKT_TYPE; ++ } ++ ++ if (skb->protocol == __constant_htons(ETH_P_8021Q)) { ++ skb_pull(skb, VLAN_HLEN); ++ skb->nh.raw += VLAN_HLEN; ++ } ++ ++ nf_bridge_save_header(skb); ++ ++#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) ++ if (nf_bridge->netoutdev) ++ realoutdev = nf_bridge->netoutdev; ++#endif ++ NF_HOOK(PF_INET, NF_IP_POST_ROUTING, skb, NULL, ++ realoutdev, br_dev_queue_push_xmit); ++ ++ return NF_STOLEN; ++ ++#ifdef CONFIG_NETFILTER_DEBUG ++print_error: ++ if (skb->dev != NULL) { ++ printk("[%s]", skb->dev->name); ++ if (has_bridge_parent(skb->dev)) ++ printk("[%s]", bridge_parent(skb->dev)->name); ++ } ++ printk(" head:%p, raw:%p, data:%p\n", skb->head, skb->mac.raw, ++ skb->data); ++ return NF_ACCEPT; ++#endif ++} ++ ++ ++/* IPv4/SABOTAGE *****************************************************/ ++ ++/* Don't hand locally destined packets to PF_INET/PRE_ROUTING ++ * for the second time. ++ */ ++static unsigned int ipv4_sabotage_in(unsigned int hook, struct sk_buff **pskb, ++ const struct net_device *in, const struct net_device *out, ++ int (*okfn)(struct sk_buff *)) ++{ ++ if ((*pskb)->nf_bridge && ++ !((*pskb)->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING)) { ++ okfn(*pskb); ++ return NF_STOLEN; ++ } ++ ++ return NF_ACCEPT; ++} ++ ++/* Postpone execution of PF_INET/FORWARD, PF_INET/LOCAL_OUT ++ * and PF_INET/POST_ROUTING until we have done the forwarding ++ * decision in the bridge code and have determined skb->physoutdev. ++ */ ++static unsigned int ipv4_sabotage_out(unsigned int hook, struct sk_buff **pskb, ++ const struct net_device *in, const struct net_device *out, ++ int (*okfn)(struct sk_buff *)) ++{ ++ struct sk_buff *skb = *pskb; ++ ++#ifdef CONFIG_SYSCTL ++ if (!brnf_call_iptables && !skb->nf_bridge) ++ return NF_ACCEPT; ++#endif ++ ++ if ((out->hard_start_xmit == br_dev_xmit && ++ okfn != br_nf_forward_finish && ++ okfn != br_nf_local_out_finish && ++ okfn != br_dev_queue_push_xmit) ++#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) ++ || ((out->priv_flags & IFF_802_1Q_VLAN) && ++ VLAN_DEV_INFO(out)->real_dev->hard_start_xmit == br_dev_xmit) ++#endif ++ ) { ++ struct nf_bridge_info *nf_bridge; ++ ++ if (!skb->nf_bridge && !nf_bridge_alloc(skb)) ++ return NF_DROP; ++ ++ nf_bridge = skb->nf_bridge; ++ ++ /* This frame will arrive on PF_BRIDGE/LOCAL_OUT and we ++ * will need the indev then. For a brouter, the real indev ++ * can be a bridge port, so we make sure br_nf_local_out() ++ * doesn't use the bridge parent of the indev by using ++ * the BRNF_DONT_TAKE_PARENT mask. ++ */ ++ if (hook == NF_IP_FORWARD && nf_bridge->physindev == NULL) { ++ nf_bridge->mask &= BRNF_DONT_TAKE_PARENT; ++ nf_bridge->physindev = (struct net_device *)in; ++ } ++#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) ++ /* the iptables outdev is br0.x, not br0 */ ++ if (out->priv_flags & IFF_802_1Q_VLAN) ++ nf_bridge->netoutdev = (struct net_device *)out; ++#endif ++ okfn(skb); ++ return NF_STOLEN; ++ } ++ ++ return NF_ACCEPT; ++} ++ ++/* For br_nf_local_out we need (prio = NF_BR_PRI_FIRST), to insure that innocent ++ * PF_BRIDGE/NF_BR_LOCAL_OUT functions don't get bridged traffic as input. ++ * For br_nf_post_routing, we need (prio = NF_BR_PRI_LAST), because ++ * ip_refrag() can return NF_STOLEN. ++ */ ++static struct nf_hook_ops br_nf_ops[] = { ++ { .hook = br_nf_pre_routing, ++ .pf = PF_BRIDGE, ++ .hooknum = NF_BR_PRE_ROUTING, ++ .priority = NF_BR_PRI_BRNF, }, ++ { .hook = br_nf_local_in, ++ .pf = PF_BRIDGE, ++ .hooknum = NF_BR_LOCAL_IN, ++ .priority = NF_BR_PRI_BRNF, }, ++ { .hook = br_nf_forward_ip, ++ .pf = PF_BRIDGE, ++ .hooknum = NF_BR_FORWARD, ++ .priority = NF_BR_PRI_BRNF /*- 1*/, }, ++/* { .hook = br_nf_forward_arp, ++ .pf = PF_BRIDGE, ++ .hooknum = NF_BR_FORWARD, ++ .priority = NF_BR_PRI_BRNF, },*/ ++ { .hook = br_nf_local_out, ++ .pf = PF_BRIDGE, ++ .hooknum = NF_BR_LOCAL_OUT, ++ .priority = NF_BR_PRI_FIRST, }, ++ { .hook = br_nf_post_routing, ++ .pf = PF_BRIDGE, ++ .hooknum = NF_BR_POST_ROUTING, ++ .priority = NF_BR_PRI_LAST, }, ++ { .hook = ipv4_sabotage_in, ++ .pf = PF_INET, ++ .hooknum = NF_IP_PRE_ROUTING, ++ .priority = NF_IP_PRI_FIRST, }, ++ { .hook = ipv4_sabotage_out, ++ .pf = PF_INET, ++ .hooknum = NF_IP_FORWARD, ++ .priority = NF_IP_PRI_BRIDGE_SABOTAGE_FORWARD, }, ++ { .hook = ipv4_sabotage_out, ++ .pf = PF_INET, ++ .hooknum = NF_IP_LOCAL_OUT, ++ .priority = NF_IP_PRI_BRIDGE_SABOTAGE_LOCAL_OUT, }, ++ { .hook = ipv4_sabotage_out, ++ .pf = PF_INET, ++ .hooknum = NF_IP_POST_ROUTING, ++ .priority = NF_IP_PRI_FIRST, }, ++}; ++ ++#ifdef CONFIG_SYSCTL ++static ++int brnf_sysctl_call_tables(ctl_table *ctl, int write, struct file * filp, ++ void *buffer, size_t *lenp) ++{ ++ int ret; ++ ++ ret = proc_dointvec(ctl, write, filp, buffer, lenp); ++ ++ if (write && *(int *)(ctl->data)) ++ *(int *)(ctl->data) = 1; ++ return ret; ++} ++ ++static ctl_table brnf_table[] = { ++ { ++ .ctl_name = NET_BRIDGE_NF_CALL_ARPTABLES, ++ .procname = "bridge-nf-call-arptables", ++ .data = &brnf_call_arptables, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &brnf_sysctl_call_tables, ++ }, ++ { ++ .ctl_name = NET_BRIDGE_NF_CALL_IPTABLES, ++ .procname = "bridge-nf-call-iptables", ++ .data = &brnf_call_iptables, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &brnf_sysctl_call_tables, ++ }, ++ { ++ .ctl_name = NET_BRIDGE_NF_FILTER_VLAN_TAGGED, ++ .procname = "bridge-nf-filter-vlan-tagged", ++ .data = &brnf_filter_vlan_tagged, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &brnf_sysctl_call_tables, ++ }, ++ { .ctl_name = 0 } ++}; ++ ++static ctl_table brnf_bridge_table[] = { ++ { ++ .ctl_name = NET_BRIDGE, ++ .procname = "bridge", ++ .mode = 0555, ++ .child = brnf_table, ++ }, ++ { .ctl_name = 0 } ++}; ++ ++static ctl_table brnf_net_table[] = { ++ { ++ .ctl_name = CTL_NET, ++ .procname = "net", ++ .mode = 0555, ++ .child = brnf_bridge_table, ++ }, ++ { .ctl_name = 0 } ++}; ++#endif ++ ++int br_netfilter_init(void) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(br_nf_ops); i++) { ++ int ret; ++ ++ if ((ret = nf_register_hook(&br_nf_ops[i])) >= 0) ++ continue; ++ ++ while (i--) ++ nf_unregister_hook(&br_nf_ops[i]); ++ ++ return ret; ++ } ++ ++#ifdef CONFIG_SYSCTL ++ brnf_sysctl_header = register_sysctl_table(brnf_net_table, 0); ++ if (brnf_sysctl_header == NULL) { ++ printk(KERN_WARNING "br_netfilter: can't register to sysctl.\n"); ++ for (i = 0; i < ARRAY_SIZE(br_nf_ops); i++) ++ nf_unregister_hook(&br_nf_ops[i]); ++ return -EFAULT; ++ } ++#endif ++ ++ printk(KERN_NOTICE "Bridge firewalling registered\n"); ++ ++ return 0; ++} ++ ++void br_netfilter_fini(void) ++{ ++ int i; ++ ++ for (i = ARRAY_SIZE(br_nf_ops) - 1; i >= 0; i--) ++ nf_unregister_hook(&br_nf_ops[i]); ++#ifdef CONFIG_SYSCTL ++ unregister_sysctl_table(brnf_sysctl_header); ++#endif ++ ++} +diff -Nurb src/linux/linux.stock/net/bridge/br_private.h src/linux/linux/net/bridge/br_private.h +--- src/linux/linux.stock/net/bridge/br_private.h 2003-10-14 04:09:32.000000000 -0400 ++++ src/linux/linux/net/bridge/br_private.h 2004-07-10 23:46:39.000000000 -0400 +@@ -145,8 +145,10 @@ + /* br_forward.c */ + extern void br_deliver(struct net_bridge_port *to, + struct sk_buff *skb); ++extern int br_dev_queue_push_xmit(struct sk_buff *skb); + extern void br_forward(struct net_bridge_port *to, + struct sk_buff *skb); ++extern int br_forward_finish(struct sk_buff *skb); + extern void br_flood_deliver(struct net_bridge *br, + struct sk_buff *skb, + int clone); +@@ -167,7 +169,8 @@ + int *ifindices); + + /* br_input.c */ +-extern void br_handle_frame(struct sk_buff *skb); ++extern int br_handle_frame_finish(struct sk_buff *skb); ++extern int br_handle_frame(struct sk_buff *skb); + + /* br_ioctl.c */ + extern void br_call_ioctl_atomic(void (*fn)(void)); +@@ -178,6 +181,10 @@ + unsigned long arg2); + extern int br_ioctl_deviceless_stub(unsigned long arg); + ++/* br_netfilter.c */ ++extern int br_netfilter_init(void); ++extern void br_netfilter_fini(void); ++ + /* br_stp.c */ + extern int br_is_root_bridge(struct net_bridge *br); + extern struct net_bridge_port *br_get_port(struct net_bridge *br, +diff -Nurb src/linux/linux.stock/net/bridge/netfilter/Config.in src/linux/linux/net/bridge/netfilter/Config.in +--- src/linux/linux.stock/net/bridge/netfilter/Config.in 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/net/bridge/netfilter/Config.in 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,22 @@ ++# ++# Bridge netfilter configuration ++# ++dep_tristate ' Bridge: ebtables' CONFIG_BRIDGE_NF_EBTABLES $CONFIG_BRIDGE ++dep_tristate ' ebt: filter table support' CONFIG_BRIDGE_EBT_T_FILTER $CONFIG_BRIDGE_NF_EBTABLES ++dep_tristate ' ebt: nat table support' CONFIG_BRIDGE_EBT_T_NAT $CONFIG_BRIDGE_NF_EBTABLES ++dep_tristate ' ebt: broute table support' CONFIG_BRIDGE_EBT_BROUTE $CONFIG_BRIDGE_NF_EBTABLES ++dep_tristate ' ebt: log support' CONFIG_BRIDGE_EBT_LOG $CONFIG_BRIDGE_NF_EBTABLES ++dep_tristate ' ebt: IP filter support' CONFIG_BRIDGE_EBT_IPF $CONFIG_BRIDGE_NF_EBTABLES ++dep_tristate ' ebt: ARP filter support' CONFIG_BRIDGE_EBT_ARPF $CONFIG_BRIDGE_NF_EBTABLES ++dep_tristate ' ebt: among filter support' CONFIG_BRIDGE_EBT_AMONG $CONFIG_BRIDGE_NF_EBTABLES ++dep_tristate ' ebt: limit filter support' CONFIG_BRIDGE_EBT_LIMIT $CONFIG_BRIDGE_NF_EBTABLES ++dep_tristate ' ebt: 802.1Q VLAN filter support' CONFIG_BRIDGE_EBT_VLANF $CONFIG_BRIDGE_NF_EBTABLES ++dep_tristate ' ebt: 802.3 filter support' CONFIG_BRIDGE_EBT_802_3 $CONFIG_BRIDGE_NF_EBTABLES ++dep_tristate ' ebt: packet type filter support' CONFIG_BRIDGE_EBT_PKTTYPE $CONFIG_BRIDGE_NF_EBTABLES ++dep_tristate ' ebt: STP filter support' CONFIG_BRIDGE_EBT_STP $CONFIG_BRIDGE_NF_EBTABLES ++dep_tristate ' ebt: mark filter support' CONFIG_BRIDGE_EBT_MARKF $CONFIG_BRIDGE_NF_EBTABLES ++dep_tristate ' ebt: arp reply target support' CONFIG_BRIDGE_EBT_ARPREPLY $CONFIG_BRIDGE_NF_EBTABLES ++dep_tristate ' ebt: snat target support' CONFIG_BRIDGE_EBT_SNAT $CONFIG_BRIDGE_NF_EBTABLES ++dep_tristate ' ebt: dnat target support' CONFIG_BRIDGE_EBT_DNAT $CONFIG_BRIDGE_NF_EBTABLES ++dep_tristate ' ebt: redirect target support' CONFIG_BRIDGE_EBT_REDIRECT $CONFIG_BRIDGE_NF_EBTABLES ++dep_tristate ' ebt: mark target support' CONFIG_BRIDGE_EBT_MARK_T $CONFIG_BRIDGE_NF_EBTABLES +diff -Nurb src/linux/linux.stock/net/bridge/netfilter/Makefile src/linux/linux/net/bridge/netfilter/Makefile +--- src/linux/linux.stock/net/bridge/netfilter/Makefile 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/net/bridge/netfilter/Makefile 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,33 @@ ++# ++# Makefile for the netfilter modules on top of bridging. ++# ++# Note! Dependencies are done automagically by 'make dep', which also ++# removes any old dependencies. DON'T put your own dependencies here ++# unless it's something special (ie not a .c file). ++# ++# Note 2! The CFLAGS definition is now in the main makefile... ++ ++O_TARGET := netfilter.o ++ ++export-objs := ebtables.o ++ ++obj-$(CONFIG_BRIDGE_NF_EBTABLES) += ebtables.o ++obj-$(CONFIG_BRIDGE_EBT_T_FILTER) += ebtable_filter.o ++obj-$(CONFIG_BRIDGE_EBT_T_NAT) += ebtable_nat.o ++obj-$(CONFIG_BRIDGE_EBT_BROUTE) += ebtable_broute.o ++obj-$(CONFIG_BRIDGE_EBT_802_3) += ebt_802_3.o ++obj-$(CONFIG_BRIDGE_EBT_ARPF) += ebt_arp.o ++obj-$(CONFIG_BRIDGE_EBT_AMONG) += ebt_among.o ++obj-$(CONFIG_BRIDGE_EBT_IPF) += ebt_ip.o ++obj-$(CONFIG_BRIDGE_EBT_LIMIT) += ebt_limit.o ++obj-$(CONFIG_BRIDGE_EBT_MARKF) += ebt_mark_m.o ++obj-$(CONFIG_BRIDGE_EBT_PKTTYPE) += ebt_pkttype.o ++obj-$(CONFIG_BRIDGE_EBT_STP) += ebt_stp.o ++obj-$(CONFIG_BRIDGE_EBT_VLANF) += ebt_vlan.o ++obj-$(CONFIG_BRIDGE_EBT_LOG) += ebt_log.o ++obj-$(CONFIG_BRIDGE_EBT_ARPREPLY) += ebt_arpreply.o ++obj-$(CONFIG_BRIDGE_EBT_DNAT) += ebt_dnat.o ++obj-$(CONFIG_BRIDGE_EBT_MARK_T) += ebt_mark.o ++obj-$(CONFIG_BRIDGE_EBT_REDIRECT) += ebt_redirect.o ++obj-$(CONFIG_BRIDGE_EBT_SNAT) += ebt_snat.o ++include $(TOPDIR)/Rules.make +diff -Nurb src/linux/linux.stock/net/bridge/netfilter/ebt_802_3.c src/linux/linux/net/bridge/netfilter/ebt_802_3.c +--- src/linux/linux.stock/net/bridge/netfilter/ebt_802_3.c 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/net/bridge/netfilter/ebt_802_3.c 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,74 @@ ++/* ++ * 802_3 ++ * ++ * Author: ++ * Chris Vitale csv@bluetail.com ++ * ++ * May 2003 ++ * ++ */ ++ ++#include <linux/netfilter_bridge/ebtables.h> ++#include <linux/netfilter_bridge/ebt_802_3.h> ++#include <linux/module.h> ++ ++static int ebt_filter_802_3(const struct sk_buff *skb, const struct net_device *in, ++ const struct net_device *out, const void *data, unsigned int datalen) ++{ ++ struct ebt_802_3_info *info = (struct ebt_802_3_info *)data; ++ struct ebt_802_3_hdr *hdr = (struct ebt_802_3_hdr *)skb->mac.ethernet; ++ uint16_t type = hdr->llc.ui.ctrl & IS_UI ? hdr->llc.ui.type : hdr->llc.ni.type; ++ ++ if (info->bitmask & EBT_802_3_SAP) { ++ if (FWINV(info->sap != hdr->llc.ui.ssap, EBT_802_3_SAP)) ++ return EBT_NOMATCH; ++ if (FWINV(info->sap != hdr->llc.ui.dsap, EBT_802_3_SAP)) ++ return EBT_NOMATCH; ++ } ++ ++ if (info->bitmask & EBT_802_3_TYPE) { ++ if (!(hdr->llc.ui.dsap == CHECK_TYPE && hdr->llc.ui.ssap == CHECK_TYPE)) ++ return EBT_NOMATCH; ++ if (FWINV(info->type != type, EBT_802_3_TYPE)) ++ return EBT_NOMATCH; ++ } ++ ++ return EBT_MATCH; ++} ++ ++static struct ebt_match filter_802_3; ++static int ebt_802_3_check(const char *tablename, unsigned int hookmask, ++ const struct ebt_entry *e, void *data, unsigned int datalen) ++{ ++ struct ebt_802_3_info *info = (struct ebt_802_3_info *)data; ++ ++ if (datalen != EBT_ALIGN(sizeof(struct ebt_802_3_info))) ++ return -EINVAL; ++ if (info->bitmask & ~EBT_802_3_MASK || info->invflags & ~EBT_802_3_MASK) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static struct ebt_match filter_802_3 = ++{ ++ .name = EBT_802_3_MATCH, ++ .match = ebt_filter_802_3, ++ .check = ebt_802_3_check, ++ .me = THIS_MODULE, ++}; ++ ++static int __init init(void) ++{ ++ return ebt_register_match(&filter_802_3); ++} ++ ++static void __exit fini(void) ++{ ++ ebt_unregister_match(&filter_802_3); ++} ++ ++module_init(init); ++module_exit(fini); ++EXPORT_NO_SYMBOLS; ++MODULE_LICENSE("GPL"); +diff -Nurb src/linux/linux.stock/net/bridge/netfilter/ebt_among.c src/linux/linux/net/bridge/netfilter/ebt_among.c +--- src/linux/linux.stock/net/bridge/netfilter/ebt_among.c 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/net/bridge/netfilter/ebt_among.c 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,223 @@ ++/* ++ * ebt_among ++ * ++ * Authors: ++ * Grzegorz Borowiak <grzes@gnu.univ.gda.pl> ++ * ++ * August, 2003 ++ * ++ */ ++ ++#include <linux/netfilter_bridge/ebtables.h> ++#include <linux/netfilter_bridge/ebt_among.h> ++#include <linux/ip.h> ++#include <linux/if_arp.h> ++#include <linux/module.h> ++ ++static int ebt_mac_wormhash_contains(const struct ebt_mac_wormhash *wh, ++ const char *mac, uint32_t ip) ++{ ++ /* You may be puzzled as to how this code works. ++ * Some tricks were used, refer to ++ * include/linux/netfilter_bridge/ebt_among.h ++ * as there you can find a solution of this mystery. ++ */ ++ const struct ebt_mac_wormhash_tuple *p; ++ int start, limit, i; ++ uint32_t cmp[2] = { 0, 0 }; ++ int key = (const unsigned char) mac[5]; ++ ++ memcpy(((char *) cmp) + 2, mac, 6); ++ start = wh->table[key]; ++ limit = wh->table[key + 1]; ++ if (ip) { ++ for (i = start; i < limit; i++) { ++ p = &wh->pool[i]; ++ if (cmp[1] == p->cmp[1] && cmp[0] == p->cmp[0]) { ++ if (p->ip == 0 || p->ip == ip) { ++ return 1; ++ } ++ } ++ } ++ } else { ++ for (i = start; i < limit; i++) { ++ p = &wh->pool[i]; ++ if (cmp[1] == p->cmp[1] && cmp[0] == p->cmp[0]) { ++ if (p->ip == 0) { ++ return 1; ++ } ++ } ++ } ++ } ++ return 0; ++} ++ ++static int ebt_mac_wormhash_check_integrity(const struct ebt_mac_wormhash ++ *wh) ++{ ++ int i; ++ ++ for (i = 0; i < 256; i++) { ++ if (wh->table[i] > wh->table[i + 1]) ++ return -0x100 - i; ++ if (wh->table[i] < 0) ++ return -0x200 - i; ++ if (wh->table[i] > wh->poolsize) ++ return -0x300 - i; ++ } ++ if (wh->table[256] > wh->poolsize) ++ return -0xc00; ++ return 0; ++} ++ ++static int get_ip_dst(const struct sk_buff *skb, uint32_t * addr) ++{ ++ if (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_IP)) ++ *addr = skb->nh.iph->daddr; ++ else if (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_ARP)) { ++ uint32_t arp_len = sizeof(struct arphdr) + ++ (2 * (((*skb).nh.arph)->ar_hln)) + ++ (2 * (((*skb).nh.arph)->ar_pln)); ++ ++ /* Make sure the packet is long enough. */ ++ if ((((*skb).nh.raw) + arp_len) > (*skb).tail) ++ return -1; ++ /* IPv4 addresses are always 4 bytes. */ ++ if (((*skb).nh.arph)->ar_pln != sizeof(uint32_t)) ++ return -1; ++ ++ memcpy(addr, ((*skb).nh.raw) + sizeof(struct arphdr) + ++ (2 * (((*skb).nh.arph)->ar_hln)) + ++ (((*skb).nh.arph)->ar_pln), sizeof(uint32_t)); ++ ++ } ++ return 0; ++} ++ ++static int get_ip_src(const struct sk_buff *skb, uint32_t * addr) ++{ ++ if (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_IP)) ++ *addr = skb->nh.iph->saddr; ++ else if (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_ARP)) { ++ uint32_t arp_len = sizeof(struct arphdr) + ++ (2 * (((*skb).nh.arph)->ar_hln)) + ++ (2 * (((*skb).nh.arph)->ar_pln)); ++ ++ /* Make sure the packet is long enough. */ ++ if ((((*skb).nh.raw) + arp_len) > (*skb).tail) ++ return -1; ++ /* IPv4 addresses are always 4 bytes. */ ++ if (((*skb).nh.arph)->ar_pln != sizeof(uint32_t)) ++ return -1; ++ ++ memcpy(addr, ((*skb).nh.raw) + sizeof(struct arphdr) + ++ ((((*skb).nh.arph)->ar_hln)), sizeof(uint32_t)); ++ ++ } ++ return 0; ++} ++ ++static int ebt_filter_among(const struct sk_buff *skb, ++ const struct net_device *in, ++ const struct net_device *out, const void *data, ++ unsigned int datalen) ++{ ++ struct ebt_among_info *info = (struct ebt_among_info *) data; ++ const char *dmac, *smac; ++ const struct ebt_mac_wormhash *wh_dst, *wh_src; ++ uint32_t dip = 0, sip = 0; ++ ++ wh_dst = ebt_among_wh_dst(info); ++ wh_src = ebt_among_wh_src(info); ++ ++ if (wh_src) { ++ smac = skb->mac.ethernet->h_source; ++ if (get_ip_src(skb, &sip)) ++ return EBT_NOMATCH; ++ if (!(info->bitmask & EBT_AMONG_SRC_NEG)) { ++ /* we match only if it contains */ ++ if (!ebt_mac_wormhash_contains(wh_src, smac, sip)) ++ return EBT_NOMATCH; ++ } else { ++ /* we match only if it DOES NOT contain */ ++ if (ebt_mac_wormhash_contains(wh_src, smac, sip)) ++ return EBT_NOMATCH; ++ } ++ } ++ ++ if (wh_dst) { ++ dmac = skb->mac.ethernet->h_dest; ++ if (get_ip_dst(skb, &dip)) ++ return EBT_NOMATCH; ++ if (!(info->bitmask & EBT_AMONG_DST_NEG)) { ++ /* we match only if it contains */ ++ if (!ebt_mac_wormhash_contains(wh_dst, dmac, dip)) ++ return EBT_NOMATCH; ++ } else { ++ /* we match only if it DOES NOT contain */ ++ if (ebt_mac_wormhash_contains(wh_dst, dmac, dip)) ++ return EBT_NOMATCH; ++ } ++ } ++ ++ return EBT_MATCH; ++} ++ ++static int ebt_among_check(const char *tablename, unsigned int hookmask, ++ const struct ebt_entry *e, void *data, ++ unsigned int datalen) ++{ ++ struct ebt_among_info *info = (struct ebt_among_info *) data; ++ int expected_length = sizeof(struct ebt_among_info); ++ const struct ebt_mac_wormhash *wh_dst, *wh_src; ++ int err; ++ ++ wh_dst = ebt_among_wh_dst(info); ++ wh_src = ebt_among_wh_src(info); ++ expected_length += ebt_mac_wormhash_size(wh_dst); ++ expected_length += ebt_mac_wormhash_size(wh_src); ++ ++ if (datalen != EBT_ALIGN(expected_length)) { ++ printk(KERN_WARNING ++ "ebtables: among: wrong size: %d" ++ "against expected %d, rounded to %d\n", ++ datalen, expected_length, ++ EBT_ALIGN(expected_length)); ++ return -EINVAL; ++ } ++ if (wh_dst && (err = ebt_mac_wormhash_check_integrity(wh_dst))) { ++ printk(KERN_WARNING ++ "ebtables: among: dst integrity fail: %x\n", -err); ++ return -EINVAL; ++ } ++ if (wh_src && (err = ebt_mac_wormhash_check_integrity(wh_src))) { ++ printk(KERN_WARNING ++ "ebtables: among: src integrity fail: %x\n", -err); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static struct ebt_match filter_among = { ++ {NULL, NULL}, ++ EBT_AMONG_MATCH, ++ ebt_filter_among, ++ ebt_among_check, ++ NULL, ++ THIS_MODULE ++}; ++ ++static int __init init(void) ++{ ++ return ebt_register_match(&filter_among); ++} ++ ++static void __exit fini(void) ++{ ++ ebt_unregister_match(&filter_among); ++} ++ ++module_init(init); ++module_exit(fini); ++EXPORT_NO_SYMBOLS; ++MODULE_LICENSE("GPL"); +diff -Nurb src/linux/linux.stock/net/bridge/netfilter/ebt_arp.c src/linux/linux/net/bridge/netfilter/ebt_arp.c +--- src/linux/linux.stock/net/bridge/netfilter/ebt_arp.c 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/net/bridge/netfilter/ebt_arp.c 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,149 @@ ++/* ++ * ebt_arp ++ * ++ * Authors: ++ * Bart De Schuymer <bart.de.schuymer@pandora.be> ++ * Tim Gardner <timg@tpi.com> ++ * ++ * April, 2002 ++ * ++ */ ++ ++#include <linux/netfilter_bridge/ebtables.h> ++#include <linux/netfilter_bridge/ebt_arp.h> ++#include <linux/if_arp.h> ++#include <linux/if_ether.h> ++#include <linux/module.h> ++ ++static int ebt_filter_arp(const struct sk_buff *skb, const struct net_device *in, ++ const struct net_device *out, const void *data, unsigned int datalen) ++{ ++ struct ebt_arp_info *info = (struct ebt_arp_info *)data; ++ ++ if (info->bitmask & EBT_ARP_OPCODE && FWINV(info->opcode != ++ ((*skb).nh.arph)->ar_op, EBT_ARP_OPCODE)) ++ return EBT_NOMATCH; ++ if (info->bitmask & EBT_ARP_HTYPE && FWINV(info->htype != ++ ((*skb).nh.arph)->ar_hrd, EBT_ARP_HTYPE)) ++ return EBT_NOMATCH; ++ if (info->bitmask & EBT_ARP_PTYPE && FWINV(info->ptype != ++ ((*skb).nh.arph)->ar_pro, EBT_ARP_PTYPE)) ++ return EBT_NOMATCH; ++ ++ if (info->bitmask & (EBT_ARP_SRC_IP | EBT_ARP_DST_IP)) ++ { ++ uint32_t arp_len = sizeof(struct arphdr) + ++ (2 * (((*skb).nh.arph)->ar_hln)) + ++ (2 * (((*skb).nh.arph)->ar_pln)); ++ uint32_t dst; ++ uint32_t src; ++ ++ // Make sure the packet is long enough. ++ if ((((*skb).nh.raw) + arp_len) > (*skb).tail) ++ return EBT_NOMATCH; ++ // IPv4 addresses are always 4 bytes. ++ if (((*skb).nh.arph)->ar_pln != sizeof(uint32_t)) ++ return EBT_NOMATCH; ++ ++ if (info->bitmask & EBT_ARP_SRC_IP) { ++ memcpy(&src, ((*skb).nh.raw) + sizeof(struct arphdr) + ++ ((*skb).nh.arph)->ar_hln, sizeof(uint32_t)); ++ if (FWINV(info->saddr != (src & info->smsk), ++ EBT_ARP_SRC_IP)) ++ return EBT_NOMATCH; ++ } ++ ++ if (info->bitmask & EBT_ARP_DST_IP) { ++ memcpy(&dst, ((*skb).nh.raw)+sizeof(struct arphdr) + ++ (2*(((*skb).nh.arph)->ar_hln)) + ++ (((*skb).nh.arph)->ar_pln), sizeof(uint32_t)); ++ if (FWINV(info->daddr != (dst & info->dmsk), ++ EBT_ARP_DST_IP)) ++ return EBT_NOMATCH; ++ } ++ } ++ ++ if (info->bitmask & (EBT_ARP_SRC_MAC | EBT_ARP_DST_MAC)) ++ { ++ uint32_t arp_len = sizeof(struct arphdr) + ++ (2 * (((*skb).nh.arph)->ar_hln)) + ++ (2 * (((*skb).nh.arph)->ar_pln)); ++ unsigned char dst[ETH_ALEN]; ++ unsigned char src[ETH_ALEN]; ++ ++ // Make sure the packet is long enough. ++ if ((((*skb).nh.raw) + arp_len) > (*skb).tail) ++ return EBT_NOMATCH; ++ // MAC addresses are 6 bytes. ++ if (((*skb).nh.arph)->ar_hln != ETH_ALEN) ++ return EBT_NOMATCH; ++ if (info->bitmask & EBT_ARP_SRC_MAC) { ++ uint8_t verdict, i; ++ ++ memcpy(&src, ((*skb).nh.raw) + ++ sizeof(struct arphdr), ++ ETH_ALEN); ++ verdict = 0; ++ for (i = 0; i < 6; i++) ++ verdict |= (src[i] ^ info->smaddr[i]) & ++ info->smmsk[i]; ++ if (FWINV(verdict != 0, EBT_ARP_SRC_MAC)) ++ return EBT_NOMATCH; ++ } ++ ++ if (info->bitmask & EBT_ARP_DST_MAC) { ++ uint8_t verdict, i; ++ ++ memcpy(&dst, ((*skb).nh.raw) + ++ sizeof(struct arphdr) + ++ (((*skb).nh.arph)->ar_hln) + ++ (((*skb).nh.arph)->ar_pln), ++ ETH_ALEN); ++ verdict = 0; ++ for (i = 0; i < 6; i++) ++ verdict |= (dst[i] ^ info->dmaddr[i]) & ++ info->dmmsk[i]; ++ if (FWINV(verdict != 0, EBT_ARP_DST_MAC)) ++ return EBT_NOMATCH; ++ } ++ } ++ ++ return EBT_MATCH; ++} ++ ++static int ebt_arp_check(const char *tablename, unsigned int hookmask, ++ const struct ebt_entry *e, void *data, unsigned int datalen) ++{ ++ struct ebt_arp_info *info = (struct ebt_arp_info *)data; ++ ++ if (datalen != EBT_ALIGN(sizeof(struct ebt_arp_info))) ++ return -EINVAL; ++ if ((e->ethproto != __constant_htons(ETH_P_ARP) && ++ e->ethproto != __constant_htons(ETH_P_RARP)) || ++ e->invflags & EBT_IPROTO) ++ return -EINVAL; ++ if (info->bitmask & ~EBT_ARP_MASK || info->invflags & ~EBT_ARP_MASK) ++ return -EINVAL; ++ return 0; ++} ++ ++static struct ebt_match filter_arp = ++{ ++ {NULL, NULL}, EBT_ARP_MATCH, ebt_filter_arp, ebt_arp_check, NULL, ++ THIS_MODULE ++}; ++ ++static int __init init(void) ++{ ++ return ebt_register_match(&filter_arp); ++} ++ ++static void __exit fini(void) ++{ ++ ebt_unregister_match(&filter_arp); ++} ++ ++module_init(init); ++module_exit(fini); ++EXPORT_NO_SYMBOLS; ++MODULE_LICENSE("GPL"); +diff -Nurb src/linux/linux.stock/net/bridge/netfilter/ebt_arpreply.c src/linux/linux/net/bridge/netfilter/ebt_arpreply.c +--- src/linux/linux.stock/net/bridge/netfilter/ebt_arpreply.c 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/net/bridge/netfilter/ebt_arpreply.c 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,86 @@ ++/* ++ * ebt_arpreply ++ * ++ * Authors: ++ * Grzegorz Borowiak <grzes@gnu.univ.gda.pl> ++ * Bart De Schuymer <bdschuym@pandora.be> ++ * ++ * August, 2003 ++ * ++ */ ++ ++#include <linux/netfilter_bridge/ebtables.h> ++#include <linux/netfilter_bridge/ebt_arpreply.h> ++#include <linux/if_arp.h> ++#include <net/arp.h> ++#include <linux/module.h> ++ ++static int ebt_target_reply(struct sk_buff **pskb, unsigned int hooknr, ++ const struct net_device *in, const struct net_device *out, ++ const void *data, unsigned int datalen) ++{ ++ struct ebt_arpreply_info *info = (struct ebt_arpreply_info *)data; ++ struct arphdr *ah; ++ unsigned char *sha, *arp_ptr; ++ u32 sip, tip; ++ ++ ah = (**pskb).nh.arph; ++ if (ah->ar_op != __constant_htons(ARPOP_REQUEST) || ++ ah->ar_hln != ETH_ALEN || ah->ar_pro != htons(ETH_P_IP) || ++ ah->ar_pln != 4) ++ return EBT_CONTINUE; ++ ++ arp_ptr = (unsigned char *)(ah + 1); ++ ++ /* get source and target IP */ ++ sha = arp_ptr; ++ arp_ptr += ETH_ALEN; ++ memcpy(&sip, arp_ptr, 4); ++ arp_ptr += 4 + ETH_ALEN; ++ memcpy(&tip, arp_ptr, 4); ++ ++ arp_send(ARPOP_REPLY, ETH_P_ARP, sip, in, tip, sha, info->mac, sha); ++ ++ return info->target; ++} ++ ++static int ebt_target_reply_check(const char *tablename, unsigned int hookmask, ++ const struct ebt_entry *e, void *data, unsigned int datalen) ++{ ++ struct ebt_arpreply_info *info = (struct ebt_arpreply_info *)data; ++ ++ if (datalen != EBT_ALIGN(sizeof(struct ebt_arpreply_info))) ++ return -EINVAL; ++ if (BASE_CHAIN && info->target == EBT_RETURN) ++ return -EINVAL; ++ if (e->ethproto != __constant_htons(ETH_P_ARP) || ++ e->invflags & EBT_IPROTO) ++ return -EINVAL; ++ CLEAR_BASE_CHAIN_BIT; ++ if (strcmp(tablename, "nat") || hookmask & ~(1 << NF_BR_PRE_ROUTING)) ++ return -EINVAL; ++ return 0; ++} ++ ++static struct ebt_target reply_target = ++{ ++ .name = EBT_ARPREPLY_TARGET, ++ .target = ebt_target_reply, ++ .check = ebt_target_reply_check, ++ .me = THIS_MODULE, ++}; ++ ++static int __init init(void) ++{ ++ return ebt_register_target(&reply_target); ++} ++ ++static void __exit fini(void) ++{ ++ ebt_unregister_target(&reply_target); ++} ++ ++module_init(init); ++module_exit(fini); ++EXPORT_NO_SYMBOLS; ++MODULE_LICENSE("GPL"); +diff -Nurb src/linux/linux.stock/net/bridge/netfilter/ebt_dnat.c src/linux/linux/net/bridge/netfilter/ebt_dnat.c +--- src/linux/linux.stock/net/bridge/netfilter/ebt_dnat.c 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/net/bridge/netfilter/ebt_dnat.c 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,65 @@ ++/* ++ * ebt_dnat ++ * ++ * Authors: ++ * Bart De Schuymer <bart.de.schuymer@pandora.be> ++ * ++ * June, 2002 ++ * ++ */ ++ ++#include <linux/netfilter_bridge/ebtables.h> ++#include <linux/netfilter_bridge/ebt_nat.h> ++#include <linux/module.h> ++#include <net/sock.h> ++ ++static int ebt_target_dnat(struct sk_buff **pskb, unsigned int hooknr, ++ const struct net_device *in, const struct net_device *out, ++ const void *data, unsigned int datalen) ++{ ++ struct ebt_nat_info *info = (struct ebt_nat_info *)data; ++ ++ memcpy(((**pskb).mac.ethernet)->h_dest, info->mac, ++ ETH_ALEN * sizeof(unsigned char)); ++ return info->target; ++} ++ ++static int ebt_target_dnat_check(const char *tablename, unsigned int hookmask, ++ const struct ebt_entry *e, void *data, unsigned int datalen) ++{ ++ struct ebt_nat_info *info = (struct ebt_nat_info *)data; ++ ++ if (BASE_CHAIN && info->target == EBT_RETURN) ++ return -EINVAL; ++ CLEAR_BASE_CHAIN_BIT; ++ if ( (strcmp(tablename, "nat") || ++ (hookmask & ~((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT)))) && ++ (strcmp(tablename, "broute") || hookmask & ~(1 << NF_BR_BROUTING)) ) ++ return -EINVAL; ++ if (datalen != EBT_ALIGN(sizeof(struct ebt_nat_info))) ++ return -EINVAL; ++ if (INVALID_TARGET) ++ return -EINVAL; ++ return 0; ++} ++ ++static struct ebt_target dnat = ++{ ++ {NULL, NULL}, EBT_DNAT_TARGET, ebt_target_dnat, ebt_target_dnat_check, ++ NULL, THIS_MODULE ++}; ++ ++static int __init init(void) ++{ ++ return ebt_register_target(&dnat); ++} ++ ++static void __exit fini(void) ++{ ++ ebt_unregister_target(&dnat); ++} ++ ++module_init(init); ++module_exit(fini); ++EXPORT_NO_SYMBOLS; ++MODULE_LICENSE("GPL"); +diff -Nurb src/linux/linux.stock/net/bridge/netfilter/ebt_ip.c src/linux/linux/net/bridge/netfilter/ebt_ip.c +--- src/linux/linux.stock/net/bridge/netfilter/ebt_ip.c 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/net/bridge/netfilter/ebt_ip.c 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,121 @@ ++/* ++ * ebt_ip ++ * ++ * Authors: ++ * Bart De Schuymer <bart.de.schuymer@pandora.be> ++ * ++ * April, 2002 ++ * ++ * Changes: ++ * added ip-sport and ip-dport ++ * Innominate Security Technologies AG <mhopf@innominate.com> ++ * September, 2002 ++ */ ++ ++#include <linux/netfilter_bridge/ebtables.h> ++#include <linux/netfilter_bridge/ebt_ip.h> ++#include <linux/ip.h> ++#include <linux/in.h> ++#include <linux/module.h> ++ ++struct tcpudphdr { ++ uint16_t src; ++ uint16_t dst; ++}; ++ ++union h_u { ++ unsigned char *raw; ++ struct tcpudphdr *tuh; ++}; ++ ++static int ebt_filter_ip(const struct sk_buff *skb, const struct net_device *in, ++ const struct net_device *out, const void *data, ++ unsigned int datalen) ++{ ++ struct ebt_ip_info *info = (struct ebt_ip_info *)data; ++ ++ if (info->bitmask & EBT_IP_TOS && ++ FWINV(info->tos != ((*skb).nh.iph)->tos, EBT_IP_TOS)) ++ return EBT_NOMATCH; ++ if (info->bitmask & EBT_IP_PROTO) { ++ if (FWINV(info->protocol != ((*skb).nh.iph)->protocol, ++ EBT_IP_PROTO)) ++ return EBT_NOMATCH; ++ if ( info->protocol == IPPROTO_TCP || ++ info->protocol == IPPROTO_UDP ) ++ { ++ union h_u h; ++ h.raw = skb->data + skb->nh.iph->ihl*4; ++ if (info->bitmask & EBT_IP_DPORT) { ++ uint16_t port = ntohs(h.tuh->dst); ++ if (FWINV(port < info->dport[0] || ++ port > info->dport[1], ++ EBT_IP_DPORT)) ++ return EBT_NOMATCH; ++ } ++ if (info->bitmask & EBT_IP_SPORT) { ++ uint16_t port = ntohs(h.tuh->src); ++ if (FWINV(port < info->sport[0] || ++ port > info->sport[1], ++ EBT_IP_SPORT)) ++ return EBT_NOMATCH; ++ } ++ } ++ } ++ if (info->bitmask & EBT_IP_SOURCE && ++ FWINV((((*skb).nh.iph)->saddr & info->smsk) != ++ info->saddr, EBT_IP_SOURCE)) ++ return EBT_NOMATCH; ++ if ((info->bitmask & EBT_IP_DEST) && ++ FWINV((((*skb).nh.iph)->daddr & info->dmsk) != ++ info->daddr, EBT_IP_DEST)) ++ return EBT_NOMATCH; ++ return EBT_MATCH; ++} ++ ++static int ebt_ip_check(const char *tablename, unsigned int hookmask, ++ const struct ebt_entry *e, void *data, unsigned int datalen) ++{ ++ struct ebt_ip_info *info = (struct ebt_ip_info *)data; ++ ++ if (datalen != EBT_ALIGN(sizeof(struct ebt_ip_info))) ++ return -EINVAL; ++ if (e->ethproto != __constant_htons(ETH_P_IP) || ++ e->invflags & EBT_IPROTO) ++ return -EINVAL; ++ if (info->bitmask & ~EBT_IP_MASK || info->invflags & ~EBT_IP_MASK) ++ return -EINVAL; ++ if (info->bitmask & (EBT_IP_DPORT | EBT_IP_SPORT)) { ++ if (!info->bitmask & EBT_IPROTO) ++ return -EINVAL; ++ if (info->protocol != IPPROTO_TCP && ++ info->protocol != IPPROTO_UDP) ++ return -EINVAL; ++ } ++ if (info->bitmask & EBT_IP_DPORT && info->dport[0] > info->dport[1]) ++ return -EINVAL; ++ if (info->bitmask & EBT_IP_SPORT && info->sport[0] > info->sport[1]) ++ return -EINVAL; ++ return 0; ++} ++ ++static struct ebt_match filter_ip = ++{ ++ {NULL, NULL}, EBT_IP_MATCH, ebt_filter_ip, ebt_ip_check, NULL, ++ THIS_MODULE ++}; ++ ++static int __init init(void) ++{ ++ return ebt_register_match(&filter_ip); ++} ++ ++static void __exit fini(void) ++{ ++ ebt_unregister_match(&filter_ip); ++} ++ ++module_init(init); ++module_exit(fini); ++EXPORT_NO_SYMBOLS; ++MODULE_LICENSE("GPL"); +diff -Nurb src/linux/linux.stock/net/bridge/netfilter/ebt_limit.c src/linux/linux/net/bridge/netfilter/ebt_limit.c +--- src/linux/linux.stock/net/bridge/netfilter/ebt_limit.c 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/net/bridge/netfilter/ebt_limit.c 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,101 @@ ++/* ++ * ebt_limit ++ * ++ * Authors: ++ * Tom Marshall <tommy@home.tig-grr.com> ++ * ++ * Mostly copied from netfilter's ipt_limit.c, see that file for explanation ++ * ++ * September, 2003 ++ * ++ */ ++ ++#include <linux/netfilter_bridge/ebtables.h> ++#include <linux/netfilter_bridge/ebt_limit.h> ++#include <linux/module.h> ++ ++#include <linux/netdevice.h> ++#include <linux/spinlock.h> ++ ++static spinlock_t limit_lock = SPIN_LOCK_UNLOCKED; ++ ++#define CREDITS_PER_JIFFY 128 ++ ++static int ebt_limit_match(const struct sk_buff *skb, const struct net_device *in, ++ const struct net_device *out, const void *data, unsigned int datalen) ++{ ++ struct ebt_limit_info *info = (struct ebt_limit_info *)data; ++ unsigned long now = jiffies; ++ ++ spin_lock_bh(&limit_lock); ++ info->credit += (now - xchg(&info->prev, now)) * CREDITS_PER_JIFFY; ++ if (info->credit > info->credit_cap) ++ info->credit = info->credit_cap; ++ ++ if (info->credit >= info->cost) { ++ /* We're not limited. */ ++ info->credit -= info->cost; ++ spin_unlock_bh(&limit_lock); ++ return EBT_MATCH; ++ } ++ ++ spin_unlock_bh(&limit_lock); ++ return EBT_NOMATCH; ++} ++ ++/* Precision saver. */ ++static u_int32_t ++user2credits(u_int32_t user) ++{ ++ /* If multiplying would overflow... */ ++ if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY)) ++ /* Divide first. */ ++ return (user / EBT_LIMIT_SCALE) * HZ * CREDITS_PER_JIFFY; ++ ++ return (user * HZ * CREDITS_PER_JIFFY) / EBT_LIMIT_SCALE; ++} ++ ++static int ebt_limit_check(const char *tablename, unsigned int hookmask, ++ const struct ebt_entry *e, void *data, unsigned int datalen) ++{ ++ struct ebt_limit_info *info = (struct ebt_limit_info *)data; ++ ++ if (datalen != EBT_ALIGN(sizeof(struct ebt_limit_info))) ++ return -EINVAL; ++ ++ /* Check for overflow. */ ++ if (info->burst == 0 ++ || user2credits(info->avg * info->burst) < user2credits(info->avg)) { ++ printk("Overflow in ebt_limit: %u/%u\n", ++ info->avg, info->burst); ++ return -EINVAL; ++ } ++ ++ /* User avg in seconds * EBT_LIMIT_SCALE: convert to jiffies * 128. */ ++ info->prev = jiffies; ++ info->credit = user2credits(info->avg * info->burst); ++ info->credit_cap = user2credits(info->avg * info->burst); ++ info->cost = user2credits(info->avg); ++ return 0; ++} ++ ++static struct ebt_match ebt_limit_reg = ++{ ++ {NULL, NULL}, EBT_LIMIT_MATCH, ebt_limit_match, ebt_limit_check, NULL, ++ THIS_MODULE ++}; ++ ++static int __init init(void) ++{ ++ return ebt_register_match(&ebt_limit_reg); ++} ++ ++static void __exit fini(void) ++{ ++ ebt_unregister_match(&ebt_limit_reg); ++} ++ ++module_init(init); ++module_exit(fini); ++EXPORT_NO_SYMBOLS; ++MODULE_LICENSE("GPL"); +diff -Nurb src/linux/linux.stock/net/bridge/netfilter/ebt_log.c src/linux/linux/net/bridge/netfilter/ebt_log.c +--- src/linux/linux.stock/net/bridge/netfilter/ebt_log.c 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/net/bridge/netfilter/ebt_log.c 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,152 @@ ++/* ++ * ebt_log ++ * ++ * Authors: ++ * Bart De Schuymer <bart.de.schuymer@pandora.be> ++ * ++ * April, 2002 ++ * ++ */ ++ ++#include <linux/netfilter_bridge/ebtables.h> ++#include <linux/netfilter_bridge/ebt_log.h> ++#include <linux/module.h> ++#include <linux/ip.h> ++#include <linux/in.h> ++#include <linux/if_arp.h> ++#include <linux/spinlock.h> ++ ++static spinlock_t ebt_log_lock = SPIN_LOCK_UNLOCKED; ++ ++static int ebt_log_check(const char *tablename, unsigned int hookmask, ++ const struct ebt_entry *e, void *data, unsigned int datalen) ++{ ++ struct ebt_log_info *info = (struct ebt_log_info *)data; ++ ++ if (datalen != EBT_ALIGN(sizeof(struct ebt_log_info))) ++ return -EINVAL; ++ if (info->bitmask & ~EBT_LOG_MASK) ++ return -EINVAL; ++ if (info->loglevel >= 8) ++ return -EINVAL; ++ info->prefix[EBT_LOG_PREFIX_SIZE - 1] = '\0'; ++ return 0; ++} ++ ++struct tcpudphdr ++{ ++ uint16_t src; ++ uint16_t dst; ++}; ++ ++struct arppayload ++{ ++ unsigned char mac_src[ETH_ALEN]; ++ unsigned char ip_src[4]; ++ unsigned char mac_dst[ETH_ALEN]; ++ unsigned char ip_dst[4]; ++}; ++ ++static void print_MAC(unsigned char *p) ++{ ++ int i; ++ ++ for (i = 0; i < ETH_ALEN; i++, p++) ++ printk("%02x%c", *p, i == ETH_ALEN - 1 ? ' ':':'); ++} ++ ++#define myNIPQUAD(a) a[0], a[1], a[2], a[3] ++static void ebt_log(const struct sk_buff *skb, const struct net_device *in, ++ const struct net_device *out, const void *data, unsigned int datalen) ++{ ++ struct ebt_log_info *info = (struct ebt_log_info *)data; ++ char level_string[4] = "< >"; ++ level_string[1] = '0' + info->loglevel; ++ ++ spin_lock_bh(&ebt_log_lock); ++ printk(level_string); ++ printk("%s IN=%s OUT=%s ", info->prefix, in ? in->name : "", ++ out ? out->name : ""); ++ ++ printk("MAC source = "); ++ print_MAC((skb->mac.ethernet)->h_source); ++ printk("MAC dest = "); ++ print_MAC((skb->mac.ethernet)->h_dest); ++ ++ printk("proto = 0x%04x", ntohs(((*skb).mac.ethernet)->h_proto)); ++ ++ if ((info->bitmask & EBT_LOG_IP) && skb->mac.ethernet->h_proto == ++ htons(ETH_P_IP)){ ++ struct iphdr *iph = skb->nh.iph; ++ printk(" IP SRC=%u.%u.%u.%u IP DST=%u.%u.%u.%u,", ++ NIPQUAD(iph->saddr), NIPQUAD(iph->daddr)); ++ printk(" IP tos=0x%02X, IP proto=%d", iph->tos, iph->protocol); ++ if (iph->protocol == IPPROTO_TCP || ++ iph->protocol == IPPROTO_UDP) { ++ struct tcpudphdr *ports = (struct tcpudphdr *)(skb->data + iph->ihl*4); ++ ++ if (skb->data + iph->ihl*4 > skb->tail) { ++ printk(" INCOMPLETE TCP/UDP header"); ++ goto out; ++ } ++ printk(" SPT=%u DPT=%u", ntohs(ports->src), ++ ntohs(ports->dst)); ++ } ++ goto out; ++ } ++ ++ if ((info->bitmask & EBT_LOG_ARP) && ++ ((skb->mac.ethernet->h_proto == __constant_htons(ETH_P_ARP)) || ++ (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_RARP)))) { ++ struct arphdr * arph = skb->nh.arph; ++ printk(" ARP HTYPE=%d, PTYPE=0x%04x, OPCODE=%d", ++ ntohs(arph->ar_hrd), ntohs(arph->ar_pro), ++ ntohs(arph->ar_op)); ++ /* If it's for Ethernet and the lengths are OK, ++ * then log the ARP payload */ ++ if (arph->ar_hrd == __constant_htons(1) && ++ arph->ar_hln == ETH_ALEN && ++ arph->ar_pln == sizeof(uint32_t)) { ++ struct arppayload *arpp = (struct arppayload *)(skb->data + sizeof(*arph)); ++ ++ if (skb->data + sizeof(*arph) > skb->tail) { ++ printk(" INCOMPLETE ARP header"); ++ goto out; ++ } ++ ++ printk(" ARP MAC SRC="); ++ print_MAC(arpp->mac_src); ++ printk(" ARP IP SRC=%u.%u.%u.%u", ++ myNIPQUAD(arpp->ip_src)); ++ printk(" ARP MAC DST="); ++ print_MAC(arpp->mac_dst); ++ printk(" ARP IP DST=%u.%u.%u.%u", ++ myNIPQUAD(arpp->ip_dst)); ++ } ++ ++ } ++out: ++ printk("\n"); ++ spin_unlock_bh(&ebt_log_lock); ++} ++ ++static struct ebt_watcher log = ++{ ++ {NULL, NULL}, EBT_LOG_WATCHER, ebt_log, ebt_log_check, NULL, ++ THIS_MODULE ++}; ++ ++static int __init init(void) ++{ ++ return ebt_register_watcher(&log); ++} ++ ++static void __exit fini(void) ++{ ++ ebt_unregister_watcher(&log); ++} ++ ++module_init(init); ++module_exit(fini); ++EXPORT_NO_SYMBOLS; ++MODULE_LICENSE("GPL"); +diff -Nurb src/linux/linux.stock/net/bridge/netfilter/ebt_mark.c src/linux/linux/net/bridge/netfilter/ebt_mark.c +--- src/linux/linux.stock/net/bridge/netfilter/ebt_mark.c 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/net/bridge/netfilter/ebt_mark.c 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,66 @@ ++/* ++ * ebt_mark ++ * ++ * Authors: ++ * Bart De Schuymer <bart.de.schuymer@pandora.be> ++ * ++ * July, 2002 ++ * ++ */ ++ ++// The mark target can be used in any chain ++// I believe adding a mangle table just for marking is total overkill ++// Marking a frame doesn't really change anything in the frame anyway ++ ++#include <linux/netfilter_bridge/ebtables.h> ++#include <linux/netfilter_bridge/ebt_mark_t.h> ++#include <linux/module.h> ++ ++static int ebt_target_mark(struct sk_buff **pskb, unsigned int hooknr, ++ const struct net_device *in, const struct net_device *out, ++ const void *data, unsigned int datalen) ++{ ++ struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)data; ++ ++ if ((*pskb)->nfmark != info->mark) { ++ (*pskb)->nfmark = info->mark; ++ (*pskb)->nfcache |= NFC_ALTERED; ++ } ++ return info->target; ++} ++ ++static int ebt_target_mark_check(const char *tablename, unsigned int hookmask, ++ const struct ebt_entry *e, void *data, unsigned int datalen) ++{ ++ struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)data; ++ ++ if (datalen != EBT_ALIGN(sizeof(struct ebt_mark_t_info))) ++ return -EINVAL; ++ if (BASE_CHAIN && info->target == EBT_RETURN) ++ return -EINVAL; ++ CLEAR_BASE_CHAIN_BIT; ++ if (INVALID_TARGET) ++ return -EINVAL; ++ return 0; ++} ++ ++static struct ebt_target mark_target = ++{ ++ {NULL, NULL}, EBT_MARK_TARGET, ebt_target_mark, ++ ebt_target_mark_check, NULL, THIS_MODULE ++}; ++ ++static int __init init(void) ++{ ++ return ebt_register_target(&mark_target); ++} ++ ++static void __exit fini(void) ++{ ++ ebt_unregister_target(&mark_target); ++} ++ ++module_init(init); ++module_exit(fini); ++EXPORT_NO_SYMBOLS; ++MODULE_LICENSE("GPL"); +diff -Nurb src/linux/linux.stock/net/bridge/netfilter/ebt_mark_m.c src/linux/linux/net/bridge/netfilter/ebt_mark_m.c +--- src/linux/linux.stock/net/bridge/netfilter/ebt_mark_m.c 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/net/bridge/netfilter/ebt_mark_m.c 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,61 @@ ++/* ++ * ebt_mark_m ++ * ++ * Authors: ++ * Bart De Schuymer <bart.de.schuymer@pandora.be> ++ * ++ * July, 2002 ++ * ++ */ ++ ++#include <linux/netfilter_bridge/ebtables.h> ++#include <linux/netfilter_bridge/ebt_mark_m.h> ++#include <linux/module.h> ++ ++static int ebt_filter_mark(const struct sk_buff *skb, ++ const struct net_device *in, const struct net_device *out, const void *data, ++ unsigned int datalen) ++{ ++ struct ebt_mark_m_info *info = (struct ebt_mark_m_info *) data; ++ ++ if (info->bitmask & EBT_MARK_OR) ++ return !(!!(skb->nfmark & info->mask) ^ info->invert); ++ return !(((skb->nfmark & info->mask) == info->mark) ^ info->invert); ++} ++ ++static int ebt_mark_check(const char *tablename, unsigned int hookmask, ++ const struct ebt_entry *e, void *data, unsigned int datalen) ++{ ++ struct ebt_mark_m_info *info = (struct ebt_mark_m_info *) data; ++ ++ if (datalen != EBT_ALIGN(sizeof(struct ebt_mark_m_info))) ++ return -EINVAL; ++ if (info->bitmask & ~EBT_MARK_MASK) ++ return -EINVAL; ++ if ((info->bitmask & EBT_MARK_OR) && (info->bitmask & EBT_MARK_AND)) ++ return -EINVAL; ++ if (!info->bitmask) ++ return -EINVAL; ++ return 0; ++} ++ ++static struct ebt_match filter_mark = ++{ ++ {NULL, NULL}, EBT_MARK_MATCH, ebt_filter_mark, ebt_mark_check, NULL, ++ THIS_MODULE ++}; ++ ++static int __init init(void) ++{ ++ return ebt_register_match(&filter_mark); ++} ++ ++static void __exit fini(void) ++{ ++ ebt_unregister_match(&filter_mark); ++} ++ ++module_init(init); ++module_exit(fini); ++EXPORT_NO_SYMBOLS; ++MODULE_LICENSE("GPL"); +diff -Nurb src/linux/linux.stock/net/bridge/netfilter/ebt_pkttype.c src/linux/linux/net/bridge/netfilter/ebt_pkttype.c +--- src/linux/linux.stock/net/bridge/netfilter/ebt_pkttype.c 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/net/bridge/netfilter/ebt_pkttype.c 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,60 @@ ++/* ++ * ebt_pkttype ++ * ++ * Authors: ++ * Bart De Schuymer <bdschuym@pandora.be> ++ * ++ * April, 2003 ++ * ++ */ ++ ++#include <linux/netfilter_bridge/ebtables.h> ++#include <linux/netfilter_bridge/ebt_pkttype.h> ++#include <linux/module.h> ++ ++static int ebt_filter_pkttype(const struct sk_buff *skb, ++ const struct net_device *in, ++ const struct net_device *out, ++ const void *data, ++ unsigned int datalen) ++{ ++ struct ebt_pkttype_info *info = (struct ebt_pkttype_info *)data; ++ ++ return (skb->pkt_type != info->pkt_type) ^ info->invert; ++} ++ ++static int ebt_pkttype_check(const char *tablename, unsigned int hookmask, ++ const struct ebt_entry *e, void *data, unsigned int datalen) ++{ ++ struct ebt_pkttype_info *info = (struct ebt_pkttype_info *)data; ++ ++ if (datalen != EBT_ALIGN(sizeof(struct ebt_pkttype_info))) ++ return -EINVAL; ++ if (info->invert != 0 && info->invert != 1) ++ return -EINVAL; ++ /* Allow any pkt_type value */ ++ return 0; ++} ++ ++static struct ebt_match filter_pkttype = ++{ ++ .name = EBT_PKTTYPE_MATCH, ++ .match = ebt_filter_pkttype, ++ .check = ebt_pkttype_check, ++ .me = THIS_MODULE, ++}; ++ ++static int __init init(void) ++{ ++ return ebt_register_match(&filter_pkttype); ++} ++ ++static void __exit fini(void) ++{ ++ ebt_unregister_match(&filter_pkttype); ++} ++ ++module_init(init); ++module_exit(fini); ++EXPORT_NO_SYMBOLS; ++MODULE_LICENSE("GPL"); +diff -Nurb src/linux/linux.stock/net/bridge/netfilter/ebt_redirect.c src/linux/linux/net/bridge/netfilter/ebt_redirect.c +--- src/linux/linux.stock/net/bridge/netfilter/ebt_redirect.c 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/net/bridge/netfilter/ebt_redirect.c 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,71 @@ ++/* ++ * ebt_redirect ++ * ++ * Authors: ++ * Bart De Schuymer <bart.de.schuymer@pandora.be> ++ * ++ * April, 2002 ++ * ++ */ ++ ++#include <linux/netfilter_bridge/ebtables.h> ++#include <linux/netfilter_bridge/ebt_redirect.h> ++#include <linux/module.h> ++#include <net/sock.h> ++#include "../br_private.h" ++ ++static int ebt_target_redirect(struct sk_buff **pskb, unsigned int hooknr, ++ const struct net_device *in, const struct net_device *out, ++ const void *data, unsigned int datalen) ++{ ++ struct ebt_redirect_info *info = (struct ebt_redirect_info *)data; ++ ++ if (hooknr != NF_BR_BROUTING) ++ memcpy((**pskb).mac.ethernet->h_dest, ++ in->br_port->br->dev.dev_addr, ETH_ALEN); ++ else { ++ memcpy((**pskb).mac.ethernet->h_dest, ++ in->dev_addr, ETH_ALEN); ++ (*pskb)->pkt_type = PACKET_HOST; ++ } ++ return info->target; ++} ++ ++static int ebt_target_redirect_check(const char *tablename, unsigned int hookmask, ++ const struct ebt_entry *e, void *data, unsigned int datalen) ++{ ++ struct ebt_redirect_info *info = (struct ebt_redirect_info *)data; ++ ++ if (datalen != EBT_ALIGN(sizeof(struct ebt_redirect_info))) ++ return -EINVAL; ++ if (BASE_CHAIN && info->target == EBT_RETURN) ++ return -EINVAL; ++ CLEAR_BASE_CHAIN_BIT; ++ if ( (strcmp(tablename, "nat") || hookmask & ~(1 << NF_BR_PRE_ROUTING)) && ++ (strcmp(tablename, "broute") || hookmask & ~(1 << NF_BR_BROUTING)) ) ++ return -EINVAL; ++ if (INVALID_TARGET) ++ return -EINVAL; ++ return 0; ++} ++ ++static struct ebt_target redirect_target = ++{ ++ {NULL, NULL}, EBT_REDIRECT_TARGET, ebt_target_redirect, ++ ebt_target_redirect_check, NULL, THIS_MODULE ++}; ++ ++static int __init init(void) ++{ ++ return ebt_register_target(&redirect_target); ++} ++ ++static void __exit fini(void) ++{ ++ ebt_unregister_target(&redirect_target); ++} ++ ++module_init(init); ++module_exit(fini); ++EXPORT_NO_SYMBOLS; ++MODULE_LICENSE("GPL"); +diff -Nurb src/linux/linux.stock/net/bridge/netfilter/ebt_snat.c src/linux/linux/net/bridge/netfilter/ebt_snat.c +--- src/linux/linux.stock/net/bridge/netfilter/ebt_snat.c 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/net/bridge/netfilter/ebt_snat.c 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,64 @@ ++/* ++ * ebt_snat ++ * ++ * Authors: ++ * Bart De Schuymer <bart.de.schuymer@pandora.be> ++ * ++ * June, 2002 ++ * ++ */ ++ ++#include <linux/netfilter_bridge/ebtables.h> ++#include <linux/netfilter_bridge/ebt_nat.h> ++#include <linux/module.h> ++ ++static int ebt_target_snat(struct sk_buff **pskb, unsigned int hooknr, ++ const struct net_device *in, const struct net_device *out, ++ const void *data, unsigned int datalen) ++{ ++ struct ebt_nat_info *info = (struct ebt_nat_info *) data; ++ ++ memcpy(((**pskb).mac.ethernet)->h_source, info->mac, ++ ETH_ALEN * sizeof(unsigned char)); ++ return info->target; ++} ++ ++static int ebt_target_snat_check(const char *tablename, unsigned int hookmask, ++ const struct ebt_entry *e, void *data, unsigned int datalen) ++{ ++ struct ebt_nat_info *info = (struct ebt_nat_info *) data; ++ ++ if (datalen != EBT_ALIGN(sizeof(struct ebt_nat_info))) ++ return -EINVAL; ++ if (BASE_CHAIN && info->target == EBT_RETURN) ++ return -EINVAL; ++ CLEAR_BASE_CHAIN_BIT; ++ if (strcmp(tablename, "nat")) ++ return -EINVAL; ++ if (hookmask & ~(1 << NF_BR_POST_ROUTING)) ++ return -EINVAL; ++ if (INVALID_TARGET) ++ return -EINVAL; ++ return 0; ++} ++ ++static struct ebt_target snat = ++{ ++ {NULL, NULL}, EBT_SNAT_TARGET, ebt_target_snat, ebt_target_snat_check, ++ NULL, THIS_MODULE ++}; ++ ++static int __init init(void) ++{ ++ return ebt_register_target(&snat); ++} ++ ++static void __exit fini(void) ++{ ++ ebt_unregister_target(&snat); ++} ++ ++module_init(init); ++module_exit(fini); ++EXPORT_NO_SYMBOLS; ++MODULE_LICENSE("GPL"); +diff -Nurb src/linux/linux.stock/net/bridge/netfilter/ebt_stp.c src/linux/linux/net/bridge/netfilter/ebt_stp.c +--- src/linux/linux.stock/net/bridge/netfilter/ebt_stp.c 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/net/bridge/netfilter/ebt_stp.c 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,191 @@ ++/* ++ * ebt_stp ++ * ++ * Authors: ++ * Bart De Schuymer <bdschuym@pandora.be> ++ * Stephen Hemminger <shemminger@osdl.org> ++ * ++ * June, 2003 ++ */ ++ ++#include <linux/netfilter_bridge/ebtables.h> ++#include <linux/netfilter_bridge/ebt_stp.h> ++#include <linux/module.h> ++ ++#define BPDU_TYPE_CONFIG 0 ++#define BPDU_TYPE_TCN 0x80 ++ ++struct stp_header { ++ uint8_t dsap; ++ uint8_t ssap; ++ uint8_t ctrl; ++ uint8_t pid; ++ uint8_t vers; ++ uint8_t type; ++}; ++ ++struct stp_config_pdu { ++ uint8_t flags; ++ uint8_t root[8]; ++ uint8_t root_cost[4]; ++ uint8_t sender[8]; ++ uint8_t port[2]; ++ uint8_t msg_age[2]; ++ uint8_t max_age[2]; ++ uint8_t hello_time[2]; ++ uint8_t forward_delay[2]; ++}; ++ ++#define NR16(p) (p[0] << 8 | p[1]) ++#define NR32(p) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]) ++ ++static int ebt_filter_config(struct ebt_stp_info *info, ++ struct stp_config_pdu *stpc) ++{ ++ struct ebt_stp_config_info *c; ++ uint16_t v16; ++ uint32_t v32; ++ int verdict, i; ++ ++ c = &info->config; ++ if ((info->bitmask & EBT_STP_FLAGS) && ++ FWINV(c->flags != stpc->flags, EBT_STP_FLAGS)) ++ return EBT_NOMATCH; ++ if (info->bitmask & EBT_STP_ROOTPRIO) { ++ v16 = NR16(stpc->root); ++ if (FWINV(v16 < c->root_priol || ++ v16 > c->root_priou, EBT_STP_ROOTPRIO)) ++ return EBT_NOMATCH; ++ } ++ if (info->bitmask & EBT_STP_ROOTADDR) { ++ verdict = 0; ++ for (i = 0; i < 6; i++) ++ verdict |= (stpc->root[2+i] ^ c->root_addr[i]) & ++ c->root_addrmsk[i]; ++ if (FWINV(verdict != 0, EBT_STP_ROOTADDR)) ++ return EBT_NOMATCH; ++ } ++ if (info->bitmask & EBT_STP_ROOTCOST) { ++ v32 = NR32(stpc->root_cost); ++ if (FWINV(v32 < c->root_costl || ++ v32 > c->root_costu, EBT_STP_ROOTCOST)) ++ return EBT_NOMATCH; ++ } ++ if (info->bitmask & EBT_STP_SENDERPRIO) { ++ v16 = NR16(stpc->sender); ++ if (FWINV(v16 < c->sender_priol || ++ v16 > c->sender_priou, EBT_STP_SENDERPRIO)) ++ return EBT_NOMATCH; ++ } ++ if (info->bitmask & EBT_STP_SENDERADDR) { ++ verdict = 0; ++ for (i = 0; i < 6; i++) ++ verdict |= (stpc->sender[2+i] ^ c->sender_addr[i]) & ++ c->sender_addrmsk[i]; ++ if (FWINV(verdict != 0, EBT_STP_SENDERADDR)) ++ return EBT_NOMATCH; ++ } ++ if (info->bitmask & EBT_STP_PORT) { ++ v16 = NR16(stpc->port); ++ if (FWINV(v16 < c->portl || ++ v16 > c->portu, EBT_STP_PORT)) ++ return EBT_NOMATCH; ++ } ++ if (info->bitmask & EBT_STP_MSGAGE) { ++ v16 = NR16(stpc->msg_age); ++ if (FWINV(v16 < c->msg_agel || ++ v16 > c->msg_ageu, EBT_STP_MSGAGE)) ++ return EBT_NOMATCH; ++ } ++ if (info->bitmask & EBT_STP_MAXAGE) { ++ v16 = NR16(stpc->max_age); ++ if (FWINV(v16 < c->max_agel || ++ v16 > c->max_ageu, EBT_STP_MAXAGE)) ++ return EBT_NOMATCH; ++ } ++ if (info->bitmask & EBT_STP_HELLOTIME) { ++ v16 = NR16(stpc->hello_time); ++ if (FWINV(v16 < c->hello_timel || ++ v16 > c->hello_timeu, EBT_STP_HELLOTIME)) ++ return EBT_NOMATCH; ++ } ++ if (info->bitmask & EBT_STP_FWDD) { ++ v16 = NR16(stpc->forward_delay); ++ if (FWINV(v16 < c->forward_delayl || ++ v16 > c->forward_delayu, EBT_STP_FWDD)) ++ return EBT_NOMATCH; ++ } ++ return EBT_MATCH; ++} ++ ++static int ebt_filter_stp(const struct sk_buff *skb, const struct net_device *in, ++ const struct net_device *out, const void *data, unsigned int datalen) ++{ ++ struct ebt_stp_info *info = (struct ebt_stp_info *)data; ++ struct stp_header stph; ++ uint8_t header[6] = {0x42, 0x42, 0x03, 0x00, 0x00, 0x00}; ++ if (skb_copy_bits(skb, 0, &stph, sizeof(stph))) ++ return EBT_NOMATCH; ++ ++ /* The stp code only considers these */ ++ if (memcmp(&stph, header, sizeof(header))) ++ return EBT_NOMATCH; ++ ++ if (info->bitmask & EBT_STP_TYPE ++ && FWINV(info->type != stph.type, EBT_STP_TYPE)) ++ return EBT_NOMATCH; ++ ++ if (stph.type == BPDU_TYPE_CONFIG && ++ info->bitmask & EBT_STP_CONFIG_MASK) { ++ struct stp_config_pdu stpc; ++ ++ if (skb_copy_bits(skb, sizeof(stph), &stpc, sizeof(stpc))) ++ return EBT_NOMATCH; ++ return ebt_filter_config(info, &stpc); ++ } ++ return EBT_MATCH; ++} ++ ++static int ebt_stp_check(const char *tablename, unsigned int hookmask, ++ const struct ebt_entry *e, void *data, unsigned int datalen) ++{ ++ struct ebt_stp_info *info = (struct ebt_stp_info *)data; ++ int len = EBT_ALIGN(sizeof(struct ebt_stp_info)); ++ uint8_t bridge_ula[6] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }; ++ uint8_t msk[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; ++ ++ if (info->bitmask & ~EBT_STP_MASK || info->invflags & ~EBT_STP_MASK || ++ !(info->bitmask & EBT_STP_MASK)) ++ return -EINVAL; ++ if (datalen != len) ++ return -EINVAL; ++ /* Make sure the match only receives stp frames */ ++ if (memcmp(e->destmac, bridge_ula, ETH_ALEN) || ++ memcmp(e->destmsk, msk, ETH_ALEN) || !(e->bitmask & EBT_DESTMAC)) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static struct ebt_match filter_stp = ++{ ++ .name = EBT_STP_MATCH, ++ .match = ebt_filter_stp, ++ .check = ebt_stp_check, ++ .me = THIS_MODULE, ++}; ++ ++static int __init init(void) ++{ ++ return ebt_register_match(&filter_stp); ++} ++ ++static void __exit fini(void) ++{ ++ ebt_unregister_match(&filter_stp); ++} ++ ++module_init(init); ++module_exit(fini); ++EXPORT_NO_SYMBOLS; ++MODULE_LICENSE("GPL"); +diff -Nurb src/linux/linux.stock/net/bridge/netfilter/ebt_vlan.c src/linux/linux/net/bridge/netfilter/ebt_vlan.c +--- src/linux/linux.stock/net/bridge/netfilter/ebt_vlan.c 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/net/bridge/netfilter/ebt_vlan.c 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,259 @@ ++/* ++ * Description: EBTables 802.1Q match extension kernelspace module. ++ * Authors: Nick Fedchik <nick@fedchik.org.ua> ++ * Bart De Schuymer <bart.de.schuymer@pandora.be> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include <linux/if_ether.h> ++#include <linux/if_vlan.h> ++#include <linux/module.h> ++#include <linux/netfilter_bridge/ebtables.h> ++#include <linux/netfilter_bridge/ebt_vlan.h> ++ ++static unsigned char debug; ++#define MODULE_VERSION "0.6" ++ ++MODULE_PARM(debug, "0-1b"); ++MODULE_PARM_DESC(debug, "debug=1 is turn on debug messages"); ++MODULE_AUTHOR("Nick Fedchik <nick@fedchik.org.ua>"); ++MODULE_DESCRIPTION("802.1Q match module (ebtables extension), v" ++ MODULE_VERSION); ++MODULE_LICENSE("GPL"); ++ ++ ++#define DEBUG_MSG(args...) if (debug) printk (KERN_DEBUG "ebt_vlan: " args) ++#define INV_FLAG(_inv_flag_) (info->invflags & _inv_flag_) ? "!" : "" ++#define GET_BITMASK(_BIT_MASK_) info->bitmask & _BIT_MASK_ ++#define SET_BITMASK(_BIT_MASK_) info->bitmask |= _BIT_MASK_ ++#define EXIT_ON_MISMATCH(_MATCH_,_MASK_) if (!((info->_MATCH_ == _MATCH_)^!!(info->invflags & _MASK_))) return 1; ++ ++/* ++ * Function description: ebt_filter_vlan() is main engine for ++ * checking passed 802.1Q frame according to ++ * the passed extension parameters (in the *data buffer) ++ * ebt_filter_vlan() is called after successfull check the rule params ++ * by ebt_check_vlan() function. ++ * Parameters: ++ * const struct sk_buff *skb - pointer to passed ethernet frame buffer ++ * const void *data - pointer to passed extension parameters ++ * unsigned int datalen - length of passed *data buffer ++ * const struct net_device *in - ++ * const struct net_device *out - ++ * const struct ebt_counter *c - ++ * Returned values: ++ * 0 - ok (all rule params matched) ++ * 1 - miss (rule params not acceptable to the parsed frame) ++ */ ++static int ++ebt_filter_vlan(const struct sk_buff *skb, ++ const struct net_device *in, ++ const struct net_device *out, ++ const void *data, unsigned int datalen) ++{ ++ struct ebt_vlan_info *info = (struct ebt_vlan_info *) data; /* userspace data */ ++ struct vlan_ethhdr *frame = (struct vlan_ethhdr *) skb->mac.raw; /* Passed tagged frame */ ++ ++ unsigned short TCI; /* Whole TCI, given from parsed frame */ ++ unsigned short id; /* VLAN ID, given from frame TCI */ ++ unsigned char prio; /* user_priority, given from frame TCI */ ++ unsigned short encap; /* VLAN encapsulated Type/Length field, given from orig frame */ ++ ++ /* ++ * Tag Control Information (TCI) consists of the following elements: ++ * - User_priority. The user_priority field is three bits in length, ++ * interpreted as a binary number. ++ * - Canonical Format Indicator (CFI). The Canonical Format Indicator ++ * (CFI) is a single bit flag value. Currently ignored. ++ * - VLAN Identifier (VID). The VID is encoded as ++ * an unsigned binary number. ++ */ ++ TCI = ntohs(frame->h_vlan_TCI); ++ id = TCI & VLAN_VID_MASK; ++ prio = (TCI >> 13) & 0x7; ++ encap = frame->h_vlan_encapsulated_proto; ++ ++ /* ++ * Checking VLAN Identifier (VID) ++ */ ++ if (GET_BITMASK(EBT_VLAN_ID)) { /* Is VLAN ID parsed? */ ++ EXIT_ON_MISMATCH(id, EBT_VLAN_ID); ++ } ++ /* ++ * Checking user_priority ++ */ ++ if (GET_BITMASK(EBT_VLAN_PRIO)) { /* Is VLAN user_priority parsed? */ ++ EXIT_ON_MISMATCH(prio, EBT_VLAN_PRIO); ++ } ++ /* ++ * Checking Encapsulated Proto (Length/Type) field ++ */ ++ if (GET_BITMASK(EBT_VLAN_ENCAP)) { /* Is VLAN Encap parsed? */ ++ EXIT_ON_MISMATCH(encap, EBT_VLAN_ENCAP); ++ } ++ /* ++ * All possible extension parameters was parsed. ++ * If rule never returned by missmatch, then all ok. ++ */ ++ return 0; ++} ++ ++/* ++ * Function description: ebt_vlan_check() is called when userspace ++ * delivers the table entry to the kernel, ++ * and to check that userspace doesn't give a bad table. ++ * Parameters: ++ * const char *tablename - table name string ++ * unsigned int hooknr - hook number ++ * const struct ebt_entry *e - ebtables entry basic set ++ * const void *data - pointer to passed extension parameters ++ * unsigned int datalen - length of passed *data buffer ++ * Returned values: ++ * 0 - ok (all delivered rule params are correct) ++ * 1 - miss (rule params is out of range, invalid, incompatible, etc.) ++ */ ++static int ++ebt_check_vlan(const char *tablename, ++ unsigned int hooknr, ++ const struct ebt_entry *e, void *data, unsigned int datalen) ++{ ++ struct ebt_vlan_info *info = (struct ebt_vlan_info *) data; ++ ++ /* ++ * Parameters buffer overflow check ++ */ ++ if (datalen != EBT_ALIGN(sizeof(struct ebt_vlan_info))) { ++ DEBUG_MSG ++ ("passed size %d is not eq to ebt_vlan_info (%d)\n", ++ datalen, sizeof(struct ebt_vlan_info)); ++ return -EINVAL; ++ } ++ ++ /* ++ * Is it 802.1Q frame checked? ++ */ ++ if (e->ethproto != __constant_htons(ETH_P_8021Q)) { ++ DEBUG_MSG ++ ("passed entry proto %2.4X is not 802.1Q (8100)\n", ++ (unsigned short) ntohs(e->ethproto)); ++ return -EINVAL; ++ } ++ ++ /* ++ * Check for bitmask range ++ * True if even one bit is out of mask ++ */ ++ if (info->bitmask & ~EBT_VLAN_MASK) { ++ DEBUG_MSG("bitmask %2X is out of mask (%2X)\n", ++ info->bitmask, EBT_VLAN_MASK); ++ return -EINVAL; ++ } ++ ++ /* ++ * Check for inversion flags range ++ */ ++ if (info->invflags & ~EBT_VLAN_MASK) { ++ DEBUG_MSG("inversion flags %2X is out of mask (%2X)\n", ++ info->invflags, EBT_VLAN_MASK); ++ return -EINVAL; ++ } ++ ++ /* ++ * Reserved VLAN ID (VID) values ++ * ----------------------------- ++ * 0 - The null VLAN ID. ++ * 1 - The default Port VID (PVID) ++ * 0x0FFF - Reserved for implementation use. ++ * if_vlan.h: VLAN_GROUP_ARRAY_LEN 4096. ++ */ ++ if (GET_BITMASK(EBT_VLAN_ID)) { /* when vlan-id param was spec-ed */ ++ if (!!info->id) { /* if id!=0 => check vid range */ ++ if (info->id > VLAN_GROUP_ARRAY_LEN) { ++ DEBUG_MSG ++ ("id %d is out of range (1-4096)\n", ++ info->id); ++ return -EINVAL; ++ } ++ /* ++ * Note: This is valid VLAN-tagged frame point. ++ * Any value of user_priority are acceptable, ++ * but should be ignored according to 802.1Q Std. ++ * So we just drop the prio flag. ++ */ ++ info->bitmask &= ~EBT_VLAN_PRIO; ++ } ++ /* ++ * Else, id=0 (null VLAN ID) => user_priority range (any?) ++ */ ++ } ++ ++ if (GET_BITMASK(EBT_VLAN_PRIO)) { ++ if ((unsigned char) info->prio > 7) { ++ DEBUG_MSG ++ ("prio %d is out of range (0-7)\n", ++ info->prio); ++ return -EINVAL; ++ } ++ } ++ /* ++ * Check for encapsulated proto range - it is possible to be ++ * any value for u_short range. ++ * if_ether.h: ETH_ZLEN 60 - Min. octets in frame sans FCS ++ */ ++ if (GET_BITMASK(EBT_VLAN_ENCAP)) { ++ if ((unsigned short) ntohs(info->encap) < ETH_ZLEN) { ++ DEBUG_MSG ++ ("encap frame length %d is less than minimal\n", ++ ntohs(info->encap)); ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ ++static struct ebt_match filter_vlan = { ++ {NULL, NULL}, ++ EBT_VLAN_MATCH, ++ ebt_filter_vlan, ++ ebt_check_vlan, ++ NULL, ++ THIS_MODULE ++}; ++ ++/* ++ * Module initialization function. ++ */ ++static int __init init(void) ++{ ++ DEBUG_MSG("ebtables 802.1Q extension module v" ++ MODULE_VERSION "\n"); ++ DEBUG_MSG("module debug=%d\n", !!debug); ++ return ebt_register_match(&filter_vlan); ++} ++ ++/* ++ * Module "finalization" function ++ */ ++static void __exit fini(void) ++{ ++ ebt_unregister_match(&filter_vlan); ++} ++ ++module_init(init); ++module_exit(fini); ++ ++EXPORT_NO_SYMBOLS; +diff -Nurb src/linux/linux.stock/net/bridge/netfilter/ebtable_broute.c src/linux/linux/net/bridge/netfilter/ebtable_broute.c +--- src/linux/linux.stock/net/bridge/netfilter/ebtable_broute.c 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/net/bridge/netfilter/ebtable_broute.c 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,79 @@ ++/* ++ * ebtable_broute ++ * ++ * Authors: ++ * Bart De Schuymer <bart.de.schuymer@pandora.be> ++ * ++ * April, 2002 ++ * ++ * This table lets you choose between routing and bridging for frames ++ * entering on a bridge enslaved nic. This table is traversed before any ++ * other ebtables table. See net/bridge/br_input.c. ++ */ ++ ++#include <linux/netfilter_bridge/ebtables.h> ++#include <linux/module.h> ++#include <linux/if_bridge.h> ++#include <linux/brlock.h> ++ ++// EBT_ACCEPT means the frame will be bridged ++// EBT_DROP means the frame will be routed ++static struct ebt_entries initial_chain = ++ {0, "BROUTING", 0, EBT_ACCEPT, 0}; ++ ++static struct ebt_replace initial_table = ++{ ++ "broute", 1 << NF_BR_BROUTING, 0, sizeof(struct ebt_entries), ++ { [NF_BR_BROUTING]&initial_chain}, 0, NULL, (char *)&initial_chain ++}; ++ ++static int check(const struct ebt_table_info *info, unsigned int valid_hooks) ++{ ++ if (valid_hooks & ~(1 << NF_BR_BROUTING)) ++ return -EINVAL; ++ return 0; ++} ++ ++static struct ebt_table broute_table = ++{ ++ {NULL, NULL}, "broute", &initial_table, 1 << NF_BR_BROUTING, ++ RW_LOCK_UNLOCKED, check, NULL ++}; ++ ++static int ebt_broute(struct sk_buff **pskb) ++{ ++ int ret; ++ ++ ret = ebt_do_table(NF_BR_BROUTING, pskb, (*pskb)->dev, NULL, ++ &broute_table); ++ if (ret == NF_DROP) ++ return 1; // route it ++ return 0; // bridge it ++} ++ ++static int __init init(void) ++{ ++ int ret; ++ ++ ret = ebt_register_table(&broute_table); ++ if (ret < 0) ++ return ret; ++ br_write_lock_bh(BR_NETPROTO_LOCK); ++ // see br_input.c ++ br_should_route_hook = ebt_broute; ++ br_write_unlock_bh(BR_NETPROTO_LOCK); ++ return ret; ++} ++ ++static void __exit fini(void) ++{ ++ br_write_lock_bh(BR_NETPROTO_LOCK); ++ br_should_route_hook = NULL; ++ br_write_unlock_bh(BR_NETPROTO_LOCK); ++ ebt_unregister_table(&broute_table); ++} ++ ++module_init(init); ++module_exit(fini); ++EXPORT_NO_SYMBOLS; ++MODULE_LICENSE("GPL"); +diff -Nurb src/linux/linux.stock/net/bridge/netfilter/ebtable_filter.c src/linux/linux/net/bridge/netfilter/ebtable_filter.c +--- src/linux/linux.stock/net/bridge/netfilter/ebtable_filter.c 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/net/bridge/netfilter/ebtable_filter.c 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,90 @@ ++/* ++ * ebtable_filter ++ * ++ * Authors: ++ * Bart De Schuymer <bart.de.schuymer@pandora.be> ++ * ++ * April, 2002 ++ * ++ */ ++ ++#include <linux/netfilter_bridge/ebtables.h> ++#include <linux/module.h> ++ ++#define FILTER_VALID_HOOKS ((1 << NF_BR_LOCAL_IN) | (1 << NF_BR_FORWARD) | \ ++ (1 << NF_BR_LOCAL_OUT)) ++ ++static struct ebt_entries initial_chains[] = ++{ ++ {0, "INPUT", 0, EBT_ACCEPT, 0}, ++ {0, "FORWARD", 0, EBT_ACCEPT, 0}, ++ {0, "OUTPUT", 0, EBT_ACCEPT, 0} ++}; ++ ++static struct ebt_replace initial_table = ++{ ++ "filter", FILTER_VALID_HOOKS, 0, 3 * sizeof(struct ebt_entries), ++ { [NF_BR_LOCAL_IN]&initial_chains[0], [NF_BR_FORWARD]&initial_chains[1], ++ [NF_BR_LOCAL_OUT]&initial_chains[2] }, 0, NULL, (char *)initial_chains ++}; ++ ++static int check(const struct ebt_table_info *info, unsigned int valid_hooks) ++{ ++ if (valid_hooks & ~FILTER_VALID_HOOKS) ++ return -EINVAL; ++ return 0; ++} ++ ++static struct ebt_table frame_filter = ++{ ++ {NULL, NULL}, "filter", &initial_table, FILTER_VALID_HOOKS, ++ RW_LOCK_UNLOCKED, check, NULL ++}; ++ ++static unsigned int ++ebt_hook (unsigned int hook, struct sk_buff **pskb, const struct net_device *in, ++ const struct net_device *out, int (*okfn)(struct sk_buff *)) ++{ ++ return ebt_do_table(hook, pskb, in, out, &frame_filter); ++} ++ ++static struct nf_hook_ops ebt_ops_filter[] = { ++ { { NULL, NULL }, ebt_hook, PF_BRIDGE, NF_BR_LOCAL_IN, ++ NF_BR_PRI_FILTER_BRIDGED}, ++ { { NULL, NULL }, ebt_hook, PF_BRIDGE, NF_BR_FORWARD, ++ NF_BR_PRI_FILTER_BRIDGED}, ++ { { NULL, NULL }, ebt_hook, PF_BRIDGE, NF_BR_LOCAL_OUT, ++ NF_BR_PRI_FILTER_OTHER} ++}; ++ ++static int __init init(void) ++{ ++ int i, j, ret; ++ ++ ret = ebt_register_table(&frame_filter); ++ if (ret < 0) ++ return ret; ++ for (i = 0; i < sizeof(ebt_ops_filter) / sizeof(ebt_ops_filter[0]); i++) ++ if ((ret = nf_register_hook(&ebt_ops_filter[i])) < 0) ++ goto cleanup; ++ return ret; ++cleanup: ++ for (j = 0; j < i; j++) ++ nf_unregister_hook(&ebt_ops_filter[j]); ++ ebt_unregister_table(&frame_filter); ++ return ret; ++} ++ ++static void __exit fini(void) ++{ ++ int i; ++ ++ for (i = 0; i < sizeof(ebt_ops_filter) / sizeof(ebt_ops_filter[0]); i++) ++ nf_unregister_hook(&ebt_ops_filter[i]); ++ ebt_unregister_table(&frame_filter); ++} ++ ++module_init(init); ++module_exit(fini); ++EXPORT_NO_SYMBOLS; ++MODULE_LICENSE("GPL"); +diff -Nurb src/linux/linux.stock/net/bridge/netfilter/ebtable_nat.c src/linux/linux/net/bridge/netfilter/ebtable_nat.c +--- src/linux/linux.stock/net/bridge/netfilter/ebtable_nat.c 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/net/bridge/netfilter/ebtable_nat.c 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,96 @@ ++/* ++ * ebtable_nat ++ * ++ * Authors: ++ * Bart De Schuymer <bart.de.schuymer@pandora.be> ++ * ++ * April, 2002 ++ * ++ */ ++ ++#include <linux/netfilter_bridge/ebtables.h> ++#include <linux/module.h> ++#define NAT_VALID_HOOKS ((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT) | \ ++ (1 << NF_BR_POST_ROUTING)) ++ ++static struct ebt_entries initial_chains[] = ++{ ++ {0, "PREROUTING", 0, EBT_ACCEPT, 0}, ++ {0, "OUTPUT", 0, EBT_ACCEPT, 0}, ++ {0, "POSTROUTING", 0, EBT_ACCEPT, 0} ++}; ++ ++static struct ebt_replace initial_table = ++{ ++ "nat", NAT_VALID_HOOKS, 0, 3 * sizeof(struct ebt_entries), ++ { [NF_BR_PRE_ROUTING]&initial_chains[0], [NF_BR_LOCAL_OUT]&initial_chains[1], ++ [NF_BR_POST_ROUTING]&initial_chains[2] }, 0, NULL, (char *)initial_chains ++}; ++ ++static int check(const struct ebt_table_info *info, unsigned int valid_hooks) ++{ ++ if (valid_hooks & ~NAT_VALID_HOOKS) ++ return -EINVAL; ++ return 0; ++} ++ ++static struct ebt_table frame_nat = ++{ ++ {NULL, NULL}, "nat", &initial_table, NAT_VALID_HOOKS, ++ RW_LOCK_UNLOCKED, check, NULL ++}; ++ ++static unsigned int ++ebt_nat_dst(unsigned int hook, struct sk_buff **pskb, const struct net_device *in ++ , const struct net_device *out, int (*okfn)(struct sk_buff *)) ++{ ++ return ebt_do_table(hook, pskb, in, out, &frame_nat); ++} ++ ++static unsigned int ++ebt_nat_src(unsigned int hook, struct sk_buff **pskb, const struct net_device *in ++ , const struct net_device *out, int (*okfn)(struct sk_buff *)) ++{ ++ return ebt_do_table(hook, pskb, in, out, &frame_nat); ++} ++ ++static struct nf_hook_ops ebt_ops_nat[] = { ++ { { NULL, NULL }, ebt_nat_dst, PF_BRIDGE, NF_BR_LOCAL_OUT, ++ NF_BR_PRI_NAT_DST_OTHER}, ++ { { NULL, NULL }, ebt_nat_src, PF_BRIDGE, NF_BR_POST_ROUTING, ++ NF_BR_PRI_NAT_SRC}, ++ { { NULL, NULL }, ebt_nat_dst, PF_BRIDGE, NF_BR_PRE_ROUTING, ++ NF_BR_PRI_NAT_DST_BRIDGED}, ++}; ++ ++static int __init init(void) ++{ ++ int i, ret, j; ++ ++ ret = ebt_register_table(&frame_nat); ++ if (ret < 0) ++ return ret; ++ for (i = 0; i < sizeof(ebt_ops_nat) / sizeof(ebt_ops_nat[0]); i++) ++ if ((ret = nf_register_hook(&ebt_ops_nat[i])) < 0) ++ goto cleanup; ++ return ret; ++cleanup: ++ for (j = 0; j < i; j++) ++ nf_unregister_hook(&ebt_ops_nat[j]); ++ ebt_unregister_table(&frame_nat); ++ return ret; ++} ++ ++static void __exit fini(void) ++{ ++ int i; ++ ++ for (i = 0; i < sizeof(ebt_ops_nat) / sizeof(ebt_ops_nat[0]); i++) ++ nf_unregister_hook(&ebt_ops_nat[i]); ++ ebt_unregister_table(&frame_nat); ++} ++ ++module_init(init); ++module_exit(fini); ++EXPORT_NO_SYMBOLS; ++MODULE_LICENSE("GPL"); +diff -Nurb src/linux/linux.stock/net/bridge/netfilter/ebtables.c src/linux/linux/net/bridge/netfilter/ebtables.c +--- src/linux/linux.stock/net/bridge/netfilter/ebtables.c 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/net/bridge/netfilter/ebtables.c 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,1490 @@ ++/* ++ * ebtables ++ * ++ * Author: ++ * Bart De Schuymer <bart.de.schuymer@pandora.be> ++ * ++ * ebtables.c,v 2.0, July, 2002 ++ * ++ * This code is stongly inspired on the iptables code which is ++ * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling ++ * ++ * 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. ++ */ ++ ++// used for print_string ++#include <linux/sched.h> ++#include <linux/tty.h> ++ ++#include <linux/kmod.h> ++#include <linux/module.h> ++#include <linux/vmalloc.h> ++#include <linux/netfilter_bridge/ebtables.h> ++#include <linux/spinlock.h> ++#include <asm/uaccess.h> ++#include <linux/smp.h> ++#include <net/sock.h> ++// needed for logical [in,out]-dev filtering ++#include "../br_private.h" ++ ++// list_named_find ++#define ASSERT_READ_LOCK(x) ++#define ASSERT_WRITE_LOCK(x) ++#include <linux/netfilter_ipv4/listhelp.h> ++ ++#if 0 // use this for remote debugging ++// Copyright (C) 1998 by Ori Pomerantz ++// Print the string to the appropriate tty, the one ++// the current task uses ++static void print_string(char *str) ++{ ++ struct tty_struct *my_tty; ++ ++ /* The tty for the current task */ ++ my_tty = current->tty; ++ if (my_tty != NULL) { ++ (*(my_tty->driver).write)(my_tty, 0, str, strlen(str)); ++ (*(my_tty->driver).write)(my_tty, 0, "\015\012", 2); ++ } ++} ++ ++#define BUGPRINT(args) print_string(args); ++#else ++#define BUGPRINT(format, args...) printk("kernel msg: ebtables bug: please "\ ++ "report to author: "format, ## args) ++// #define BUGPRINT(format, args...) ++#endif ++#define MEMPRINT(format, args...) printk("kernel msg: ebtables "\ ++ ": out of memory: "format, ## args) ++// #define MEMPRINT(format, args...) ++ ++ ++ ++// Each cpu has its own set of counters, so there is no need for write_lock in ++// the softirq ++// For reading or updating the counters, the user context needs to ++// get a write_lock ++ ++// The size of each set of counters is altered to get cache alignment ++#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1)) ++#define COUNTER_OFFSET(n) (SMP_ALIGN(n * sizeof(struct ebt_counter))) ++#define COUNTER_BASE(c, n, cpu) ((struct ebt_counter *)(((char *)c) + \ ++ COUNTER_OFFSET(n) * cpu)) ++ ++ ++ ++static DECLARE_MUTEX(ebt_mutex); ++static LIST_HEAD(ebt_tables); ++static LIST_HEAD(ebt_targets); ++static LIST_HEAD(ebt_matches); ++static LIST_HEAD(ebt_watchers); ++ ++static struct ebt_target ebt_standard_target = ++{ {NULL, NULL}, EBT_STANDARD_TARGET, NULL, NULL, NULL, NULL}; ++ ++static inline int ebt_do_watcher (struct ebt_entry_watcher *w, ++ const struct sk_buff *skb, const struct net_device *in, ++ const struct net_device *out) ++{ ++ w->u.watcher->watcher(skb, in, out, w->data, ++ w->watcher_size); ++ // watchers don't give a verdict ++ return 0; ++} ++ ++static inline int ebt_do_match (struct ebt_entry_match *m, ++ const struct sk_buff *skb, const struct net_device *in, ++ const struct net_device *out) ++{ ++ return m->u.match->match(skb, in, out, m->data, ++ m->match_size); ++} ++ ++static inline int ebt_dev_check(char *entry, const struct net_device *device) ++{ ++ if (*entry == '\0') ++ return 0; ++ if (!device) ++ return 1; ++ return !!strcmp(entry, device->name); ++} ++ ++#define FWINV2(bool,invflg) ((bool) ^ !!(e->invflags & invflg)) ++// process standard matches ++static inline int ebt_basic_match(struct ebt_entry *e, struct ethhdr *h, ++ const struct net_device *in, const struct net_device *out) ++{ ++ int verdict, i; ++ ++ if (e->bitmask & EBT_802_3) { ++ if (FWINV2(ntohs(h->h_proto) >= 1536, EBT_IPROTO)) ++ return 1; ++ } else if (!(e->bitmask & EBT_NOPROTO) && ++ FWINV2(e->ethproto != h->h_proto, EBT_IPROTO)) ++ return 1; ++ ++ if (FWINV2(ebt_dev_check(e->in, in), EBT_IIN)) ++ return 1; ++ if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT)) ++ return 1; ++ if ((!in || !in->br_port) ? 0 : FWINV2(ebt_dev_check( ++ e->logical_in, &in->br_port->br->dev), EBT_ILOGICALIN)) ++ return 1; ++ if ((!out || !out->br_port) ? 0 : FWINV2(ebt_dev_check( ++ e->logical_out, &out->br_port->br->dev), EBT_ILOGICALOUT)) ++ return 1; ++ ++ if (e->bitmask & EBT_SOURCEMAC) { ++ verdict = 0; ++ for (i = 0; i < 6; i++) ++ verdict |= (h->h_source[i] ^ e->sourcemac[i]) & ++ e->sourcemsk[i]; ++ if (FWINV2(verdict != 0, EBT_ISOURCE) ) ++ return 1; ++ } ++ if (e->bitmask & EBT_DESTMAC) { ++ verdict = 0; ++ for (i = 0; i < 6; i++) ++ verdict |= (h->h_dest[i] ^ e->destmac[i]) & ++ e->destmsk[i]; ++ if (FWINV2(verdict != 0, EBT_IDEST) ) ++ return 1; ++ } ++ return 0; ++} ++ ++// Do some firewalling ++unsigned int ebt_do_table (unsigned int hook, struct sk_buff **pskb, ++ const struct net_device *in, const struct net_device *out, ++ struct ebt_table *table) ++{ ++ int i, nentries; ++ struct ebt_entry *point; ++ struct ebt_counter *counter_base, *cb_base; ++ struct ebt_entry_target *t; ++ int verdict, sp = 0; ++ struct ebt_chainstack *cs; ++ struct ebt_entries *chaininfo; ++ char *base; ++ struct ebt_table_info *private = table->private; ++ ++ read_lock_bh(&table->lock); ++ cb_base = COUNTER_BASE(private->counters, private->nentries, ++ cpu_number_map(smp_processor_id())); ++ if (private->chainstack) ++ cs = private->chainstack[cpu_number_map(smp_processor_id())]; ++ else ++ cs = NULL; ++ chaininfo = private->hook_entry[hook]; ++ nentries = private->hook_entry[hook]->nentries; ++ point = (struct ebt_entry *)(private->hook_entry[hook]->data); ++ counter_base = cb_base + private->hook_entry[hook]->counter_offset; ++ // base for chain jumps ++ base = private->entries; ++ i = 0; ++ while (i < nentries) { ++ if (ebt_basic_match(point, (**pskb).mac.ethernet, in, out)) ++ goto letscontinue; ++ ++ if (EBT_MATCH_ITERATE(point, ebt_do_match, *pskb, in, out) != 0) ++ goto letscontinue; ++ ++ // increase counter ++ (*(counter_base + i)).pcnt++; ++ (*(counter_base + i)).bcnt+=(**pskb).len; ++ ++ // these should only watch: not modify, nor tell us ++ // what to do with the packet ++ EBT_WATCHER_ITERATE(point, ebt_do_watcher, *pskb, in, ++ out); ++ ++ t = (struct ebt_entry_target *) ++ (((char *)point) + point->target_offset); ++ // standard target ++ if (!t->u.target->target) ++ verdict = ((struct ebt_standard_target *)t)->verdict; ++ else ++ verdict = t->u.target->target(pskb, hook, ++ in, out, t->data, t->target_size); ++ if (verdict == EBT_ACCEPT) { ++ read_unlock_bh(&table->lock); ++ return NF_ACCEPT; ++ } ++ if (verdict == EBT_DROP) { ++ read_unlock_bh(&table->lock); ++ return NF_DROP; ++ } ++ if (verdict == EBT_RETURN) { ++letsreturn: ++#ifdef CONFIG_NETFILTER_DEBUG ++ if (sp == 0) { ++ BUGPRINT("RETURN on base chain"); ++ // act like this is EBT_CONTINUE ++ goto letscontinue; ++ } ++#endif ++ sp--; ++ // put all the local variables right ++ i = cs[sp].n; ++ chaininfo = cs[sp].chaininfo; ++ nentries = chaininfo->nentries; ++ point = cs[sp].e; ++ counter_base = cb_base + ++ chaininfo->counter_offset; ++ continue; ++ } ++ if (verdict == EBT_CONTINUE) ++ goto letscontinue; ++#ifdef CONFIG_NETFILTER_DEBUG ++ if (verdict < 0) { ++ BUGPRINT("bogus standard verdict\n"); ++ read_unlock_bh(&table->lock); ++ return NF_DROP; ++ } ++#endif ++ // jump to a udc ++ cs[sp].n = i + 1; ++ cs[sp].chaininfo = chaininfo; ++ cs[sp].e = (struct ebt_entry *) ++ (((char *)point) + point->next_offset); ++ i = 0; ++ chaininfo = (struct ebt_entries *) (base + verdict); ++#ifdef CONFIG_NETFILTER_DEBUG ++ if (chaininfo->distinguisher) { ++ BUGPRINT("jump to non-chain\n"); ++ read_unlock_bh(&table->lock); ++ return NF_DROP; ++ } ++#endif ++ nentries = chaininfo->nentries; ++ point = (struct ebt_entry *)chaininfo->data; ++ counter_base = cb_base + chaininfo->counter_offset; ++ sp++; ++ continue; ++letscontinue: ++ point = (struct ebt_entry *) ++ (((char *)point) + point->next_offset); ++ i++; ++ } ++ ++ // I actually like this :) ++ if (chaininfo->policy == EBT_RETURN) ++ goto letsreturn; ++ if (chaininfo->policy == EBT_ACCEPT) { ++ read_unlock_bh(&table->lock); ++ return NF_ACCEPT; ++ } ++ read_unlock_bh(&table->lock); ++ return NF_DROP; ++} ++ ++// If it succeeds, returns element and locks mutex ++static inline void * ++find_inlist_lock_noload(struct list_head *head, const char *name, int *error, ++ struct semaphore *mutex) ++{ ++ void *ret; ++ ++ *error = down_interruptible(mutex); ++ if (*error != 0) ++ return NULL; ++ ++ ret = list_named_find(head, name); ++ if (!ret) { ++ *error = -ENOENT; ++ up(mutex); ++ } ++ return ret; ++} ++ ++#ifndef CONFIG_KMOD ++#define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m)) ++#else ++static void * ++find_inlist_lock(struct list_head *head, const char *name, const char *prefix, ++ int *error, struct semaphore *mutex) ++{ ++ void *ret; ++ ++ ret = find_inlist_lock_noload(head, name, error, mutex); ++ if (!ret) { ++ char modulename[EBT_FUNCTION_MAXNAMELEN + strlen(prefix) + 1]; ++ strcpy(modulename, prefix); ++ strcat(modulename, name); ++ request_module(modulename); ++ ret = find_inlist_lock_noload(head, name, error, mutex); ++ } ++ return ret; ++} ++#endif ++ ++static inline struct ebt_table * ++find_table_lock(const char *name, int *error, struct semaphore *mutex) ++{ ++ return find_inlist_lock(&ebt_tables, name, "ebtable_", error, mutex); ++} ++ ++static inline struct ebt_match * ++find_match_lock(const char *name, int *error, struct semaphore *mutex) ++{ ++ return find_inlist_lock(&ebt_matches, name, "ebt_", error, mutex); ++} ++ ++static inline struct ebt_watcher * ++find_watcher_lock(const char *name, int *error, struct semaphore *mutex) ++{ ++ return find_inlist_lock(&ebt_watchers, name, "ebt_", error, mutex); ++} ++ ++static inline struct ebt_target * ++find_target_lock(const char *name, int *error, struct semaphore *mutex) ++{ ++ return find_inlist_lock(&ebt_targets, name, "ebt_", error, mutex); ++} ++ ++static inline int ++ebt_check_match(struct ebt_entry_match *m, struct ebt_entry *e, ++ const char *name, unsigned int hookmask, unsigned int *cnt) ++{ ++ struct ebt_match *match; ++ int ret; ++ ++ if (((char *)m) + m->match_size + sizeof(struct ebt_entry_match) > ++ ((char *)e) + e->watchers_offset) ++ return -EINVAL; ++ match = find_match_lock(m->u.name, &ret, &ebt_mutex); ++ if (!match) ++ return ret; ++ m->u.match = match; ++ if (match->me) ++ __MOD_INC_USE_COUNT(match->me); ++ up(&ebt_mutex); ++ if (match->check && ++ match->check(name, hookmask, e, m->data, m->match_size) != 0) { ++ BUGPRINT("match->check failed\n"); ++ if (match->me) ++ __MOD_DEC_USE_COUNT(match->me); ++ return -EINVAL; ++ } ++ (*cnt)++; ++ return 0; ++} ++ ++static inline int ++ebt_check_watcher(struct ebt_entry_watcher *w, struct ebt_entry *e, ++ const char *name, unsigned int hookmask, unsigned int *cnt) ++{ ++ struct ebt_watcher *watcher; ++ int ret; ++ ++ if (((char *)w) + w->watcher_size + sizeof(struct ebt_entry_watcher) > ++ ((char *)e) + e->target_offset) ++ return -EINVAL; ++ watcher = find_watcher_lock(w->u.name, &ret, &ebt_mutex); ++ if (!watcher) ++ return ret; ++ w->u.watcher = watcher; ++ if (watcher->me) ++ __MOD_INC_USE_COUNT(watcher->me); ++ up(&ebt_mutex); ++ if (watcher->check && ++ watcher->check(name, hookmask, e, w->data, w->watcher_size) != 0) { ++ BUGPRINT("watcher->check failed\n"); ++ if (watcher->me) ++ __MOD_DEC_USE_COUNT(watcher->me); ++ return -EINVAL; ++ } ++ (*cnt)++; ++ return 0; ++} ++ ++// this one is very careful, as it is the first function ++// to parse the userspace data ++static inline int ++ebt_check_entry_size_and_hooks(struct ebt_entry *e, ++ struct ebt_table_info *newinfo, char *base, char *limit, ++ struct ebt_entries **hook_entries, unsigned int *n, unsigned int *cnt, ++ unsigned int *totalcnt, unsigned int *udc_cnt, unsigned int valid_hooks) ++{ ++ int i; ++ ++ for (i = 0; i < NF_BR_NUMHOOKS; i++) { ++ if ((valid_hooks & (1 << i)) == 0) ++ continue; ++ if ( (char *)hook_entries[i] - base == ++ (char *)e - newinfo->entries) ++ break; ++ } ++ // beginning of a new chain ++ // if i == NF_BR_NUMHOOKS it must be a user defined chain ++ if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) { ++ if ((e->bitmask & EBT_ENTRY_OR_ENTRIES) != 0) { ++ // we make userspace set this right, ++ // so there is no misunderstanding ++ BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set " ++ "in distinguisher\n"); ++ return -EINVAL; ++ } ++ // this checks if the previous chain has as many entries ++ // as it said it has ++ if (*n != *cnt) { ++ BUGPRINT("nentries does not equal the nr of entries " ++ "in the chain\n"); ++ return -EINVAL; ++ } ++ // before we look at the struct, be sure it is not too big ++ if ((char *)hook_entries[i] + sizeof(struct ebt_entries) ++ > limit) { ++ BUGPRINT("entries_size too small\n"); ++ return -EINVAL; ++ } ++ if (((struct ebt_entries *)e)->policy != EBT_DROP && ++ ((struct ebt_entries *)e)->policy != EBT_ACCEPT) { ++ // only RETURN from udc ++ if (i != NF_BR_NUMHOOKS || ++ ((struct ebt_entries *)e)->policy != EBT_RETURN) { ++ BUGPRINT("bad policy\n"); ++ return -EINVAL; ++ } ++ } ++ if (i == NF_BR_NUMHOOKS) // it's a user defined chain ++ (*udc_cnt)++; ++ else ++ newinfo->hook_entry[i] = (struct ebt_entries *)e; ++ if (((struct ebt_entries *)e)->counter_offset != *totalcnt) { ++ BUGPRINT("counter_offset != totalcnt"); ++ return -EINVAL; ++ } ++ *n = ((struct ebt_entries *)e)->nentries; ++ *cnt = 0; ++ return 0; ++ } ++ // a plain old entry, heh ++ if (sizeof(struct ebt_entry) > e->watchers_offset || ++ e->watchers_offset > e->target_offset || ++ e->target_offset >= e->next_offset) { ++ BUGPRINT("entry offsets not in right order\n"); ++ return -EINVAL; ++ } ++ // this is not checked anywhere else ++ if (e->next_offset - e->target_offset < sizeof(struct ebt_entry_target)) { ++ BUGPRINT("target size too small\n"); ++ return -EINVAL; ++ } ++ ++ (*cnt)++; ++ (*totalcnt)++; ++ return 0; ++} ++ ++struct ebt_cl_stack ++{ ++ struct ebt_chainstack cs; ++ int from; ++ unsigned int hookmask; ++}; ++ ++// we need these positions to check that the jumps to a different part of the ++// entries is a jump to the beginning of a new chain. ++static inline int ++ebt_get_udc_positions(struct ebt_entry *e, struct ebt_table_info *newinfo, ++ struct ebt_entries **hook_entries, unsigned int *n, unsigned int valid_hooks, ++ struct ebt_cl_stack *udc) ++{ ++ int i; ++ ++ // we're only interested in chain starts ++ if (e->bitmask & EBT_ENTRY_OR_ENTRIES) ++ return 0; ++ for (i = 0; i < NF_BR_NUMHOOKS; i++) { ++ if ((valid_hooks & (1 << i)) == 0) ++ continue; ++ if (newinfo->hook_entry[i] == (struct ebt_entries *)e) ++ break; ++ } ++ // only care about udc ++ if (i != NF_BR_NUMHOOKS) ++ return 0; ++ ++ udc[*n].cs.chaininfo = (struct ebt_entries *)e; ++ // these initialisations are depended on later in check_chainloops() ++ udc[*n].cs.n = 0; ++ udc[*n].hookmask = 0; ++ ++ (*n)++; ++ return 0; ++} ++ ++static inline int ++ebt_cleanup_match(struct ebt_entry_match *m, unsigned int *i) ++{ ++ if (i && (*i)-- == 0) ++ return 1; ++ if (m->u.match->destroy) ++ m->u.match->destroy(m->data, m->match_size); ++ if (m->u.match->me) ++ __MOD_DEC_USE_COUNT(m->u.match->me); ++ ++ return 0; ++} ++ ++static inline int ++ebt_cleanup_watcher(struct ebt_entry_watcher *w, unsigned int *i) ++{ ++ if (i && (*i)-- == 0) ++ return 1; ++ if (w->u.watcher->destroy) ++ w->u.watcher->destroy(w->data, w->watcher_size); ++ if (w->u.watcher->me) ++ __MOD_DEC_USE_COUNT(w->u.watcher->me); ++ ++ return 0; ++} ++ ++static inline int ++ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt) ++{ ++ struct ebt_entry_target *t; ++ ++ if ((e->bitmask & EBT_ENTRY_OR_ENTRIES) == 0) ++ return 0; ++ // we're done ++ if (cnt && (*cnt)-- == 0) ++ return 1; ++ EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, NULL); ++ EBT_MATCH_ITERATE(e, ebt_cleanup_match, NULL); ++ t = (struct ebt_entry_target *)(((char *)e) + e->target_offset); ++ if (t->u.target->destroy) ++ t->u.target->destroy(t->data, t->target_size); ++ if (t->u.target->me) ++ __MOD_DEC_USE_COUNT(t->u.target->me); ++ ++ return 0; ++} ++ ++static inline int ++ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo, ++ const char *name, unsigned int *cnt, unsigned int valid_hooks, ++ struct ebt_cl_stack *cl_s, unsigned int udc_cnt) ++{ ++ struct ebt_entry_target *t; ++ struct ebt_target *target; ++ unsigned int i, j, hook = 0, hookmask = 0; ++ int ret; ++ ++ // Don't mess with the struct ebt_entries ++ if ((e->bitmask & EBT_ENTRY_OR_ENTRIES) == 0) ++ return 0; ++ ++ if (e->bitmask & ~EBT_F_MASK) { ++ BUGPRINT("Unknown flag for bitmask\n"); ++ return -EINVAL; ++ } ++ if (e->invflags & ~EBT_INV_MASK) { ++ BUGPRINT("Unknown flag for inv bitmask\n"); ++ return -EINVAL; ++ } ++ if ( (e->bitmask & EBT_NOPROTO) && (e->bitmask & EBT_802_3) ) { ++ BUGPRINT("NOPROTO & 802_3 not allowed\n"); ++ return -EINVAL; ++ } ++ // what hook do we belong to? ++ for (i = 0; i < NF_BR_NUMHOOKS; i++) { ++ if ((valid_hooks & (1 << i)) == 0) ++ continue; ++ if ((char *)newinfo->hook_entry[i] < (char *)e) ++ hook = i; ++ else ++ break; ++ } ++ // (1 << NF_BR_NUMHOOKS) tells the check functions the rule is on ++ // a base chain ++ if (i < NF_BR_NUMHOOKS) ++ hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS); ++ else { ++ for (i = 0; i < udc_cnt; i++) ++ if ((char *)(cl_s[i].cs.chaininfo) > (char *)e) ++ break; ++ if (i == 0) ++ hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS); ++ else ++ hookmask = cl_s[i - 1].hookmask; ++ } ++ i = 0; ++ ret = EBT_MATCH_ITERATE(e, ebt_check_match, e, name, hookmask, &i); ++ if (ret != 0) ++ goto cleanup_matches; ++ j = 0; ++ ret = EBT_WATCHER_ITERATE(e, ebt_check_watcher, e, name, hookmask, &j); ++ if (ret != 0) ++ goto cleanup_watchers; ++ t = (struct ebt_entry_target *)(((char *)e) + e->target_offset); ++ target = find_target_lock(t->u.name, &ret, &ebt_mutex); ++ if (!target) ++ goto cleanup_watchers; ++ if (target->me) ++ __MOD_INC_USE_COUNT(target->me); ++ up(&ebt_mutex); ++ ++ t->u.target = target; ++ if (t->u.target == &ebt_standard_target) { ++ if (e->target_offset + sizeof(struct ebt_standard_target) > ++ e->next_offset) { ++ BUGPRINT("Standard target size too big\n"); ++ ret = -EFAULT; ++ goto cleanup_watchers; ++ } ++ if (((struct ebt_standard_target *)t)->verdict < ++ -NUM_STANDARD_TARGETS) { ++ BUGPRINT("Invalid standard target\n"); ++ ret = -EFAULT; ++ goto cleanup_watchers; ++ } ++ } else if ((e->target_offset + t->target_size + ++ sizeof(struct ebt_entry_target) > e->next_offset) || ++ (t->u.target->check && ++ t->u.target->check(name, hookmask, e, t->data, t->target_size) != 0)){ ++ if (t->u.target->me) ++ __MOD_DEC_USE_COUNT(t->u.target->me); ++ ret = -EFAULT; ++ goto cleanup_watchers; ++ } ++ (*cnt)++; ++ return 0; ++cleanup_watchers: ++ EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, &j); ++cleanup_matches: ++ EBT_MATCH_ITERATE(e, ebt_cleanup_match, &i); ++ return ret; ++} ++ ++// checks for loops and sets the hook mask for udc ++// the hook mask for udc tells us from which base chains the udc can be ++// accessed. This mask is a parameter to the check() functions of the extensions ++static int check_chainloops(struct ebt_entries *chain, ++ struct ebt_cl_stack *cl_s, unsigned int udc_cnt, ++ unsigned int hooknr, char *base) ++{ ++ int i, chain_nr = -1, pos = 0, nentries = chain->nentries, verdict; ++ struct ebt_entry *e = (struct ebt_entry *)chain->data; ++ struct ebt_entry_target *t; ++ ++ while (pos < nentries || chain_nr != -1) { ++ // end of udc, go back one 'recursion' step ++ if (pos == nentries) { ++ // put back values of the time when this chain was called ++ e = cl_s[chain_nr].cs.e; ++ if (cl_s[chain_nr].from != -1) ++ nentries = ++ cl_s[cl_s[chain_nr].from].cs.chaininfo->nentries; ++ else ++ nentries = chain->nentries; ++ pos = cl_s[chain_nr].cs.n; ++ // make sure we won't see a loop that isn't one ++ cl_s[chain_nr].cs.n = 0; ++ chain_nr = cl_s[chain_nr].from; ++ if (pos == nentries) ++ continue; ++ } ++ t = (struct ebt_entry_target *) ++ (((char *)e) + e->target_offset); ++ if (strcmp(t->u.name, EBT_STANDARD_TARGET)) ++ goto letscontinue; ++ if (e->target_offset + sizeof(struct ebt_standard_target) > ++ e->next_offset) { ++ BUGPRINT("Standard target size too big\n"); ++ return -1; ++ } ++ verdict = ((struct ebt_standard_target *)t)->verdict; ++ if (verdict >= 0) { // jump to another chain ++ struct ebt_entries *hlp2 = ++ (struct ebt_entries *)(base + verdict); ++ for (i = 0; i < udc_cnt; i++) ++ if (hlp2 == cl_s[i].cs.chaininfo) ++ break; ++ // bad destination or loop ++ if (i == udc_cnt) { ++ BUGPRINT("bad destination\n"); ++ return -1; ++ } ++ if (cl_s[i].cs.n) { ++ BUGPRINT("loop\n"); ++ return -1; ++ } ++ // this can't be 0, so the above test is correct ++ cl_s[i].cs.n = pos + 1; ++ pos = 0; ++ cl_s[i].cs.e = ((void *)e + e->next_offset); ++ e = (struct ebt_entry *)(hlp2->data); ++ nentries = hlp2->nentries; ++ cl_s[i].from = chain_nr; ++ chain_nr = i; ++ // this udc is accessible from the base chain for hooknr ++ cl_s[i].hookmask |= (1 << hooknr); ++ continue; ++ } ++letscontinue: ++ e = (void *)e + e->next_offset; ++ pos++; ++ } ++ return 0; ++} ++ ++// do the parsing of the table/chains/entries/matches/watchers/targets, heh ++static int translate_table(struct ebt_replace *repl, ++ struct ebt_table_info *newinfo) ++{ ++ unsigned int i, j, k, udc_cnt; ++ int ret; ++ struct ebt_cl_stack *cl_s = NULL; // used in the checking for chain loops ++ ++ i = 0; ++ while (i < NF_BR_NUMHOOKS && !(repl->valid_hooks & (1 << i))) ++ i++; ++ if (i == NF_BR_NUMHOOKS) { ++ BUGPRINT("No valid hooks specified\n"); ++ return -EINVAL; ++ } ++ if (repl->hook_entry[i] != (struct ebt_entries *)repl->entries) { ++ BUGPRINT("Chains don't start at beginning\n"); ++ return -EINVAL; ++ } ++ // make sure chains are ordered after each other in same order ++ // as their corresponding hooks ++ for (j = i + 1; j < NF_BR_NUMHOOKS; j++) { ++ if (!(repl->valid_hooks & (1 << j))) ++ continue; ++ if ( repl->hook_entry[j] <= repl->hook_entry[i] ) { ++ BUGPRINT("Hook order must be followed\n"); ++ return -EINVAL; ++ } ++ i = j; ++ } ++ ++ for (i = 0; i < NF_BR_NUMHOOKS; i++) ++ newinfo->hook_entry[i] = NULL; ++ ++ newinfo->entries_size = repl->entries_size; ++ newinfo->nentries = repl->nentries; ++ ++ // do some early checkings and initialize some things ++ i = 0; // holds the expected nr. of entries for the chain ++ j = 0; // holds the up to now counted entries for the chain ++ k = 0; // holds the total nr. of entries, should equal ++ // newinfo->nentries afterwards ++ udc_cnt = 0; // will hold the nr. of user defined chains (udc) ++ ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size, ++ ebt_check_entry_size_and_hooks, newinfo, repl->entries, ++ repl->entries + repl->entries_size, repl->hook_entry, &i, &j, &k, ++ &udc_cnt, repl->valid_hooks); ++ ++ if (ret != 0) ++ return ret; ++ ++ if (i != j) { ++ BUGPRINT("nentries does not equal the nr of entries in the " ++ "(last) chain\n"); ++ return -EINVAL; ++ } ++ if (k != newinfo->nentries) { ++ BUGPRINT("Total nentries is wrong\n"); ++ return -EINVAL; ++ } ++ ++ // check if all valid hooks have a chain ++ for (i = 0; i < NF_BR_NUMHOOKS; i++) { ++ if (newinfo->hook_entry[i] == NULL && ++ (repl->valid_hooks & (1 << i))) { ++ BUGPRINT("Valid hook without chain\n"); ++ return -EINVAL; ++ } ++ } ++ ++ // Get the location of the udc, put them in an array ++ // While we're at it, allocate the chainstack ++ if (udc_cnt) { ++ // this will get free'd in do_replace()/ebt_register_table() ++ // if an error occurs ++ newinfo->chainstack = (struct ebt_chainstack **) ++ vmalloc(smp_num_cpus * sizeof(struct ebt_chainstack)); ++ if (!newinfo->chainstack) ++ return -ENOMEM; ++ for (i = 0; i < smp_num_cpus; i++) { ++ newinfo->chainstack[i] = ++ vmalloc(udc_cnt * sizeof(struct ebt_chainstack)); ++ if (!newinfo->chainstack[i]) { ++ while (i) ++ vfree(newinfo->chainstack[--i]); ++ vfree(newinfo->chainstack); ++ newinfo->chainstack = NULL; ++ return -ENOMEM; ++ } ++ } ++ ++ cl_s = (struct ebt_cl_stack *) ++ vmalloc(udc_cnt * sizeof(struct ebt_cl_stack)); ++ if (!cl_s) ++ return -ENOMEM; ++ i = 0; // the i'th udc ++ EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size, ++ ebt_get_udc_positions, newinfo, repl->hook_entry, &i, ++ repl->valid_hooks, cl_s); ++ // sanity check ++ if (i != udc_cnt) { ++ BUGPRINT("i != udc_cnt\n"); ++ vfree(cl_s); ++ return -EFAULT; ++ } ++ } ++ ++ // Check for loops ++ for (i = 0; i < NF_BR_NUMHOOKS; i++) ++ if (repl->valid_hooks & (1 << i)) ++ if (check_chainloops(newinfo->hook_entry[i], ++ cl_s, udc_cnt, i, newinfo->entries)) { ++ if (cl_s) ++ vfree(cl_s); ++ return -EINVAL; ++ } ++ ++ // we now know the following (along with E=mc²): ++ // - the nr of entries in each chain is right ++ // - the size of the allocated space is right ++ // - all valid hooks have a corresponding chain ++ // - there are no loops ++ // - wrong data can still be on the level of a single entry ++ // - could be there are jumps to places that are not the ++ // beginning of a chain. This can only occur in chains that ++ // are not accessible from any base chains, so we don't care. ++ ++ // used to know what we need to clean up if something goes wrong ++ i = 0; ++ ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size, ++ ebt_check_entry, newinfo, repl->name, &i, repl->valid_hooks, ++ cl_s, udc_cnt); ++ if (ret != 0) { ++ EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size, ++ ebt_cleanup_entry, &i); ++ } ++ if (cl_s) ++ vfree(cl_s); ++ return ret; ++} ++ ++// called under write_lock ++static void get_counters(struct ebt_counter *oldcounters, ++ struct ebt_counter *counters, unsigned int nentries) ++{ ++ int i, cpu; ++ struct ebt_counter *counter_base; ++ ++ // counters of cpu 0 ++ memcpy(counters, oldcounters, ++ sizeof(struct ebt_counter) * nentries); ++ // add other counters to those of cpu 0 ++ for (cpu = 1; cpu < smp_num_cpus; cpu++) { ++ counter_base = COUNTER_BASE(oldcounters, nentries, cpu); ++ for (i = 0; i < nentries; i++) { ++ counters[i].pcnt += counter_base[i].pcnt; ++ counters[i].bcnt += counter_base[i].bcnt; ++ } ++ } ++} ++ ++// replace the table ++static int do_replace(void *user, unsigned int len) ++{ ++ int ret, i, countersize; ++ struct ebt_table_info *newinfo; ++ struct ebt_replace tmp; ++ struct ebt_table *t; ++ struct ebt_counter *counterstmp = NULL; ++ // used to be able to unlock earlier ++ struct ebt_table_info *table; ++ ++ if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) ++ return -EFAULT; ++ ++ if (len != sizeof(tmp) + tmp.entries_size) { ++ BUGPRINT("Wrong len argument\n"); ++ return -EINVAL; ++ } ++ ++ if (tmp.entries_size == 0) { ++ BUGPRINT("Entries_size never zero\n"); ++ return -EINVAL; ++ } ++ countersize = COUNTER_OFFSET(tmp.nentries) * smp_num_cpus; ++ newinfo = (struct ebt_table_info *) ++ vmalloc(sizeof(struct ebt_table_info) + countersize); ++ if (!newinfo) ++ return -ENOMEM; ++ ++ if (countersize) ++ memset(newinfo->counters, 0, countersize); ++ ++ newinfo->entries = (char *)vmalloc(tmp.entries_size); ++ if (!newinfo->entries) { ++ ret = -ENOMEM; ++ goto free_newinfo; ++ } ++ if (copy_from_user( ++ newinfo->entries, tmp.entries, tmp.entries_size) != 0) { ++ BUGPRINT("Couldn't copy entries from userspace\n"); ++ ret = -EFAULT; ++ goto free_entries; ++ } ++ ++ // the user wants counters back ++ // the check on the size is done later, when we have the lock ++ if (tmp.num_counters) { ++ counterstmp = (struct ebt_counter *) ++ vmalloc(tmp.num_counters * sizeof(struct ebt_counter)); ++ if (!counterstmp) { ++ ret = -ENOMEM; ++ goto free_entries; ++ } ++ } ++ else ++ counterstmp = NULL; ++ ++ // this can get initialized by translate_table() ++ newinfo->chainstack = NULL; ++ ret = translate_table(&tmp, newinfo); ++ ++ if (ret != 0) ++ goto free_counterstmp; ++ ++ t = find_table_lock(tmp.name, &ret, &ebt_mutex); ++ if (!t) ++ goto free_iterate; ++ ++ // the table doesn't like it ++ if (t->check && (ret = t->check(newinfo, tmp.valid_hooks))) ++ goto free_unlock; ++ ++ if (tmp.num_counters && tmp.num_counters != t->private->nentries) { ++ BUGPRINT("Wrong nr. of counters requested\n"); ++ ret = -EINVAL; ++ goto free_unlock; ++ } ++ ++ // we have the mutex lock, so no danger in reading this pointer ++ table = t->private; ++ // we need an atomic snapshot of the counters ++ write_lock_bh(&t->lock); ++ if (tmp.num_counters) ++ get_counters(t->private->counters, counterstmp, ++ t->private->nentries); ++ ++ t->private = newinfo; ++ write_unlock_bh(&t->lock); ++ up(&ebt_mutex); ++ // So, a user can change the chains while having messed up her counter ++ // allocation. Only reason why this is done is because this way the lock ++ // is held only once, while this doesn't bring the kernel into a ++ // dangerous state. ++ if (tmp.num_counters && ++ copy_to_user(tmp.counters, counterstmp, ++ tmp.num_counters * sizeof(struct ebt_counter))) { ++ BUGPRINT("Couldn't copy counters to userspace\n"); ++ ret = -EFAULT; ++ } ++ else ++ ret = 0; ++ ++ // decrease module count and free resources ++ EBT_ENTRY_ITERATE(table->entries, table->entries_size, ++ ebt_cleanup_entry, NULL); ++ ++ vfree(table->entries); ++ if (table->chainstack) { ++ for (i = 0; i < smp_num_cpus; i++) ++ vfree(table->chainstack[i]); ++ vfree(table->chainstack); ++ } ++ vfree(table); ++ ++ if (counterstmp) ++ vfree(counterstmp); ++ return ret; ++ ++free_unlock: ++ up(&ebt_mutex); ++free_iterate: ++ EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size, ++ ebt_cleanup_entry, NULL); ++free_counterstmp: ++ if (counterstmp) ++ vfree(counterstmp); ++ // can be initialized in translate_table() ++ if (newinfo->chainstack) { ++ for (i = 0; i < smp_num_cpus; i++) ++ vfree(newinfo->chainstack[i]); ++ vfree(newinfo->chainstack); ++ } ++free_entries: ++ if (newinfo->entries) ++ vfree(newinfo->entries); ++free_newinfo: ++ if (newinfo) ++ vfree(newinfo); ++ return ret; ++} ++ ++int ebt_register_target(struct ebt_target *target) ++{ ++ int ret; ++ ++ ret = down_interruptible(&ebt_mutex); ++ if (ret != 0) ++ return ret; ++ if (!list_named_insert(&ebt_targets, target)) { ++ up(&ebt_mutex); ++ return -EEXIST; ++ } ++ up(&ebt_mutex); ++ MOD_INC_USE_COUNT; ++ ++ return 0; ++} ++ ++void ebt_unregister_target(struct ebt_target *target) ++{ ++ down(&ebt_mutex); ++ LIST_DELETE(&ebt_targets, target); ++ up(&ebt_mutex); ++ MOD_DEC_USE_COUNT; ++} ++ ++int ebt_register_match(struct ebt_match *match) ++{ ++ int ret; ++ ++ ret = down_interruptible(&ebt_mutex); ++ if (ret != 0) ++ return ret; ++ if (!list_named_insert(&ebt_matches, match)) { ++ up(&ebt_mutex); ++ return -EEXIST; ++ } ++ up(&ebt_mutex); ++ MOD_INC_USE_COUNT; ++ ++ return 0; ++} ++ ++void ebt_unregister_match(struct ebt_match *match) ++{ ++ down(&ebt_mutex); ++ LIST_DELETE(&ebt_matches, match); ++ up(&ebt_mutex); ++ MOD_DEC_USE_COUNT; ++} ++ ++int ebt_register_watcher(struct ebt_watcher *watcher) ++{ ++ int ret; ++ ++ ret = down_interruptible(&ebt_mutex); ++ if (ret != 0) ++ return ret; ++ if (!list_named_insert(&ebt_watchers, watcher)) { ++ up(&ebt_mutex); ++ return -EEXIST; ++ } ++ up(&ebt_mutex); ++ MOD_INC_USE_COUNT; ++ ++ return 0; ++} ++ ++void ebt_unregister_watcher(struct ebt_watcher *watcher) ++{ ++ down(&ebt_mutex); ++ LIST_DELETE(&ebt_watchers, watcher); ++ up(&ebt_mutex); ++ MOD_DEC_USE_COUNT; ++} ++ ++int ebt_register_table(struct ebt_table *table) ++{ ++ struct ebt_table_info *newinfo; ++ int ret, i, countersize; ++ ++ if (!table || !table->table ||!table->table->entries || ++ table->table->entries_size == 0 || ++ table->table->counters || table->private) { ++ BUGPRINT("Bad table data for ebt_register_table!!!\n"); ++ return -EINVAL; ++ } ++ ++ countersize = COUNTER_OFFSET(table->table->nentries) * smp_num_cpus; ++ newinfo = (struct ebt_table_info *) ++ vmalloc(sizeof(struct ebt_table_info) + countersize); ++ ret = -ENOMEM; ++ if (!newinfo) ++ return -ENOMEM; ++ ++ newinfo->entries = (char *)vmalloc(table->table->entries_size); ++ if (!(newinfo->entries)) ++ goto free_newinfo; ++ ++ memcpy(newinfo->entries, table->table->entries, ++ table->table->entries_size); ++ ++ if (countersize) ++ memset(newinfo->counters, 0, countersize); ++ ++ // fill in newinfo and parse the entries ++ newinfo->chainstack = NULL; ++ ret = translate_table(table->table, newinfo); ++ if (ret != 0) { ++ BUGPRINT("Translate_table failed\n"); ++ goto free_chainstack; ++ } ++ ++ if (table->check && table->check(newinfo, table->valid_hooks)) { ++ BUGPRINT("The table doesn't like its own initial data, lol\n"); ++ return -EINVAL; ++ } ++ ++ table->private = newinfo; ++ table->lock = RW_LOCK_UNLOCKED; ++ ret = down_interruptible(&ebt_mutex); ++ if (ret != 0) ++ goto free_chainstack; ++ ++ if (list_named_find(&ebt_tables, table->name)) { ++ ret = -EEXIST; ++ BUGPRINT("Table name already exists\n"); ++ goto free_unlock; ++ } ++ ++ list_prepend(&ebt_tables, table); ++ up(&ebt_mutex); ++ MOD_INC_USE_COUNT; ++ return 0; ++free_unlock: ++ up(&ebt_mutex); ++free_chainstack: ++ if (newinfo->chainstack) { ++ for (i = 0; i < smp_num_cpus; i++) ++ vfree(newinfo->chainstack[i]); ++ vfree(newinfo->chainstack); ++ } ++ vfree(newinfo->entries); ++free_newinfo: ++ vfree(newinfo); ++ return ret; ++} ++ ++void ebt_unregister_table(struct ebt_table *table) ++{ ++ int i; ++ ++ if (!table) { ++ BUGPRINT("Request to unregister NULL table!!!\n"); ++ return; ++ } ++ down(&ebt_mutex); ++ LIST_DELETE(&ebt_tables, table); ++ up(&ebt_mutex); ++ EBT_ENTRY_ITERATE(table->private->entries, ++ table->private->entries_size, ebt_cleanup_entry, NULL); ++ if (table->private->entries) ++ vfree(table->private->entries); ++ if (table->private->chainstack) { ++ for (i = 0; i < smp_num_cpus; i++) ++ vfree(table->private->chainstack[i]); ++ vfree(table->private->chainstack); ++ } ++ vfree(table->private); ++ MOD_DEC_USE_COUNT; ++} ++ ++// userspace just supplied us with counters ++static int update_counters(void *user, unsigned int len) ++{ ++ int i, ret; ++ struct ebt_counter *tmp; ++ struct ebt_replace hlp; ++ struct ebt_table *t; ++ ++ if (copy_from_user(&hlp, user, sizeof(hlp))) ++ return -EFAULT; ++ ++ if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter)) ++ return -EINVAL; ++ if (hlp.num_counters == 0) ++ return -EINVAL; ++ ++ if ( !(tmp = (struct ebt_counter *) ++ vmalloc(hlp.num_counters * sizeof(struct ebt_counter))) ){ ++ MEMPRINT("Update_counters && nomemory\n"); ++ return -ENOMEM; ++ } ++ ++ t = find_table_lock(hlp.name, &ret, &ebt_mutex); ++ if (!t) ++ goto free_tmp; ++ ++ if (hlp.num_counters != t->private->nentries) { ++ BUGPRINT("Wrong nr of counters\n"); ++ ret = -EINVAL; ++ goto unlock_mutex; ++ } ++ ++ if ( copy_from_user(tmp, hlp.counters, ++ hlp.num_counters * sizeof(struct ebt_counter)) ) { ++ BUGPRINT("Updata_counters && !cfu\n"); ++ ret = -EFAULT; ++ goto unlock_mutex; ++ } ++ ++ // we want an atomic add of the counters ++ write_lock_bh(&t->lock); ++ ++ // we add to the counters of the first cpu ++ for (i = 0; i < hlp.num_counters; i++) { ++ t->private->counters[i].pcnt += tmp[i].pcnt; ++ t->private->counters[i].bcnt += tmp[i].bcnt; ++ } ++ ++ write_unlock_bh(&t->lock); ++ ret = 0; ++unlock_mutex: ++ up(&ebt_mutex); ++free_tmp: ++ vfree(tmp); ++ return ret; ++} ++ ++static inline int ebt_make_matchname(struct ebt_entry_match *m, ++ char *base, char *ubase) ++{ ++ char *hlp = ubase - base + (char *)m; ++ if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN)) ++ return -EFAULT; ++ return 0; ++} ++ ++static inline int ebt_make_watchername(struct ebt_entry_watcher *w, ++ char *base, char *ubase) ++{ ++ char *hlp = ubase - base + (char *)w; ++ if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN)) ++ return -EFAULT; ++ return 0; ++} ++ ++static inline int ebt_make_names(struct ebt_entry *e, char *base, char *ubase) ++{ ++ int ret; ++ char *hlp; ++ struct ebt_entry_target *t; ++ ++ if ((e->bitmask & EBT_ENTRY_OR_ENTRIES) == 0) ++ return 0; ++ ++ hlp = ubase - base + (char *)e + e->target_offset; ++ t = (struct ebt_entry_target *)(((char *)e) + e->target_offset); ++ ++ ret = EBT_MATCH_ITERATE(e, ebt_make_matchname, base, ubase); ++ if (ret != 0) ++ return ret; ++ ret = EBT_WATCHER_ITERATE(e, ebt_make_watchername, base, ubase); ++ if (ret != 0) ++ return ret; ++ if (copy_to_user(hlp, t->u.target->name, EBT_FUNCTION_MAXNAMELEN)) ++ return -EFAULT; ++ return 0; ++} ++ ++// called with ebt_mutex down ++static int copy_everything_to_user(struct ebt_table *t, void *user, ++ int *len, int cmd) ++{ ++ struct ebt_replace tmp; ++ struct ebt_counter *counterstmp, *oldcounters; ++ unsigned int entries_size, nentries; ++ char *entries; ++ ++ if (cmd == EBT_SO_GET_ENTRIES) { ++ entries_size = t->private->entries_size; ++ nentries = t->private->nentries; ++ entries = t->private->entries; ++ oldcounters = t->private->counters; ++ } else { ++ entries_size = t->table->entries_size; ++ nentries = t->table->nentries; ++ entries = t->table->entries; ++ oldcounters = t->table->counters; ++ } ++ ++ if (copy_from_user(&tmp, user, sizeof(tmp))) { ++ BUGPRINT("Cfu didn't work\n"); ++ return -EFAULT; ++ } ++ ++ if (*len != sizeof(struct ebt_replace) + entries_size + ++ (tmp.num_counters? nentries * sizeof(struct ebt_counter): 0)) { ++ BUGPRINT("Wrong size\n"); ++ return -EINVAL; ++ } ++ ++ if (tmp.nentries != nentries) { ++ BUGPRINT("Nentries wrong\n"); ++ return -EINVAL; ++ } ++ ++ if (tmp.entries_size != entries_size) { ++ BUGPRINT("Wrong size\n"); ++ return -EINVAL; ++ } ++ ++ // userspace might not need the counters ++ if (tmp.num_counters) { ++ if (tmp.num_counters != nentries) { ++ BUGPRINT("Num_counters wrong\n"); ++ return -EINVAL; ++ } ++ counterstmp = (struct ebt_counter *) ++ vmalloc(nentries * sizeof(struct ebt_counter)); ++ if (!counterstmp) { ++ MEMPRINT("Couldn't copy counters, out of memory\n"); ++ return -ENOMEM; ++ } ++ write_lock_bh(&t->lock); ++ get_counters(oldcounters, counterstmp, nentries); ++ write_unlock_bh(&t->lock); ++ ++ if (copy_to_user(tmp.counters, counterstmp, ++ nentries * sizeof(struct ebt_counter))) { ++ BUGPRINT("Couldn't copy counters to userspace\n"); ++ vfree(counterstmp); ++ return -EFAULT; ++ } ++ vfree(counterstmp); ++ } ++ ++ if (copy_to_user(tmp.entries, entries, entries_size)) { ++ BUGPRINT("Couldn't copy entries to userspace\n"); ++ return -EFAULT; ++ } ++ // set the match/watcher/target names right ++ return EBT_ENTRY_ITERATE(entries, entries_size, ++ ebt_make_names, entries, tmp.entries); ++} ++ ++static int do_ebt_set_ctl(struct sock *sk, ++ int cmd, void *user, unsigned int len) ++{ ++ int ret; ++ ++ switch(cmd) { ++ case EBT_SO_SET_ENTRIES: ++ ret = do_replace(user, len); ++ break; ++ case EBT_SO_SET_COUNTERS: ++ ret = update_counters(user, len); ++ break; ++ default: ++ ret = -EINVAL; ++ } ++ return ret; ++} ++ ++static int do_ebt_get_ctl(struct sock *sk, int cmd, void *user, int *len) ++{ ++ int ret; ++ struct ebt_replace tmp; ++ struct ebt_table *t; ++ ++ if (copy_from_user(&tmp, user, sizeof(tmp))) ++ return -EFAULT; ++ ++ t = find_table_lock(tmp.name, &ret, &ebt_mutex); ++ if (!t) ++ return ret; ++ ++ switch(cmd) { ++ case EBT_SO_GET_INFO: ++ case EBT_SO_GET_INIT_INFO: ++ if (*len != sizeof(struct ebt_replace)){ ++ ret = -EINVAL; ++ up(&ebt_mutex); ++ break; ++ } ++ if (cmd == EBT_SO_GET_INFO) { ++ tmp.nentries = t->private->nentries; ++ tmp.entries_size = t->private->entries_size; ++ tmp.valid_hooks = t->valid_hooks; ++ } else { ++ tmp.nentries = t->table->nentries; ++ tmp.entries_size = t->table->entries_size; ++ tmp.valid_hooks = t->table->valid_hooks; ++ } ++ up(&ebt_mutex); ++ if (copy_to_user(user, &tmp, *len) != 0){ ++ BUGPRINT("c2u Didn't work\n"); ++ ret = -EFAULT; ++ break; ++ } ++ ret = 0; ++ break; ++ ++ case EBT_SO_GET_ENTRIES: ++ case EBT_SO_GET_INIT_ENTRIES: ++ ret = copy_everything_to_user(t, user, len, cmd); ++ up(&ebt_mutex); ++ break; ++ ++ default: ++ up(&ebt_mutex); ++ ret = -EINVAL; ++ } ++ ++ return ret; ++} ++ ++static struct nf_sockopt_ops ebt_sockopts = ++{ { NULL, NULL }, PF_INET, EBT_BASE_CTL, EBT_SO_SET_MAX + 1, do_ebt_set_ctl, ++ EBT_BASE_CTL, EBT_SO_GET_MAX + 1, do_ebt_get_ctl, 0, NULL ++}; ++ ++static int __init init(void) ++{ ++ int ret; ++ ++ down(&ebt_mutex); ++ list_named_insert(&ebt_targets, &ebt_standard_target); ++ up(&ebt_mutex); ++ if ((ret = nf_register_sockopt(&ebt_sockopts)) < 0) ++ return ret; ++ ++ printk(KERN_NOTICE "Ebtables v2.0 registered\n"); ++ return 0; ++} ++ ++static void __exit fini(void) ++{ ++ nf_unregister_sockopt(&ebt_sockopts); ++ printk(KERN_NOTICE "Ebtables v2.0 unregistered\n"); ++} ++ ++EXPORT_SYMBOL(ebt_register_table); ++EXPORT_SYMBOL(ebt_unregister_table); ++EXPORT_SYMBOL(ebt_register_match); ++EXPORT_SYMBOL(ebt_unregister_match); ++EXPORT_SYMBOL(ebt_register_watcher); ++EXPORT_SYMBOL(ebt_unregister_watcher); ++EXPORT_SYMBOL(ebt_register_target); ++EXPORT_SYMBOL(ebt_unregister_target); ++EXPORT_SYMBOL(ebt_do_table); ++module_init(init); ++module_exit(fini); ++MODULE_LICENSE("GPL"); +diff -Nurb src/linux/linux.stock/net/core/dev.c src/linux/linux/net/core/dev.c +--- src/linux/linux.stock/net/core/dev.c 2003-10-14 04:02:55.000000000 -0400 ++++ src/linux/linux/net/core/dev.c 2004-07-10 23:46:39.000000000 -0400 +@@ -1393,7 +1393,7 @@ + + + #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) +-void (*br_handle_frame_hook)(struct sk_buff *skb) = NULL; ++int (*br_handle_frame_hook)(struct sk_buff *skb) = NULL; + #endif + + static __inline__ int handle_bridge(struct sk_buff *skb, +@@ -1410,7 +1410,6 @@ + } + } + +- br_handle_frame_hook(skb); + return ret; + } + +@@ -1470,7 +1469,12 @@ + #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) + if (skb->dev->br_port != NULL && + br_handle_frame_hook != NULL) { +- return handle_bridge(skb, pt_prev); ++ int ret; ++ ++ ret = handle_bridge(skb, pt_prev); ++ if (br_handle_frame_hook(skb) == 0) ++ return ret; ++ pt_prev = NULL; + } + #endif + +diff -Nurb src/linux/linux.stock/net/core/netfilter.c src/linux/linux/net/core/netfilter.c +--- src/linux/linux.stock/net/core/netfilter.c 2004-07-10 23:29:56.000000000 -0400 ++++ src/linux/linux/net/core/netfilter.c 2004-07-10 23:46:39.000000000 -0400 +@@ -344,10 +344,15 @@ + const struct net_device *indev, + const struct net_device *outdev, + struct list_head **i, +- int (*okfn)(struct sk_buff *)) ++ int (*okfn)(struct sk_buff *), ++ int hook_thresh) + { + for (*i = (*i)->next; *i != head; *i = (*i)->next) { + struct nf_hook_ops *elem = (struct nf_hook_ops *)*i; ++ ++ if (hook_thresh > elem->priority) ++ continue; ++ + switch (elem->hook(hook, skb, indev, outdev, okfn)) { + case NF_QUEUE: + return NF_QUEUE; +@@ -415,6 +420,10 @@ + { + int status; + struct nf_info *info; ++#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) ++ struct net_device *physindev = NULL; ++ struct net_device *physoutdev = NULL; ++#endif + + if (!queue_handler[pf].outfn) { + kfree_skb(skb); +@@ -437,11 +446,24 @@ + if (indev) dev_hold(indev); + if (outdev) dev_hold(outdev); + ++#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) ++ if (skb->nf_bridge) { ++ physindev = skb->nf_bridge->physindev; ++ if (physindev) dev_hold(physindev); ++ physoutdev = skb->nf_bridge->physoutdev; ++ if (physoutdev) dev_hold(physoutdev); ++ } ++#endif ++ + status = queue_handler[pf].outfn(skb, info, queue_handler[pf].data); + if (status < 0) { + /* James M doesn't say fuck enough. */ + if (indev) dev_put(indev); + if (outdev) dev_put(outdev); ++#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) ++ if (physindev) dev_put(physindev); ++ if (physoutdev) dev_put(physoutdev); ++#endif + kfree(info); + kfree_skb(skb); + return; +@@ -451,7 +473,8 @@ + int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb, + struct net_device *indev, + struct net_device *outdev, +- int (*okfn)(struct sk_buff *)) ++ int (*okfn)(struct sk_buff *), ++ int hook_thresh) + { + struct list_head *elem; + unsigned int verdict; +@@ -483,7 +506,7 @@ + + elem = &nf_hooks[pf][hook]; + verdict = nf_iterate(&nf_hooks[pf][hook], &skb, hook, indev, +- outdev, &elem, okfn); ++ outdev, &elem, okfn, hook_thresh); + if (verdict == NF_QUEUE) { + NFDEBUG("nf_hook: Verdict = QUEUE.\n"); + nf_queue(skb, elem, pf, hook, indev, outdev, okfn); +@@ -512,6 +535,14 @@ + + /* We don't have BR_NETPROTO_LOCK here */ + br_read_lock_bh(BR_NETPROTO_LOCK); ++#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) ++ if (skb->nf_bridge) { ++ if (skb->nf_bridge->physindev) ++ dev_put(skb->nf_bridge->physindev); ++ if (skb->nf_bridge->physoutdev) ++ dev_put(skb->nf_bridge->physoutdev); ++ } ++#endif + for (i = nf_hooks[info->pf][info->hook].next; i != elem; i = i->next) { + if (i == &nf_hooks[info->pf][info->hook]) { + /* The module which sent it to userspace is gone. */ +@@ -532,7 +563,7 @@ + verdict = nf_iterate(&nf_hooks[info->pf][info->hook], + &skb, info->hook, + info->indev, info->outdev, &elem, +- info->okfn); ++ info->okfn, INT_MIN); + } + + switch (verdict) { +diff -Nurb src/linux/linux.stock/net/core/skbuff.c src/linux/linux/net/core/skbuff.c +--- src/linux/linux.stock/net/core/skbuff.c 2003-10-14 04:09:32.000000000 -0400 ++++ src/linux/linux/net/core/skbuff.c 2004-07-10 23:46:39.000000000 -0400 +@@ -244,6 +244,9 @@ + #ifdef CONFIG_NETFILTER_DEBUG + skb->nf_debug = 0; + #endif ++#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) ++ skb->nf_bridge = NULL; ++#endif + #endif + #ifdef CONFIG_NET_SCHED + skb->tc_index = 0; +@@ -324,6 +327,9 @@ + } + #ifdef CONFIG_NETFILTER + nf_conntrack_put(skb->nfct); ++#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) ++ nf_bridge_put(skb->nf_bridge); ++#endif + #endif + skb_headerinit(skb, NULL, 0); /* clean state */ + kfree_skbmem(skb); +@@ -390,6 +396,9 @@ + #ifdef CONFIG_NETFILTER_DEBUG + C(nf_debug); + #endif ++#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) ++ C(nf_bridge); ++#endif + #endif /*CONFIG_NETFILTER*/ + #if defined(CONFIG_HIPPI) + C(private); +@@ -402,6 +411,9 @@ + skb->cloned = 1; + #ifdef CONFIG_NETFILTER + nf_conntrack_get(skb->nfct); ++#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) ++ nf_bridge_get(skb->nf_bridge); ++#endif + #endif + return n; + } +@@ -436,6 +448,10 @@ + #ifdef CONFIG_NETFILTER_DEBUG + new->nf_debug=old->nf_debug; + #endif ++#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) ++ new->nf_bridge=old->nf_bridge; ++ nf_bridge_get(new->nf_bridge); ++#endif + #endif + #ifdef CONFIG_NET_SCHED + new->tc_index = old->tc_index; +@@ -722,8 +738,8 @@ + /* Set the tail pointer and length */ + skb_put(n,skb->len); + +- /* Copy the data only. */ +- if (skb_copy_bits(skb, 0, n->data, skb->len)) ++ /* Copy the linear data and header. */ ++ if (skb_copy_bits(skb, -newheadroom, n->head, newheadroom + skb->len)) + BUG(); + + copy_skb_header(n, skb); +diff -Nurb src/linux/linux.stock/net/ipv4/ip_output.c src/linux/linux/net/ipv4/ip_output.c +--- src/linux/linux.stock/net/ipv4/ip_output.c 2003-10-14 04:09:33.000000000 -0400 ++++ src/linux/linux/net/ipv4/ip_output.c 2004-07-10 23:46:39.000000000 -0400 +@@ -879,6 +879,10 @@ + /* Connection association is same as pre-frag packet */ + skb2->nfct = skb->nfct; + nf_conntrack_get(skb2->nfct); ++#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) ++ skb2->nf_bridge = skb->nf_bridge; ++ nf_bridge_get(skb2->nf_bridge); ++#endif + #ifdef CONFIG_NETFILTER_DEBUG + skb2->nf_debug = skb->nf_debug; + #endif +diff -Nurb src/linux/linux.stock/net/ipv4/netfilter/Config.in src/linux/linux/net/ipv4/netfilter/Config.in +--- src/linux/linux.stock/net/ipv4/netfilter/Config.in 2004-07-10 23:30:19.000000000 -0400 ++++ src/linux/linux/net/ipv4/netfilter/Config.in 2004-07-10 23:46:39.000000000 -0400 +@@ -83,6 +83,9 @@ + dep_tristate ' String match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_STRING $CONFIG_IP_NF_IPTABLES + dep_tristate ' Owner match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_OWNER $CONFIG_IP_NF_IPTABLES + fi ++ if [ "$CONFIG_BRIDGE" != "n" ]; then ++ dep_tristate ' Physdev match support' CONFIG_IP_NF_MATCH_PHYSDEV $CONFIG_IP_NF_IPTABLES ++ fi + # The targets + dep_tristate ' Packet filtering' CONFIG_IP_NF_FILTER $CONFIG_IP_NF_IPTABLES + if [ "$CONFIG_IP_NF_FILTER" != "n" ]; then +diff -Nurb src/linux/linux.stock/net/ipv4/netfilter/Makefile src/linux/linux/net/ipv4/netfilter/Makefile +--- src/linux/linux.stock/net/ipv4/netfilter/Makefile 2004-07-10 23:30:19.000000000 -0400 ++++ src/linux/linux/net/ipv4/netfilter/Makefile 2004-07-10 23:46:39.000000000 -0400 +@@ -149,6 +149,8 @@ + obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o + obj-$(CONFIG_IP_NF_MATCH_REALM) += ipt_realm.o + ++obj-$(CONFIG_IP_NF_MATCH_PHYSDEV) += ipt_physdev.o ++ + # targets + obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o + obj-$(CONFIG_IP_NF_TARGET_MIRROR) += ipt_MIRROR.o +diff -Nurb src/linux/linux.stock/net/ipv4/netfilter/ip_tables.c src/linux/linux/net/ipv4/netfilter/ip_tables.c +--- src/linux/linux.stock/net/ipv4/netfilter/ip_tables.c 2004-07-10 23:29:53.000000000 -0400 ++++ src/linux/linux/net/ipv4/netfilter/ip_tables.c 2004-07-10 23:46:39.000000000 -0400 +@@ -121,12 +121,19 @@ + static inline int + ip_packet_match(const struct iphdr *ip, + const char *indev, ++#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) ++ const char *physindev, ++#endif + const char *outdev, ++#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) ++ const char *physoutdev, ++#endif + const struct ipt_ip *ipinfo, + int isfrag) + { + size_t i; + unsigned long ret; ++ unsigned long ret2 = 1; + + #define FWINV(bool,invflg) ((bool) ^ !!(ipinfo->invflags & invflg)) + +@@ -156,7 +163,15 @@ + & ((const unsigned long *)ipinfo->iniface_mask)[i]; + } + +- if (FWINV(ret != 0, IPT_INV_VIA_IN)) { ++#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) ++ for (i = 0, ret2 = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) { ++ ret2 |= (((const unsigned long *)physindev)[i] ++ ^ ((const unsigned long *)ipinfo->iniface)[i]) ++ & ((const unsigned long *)ipinfo->iniface_mask)[i]; ++ } ++#endif ++ ++ if (FWINV(ret != 0 && ret2 != 0, IPT_INV_VIA_IN)) { + dprintf("VIA in mismatch (%s vs %s).%s\n", + indev, ipinfo->iniface, + ipinfo->invflags&IPT_INV_VIA_IN ?" (INV)":""); +@@ -169,7 +184,15 @@ + & ((const unsigned long *)ipinfo->outiface_mask)[i]; + } + +- if (FWINV(ret != 0, IPT_INV_VIA_OUT)) { ++#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) ++ for (i = 0, ret2 = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) { ++ ret2 |= (((const unsigned long *)physoutdev)[i] ++ ^ ((const unsigned long *)ipinfo->outiface)[i]) ++ & ((const unsigned long *)ipinfo->outiface_mask)[i]; ++ } ++#endif ++ ++ if (FWINV(ret != 0 && ret2 != 0, IPT_INV_VIA_OUT)) { + dprintf("VIA out mismatch (%s vs %s).%s\n", + outdev, ipinfo->outiface, + ipinfo->invflags&IPT_INV_VIA_OUT ?" (INV)":""); +@@ -272,6 +295,9 @@ + /* Initializing verdict to NF_DROP keeps gcc happy. */ + unsigned int verdict = NF_DROP; + const char *indev, *outdev; ++#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) ++ const char *physindev, *physoutdev; ++#endif + void *table_base; + struct ipt_entry *e, *back; + +@@ -281,6 +307,13 @@ + datalen = (*pskb)->len - ip->ihl * 4; + indev = in ? in->name : nulldevname; + outdev = out ? out->name : nulldevname; ++#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) ++ physindev = ((*pskb)->nf_bridge && (*pskb)->nf_bridge->physindev) ? ++ (*pskb)->nf_bridge->physindev->name : nulldevname; ++ physoutdev = ((*pskb)->nf_bridge && (*pskb)->nf_bridge->physoutdev) ? ++ (*pskb)->nf_bridge->physoutdev->name : nulldevname; ++#endif ++ + /* We handle fragments by dealing with the first fragment as + * if it was a normal packet. All other fragments are treated + * normally, except that they will NEVER match rules that ask +@@ -316,7 +349,15 @@ + IP_NF_ASSERT(e); + IP_NF_ASSERT(back); + (*pskb)->nfcache |= e->nfcache; +- if (ip_packet_match(ip, indev, outdev, &e->ip, offset)) { ++ if (ip_packet_match(ip, indev, ++#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) ++ physindev, ++#endif ++ outdev, ++#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) ++ physoutdev, ++#endif ++ &e->ip, offset)) { + struct ipt_entry_target *t; + + if (IPT_MATCH_ITERATE(e, do_match, +diff -Nurb src/linux/linux.stock/net/ipv4/netfilter/ipt_LOG.c src/linux/linux/net/ipv4/netfilter/ipt_LOG.c +--- src/linux/linux.stock/net/ipv4/netfilter/ipt_LOG.c 2004-07-10 23:29:56.000000000 -0400 ++++ src/linux/linux/net/ipv4/netfilter/ipt_LOG.c 2004-07-10 23:46:39.000000000 -0400 +@@ -319,6 +319,18 @@ + prefix == NULL ? loginfo->prefix : prefix, + in ? in->name : "", + out ? out->name : ""); ++#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) ++ if ((*pskb)->nf_bridge) { ++ struct net_device *physindev = (*pskb)->nf_bridge->physindev; ++ struct net_device *physoutdev = (*pskb)->nf_bridge->physoutdev; ++ ++ if (physindev && in != physindev) ++ printk("PHYSIN=%s ", physindev->name); ++ if (physoutdev && out != physoutdev) ++ printk("PHYSOUT=%s ", physoutdev->name); ++ } ++#endif ++ + if (in && !out) { + /* MAC logging for input chain only. */ + printk("MAC="); +diff -Nurb src/linux/linux.stock/net/ipv4/netfilter/ipt_physdev.c src/linux/linux/net/ipv4/netfilter/ipt_physdev.c +--- src/linux/linux.stock/net/ipv4/netfilter/ipt_physdev.c 1969-12-31 19:00:00.000000000 -0500 ++++ src/linux/linux/net/ipv4/netfilter/ipt_physdev.c 2004-07-10 23:46:39.000000000 -0400 +@@ -0,0 +1,127 @@ ++/* Kernel module to match the bridge port in and ++ * out device for IP packets coming into contact with a bridge. */ ++#include <linux/module.h> ++#include <linux/skbuff.h> ++#include <linux/netfilter_ipv4/ipt_physdev.h> ++#include <linux/netfilter_ipv4/ip_tables.h> ++#include <linux/netfilter_bridge.h> ++#include <linux/netdevice.h> ++#define MATCH 1 ++#define NOMATCH 0 ++ ++static int ++match(const struct sk_buff *skb, ++ const struct net_device *in, ++ const struct net_device *out, ++ const void *matchinfo, ++ int offset, ++ const void *hdr, ++ u_int16_t datalen, ++ int *hotdrop) ++{ ++ int i; ++ static const char nulldevname[IFNAMSIZ] = { 0 }; ++ const struct ipt_physdev_info *info = matchinfo; ++ unsigned long ret; ++ const char *indev, *outdev; ++ struct nf_bridge_info *nf_bridge; ++ ++ /* Not a bridged IP packet or no info available yet: ++ * LOCAL_OUT/mangle and LOCAL_OUT/nat don't know if ++ * the destination device will be a bridge. */ ++ if (!(nf_bridge = skb->nf_bridge)) { ++ /* Return MATCH if the invert flags of the used options are on */ ++ if ((info->bitmask & IPT_PHYSDEV_OP_BRIDGED) && ++ !(info->invert & IPT_PHYSDEV_OP_BRIDGED)) ++ return NOMATCH; ++ if ((info->bitmask & IPT_PHYSDEV_OP_ISIN) && ++ !(info->invert & IPT_PHYSDEV_OP_ISIN)) ++ return NOMATCH; ++ if ((info->bitmask & IPT_PHYSDEV_OP_ISOUT) && ++ !(info->invert & IPT_PHYSDEV_OP_ISOUT)) ++ return NOMATCH; ++ if ((info->bitmask & IPT_PHYSDEV_OP_IN) && ++ !(info->invert & IPT_PHYSDEV_OP_IN)) ++ return NOMATCH; ++ if ((info->bitmask & IPT_PHYSDEV_OP_OUT) && ++ !(info->invert & IPT_PHYSDEV_OP_OUT)) ++ return NOMATCH; ++ return MATCH; ++ } ++ ++ /* This only makes sense in the FORWARD and POSTROUTING chains */ ++ if ((info->bitmask & IPT_PHYSDEV_OP_BRIDGED) && ++ (!!(nf_bridge->mask & BRNF_BRIDGED) ^ ++ !(info->invert & IPT_PHYSDEV_OP_BRIDGED))) ++ return NOMATCH; ++ ++ if ((info->bitmask & IPT_PHYSDEV_OP_ISIN && ++ (!nf_bridge->physindev ^ !!(info->invert & IPT_PHYSDEV_OP_ISIN))) || ++ (info->bitmask & IPT_PHYSDEV_OP_ISOUT && ++ (!nf_bridge->physoutdev ^ !!(info->invert & IPT_PHYSDEV_OP_ISOUT)))) ++ return NOMATCH; ++ ++ if (!(info->bitmask & IPT_PHYSDEV_OP_IN)) ++ goto match_outdev; ++ indev = nf_bridge->physindev ? nf_bridge->physindev->name : nulldevname; ++ for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) { ++ ret |= (((const unsigned long *)indev)[i] ++ ^ ((const unsigned long *)info->physindev)[i]) ++ & ((const unsigned long *)info->in_mask)[i]; ++ } ++ ++ if ((ret == 0) ^ !(info->invert & IPT_PHYSDEV_OP_IN)) ++ return NOMATCH; ++ ++match_outdev: ++ if (!(info->bitmask & IPT_PHYSDEV_OP_OUT)) ++ return MATCH; ++ outdev = nf_bridge->physoutdev ? ++ nf_bridge->physoutdev->name : nulldevname; ++ for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) { ++ ret |= (((const unsigned long *)outdev)[i] ++ ^ ((const unsigned long *)info->physoutdev)[i]) ++ & ((const unsigned long *)info->out_mask)[i]; ++ } ++ ++ return (ret != 0) ^ !(info->invert & IPT_PHYSDEV_OP_OUT); ++} ++ ++static int ++checkentry(const char *tablename, ++ const struct ipt_ip *ip, ++ void *matchinfo, ++ unsigned int matchsize, ++ unsigned int hook_mask) ++{ ++ const struct ipt_physdev_info *info = matchinfo; ++ ++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_physdev_info))) ++ return 0; ++ if (!(info->bitmask & IPT_PHYSDEV_OP_MASK) || ++ info->bitmask & ~IPT_PHYSDEV_OP_MASK) ++ return 0; ++ return 1; ++} ++ ++static struct ipt_match physdev_match = { ++ .name = "physdev", ++ .match = &match, ++ .checkentry = &checkentry, ++ .me = THIS_MODULE, ++}; ++ ++static int __init init(void) ++{ ++ return ipt_register_match(&physdev_match); ++} ++ ++static void __exit fini(void) ++{ ++ ipt_unregister_match(&physdev_match); ++} ++ ++module_init(init); ++module_exit(fini); ++MODULE_LICENSE("GPL"); ++EXPORT_NO_SYMBOLS; diff --git a/obsolete-buildroot/sources/openwrt/patches/wrt54g-router.patch b/obsolete-buildroot/sources/openwrt/patches/wrt54g-router.patch new file mode 100644 index 0000000000..4098f792e2 --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/patches/wrt54g-router.patch @@ -0,0 +1,240 @@ +diff -bBurN WRT54G/release/src/router/rc/Makefile-openwrt WRT54G.new/release/src/router/rc/Makefile-openwrt +--- WRT54G/release/src/router/rc/Makefile-openwrt 1969-12-31 18:00:00.000000000 -0600 ++++ WRT54G.new/release/src/router/rc/Makefile-openwrt 2004-03-03 16:23:40.000000000 -0600 +@@ -0,0 +1,44 @@ ++# Copyright 2001-2003, Broadcom Corporation ++# All Rights Reserved. ++# ++# ++# THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY ++# KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM ++# SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS ++# FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE ++# ++ ++# ++# Router Wireless Interface Configuration Utility Makefile ++# ++# Copyright 2003, Broadcom Corporation ++# All Rights Reserved. ++# ++# ++# $Id: Makefile,v 1.2 2004/01/13 00:55:58 mbm Exp $ ++# ++ ++CFLAGS += -I. -I$(TOP)/shared -I$(SRCBASE)/include -Wall ++#CFLAGS += -g -DDEBUG ++CFLAGS += -s -Os ++LDFLAGS += -L$(TOP)/shared -lshared -L$(TOP)/nvram -lnvram ++ ++OBJS := mtd.o crc.o #http.o ++ ++vpath %.c $(TOP)/shared $(SRCBASE)/rts/src ++ ++all: mtd ++ ++clean: ++ rm -f *.o mtd ++ ++install: all ++ install -d $(INSTALLDIR)/sbin ++ install mtd $(INSTALLDIR)/sbin ++ $(STRIP) $(INSTALLDIR)/sbin/mtd ++ ++mtd.o: mtd.c ++ $(CC) -c $^ $(CFLAGS) $(CPPFLAGS) -DOPENWRT_MTD #-DOPENWRT_MTD_HTTP_GET ++ ++mtd: $(OBJS) ++ $(CC) -o $@ $^ $(LDFLAGS) +diff -bBurN WRT54G/release/src/router/rc/mtd.c WRT54G.new/release/src/router/rc/mtd.c +--- WRT54G/release/src/router/rc/mtd.c 2004-01-19 20:34:50.000000000 -0600 ++++ WRT54G.new/release/src/router/rc/mtd.c 2004-03-03 16:24:42.000000000 -0600 +@@ -37,6 +37,86 @@ + #include <cy_conf.h> + #include <utils.h> + ++ ++#ifdef OPENWRT_MTD ++ ++extern int ++mtd_open(const char *mtd, int flags); ++extern int ++mtd_erase(const char *mtd); ++extern int ++mtd_write(const char *path, const char *mtd); ++ ++/* Slightly modified version of mtd_erase. */ ++int ++mtd_unlock(const char *mtd) ++{ ++ int mtd_fd; ++ mtd_info_t mtd_info; ++ erase_info_t erase_info; ++ ++ /* Open MTD device */ ++ if ((mtd_fd = mtd_open(mtd, O_RDWR)) < 0) { ++ perror(mtd); ++ return errno; ++ } ++ ++ /* Get sector size */ ++ if (ioctl(mtd_fd, MEMGETINFO, &mtd_info) != 0) { ++ perror(mtd); ++ close(mtd_fd); ++ return errno; ++ } ++ ++ erase_info.length = mtd_info.erasesize; ++ ++ for (erase_info.start = 0; ++ erase_info.start < mtd_info.size; ++ erase_info.start += mtd_info.erasesize) { ++ (void) ioctl(mtd_fd, MEMUNLOCK, &erase_info); ++/* if (ioctl(mtd_fd, MEMERASE, &erase_info) != 0) { */ ++/* perror(mtd); */ ++/* close(mtd_fd); */ ++/* return errno; */ ++/* } */ ++ } ++ ++ close(mtd_fd); ++ return 0; ++} ++ ++int main(int argc, char **argv) { ++ if(argc == 3 && strcasecmp(argv[1],"unlock")==0) { ++ printf("Unlocking %s\n",argv[2]); ++ return mtd_unlock(argv[2]); ++ } ++ if(argc == 3 && strcasecmp(argv[1],"erase")==0) { ++ printf("Erasing %s\n",argv[2]); ++ return mtd_erase(argv[2]); ++ } ++ if(argc == 4 && strcasecmp(argv[1],"write")==0) { ++ printf("writing %s to %s\n",argv[2],argv[3]); ++ return mtd_write(argv[2],argv[3]); ++ } ++ ++ printf("no valid command given\n"); ++ return -1; ++} ++ ++#ifndef OPENWRT_MTD_HTTP_GET ++/* Dummy routines when no http support. */ ++int ++http_get(const char *server, char *buf, size_t count, off_t offset) ++{ ++ printf("error opening %s\n",server); ++ exit(-1); ++} ++#endif ++ ++#define check_action() (fp ? ACT_IDLE : ACT_WEBS_UPGRADE) ++ ++#endif ++ + /* + * Open an MTD device + * @param mtd path to or partition name of MTD device +diff -bBurN WRT54G/release/src/router/shared/Makefile-openwrt WRT54G.new/release/src/router/shared/Makefile-openwrt +--- WRT54G/release/src/router/shared/Makefile-openwrt 1969-12-31 18:00:00.000000000 -0600 ++++ WRT54G.new/release/src/router/shared/Makefile-openwrt 2004-03-03 12:39:17.000000000 -0600 +@@ -0,0 +1,41 @@ ++# ++# Linux router shared code Makefile ++# ++# Copyright 2001-2003, Broadcom Corporation ++# All Rights Reserved. ++# ++# THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY ++# KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM ++# SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS ++# FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. ++# ++# $Id: Makefile,v 1.3 2004/01/13 00:51:09 mbm Exp $ ++# ++ifneq ($(wildcard $(SRCBASE)/cy_conf.mak),) ++ include $(SRCBASE)/cy_conf.mak ++endif ++ ++CFLAGS += -I. -I$(SRCBASE)/include -Wall -I$(SRCBASE)/ ++#CFLAGS += -g -DDEBUG ++CFLAGS += -s -Os ++LDFLAGS += -L. ++ ++all: libshared.so ++ ++install: all ++ install -d $(INSTALLDIR)/usr/lib ++ install -m 755 libshared.so $(INSTALLDIR)/usr/lib ++ $(STRIP) $(INSTALLDIR)/usr/lib/libshared.so ++ ++clean: ++ rm -f *.o *.so ++ ++libshared.so: shutils.o wl.o wl_linux.o defaults.o ++ $(LD) -shared -o $@ $^ ++ ++build_date.o: build_date.c ++ ++build_date: ++ echo "const char *builddate = \"`date`\";" > build_date.c ++ ++*.o: $(CY_DEPS) +diff -bBurN WRT54GS/release/src/router/nvram/nvram_linux.c-dist WRT54GS.new/release/src/router/nvram/nvram_linux.c +--- WRT54GS/release/src/router/nvram/nvram_linux.c-dist 2004-03-30 10:04:10.000000000 -0600 ++++ WRT54GS/release/src/router/nvram/nvram_linux.c 2004-03-30 10:10:09.000000000 -0600 +@@ -27,8 +27,10 @@ + #include <typedefs.h> + #include <bcmnvram.h> + #include <nvram_convert.h> ++#ifndef OPENWRT_NVRAM + #include <shutils.h> + #include <utils.h> ++#endif + + #define PATH_DEV_NVRAM "/dev/nvram" + +@@ -182,6 +184,20 @@ + { + int ret; + ++#ifdef OPENWRT_NVRAM ++ fprintf(stderr, "nvram_commit(): start\n"); ++ ++ if (nvram_fd < 0) ++ if ((ret = nvram_init(NULL))) ++ return ret; ++ ++ ret = ioctl(nvram_fd, NVRAM_MAGIC, NULL); ++ ++ if (ret < 0) ++ perror(PATH_DEV_NVRAM); ++ ++ fprintf(stderr, "nvram_commit(): end\n"); ++#else + cprintf("nvram_commit(): start\n"); + + if((check_action() == ACT_IDLE) || +@@ -200,6 +216,7 @@ + } + else + cprintf("nvram_commit(): nothing to do...\n"); ++#endif + + return ret; + } +@@ -272,6 +289,7 @@ + return j; + } + ++#ifndef OPENWRT_NVRAM + int + check_action(void) + { +@@ -318,3 +336,5 @@ + + return 0; + } ++ ++#endif diff --git a/obsolete-buildroot/sources/openwrt/patches/wrt54g-shared.patch b/obsolete-buildroot/sources/openwrt/patches/wrt54g-shared.patch new file mode 100644 index 0000000000..f357885bcc --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/patches/wrt54g-shared.patch @@ -0,0 +1,11 @@ +--- WRT54G/release/src/shared/sbpci.c-dist 2004-03-15 13:13:37.000000000 -0600 ++++ WRT54G/release/src/shared/sbpci.c 2004-03-15 13:15:38.000000000 -0600 +@@ -269,7 +269,7 @@ + sb_core_reset(sbh, 0); + + /* In some board, */ +- if(nvram_match("boardtype", "bcm94710dev")) ++ if(nvram_match("boardtype", "bcm94710dev") || nvram_match("boardtype", "bcm94710ap")) + CT4712_WR = 0; + else + CT4712_WR = 1; diff --git a/obsolete-buildroot/sources/openwrt/tools/addpattern.c b/obsolete-buildroot/sources/openwrt/tools/addpattern.c new file mode 100644 index 0000000000..dbf8ed690e --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/tools/addpattern.c @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2004 Manuel Novoa III <mjn3@codepoet.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* July 29, 2004 + * + * This is a hacked replacement for the 'addpattern' utility used to + * create wrt54g .bin firmware files. It isn't pretty, but it does + * the job for me. + * + * Extensions: + * -v allows setting the version string on the command line. + * -{0|1} sets the (currently ignored) hw_ver flag in the header + * to 0 or 1 respectively. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <sys/stat.h> + +/**********************************************************************/ + +#define CODE_ID "U2ND" /* from code_pattern.h */ +#define CODE_PATTERN "W54S" /* from code_pattern.h */ + +#define CYBERTAN_VERSION "v2.07.1" /* from cyutils.h */ +/* #define CYBERTAN_VERSION "v2.04.3" */ + +struct code_header { /* from cyutils.h */ + char magic[4]; + char res1[4]; /* for extra magic */ + char fwdate[3]; + char fwvern[3]; + char id[4]; /* U2ND */ +#if 0 + unsigned char res2[14]; +#else + char hw_ver; /* 0: for 4702, 1: for 4712 -- new in 2.04.3 */ + unsigned char res2[13]; +#endif +} ; + +/**********************************************************************/ + +void usage(void) __attribute__ (( __noreturn__ )); + +void usage(void) +{ + fprintf(stderr, "Usage: addpattern [-i trxfile] [-o binfile] [-p pattern] [-g] [-v v#.#.#] [-{0|1}]\n"); + exit(EXIT_FAILURE); +} + +int main(int argc, char **argv) +{ + char buf[1024]; /* keep this at 1k or adjust garbage calc below */ + struct code_header *hdr; + FILE *in = stdin; + FILE *out = stdout; + char *ifn = NULL; + char *ofn = NULL; + char *pattern = CODE_PATTERN; + char *version = CYBERTAN_VERSION; + int gflag = 0; + int c; + int v0, v1, v2; + size_t off, n; + time_t t; + struct tm *ptm; + + fprintf(stderr, "mjn3's addpattern replacement - v0.80\n"); + + hdr = (struct code_header *) buf; + + while ((c = getopt(argc, argv, "i:o:p:gv:01")) != -1) { + switch (c) { + case 'i': + ifn = optarg; + break; + case 'o': + ofn = optarg; + break; + case 'p': + pattern = optarg; + break; + case 'g': + gflag = 1; + break; + case 'v': /* extension to allow setting version */ + version = optarg; + break; + case '0': + hdr->hw_ver = 0; + break; + case '1': + hdr->hw_ver = 1; + break; + default: + usage(); + } + } + + if (optind != argc) { + fprintf(stderr, "illegal arg \"%s\"\n", argv[optind]); + usage(); + } + + if (strlen(pattern) != 4) { + fprintf(stderr, "illegal pattern \"%s\": length != 4\n", pattern); + usage(); + } + + if (ifn && !(in = fopen(ifn, "r"))) { + fprintf(stderr, "can not open \"%s\" for reading\n", ifn); + usage(); + } + + if (ofn && !(out = fopen(ofn, "w"))) { + fprintf(stderr, "can not open \"%s\" for writing\n", ofn); + usage(); + } + + if (time(&t) == (time_t)(-1)) { + fprintf(stderr, "time call failed\n"); + return EXIT_FAILURE; + } + + ptm = localtime(&t); + + if (3 != sscanf(version, "v%d.%d.%d", &v0, &v1, &v2)) { + fprintf(stderr, "bad version string \"%s\"\n", version); + return EXIT_FAILURE; + } + + memset(hdr, 0, sizeof(struct code_header)); + memcpy(&hdr->magic, pattern, 4); + hdr->fwdate[0] = ptm->tm_year % 100; + hdr->fwdate[1] = ptm->tm_mon + 1; + hdr->fwdate[2] = ptm->tm_mday; + hdr->fwvern[0] = v0; + hdr->fwvern[1] = v1; + hdr->fwvern[2] = v2; + memcpy(&hdr->id, CODE_ID, strlen(CODE_ID)); + + off = sizeof(struct code_header); + + fprintf(stderr, "writing firmware v%d.%d.%d on %d/%d/%d (y/m/d)\n", + v0, v1, v2, + hdr->fwdate[0], hdr->fwdate[1], hdr->fwdate[2]); + + + while ((n = fread(buf + off, 1, sizeof(buf)-off, in) + off) > 0) { + off = 0; + if (n < sizeof(buf)) { + if (ferror(in)) { + FREAD_ERROR: + fprintf(stderr, "fread error\n"); + return EXIT_FAILURE; + } + if (gflag) { + gflag = sizeof(buf) - n; + memset(buf + n, 0xff, gflag); + fprintf(stderr, "adding %d bytes of garbage\n", gflag); + n = sizeof(buf); + } + } + if (!fwrite(buf, n, 1, out)) { + FWRITE_ERROR: + fprintf(stderr, "fwrite error\n"); + return EXIT_FAILURE; + } + } + + if (ferror(in)) { + goto FREAD_ERROR; + } + + if (fflush(out)) { + goto FWRITE_ERROR; + } + + fclose(in); + fclose(out); + + return EXIT_SUCCESS; +} diff --git a/obsolete-buildroot/sources/openwrt/tools/trx.c b/obsolete-buildroot/sources/openwrt/tools/trx.c new file mode 100644 index 0000000000..5ec53fdcb3 --- /dev/null +++ b/obsolete-buildroot/sources/openwrt/tools/trx.c @@ -0,0 +1,316 @@ +/* + * Copyright (C) 2004 Manuel Novoa III <mjn3@codepoet.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* July 29, 2004 + * + * This is a hacked replacement for the 'trx' utility used to create + * wrt54g .trx firmware files. It isn't pretty, but it does the job + * for me. + * + * As an extension, you can specify a larger maximum length for the + * .trx file using '-m'. It will be rounded up to be a multiple of 4K. + * NOTE: This space will be malloc()'d. + * + * TODO: Support '-b' option to specify offsets for each file. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <stdint.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> + +uint32_t crc32buf(char *buf, size_t len); + +/**********************************************************************/ +/* from trxhdr.h */ + +#define TRX_MAGIC 0x30524448 /* "HDR0" */ +#define TRX_VERSION 1 +#define TRX_MAX_LEN 0x3A0000 +#define TRX_NO_HEADER 1 /* Do not write TRX header */ + +struct trx_header { + uint32_t magic; /* "HDR0" */ + uint32_t len; /* Length of file including header */ + uint32_t crc32; /* 32-bit CRC from flag_version to end of file */ + uint32_t flag_version; /* 0:15 flags, 16:31 version */ + uint32_t offsets[3]; /* Offsets of partitions from start of header */ +}; + +/**********************************************************************/ + +void usage(void) __attribute__ (( __noreturn__ )); + +void usage(void) +{ + fprintf(stderr, "Usage: trx [-o outfile] [-m maxlen] file [file [file]]\n"); + exit(EXIT_FAILURE); +} + +int main(int argc, char **argv) +{ + FILE *out = stdout; + FILE *in; + char *ofn = NULL; + char *buf; + char *e; + int c, i; + size_t n; + unsigned long maxlen = TRX_MAX_LEN; + struct trx_header *p; + + fprintf(stderr, "mjn3's trx replacement - v0.80\n"); + + while ((c = getopt(argc, argv, "o:m:")) != -1) { + switch (c) { + case 'o': + ofn = optarg; + break; + case 'm': + errno = 0; + maxlen = strtoul(optarg, &e, 0); + if (errno || (e == optarg) || *e) { + fprintf(stderr, "illegal numeric string\n"); + usage(); + } +#undef ROUND +#define ROUND 0x1000 + if (maxlen & (ROUND-1)) { + maxlen += (ROUND - (maxlen & (ROUND-1))); + } + if (maxlen < ROUND) { + fprintf(stderr, "maxlen too small (or wrapped)\n"); + usage(); + } + break; + default: + usage(); + } + } + + if (ofn && !(out = fopen(ofn, "w"))) { + fprintf(stderr, "can not open \"%s\" for writing\n", ofn); + usage(); + } + + if (optind == argc) { + fprintf(stderr, "we require at least one arg\n"); + usage(); + } + + if (argc - optind > 3) { + fprintf(stderr, "too many args: %d > 3\n", argc - optind); + usage(); + } + + if (maxlen > TRX_MAX_LEN) { + fprintf(stderr, "WARNING: maxlen exceeds default maximum! Beware of overwriting nvram!\n"); + } + + if (!(buf = malloc(maxlen))) { + fprintf(stderr, "malloc failed\n"); + return EXIT_FAILURE; + } + + p = (struct trx_header *) buf; + + p->magic = TRX_MAGIC; + p->len = sizeof(struct trx_header); + p->flag_version = (TRX_VERSION << 16); + + i = 0; + + while (optind < argc) { + p->offsets[i++] = p->len; + + if (!(in = fopen(argv[optind], "r"))) { + fprintf(stderr, "can not open \"%s\" for reading\n", argv[optind]); + usage(); + } + + n = fread(buf + p->len, 1, maxlen - p->len, in); + if (!feof(in)) { + fprintf(stderr, "fread failure or file \"%s\" too large\n", + argv[optind]); + fclose(in); + return EXIT_FAILURE; + } + + fclose(in); + + ++optind; + + if (optind < argc) { +#undef ROUND +#define ROUND 4 + if (n & (ROUND-1)) { + memset(buf + p->len + n, 0, ROUND - (n & (ROUND-1))); + n += ROUND - (n & (ROUND-1)); + } + } + + p->len += n; + } + +#undef ROUND +#define ROUND 0x1000 + n = p->len & (ROUND-1); + if (n) { + memset(buf + p->len, 0, ROUND - n); + p->len += ROUND - n; + } + + p->crc32 = crc32buf((char *) &p->flag_version, + p->len - offsetof(struct trx_header, flag_version)); + + if (!fwrite(buf, p->len, 1, out) || fflush(out)) { + fprintf(stderr, "fwrite failed\n"); + return EXIT_FAILURE; + } + + fclose(out); + + return EXIT_SUCCESS; +} + +/**********************************************************************/ +/* The following was grabbed and tweaked from the old snippets collection + * of public domain C code. */ + +/**********************************************************************\ +|* Demonstration program to compute the 32-bit CRC used as the frame *| +|* check sequence in ADCCP (ANSI X3.66, also known as FIPS PUB 71 *| +|* and FED-STD-1003, the U.S. versions of CCITT's X.25 link-level *| +|* protocol). The 32-bit FCS was added via the Federal Register, *| +|* 1 June 1982, p.23798. I presume but don't know for certain that *| +|* this polynomial is or will be included in CCITT V.41, which *| +|* defines the 16-bit CRC (often called CRC-CCITT) polynomial. FIPS *| +|* PUB 78 says that the 32-bit FCS reduces otherwise undetected *| +|* errors by a factor of 10^-5 over 16-bit FCS. *| +\**********************************************************************/ + +/* Copyright (C) 1986 Gary S. Brown. You may use this program, or + code or tables extracted from it, as desired without restriction.*/ + +/* First, the polynomial itself and its table of feedback terms. The */ +/* polynomial is */ +/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ +/* Note that we take it "backwards" and put the highest-order term in */ +/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ +/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ +/* the MSB being 1. */ + +/* Note that the usual hardware shift register implementation, which */ +/* is what we're using (we're merely optimizing it by doing eight-bit */ +/* chunks at a time) shifts bits into the lowest-order term. In our */ +/* implementation, that means shifting towards the right. Why do we */ +/* do it this way? Because the calculated CRC must be transmitted in */ +/* order from highest-order term to lowest-order term. UARTs transmit */ +/* characters in order from LSB to MSB. By storing the CRC this way, */ +/* we hand it to the UART in the order low-byte to high-byte; the UART */ +/* sends each low-bit to hight-bit; and the result is transmission bit */ +/* by bit from highest- to lowest-order term without requiring any bit */ +/* shuffling on our part. Reception works similarly. */ + +/* The feedback terms table consists of 256, 32-bit entries. Notes: */ +/* */ +/* 1. The table can be generated at runtime if desired; code to do so */ +/* is shown later. It might not be obvious, but the feedback */ +/* terms simply represent the results of eight shift/xor opera- */ +/* tions for all combinations of data and CRC register values. */ +/* */ +/* 2. The CRC accumulation logic is the same for all CRC polynomials, */ +/* be they sixteen or thirty-two bits wide. You simply choose the */ +/* appropriate table. Alternatively, because the table can be */ +/* generated at runtime, you can start by generating the table for */ +/* the polynomial in question and use exactly the same "updcrc", */ +/* if your application needn't simultaneously handle two CRC */ +/* polynomials. (Note, however, that XMODEM is strange.) */ +/* */ +/* 3. For 16-bit CRCs, the table entries need be only 16 bits wide; */ +/* of course, 32-bit entries work OK if the high 16 bits are zero. */ +/* */ +/* 4. The values must be right-shifted by eight bits by the "updcrc" */ +/* logic; the shift must be unsigned (bring in zeroes). On some */ +/* hardware you could probably optimize the shift in assembler by */ +/* using byte-swap instructions. */ + +static const uint32_t crc_32_tab[] = { /* CRC polynomial 0xedb88320 */ +0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, +0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, +0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, +0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, +0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, +0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, +0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, +0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, +0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, +0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, +0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, +0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, +0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, +0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, +0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, +0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, +0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, +0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, +0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, +0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, +0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, +0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, +0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, +0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, +0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, +0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, +0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, +0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, +0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, +0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, +0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, +0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, +0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, +0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, +0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, +0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, +0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, +0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, +0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, +0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, +0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, +0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, +0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +#define UPDC32(octet,crc) (crc_32_tab[((crc) ^ (octet)) & 0xff] ^ ((crc) >> 8)) + +uint32_t crc32buf(char *buf, size_t len) +{ + uint32_t crc; + + crc = 0xFFFFFFFF; + + for ( ; len; --len, ++buf) + { + crc = UPDC32(*buf, crc); + } + + return crc; +} |