## Automatically generated incremental diff
## From:   linux-2.5.67-bk7
## To:     linux-2.5.67-bk8
## Robot:  $Id: make-incremental-diff,v 1.11 2002/02/20 02:59:33 hpa Exp $

diff -urN linux-2.5.67-bk7/Makefile linux-2.5.67-bk8/Makefile
--- linux-2.5.67-bk7/Makefile	2003-04-17 04:38:24.000000000 -0700
+++ linux-2.5.67-bk8/Makefile	2003-04-17 04:38:33.000000000 -0700
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 5
 SUBLEVEL = 67
-EXTRAVERSION = -bk7
+EXTRAVERSION = -bk8
 
 # *DOCUMENTATION*
 # To see a list of typical targets execute "make help"
diff -urN linux-2.5.67-bk7/arch/i386/kernel/process.c linux-2.5.67-bk8/arch/i386/kernel/process.c
--- linux-2.5.67-bk7/arch/i386/kernel/process.c	2003-04-07 10:30:32.000000000 -0700
+++ linux-2.5.67-bk8/arch/i386/kernel/process.c	2003-04-17 04:38:34.000000000 -0700
@@ -324,7 +324,7 @@
 		int idx;
 
 		err = -EFAULT;
-		if (copy_from_user(&info, (void *)childregs->esi, sizeof(info)))
+		if (copy_from_user(&info, (void __user *)childregs->esi, sizeof(info)))
 			goto out;
 		err = -EINVAL;
 		if (LDT_empty(&info))
@@ -567,11 +567,14 @@
 	int error;
 	char * filename;
 
-	filename = getname((char *) regs.ebx);
+	filename = getname((char __user *) regs.ebx);
 	error = PTR_ERR(filename);
 	if (IS_ERR(filename))
 		goto out;
-	error = do_execve(filename, (char **) regs.ecx, (char **) regs.edx, &regs);
+	error = do_execve(filename,
+			(char __user * __user *) regs.ecx,
+			(char __user * __user *) regs.edx,
+			&regs);
 	if (error == 0) {
 		current->ptrace &= ~PT_DTRACE;
 		/* Make sure we don't return using sysenter.. */
@@ -633,7 +636,7 @@
 /*
  * Set a given TLS descriptor:
  */
-asmlinkage int sys_set_thread_area(struct user_desc *u_info)
+asmlinkage int sys_set_thread_area(struct user_desc __user *u_info)
 {
 	struct thread_struct *t = &current->thread;
 	struct user_desc info;
@@ -700,7 +703,7 @@
 #define GET_PRESENT(desc)	(((desc)->b >> 15) & 1)
 #define GET_USEABLE(desc)	(((desc)->b >> 20) & 1)
 
-asmlinkage int sys_get_thread_area(struct user_desc *u_info)
+asmlinkage int sys_get_thread_area(struct user_desc __user *u_info)
 {
 	struct user_desc info;
 	struct desc_struct *desc;
diff -urN linux-2.5.67-bk7/arch/parisc/kernel/sys_parisc32.c linux-2.5.67-bk8/arch/parisc/kernel/sys_parisc32.c
--- linux-2.5.67-bk7/arch/parisc/kernel/sys_parisc32.c	2003-04-17 04:38:24.000000000 -0700
+++ linux-2.5.67-bk8/arch/parisc/kernel/sys_parisc32.c	2003-04-17 04:38:35.000000000 -0700
@@ -475,81 +475,6 @@
     return do_sys_settimeofday(tv ? &ktv : NULL, tz ? &ktz : NULL);
 }
 
-struct rusage32 {
-        struct compat_timeval ru_utime;
-        struct compat_timeval ru_stime;
-        int    ru_maxrss;
-        int    ru_ixrss;
-        int    ru_idrss;
-        int    ru_isrss;
-        int    ru_minflt;
-        int    ru_majflt;
-        int    ru_nswap;
-        int    ru_inblock;
-        int    ru_oublock;
-        int    ru_msgsnd; 
-        int    ru_msgrcv; 
-        int    ru_nsignals;
-        int    ru_nvcsw;
-        int    ru_nivcsw;
-};
-
-static int
-put_rusage32(struct rusage32 *ru32p, struct rusage *r)
-{
-	struct rusage32 r32;
-#undef CP
-#define CP(t) r32.t = r->t;
-	CP(ru_utime.tv_sec); CP(ru_utime.tv_usec);
-	CP(ru_stime.tv_sec); CP(ru_stime.tv_usec);
-	CP(ru_maxrss);
-	CP(ru_ixrss);
-	CP(ru_idrss);
-	CP(ru_isrss);
-	CP(ru_minflt);
-	CP(ru_majflt);
-	CP(ru_nswap);
-	CP(ru_inblock);
-	CP(ru_oublock);
-	CP(ru_msgsnd);
-	CP(ru_msgrcv);
-	CP(ru_nsignals);
-	CP(ru_nvcsw);
-	CP(ru_nivcsw);
-	return copy_to_user(ru32p, &r32, sizeof r32);
-}
-
-asmlinkage int
-sys32_getrusage(int who, struct rusage32 *ru)
-{
-	struct rusage r;
-	int ret;
-	extern asmlinkage int sys_getrusage(int who, struct rusage *ru);
-		
-	KERNEL_SYSCALL(ret, sys_getrusage, who, &r);
-	if (put_rusage32(ru, &r)) return -EFAULT;
-	return ret;
-}
-
-asmlinkage int
-sys32_wait4(compat_pid_t pid, unsigned int * stat_addr, int options,
-	    struct rusage32 * ru)
-{
-	if (!ru)
-		return sys_wait4(pid, stat_addr, options, NULL);
-	else {
-		struct rusage r;
-		int ret;
-		unsigned int status;
-	
-		KERNEL_SYSCALL(ret, sys_wait4, pid, stat_addr ? &status : NULL, options, &r);
-		if (put_rusage32(ru, &r)) return -EFAULT;
-		if (stat_addr && put_user(status, stat_addr))
-			return -EFAULT;
-		return ret;
-	}
-}
-
 int cp_compat_stat(struct kstat *stat, struct compat_stat *statbuf)
 {
 	int err;
@@ -721,74 +646,6 @@
 	return error;
 }
 
-struct rlimit32 {
-	__u32	rlim_cur;
-	__u32	rlim_max;
-};
-
-#define RLIM32_INFINITY 0xffffffff
-
-asmlinkage long sys32_getrlimit(unsigned int resource, struct rlimit32 *rlim)
-{
-	struct rlimit32 rlim32;
-	struct rlimit *rlimip;
-
-	if (resource >= RLIM_NLIMITS)
-		return -EINVAL;
-	rlimip = current->rlim + resource;
-	if (rlimip->rlim_cur >= RLIM32_INFINITY) {
-		rlim32.rlim_cur = RLIM32_INFINITY;
-	} else {
-		rlim32.rlim_cur = rlimip->rlim_cur;
-	}
-	if (rlimip->rlim_max >= RLIM32_INFINITY) {
-		rlim32.rlim_max = RLIM32_INFINITY;
-	} else {
-		rlim32.rlim_max = rlimip->rlim_max;
-	}
-	return copy_to_user(rlim, &rlim32, sizeof (struct rlimit32));
-}
-
-asmlinkage long sys32_setrlimit(unsigned int resource, struct rlimit32 *rlim)
-{
-	struct rlimit32 rlim32;
-	struct rlimit new_rlim, *old_rlim;
-
-	if (resource >= RLIM_NLIMITS)
-		return -EINVAL;
-	if (copy_from_user(&rlim32, rlim, sizeof(rlim)))
-		return -EFAULT;
-	if (rlim32.rlim_cur == RLIM32_INFINITY) {
-		new_rlim.rlim_cur = RLIM_INFINITY;
-	} else {
-		new_rlim.rlim_cur = rlim32.rlim_cur;
-	}
-	if (rlim32.rlim_max == RLIM32_INFINITY) {
-		new_rlim.rlim_max = RLIM_INFINITY;
-	} else {
-		new_rlim.rlim_max = rlim32.rlim_max;
-	}
-
-	old_rlim = current->rlim + resource;
-	if (((new_rlim.rlim_cur > old_rlim->rlim_max) ||
-	     (new_rlim.rlim_max > old_rlim->rlim_max)) &&
-	    !capable(CAP_SYS_RESOURCE))
-		return -EPERM;
-	if (resource == RLIMIT_NOFILE) {
-		if (new_rlim.rlim_cur > NR_OPEN || new_rlim.rlim_max > NR_OPEN)
-			return -EPERM;
-	}
-	if (resource == RLIMIT_STACK) {
-		if (new_rlim.rlim_max > 1024 * 1024 * 1024) {
-			new_rlim.rlim_max = 1024 * 1024 * 1024;
-		}
-		new_rlim.rlim_max = PAGE_ALIGN(new_rlim.rlim_max);
-	}
-	
-	*old_rlim = new_rlim;
-	return 0;
-}
-
 static int copy_mount_stuff_to_kernel(const void *user, unsigned long *kernel)
 {
 	int i;
diff -urN linux-2.5.67-bk7/arch/parisc/kernel/syscall.S linux-2.5.67-bk8/arch/parisc/kernel/syscall.S
--- linux-2.5.67-bk7/arch/parisc/kernel/syscall.S	2003-04-17 04:38:24.000000000 -0700
+++ linux-2.5.67-bk8/arch/parisc/kernel/syscall.S	2003-04-17 04:38:35.000000000 -0700
@@ -431,9 +431,9 @@
 	ENTRY_COMP(sigpending)
 	ENTRY_SAME(sethostname)
 	/* Following 3 have linux-common-code structs containing longs -( */
-	ENTRY_DIFF(setrlimit)		/* 75 */
-	ENTRY_DIFF(getrlimit)
-	ENTRY_DIFF(getrusage)
+	ENTRY_COMP(setrlimit)		/* 75 */
+	ENTRY_COMP(getrlimit)
+	ENTRY_COMP(getrusage)
 	/* struct timeval and timezone are maybe?? consistent wide and narrow */
 	ENTRY_DIFF(gettimeofday)
 	ENTRY_DIFF(settimeofday)
@@ -476,7 +476,7 @@
 	ENTRY_SAME(fstat64)
 	ENTRY_SAME(vfork_wrapper)
 	/* struct rusage contains longs... */
-	ENTRY_DIFF(wait4)
+	ENTRY_COMP(wait4)
 	ENTRY_SAME(swapoff)		/* 115 */
 	ENTRY_DIFF(sysinfo)
 	ENTRY_SAME(shutdown)
diff -urN linux-2.5.67-bk7/arch/ppc64/kernel/misc.S linux-2.5.67-bk8/arch/ppc64/kernel/misc.S
--- linux-2.5.67-bk7/arch/ppc64/kernel/misc.S	2003-04-17 04:38:24.000000000 -0700
+++ linux-2.5.67-bk8/arch/ppc64/kernel/misc.S	2003-04-17 04:38:35.000000000 -0700
@@ -577,9 +577,9 @@
 	.llong .sys_sigsuspend
 	.llong .compat_sys_sigpending
 	.llong .sys32_sethostname
-	.llong .sys32_setrlimit	        /* 75 */
-	.llong .sys32_old_getrlimit
-	.llong .sys32_getrusage
+	.llong .compat_sys_setrlimit	        /* 75 */
+	.llong .compat_sys_old_getrlimit
+	.llong .compat_sys_getrusage
 	.llong .sys32_gettimeofday
 	.llong .sys32_settimeofday
 	.llong .sys32_getgroups	        /* 80 */
@@ -616,7 +616,7 @@
 	.llong .sys_vhangup
 	.llong .sys_ni_syscall		/* old idle syscall */
 	.llong .sys_ni_syscall		/* old vm86 syscall */
-	.llong .sys32_wait4
+	.llong .compat_sys_wait4
 	.llong .sys_swapoff		/* 115 */
 	.llong .sys32_sysinfo
 	.llong .sys32_ipc
@@ -692,7 +692,7 @@
 	.llong .sys_ni_syscall		/* reserved for streams1 */
 	.llong .sys_ni_syscall		/* reserved for streams2 */
 	.llong .sys_vfork
-	.llong .sys32_getrlimit	        /* 190 */
+	.llong .compat_sys_getrlimit	        /* 190 */
 	.llong .sys32_readahead
 	.llong .sys32_mmap2
 	.llong .sys32_truncate64
diff -urN linux-2.5.67-bk7/arch/ppc64/kernel/sys_ppc32.c linux-2.5.67-bk8/arch/ppc64/kernel/sys_ppc32.c
--- linux-2.5.67-bk7/arch/ppc64/kernel/sys_ppc32.c	2003-04-17 04:38:24.000000000 -0700
+++ linux-2.5.67-bk8/arch/ppc64/kernel/sys_ppc32.c	2003-04-17 04:38:35.000000000 -0700
@@ -1125,152 +1125,6 @@
 		 __put_user(i->tv_usec, &o->tv_usec)));
 }
 
-
-
-
-#define RLIM_INFINITY32	0xffffffff
-#define RESOURCE32(x) ((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x)
-
-struct rlimit32 {
-	u32	rlim_cur;
-	u32	rlim_max;
-};
-
-extern asmlinkage long sys_getrlimit(unsigned int resource, struct rlimit *rlim);
-asmlinkage long sys32_getrlimit(unsigned int resource, struct rlimit32 *rlim)
-{
-	struct rlimit r;
-	int ret;
-	mm_segment_t old_fs = get_fs();
-	
-	set_fs (KERNEL_DS);
-	ret = sys_getrlimit(resource, &r);
-	set_fs(old_fs);
-	if (!ret) {
-		ret = put_user(RESOURCE32(r.rlim_cur), &rlim->rlim_cur);
-		ret |= __put_user(RESOURCE32(r.rlim_max), &rlim->rlim_max);
-	}
-	
-	return ret;
-}
-
-/* Back compatibility for getrlimit. Needed for some apps. */
-asmlinkage long sys32_old_getrlimit(unsigned int resource, struct rlimit32* rlim)
-{
-	struct rlimit   x;    // 64-bit version of the resource limits.
-	struct rlimit32 x32;  // 32-bit version of the resource limits.
-
-	if (resource >= RLIM_NLIMITS)
-		return -EINVAL;
-
-	memcpy(&x, current->rlim+resource, sizeof(struct rlimit));
-
-	if (x.rlim_cur > RLIM_INFINITY32)
-		x32.rlim_cur = RLIM_INFINITY32;
-	else
-		x32.rlim_cur = x.rlim_cur;
-
-	if (x.rlim_max > RLIM_INFINITY32)
-		x32.rlim_max = RLIM_INFINITY32;
-	else
-		x32.rlim_max = x.rlim_max;
-
-	return (copy_to_user(rlim, &x32, sizeof(x32))) ? (-EFAULT) : 0;
-}
-
-extern asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit *rlim);
-asmlinkage long sys32_setrlimit(unsigned int resource, struct rlimit32 *rlim)
-{
-	struct rlimit r;
-	long ret;
-	mm_segment_t old_fs = get_fs ();
-	
-	if (resource >= RLIM_NLIMITS) return -EINVAL;	
-	if (get_user (r.rlim_cur, &rlim->rlim_cur) ||
-	    __get_user (r.rlim_max, &rlim->rlim_max))
-		return -EFAULT;
-	if (r.rlim_cur >= RLIM_INFINITY32)
-		r.rlim_cur = RLIM_INFINITY;
-	if (r.rlim_max >= RLIM_INFINITY32)
-		r.rlim_max = RLIM_INFINITY;
-	set_fs (KERNEL_DS);
-	ret = sys_setrlimit(resource, &r);
-	set_fs (old_fs);
-	
-	return ret;
-}
-
-
-struct rusage32 {
-        struct compat_timeval ru_utime;
-        struct compat_timeval ru_stime;
-        s32    ru_maxrss;
-        s32    ru_ixrss;
-        s32    ru_idrss;
-        s32    ru_isrss;
-        s32    ru_minflt;
-        s32    ru_majflt;
-        s32    ru_nswap;
-        s32    ru_inblock;
-        s32    ru_oublock;
-        s32    ru_msgsnd; 
-        s32    ru_msgrcv; 
-        s32    ru_nsignals;
-        s32    ru_nvcsw;
-        s32    ru_nivcsw;
-};
-
-static int put_rusage (struct rusage32 *ru, struct rusage *r)
-{
-	int err;
-	
-	err = put_user (r->ru_utime.tv_sec, &ru->ru_utime.tv_sec);
-	err |= __put_user (r->ru_utime.tv_usec, &ru->ru_utime.tv_usec);
-	err |= __put_user (r->ru_stime.tv_sec, &ru->ru_stime.tv_sec);
-	err |= __put_user (r->ru_stime.tv_usec, &ru->ru_stime.tv_usec);
-	err |= __put_user (r->ru_maxrss, &ru->ru_maxrss);
-	err |= __put_user (r->ru_ixrss, &ru->ru_ixrss);
-	err |= __put_user (r->ru_idrss, &ru->ru_idrss);
-	err |= __put_user (r->ru_isrss, &ru->ru_isrss);
-	err |= __put_user (r->ru_minflt, &ru->ru_minflt);
-	err |= __put_user (r->ru_majflt, &ru->ru_majflt);
-	err |= __put_user (r->ru_nswap, &ru->ru_nswap);
-	err |= __put_user (r->ru_inblock, &ru->ru_inblock);
-	err |= __put_user (r->ru_oublock, &ru->ru_oublock);
-	err |= __put_user (r->ru_msgsnd, &ru->ru_msgsnd);
-	err |= __put_user (r->ru_msgrcv, &ru->ru_msgrcv);
-	err |= __put_user (r->ru_nsignals, &ru->ru_nsignals);
-	err |= __put_user (r->ru_nvcsw, &ru->ru_nvcsw);
-	err |= __put_user (r->ru_nivcsw, &ru->ru_nivcsw);
-	return err;
-}
-
-
-extern asmlinkage long sys_getrusage(int who, struct rusage *ru);
-
-/* Note: it is necessary to treat who as an unsigned int, 
- * with the corresponding cast to a signed int to insure that the 
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long sys32_getrusage(u32 who, struct rusage32 *ru)
-{
-	struct rusage r;
-	int ret;
-	mm_segment_t old_fs = get_fs();
-	
-	set_fs (KERNEL_DS);
-	ret = sys_getrusage((int)who, &r);
-	set_fs (old_fs);
-	if (put_rusage (ru, &r)) 
-		return -EFAULT;
-
-	return ret;
-}
-
-
-
-
 struct sysinfo32 {
         s32 uptime;
         u32 loads[3];
@@ -2340,35 +2194,6 @@
 }
 
 
-extern asmlinkage long sys_wait4(pid_t pid, unsigned int * stat_addr, int options, struct rusage * ru);
-
-/* Note: it is necessary to treat pid and options as unsigned ints,
- * with the corresponding cast to a signed int to insure that the 
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long sys32_wait4(u32 pid, unsigned int * stat_addr, u32 options, struct rusage * ru)
-{
-	if (!ru)
-		return sys_wait4((int)pid, stat_addr, options, NULL);
-	else {
-		struct rusage r;
-		int ret;
-		unsigned int status;
-		mm_segment_t old_fs = get_fs();
-		
-		set_fs (KERNEL_DS);
-		ret = sys_wait4((int)pid, stat_addr ? &status : NULL, options, &r);
-		set_fs (old_fs);
-		if (put_rusage ((struct rusage32 *)ru, &r)) return -EFAULT;
-		if (stat_addr && put_user (status, stat_addr))
-			return -EFAULT;
-		return ret;
-	}
-	
-}
-
-
 extern asmlinkage long sys_waitpid(pid_t pid, unsigned int * stat_addr, int options);
 
 /* Note: it is necessary to treat pid and options as unsigned ints,
diff -urN linux-2.5.67-bk7/arch/s390/kernel/compat_linux.c linux-2.5.67-bk8/arch/s390/kernel/compat_linux.c
--- linux-2.5.67-bk7/arch/s390/kernel/compat_linux.c	2003-04-17 04:38:24.000000000 -0700
+++ linux-2.5.67-bk8/arch/s390/kernel/compat_linux.c	2003-04-17 04:38:35.000000000 -0700
@@ -1492,26 +1492,6 @@
 	return err;
 }
 
-asmlinkage int sys32_wait4(compat_pid_t pid, unsigned int *stat_addr, int options, struct rusage32 *ru)
-{
-	if (!ru)
-		return sys_wait4(pid, stat_addr, options, NULL);
-	else {
-		struct rusage r;
-		int ret;
-		unsigned int status;
-		mm_segment_t old_fs = get_fs();
-		
-		set_fs (KERNEL_DS);
-		ret = sys_wait4(pid, stat_addr ? &status : NULL, options, &r);
-		set_fs (old_fs);
-		if (put_rusage (ru, &r)) return -EFAULT;
-		if (stat_addr && put_user (status, stat_addr))
-			return -EFAULT;
-		return ret;
-	}
-}
-
 struct sysinfo32 {
         s32 uptime;
         u32 loads[3];
@@ -1733,87 +1713,6 @@
 	return ret;
 }
 
-#define RLIM_OLD_INFINITY32	0x7fffffff
-#define RLIM_INFINITY32		0xffffffff
-#define RESOURCE32_OLD(x)	((x > RLIM_OLD_INFINITY32) ? RLIM_OLD_INFINITY32 : x)
-#define RESOURCE32(x) 		((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x)
-
-struct rlimit32 {
-	u32	rlim_cur;
-	u32	rlim_max;
-};
-
-extern asmlinkage long sys_getrlimit(unsigned int resource, struct rlimit *rlim);
-
-asmlinkage int sys32_old_getrlimit(unsigned int resource, struct rlimit32 *rlim)
-{
-	struct rlimit r;
-	int ret;
-	mm_segment_t old_fs = get_fs ();
-	
-	set_fs (KERNEL_DS);
-	ret = sys_getrlimit(resource, &r);
-	set_fs (old_fs);
-	if (!ret) {
-		ret = put_user (RESOURCE32_OLD(r.rlim_cur), &rlim->rlim_cur);
-		ret |= __put_user (RESOURCE32_OLD(r.rlim_max), &rlim->rlim_max);
-	}
-	return ret;
-}
-
-asmlinkage int sys32_getrlimit(unsigned int resource, struct rlimit32 *rlim)
-{
-	struct rlimit r;
-	int ret;
-	mm_segment_t old_fs = get_fs ();
-	
-	set_fs (KERNEL_DS);
-	ret = sys_getrlimit(resource, &r);
-	set_fs (old_fs);
-	if (!ret) {
-		ret = put_user (RESOURCE32(r.rlim_cur), &rlim->rlim_cur);
-		ret |= __put_user (RESOURCE32(r.rlim_max), &rlim->rlim_max);
-	}
-	return ret;
-}
-
-extern asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim);
-
-asmlinkage int sys32_setrlimit(unsigned int resource, struct rlimit32 *rlim)
-{
-	struct rlimit r;
-	int ret;
-	mm_segment_t old_fs = get_fs ();
-
-	if (resource >= RLIM_NLIMITS) return -EINVAL;	
-	if (get_user (r.rlim_cur, &rlim->rlim_cur) ||
-	    __get_user (r.rlim_max, &rlim->rlim_max))
-		return -EFAULT;
-	if (r.rlim_cur == RLIM_INFINITY32)
-		r.rlim_cur = RLIM_INFINITY;
-	if (r.rlim_max == RLIM_INFINITY32)
-		r.rlim_max = RLIM_INFINITY;
-	set_fs (KERNEL_DS);
-	ret = sys_setrlimit(resource, &r);
-	set_fs (old_fs);
-	return ret;
-}
-
-extern asmlinkage int sys_getrusage(int who, struct rusage *ru);
-
-asmlinkage int sys32_getrusage(int who, struct rusage32 *ru)
-{
-	struct rusage r;
-	int ret;
-	mm_segment_t old_fs = get_fs();
-		
-	set_fs (KERNEL_DS);
-	ret = sys_getrusage(who, &r);
-	set_fs (old_fs);
-	if (put_rusage (ru, &r)) return -EFAULT;
-	return ret;
-}
-
 extern void check_pending(int signum);
 
 /*
diff -urN linux-2.5.67-bk7/arch/s390/kernel/compat_wrapper.S linux-2.5.67-bk8/arch/s390/kernel/compat_wrapper.S
--- linux-2.5.67-bk7/arch/s390/kernel/compat_wrapper.S	2003-04-17 04:38:24.000000000 -0700
+++ linux-2.5.67-bk8/arch/s390/kernel/compat_wrapper.S	2003-04-17 04:38:35.000000000 -0700
@@ -299,34 +299,34 @@
 	lgfr	%r3,%r3			# int
 	jg	sys_sethostname		# branch to system call
 
-	.globl  sys32_setrlimit_wrapper 
-sys32_setrlimit_wrapper:
+	.globl  compat_sys_setrlimit_wrapper 
+compat_sys_setrlimit_wrapper:
 	llgfr	%r2,%r2			# unsigned int
 	llgtr	%r3,%r3			# struct rlimit_emu31 *
-	jg	sys32_setrlimit		# branch to system call
+	jg	compat_sys_setrlimit	# branch to system call
 
-	.globl  sys32_old_getrlimit_wrapper 
-sys32_old_getrlimit_wrapper:
+	.globl  compat_sys_old_getrlimit_wrapper 
+compat_sys_old_getrlimit_wrapper:
 	llgfr	%r2,%r2			# unsigned int
 	llgtr	%r3,%r3			# struct rlimit_emu31 *
-	jg	sys32_old_getrlimit	# branch to system call
+	jg	compat_sys_old_getrlimit # branch to system call
 
-	.globl  sys32_getrlimit_wrapper 
-sys32_getrlimit_wrapper:
+	.globl  compat_sys_getrlimit_wrapper 
+compat_sys_getrlimit_wrapper:
 	llgfr	%r2,%r2			# unsigned int
 	llgtr	%r3,%r3			# struct rlimit_emu31 *
-	jg	sys32_getrlimit		# branch to system call
+	jg	compat_sys_getrlimit	# branch to system call
 
 	.globl  sys32_mmap2_wrapper 
 sys32_mmap2_wrapper:
 	llgtr	%r2,%r2			# struct mmap_arg_struct_emu31 *
 	jg	sys32_mmap2			# branch to system call
 
-	.globl  sys32_getrusage_wrapper 
-sys32_getrusage_wrapper:
+	.globl  compat_sys_getrusage_wrapper 
+compat_sys_getrusage_wrapper:
 	lgfr	%r2,%r2			# int
 	llgtr	%r3,%r3			# struct rusage_emu31 *
-	jg	sys32_getrusage		# branch to system call
+	jg	compat_sys_getrusage	# branch to system call
 
 	.globl  sys32_gettimeofday_wrapper 
 sys32_gettimeofday_wrapper:
@@ -498,13 +498,13 @@
 
 #sys32_vhangup_wrapper			# void 
 
-	.globl  sys32_wait4_wrapper 
-sys32_wait4_wrapper:
+	.globl  compat_sys_wait4_wrapper 
+compat_sys_wait4_wrapper:
 	lgfr	%r2,%r2			# pid_t
 	llgtr	%r3,%r3			# unsigned int *
 	lgfr	%r4,%r4			# int
 	llgtr	%r5,%r5			# struct rusage *
-	jg	sys32_wait4		# branch to system call
+	jg	compat_sys_wait4	# branch to system call
 
 	.globl  sys32_swapoff_wrapper 
 sys32_swapoff_wrapper:
diff -urN linux-2.5.67-bk7/arch/sparc64/kernel/sys_sparc32.c linux-2.5.67-bk8/arch/sparc64/kernel/sys_sparc32.c
--- linux-2.5.67-bk7/arch/sparc64/kernel/sys_sparc32.c	2003-04-17 04:38:25.000000000 -0700
+++ linux-2.5.67-bk8/arch/sparc64/kernel/sys_sparc32.c	2003-04-17 04:38:36.000000000 -0700
@@ -1521,70 +1521,6 @@
 	return err;
 }
 
-struct rusage32 {
-        struct compat_timeval ru_utime;
-        struct compat_timeval ru_stime;
-        s32    ru_maxrss;
-        s32    ru_ixrss;
-        s32    ru_idrss;
-        s32    ru_isrss;
-        s32    ru_minflt;
-        s32    ru_majflt;
-        s32    ru_nswap;
-        s32    ru_inblock;
-        s32    ru_oublock;
-        s32    ru_msgsnd; 
-        s32    ru_msgrcv; 
-        s32    ru_nsignals;
-        s32    ru_nvcsw;
-        s32    ru_nivcsw;
-};
-
-static int put_rusage (struct rusage32 *ru, struct rusage *r)
-{
-	int err;
-	
-	err = put_user (r->ru_utime.tv_sec, &ru->ru_utime.tv_sec);
-	err |= __put_user (r->ru_utime.tv_usec, &ru->ru_utime.tv_usec);
-	err |= __put_user (r->ru_stime.tv_sec, &ru->ru_stime.tv_sec);
-	err |= __put_user (r->ru_stime.tv_usec, &ru->ru_stime.tv_usec);
-	err |= __put_user (r->ru_maxrss, &ru->ru_maxrss);
-	err |= __put_user (r->ru_ixrss, &ru->ru_ixrss);
-	err |= __put_user (r->ru_idrss, &ru->ru_idrss);
-	err |= __put_user (r->ru_isrss, &ru->ru_isrss);
-	err |= __put_user (r->ru_minflt, &ru->ru_minflt);
-	err |= __put_user (r->ru_majflt, &ru->ru_majflt);
-	err |= __put_user (r->ru_nswap, &ru->ru_nswap);
-	err |= __put_user (r->ru_inblock, &ru->ru_inblock);
-	err |= __put_user (r->ru_oublock, &ru->ru_oublock);
-	err |= __put_user (r->ru_msgsnd, &ru->ru_msgsnd);
-	err |= __put_user (r->ru_msgrcv, &ru->ru_msgrcv);
-	err |= __put_user (r->ru_nsignals, &ru->ru_nsignals);
-	err |= __put_user (r->ru_nvcsw, &ru->ru_nvcsw);
-	err |= __put_user (r->ru_nivcsw, &ru->ru_nivcsw);
-	return err;
-}
-
-asmlinkage int sys32_wait4(compat_pid_t pid, unsigned int *stat_addr, int options, struct rusage32 *ru)
-{
-	if (!ru)
-		return sys_wait4(pid, stat_addr, options, NULL);
-	else {
-		struct rusage r;
-		int ret;
-		unsigned int status;
-		mm_segment_t old_fs = get_fs();
-		
-		set_fs (KERNEL_DS);
-		ret = sys_wait4(pid, stat_addr ? &status : NULL, options, &r);
-		set_fs (old_fs);
-		if (put_rusage (ru, &r)) return -EFAULT;
-		if (stat_addr && put_user (status, stat_addr))
-			return -EFAULT;
-		return ret;
-	}
-}
-
 struct sysinfo32 {
         s32 uptime;
         u32 loads[3];
@@ -1805,69 +1741,6 @@
 	return ret;
 }
 
-#define RLIM_INFINITY32	0x7fffffff
-#define RESOURCE32(x) ((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x)
-
-struct rlimit32 {
-	u32	rlim_cur;
-	u32	rlim_max;
-};
-
-extern asmlinkage int sys_getrlimit(unsigned int resource, struct rlimit *rlim);
-
-asmlinkage int sys32_getrlimit(unsigned int resource, struct rlimit32 *rlim)
-{
-	struct rlimit r;
-	int ret;
-	mm_segment_t old_fs = get_fs ();
-	
-	set_fs (KERNEL_DS);
-	ret = sys_getrlimit(resource, &r);
-	set_fs (old_fs);
-	if (!ret) {
-		ret = put_user (RESOURCE32(r.rlim_cur), &rlim->rlim_cur);
-		ret |= __put_user (RESOURCE32(r.rlim_max), &rlim->rlim_max);
-	}
-	return ret;
-}
-
-extern asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim);
-
-asmlinkage int sys32_setrlimit(unsigned int resource, struct rlimit32 *rlim)
-{
-	struct rlimit r;
-	int ret;
-	mm_segment_t old_fs = get_fs ();
-
-	if (resource >= RLIM_NLIMITS) return -EINVAL;	
-	if (get_user (r.rlim_cur, &rlim->rlim_cur) ||
-	    __get_user (r.rlim_max, &rlim->rlim_max))
-		return -EFAULT;
-	if (r.rlim_cur == RLIM_INFINITY32)
-		r.rlim_cur = RLIM_INFINITY;
-	if (r.rlim_max == RLIM_INFINITY32)
-		r.rlim_max = RLIM_INFINITY;
-	set_fs (KERNEL_DS);
-	ret = sys_setrlimit(resource, &r);
-	set_fs (old_fs);
-	return ret;
-}
-
-extern asmlinkage int sys_getrusage(int who, struct rusage *ru);
-
-asmlinkage int sys32_getrusage(int who, struct rusage32 *ru)
-{
-	struct rusage r;
-	int ret;
-	mm_segment_t old_fs = get_fs();
-		
-	set_fs (KERNEL_DS);
-	ret = sys_getrusage(who, &r);
-	set_fs (old_fs);
-	if (put_rusage (ru, &r)) return -EFAULT;
-	return ret;
-}
-
 extern void check_pending(int signum);
 
 asmlinkage int sys32_sigaction (int sig, struct old_sigaction32 *act, struct old_sigaction32 *oact)
diff -urN linux-2.5.67-bk7/arch/sparc64/kernel/systbls.S linux-2.5.67-bk8/arch/sparc64/kernel/systbls.S
--- linux-2.5.67-bk7/arch/sparc64/kernel/systbls.S	2003-04-17 04:38:25.000000000 -0700
+++ linux-2.5.67-bk8/arch/sparc64/kernel/systbls.S	2003-04-17 04:38:36.000000000 -0700
@@ -20,7 +20,7 @@
 	.globl sys_call_table32
 sys_call_table32:
 /*0*/	.word sys_restart_syscall, sparc_exit, sys_fork, sys_read, sys_write
-/*5*/	.word sparc32_open, sys_close, sys32_wait4, sys_creat, sys_link
+/*5*/	.word sparc32_open, sys_close, compat_sys_wait4, sys_creat, sys_link
 /*10*/  .word sys_unlink, sunos_execv, sys_chdir, sys32_chown16, sys32_mknod
 /*15*/	.word sys32_chmod, sys32_lchown16, sparc_brk, sys_perfctr, sys32_lseek
 /*20*/	.word sys_getpid, sys_capget, sys_capset, sys32_setuid16, sys32_getuid16
@@ -42,13 +42,13 @@
 /*100*/ .word sys_getpriority, sys32_rt_sigreturn, sys32_rt_sigaction, sys32_rt_sigprocmask, sys32_rt_sigpending
 	.word sys32_rt_sigtimedwait, sys32_rt_sigqueueinfo, sys32_rt_sigsuspend, sys_setresuid, sys_getresuid
 /*110*/	.word sys_setresgid, sys_getresgid, sys_setregid, sys_nis_syscall, sys_nis_syscall
-	.word sys_getgroups, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_getcwd
+	.word sys_getgroups, sys32_gettimeofday, compat_sys_getrusage, sys_nis_syscall, sys_getcwd
 /*120*/	.word sys32_readv, sys32_writev, sys32_settimeofday, sys32_fchown16, sys_fchmod
 	.word sys_nis_syscall, sys32_setreuid16, sys32_setregid16, sys_rename, sys_truncate
 /*130*/	.word sys_ftruncate, sys_flock, sys_lstat64, sys_nis_syscall, sys_nis_syscall
 	.word sys_nis_syscall, sys_mkdir, sys_rmdir, sys32_utimes, sys_stat64
-/*140*/	.word sys32_sendfile64, sys_nis_syscall, compat_sys_futex, sys_gettid, sys32_getrlimit
-	.word sys32_setrlimit, sys_pivot_root, sys32_prctl, sys32_pciconfig_read, sys32_pciconfig_write
+/*140*/	.word sys32_sendfile64, sys_nis_syscall, compat_sys_futex, sys_gettid, compat_sys_getrlimit
+	.word compat_sys_setrlimit, sys_pivot_root, sys32_prctl, sys32_pciconfig_read, sys32_pciconfig_write
 /*150*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64
 	.word compat_sys_fcntl64, sys_ni_syscall, compat_sys_statfs, compat_sys_fstatfs, sys_oldumount
 /*160*/	.word compat_sys_sched_setaffinity, compat_sys_sched_getaffinity, sys_getdomainname, sys_setdomainname, sys_nis_syscall
diff -urN linux-2.5.67-bk7/arch/x86_64/ia32/ia32entry.S linux-2.5.67-bk8/arch/x86_64/ia32/ia32entry.S
--- linux-2.5.67-bk7/arch/x86_64/ia32/ia32entry.S	2003-04-17 04:38:25.000000000 -0700
+++ linux-2.5.67-bk8/arch/x86_64/ia32/ia32entry.S	2003-04-17 04:38:36.000000000 -0700
@@ -279,9 +279,9 @@
 	.quad stub32_sigsuspend
 	.quad compat_sys_sigpending
 	.quad sys_sethostname
-	.quad sys32_setrlimit	/* 75 */
-	.quad sys32_old_getrlimit	/* old_getrlimit */
-	.quad sys32_getrusage
+	.quad compat_sys_setrlimit	/* 75 */
+	.quad compat_sys_old_getrlimit	/* old_getrlimit */
+	.quad compat_sys_getrusage
 	.quad sys32_gettimeofday
 	.quad sys32_settimeofday
 	.quad sys_getgroups16	/* 80 */
@@ -318,7 +318,7 @@
 	.quad sys_vhangup
 	.quad ni_syscall	/* old "idle" system call */
 	.quad sys32_vm86_warning	/* vm86old */ 
-	.quad sys32_wait4
+	.quad compat_sys_wait4
 	.quad sys_swapoff		/* 115 */
 	.quad sys32_sysinfo
 	.quad sys32_ipc
@@ -395,7 +395,7 @@
 	.quad ni_syscall		/* streams1 */
 	.quad ni_syscall		/* streams2 */
 	.quad stub32_vfork            /* 190 */
-	.quad sys32_getrlimit
+	.quad compat_sys_getrlimit
 	.quad sys32_mmap2
 	.quad sys_truncate
 	.quad sys_ftruncate
diff -urN linux-2.5.67-bk7/arch/x86_64/ia32/sys_ia32.c linux-2.5.67-bk8/arch/x86_64/ia32/sys_ia32.c
--- linux-2.5.67-bk7/arch/x86_64/ia32/sys_ia32.c	2003-04-17 04:38:25.000000000 -0700
+++ linux-2.5.67-bk8/arch/x86_64/ia32/sys_ia32.c	2003-04-17 04:38:36.000000000 -0700
@@ -836,82 +836,6 @@
 	return ret;
 }
 
-#define RLIM_INFINITY32	0xffffffff
-#define RESOURCE32(x) ((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x)
-
-struct rlimit32 {
-	int	rlim_cur;
-	int	rlim_max;
-};
-
-extern asmlinkage long sys_getrlimit(unsigned int resource, struct rlimit *rlim);
-
-asmlinkage long
-sys32_getrlimit(unsigned int resource, struct rlimit32 *rlim)
-{
-	struct rlimit r;
-	int ret;
-	mm_segment_t old_fs;
-
-	old_fs = get_fs();
-	set_fs(KERNEL_DS);
-	ret = sys_getrlimit(resource, &r);
-	set_fs(old_fs);
-	if (!ret) {
-		if (verify_area(VERIFY_WRITE, rlim, sizeof(struct rlimit32)) ||
-		    __put_user(RESOURCE32(r.rlim_cur), &rlim->rlim_cur) ||
-		    __put_user(RESOURCE32(r.rlim_max), &rlim->rlim_max))
-			ret = -EFAULT;
-	}
-	return ret;
-}
-
-extern asmlinkage long sys_old_getrlimit(unsigned int resource, struct rlimit *rlim);
-
-asmlinkage long
-sys32_old_getrlimit(unsigned int resource, struct rlimit32 *rlim)
-{
-	struct rlimit r;
-	int ret;
-	mm_segment_t old_fs;
-	
-	old_fs = get_fs();
-	set_fs(KERNEL_DS);
-	ret = sys_old_getrlimit(resource, &r);
-	set_fs(old_fs);
-	if (!ret) {
-		if (verify_area(VERIFY_WRITE, rlim, sizeof(struct rlimit32)) ||
-		    __put_user(r.rlim_cur, &rlim->rlim_cur) ||
-		    __put_user(r.rlim_max, &rlim->rlim_max))
-			ret = -EFAULT;
-	}
-	return ret;
-}
-
-extern asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit *rlim);
-
-asmlinkage long
-sys32_setrlimit(unsigned int resource, struct rlimit32 *rlim)
-{
-	struct rlimit r;
-	int ret;
-	mm_segment_t old_fs = get_fs ();
-
-	if (resource >= RLIM_NLIMITS) return -EINVAL;	
-	if (verify_area(VERIFY_READ, rlim, sizeof(struct rlimit32)) ||
-	    __get_user (r.rlim_cur, &rlim->rlim_cur) ||
-	    __get_user (r.rlim_max, &rlim->rlim_max))
-		return -EFAULT;
-	if (r.rlim_cur == RLIM_INFINITY32)
-		r.rlim_cur = RLIM_INFINITY;
-	if (r.rlim_max == RLIM_INFINITY32)
-		r.rlim_max = RLIM_INFINITY;
-	set_fs (KERNEL_DS);
-	ret = sys_setrlimit(resource, &r);
-	set_fs (old_fs);
-	return ret;
-}
-
 /*
  * sys_time() can be implemented in user-level using
  * sys_gettimeofday().  x86-64 did this but i386 Linux did not
@@ -931,80 +855,10 @@
 	return i;
 }
 
-struct rusage32 {
-        struct compat_timeval ru_utime;
-        struct compat_timeval ru_stime;
-        int    ru_maxrss;
-        int    ru_ixrss;
-        int    ru_idrss;
-        int    ru_isrss;
-        int    ru_minflt;
-        int    ru_majflt;
-        int    ru_nswap;
-        int    ru_inblock;
-        int    ru_oublock;
-        int    ru_msgsnd; 
-        int    ru_msgrcv; 
-        int    ru_nsignals;
-        int    ru_nvcsw;
-        int    ru_nivcsw;
-};
-
-static int
-put_rusage (struct rusage32 *ru, struct rusage *r)
-{
-	if (verify_area(VERIFY_WRITE, ru, sizeof(struct rusage32)) ||
-	    __put_user (r->ru_utime.tv_sec, &ru->ru_utime.tv_sec) ||
-	    __put_user (r->ru_utime.tv_usec, &ru->ru_utime.tv_usec) ||
-	    __put_user (r->ru_stime.tv_sec, &ru->ru_stime.tv_sec) ||
-	    __put_user (r->ru_stime.tv_usec, &ru->ru_stime.tv_usec) ||
-	    __put_user (r->ru_maxrss, &ru->ru_maxrss) ||
-	    __put_user (r->ru_ixrss, &ru->ru_ixrss) ||
-	    __put_user (r->ru_idrss, &ru->ru_idrss) ||
-	    __put_user (r->ru_isrss, &ru->ru_isrss) ||
-	    __put_user (r->ru_minflt, &ru->ru_minflt) ||
-	    __put_user (r->ru_majflt, &ru->ru_majflt) ||
-	    __put_user (r->ru_nswap, &ru->ru_nswap) ||
-	    __put_user (r->ru_inblock, &ru->ru_inblock) ||
-	    __put_user (r->ru_oublock, &ru->ru_oublock) ||
-	    __put_user (r->ru_msgsnd, &ru->ru_msgsnd) ||
-	    __put_user (r->ru_msgrcv, &ru->ru_msgrcv) ||
-	    __put_user (r->ru_nsignals, &ru->ru_nsignals) ||
-	    __put_user (r->ru_nvcsw, &ru->ru_nvcsw) ||
-	    __put_user (r->ru_nivcsw, &ru->ru_nivcsw))
-		return -EFAULT;
-	return 0;
-}
-
-extern asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr,
-				int options, struct rusage * ru);
-
-asmlinkage long
-sys32_wait4(compat_pid_t pid, unsigned int *stat_addr, int options,
-	    struct rusage32 *ru)
-{
-	if (!ru)
-		return sys_wait4(pid, stat_addr, options, NULL);
-	else {
-		struct rusage r;
-		int ret;
-		unsigned int status;
-		mm_segment_t old_fs = get_fs();
-		
-		set_fs (KERNEL_DS);
-		ret = sys_wait4(pid, stat_addr ? &status : NULL, options, &r);
-		set_fs (old_fs);
-		if (put_rusage (ru, &r)) return -EFAULT;
-		if (stat_addr && put_user (status, stat_addr))
-			return -EFAULT;
-		return ret;
-	}
-}
-
 asmlinkage long
 sys32_waitpid(compat_pid_t pid, unsigned int *stat_addr, int options)
 {
-	return sys32_wait4(pid, stat_addr, options, NULL);
+	return compat_sys_wait4(pid, stat_addr, options, NULL);
 }
 
 
diff -urN linux-2.5.67-bk7/drivers/char/epca.c linux-2.5.67-bk8/drivers/char/epca.c
--- linux-2.5.67-bk7/drivers/char/epca.c	2003-04-07 10:31:46.000000000 -0700
+++ linux-2.5.67-bk8/drivers/char/epca.c	2003-04-17 04:38:36.000000000 -0700
@@ -481,9 +481,7 @@
 	-------------------------------------------------------------------------*/
 
 	ch->event |= 1 << event;
-	MOD_INC_USE_COUNT;
-	if (schedule_work(&ch->tqueue) == 0)
-		MOD_DEC_USE_COUNT;
+	schedule_work(&ch->tqueue);
 
 
 } /* End pc_sched_event */
@@ -604,7 +602,6 @@
 		                      ASYNC_CALLOUT_ACTIVE | ASYNC_CLOSING);
 		wake_up_interruptible(&ch->close_wait);
 
-		MOD_DEC_USE_COUNT;
 
 		restore_flags(flags);
 
@@ -692,10 +689,6 @@
 
 		shutdown(ch);
 
-		if (ch->count)
-			MOD_DEC_USE_COUNT;
-		
-
 		ch->tty   = NULL;
 		ch->event = 0;
 		ch->count = 0;
@@ -1389,8 +1382,6 @@
 	}
 
 
-	MOD_INC_USE_COUNT;
-
 	ch = &digi_channels[line];
 	boardnum = ch->boardnum;
 
@@ -1714,6 +1705,7 @@
 	memset(&pc_info, 0, sizeof(struct tty_driver));
 
 	pc_driver.magic = TTY_DRIVER_MAGIC;
+	pc_driver.owner = THIS_MODULE;
 	pc_driver.name = "ttyD"; 
 	pc_driver.major = DIGI_MAJOR; 
 	pc_driver.minor_start = 0;
diff -urN linux-2.5.67-bk7/drivers/net/e1000/e1000_main.c linux-2.5.67-bk8/drivers/net/e1000/e1000_main.c
--- linux-2.5.67-bk7/drivers/net/e1000/e1000_main.c	2003-04-07 10:31:04.000000000 -0700
+++ linux-2.5.67-bk8/drivers/net/e1000/e1000_main.c	2003-04-17 04:38:37.000000000 -0700
@@ -61,7 +61,7 @@
 
 char e1000_driver_name[] = "e1000";
 char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
-char e1000_driver_version[] = "5.0.43-k1";
+char e1000_driver_version[] = "5.0.43-k2";
 char e1000_copyright[] = "Copyright (c) 1999-2003 Intel Corporation.";
 
 /* e1000_pci_tbl - PCI Device ID Table
@@ -2000,10 +2000,16 @@
 	}
 
 #ifdef CONFIG_E1000_NAPI
-	/* Don't disable interrupts - rely on h/w interrupt
-	 * moderation to keep interrupts low.  netif_rx_schedule
-	 * is NOP if already polling. */
-	netif_rx_schedule(netdev);
+	if(netif_rx_schedule_prep(netdev)) {
+
+		/* Disable interrupts and register for poll. The flush 
+		  of the posted write is intentionally left out.
+		*/
+
+		atomic_inc(&adapter->irq_sem);
+		E1000_WRITE_REG(&adapter->hw, IMC, ~0);
+		__netif_rx_schedule(netdev);
+	}
 #else
 	for(i = 0; i < E1000_MAX_INTR; i++)
 		if(!e1000_clean_rx_irq(adapter) &&
@@ -2025,16 +2031,16 @@
 	int work_to_do = min(*budget, netdev->quota);
 	int work_done = 0;
 	
-	while(work_done < work_to_do)
-		if(!e1000_clean_rx_irq(adapter, &work_done, work_to_do) &&
-		   !e1000_clean_tx_irq(adapter))
-			break;
+	e1000_clean_tx_irq(adapter);
+	e1000_clean_rx_irq(adapter, &work_done, work_to_do);
 
 	*budget -= work_done;
 	netdev->quota -= work_done;
 	
-	if(work_done < work_to_do)
+	if(work_done < work_to_do) {
 		netif_rx_complete(netdev);
+		e1000_irq_enable(adapter);
+	}
 
 	return (work_done >= work_to_do);
 }
diff -urN linux-2.5.67-bk7/drivers/net/e1000/e1000_param.c linux-2.5.67-bk8/drivers/net/e1000/e1000_param.c
--- linux-2.5.67-bk7/drivers/net/e1000/e1000_param.c	2003-04-07 10:32:15.000000000 -0700
+++ linux-2.5.67-bk8/drivers/net/e1000/e1000_param.c	2003-04-17 04:38:37.000000000 -0700
@@ -322,7 +322,7 @@
 			.name = "Transmit Descriptors",
 			.err  = "using default of " __MODULE_STRING(DEFAULT_TXD),
 			.def  = DEFAULT_TXD,
-			.arg  = { .r { .min = MIN_TXD }}
+			.arg  = { .r = { .min = MIN_TXD }}
 		};
 		struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
 		e1000_mac_type mac_type = adapter->hw.mac_type;
diff -urN linux-2.5.67-bk7/drivers/net/fc/iph5526.c linux-2.5.67-bk8/drivers/net/fc/iph5526.c
--- linux-2.5.67-bk7/drivers/net/fc/iph5526.c	2003-04-07 10:30:57.000000000 -0700
+++ linux-2.5.67-bk8/drivers/net/fc/iph5526.c	2003-04-17 04:38:37.000000000 -0700
@@ -689,8 +689,8 @@
 			prev_IMQ_index = current_IMQ_index;
 		}
 	} /*end of for loop*/		
-	return;
 	LEAVE("tachyon_interrupt");
+       return;
 }
 
 
@@ -3375,8 +3375,8 @@
 		q = q->next;
 	}
 	DPRINTK1("Port Name does not match. Txing LOGO.");
-	return 0;
 	LEAVE("validate_login");
+       return 0;
 }
 
 static void add_to_address_cache(struct fc_info *fi, u_int *base_ptr)
diff -urN linux-2.5.67-bk7/drivers/net/rcpci45.c linux-2.5.67-bk8/drivers/net/rcpci45.c
--- linux-2.5.67-bk7/drivers/net/rcpci45.c	2003-04-07 10:32:23.000000000 -0700
+++ linux-2.5.67-bk8/drivers/net/rcpci45.c	2003-04-17 04:38:37.000000000 -0700
@@ -76,10 +76,6 @@
 
 #define NEW_MULTICAST
 
-/* PCI/45 Configuration space values */
-#define RC_PCI45_VENDOR_ID  0x4916
-#define RC_PCI45_DEVICE_ID  0x1960
-
 #define MAX_ETHER_SIZE        1520
 #define MAX_NMBR_RCV_BUFFERS    96
 #define RC_POSTED_BUFFERS_LOW_MARK MAX_NMBR_RCV_BUFFERS-16
@@ -117,7 +113,7 @@
 static int RC_allocate_and_post_buffers (struct net_device *, int);
 
 static struct pci_device_id rcpci45_pci_table[] __devinitdata = {
-	{RC_PCI45_VENDOR_ID, RC_PCI45_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+	{ PCI_VENDOR_ID_REDCREEK, PCI_DEVICE_ID_RC45, PCI_ANY_ID, PCI_ANY_ID,},
 	{}
 };
 MODULE_DEVICE_TABLE (pci, rcpci45_pci_table);
@@ -207,7 +203,7 @@
 	 * messages. Thus, we need contiguous physical pages of
 	 * memory.
 	 */
-	pDpa->msgbuf = kmalloc (MSG_BUF_SIZE, GFP_DMA|GFP_ATOMIC|GFP_KERNEL);
+	pDpa->msgbuf = kmalloc (MSG_BUF_SIZE, GFP_DMA | GFP_KERNEL);
 	if (!pDpa->msgbuf) {
 		printk (KERN_ERR "(rcpci45 driver:) \
 			Could not allocate %d byte memory for the \
@@ -1000,7 +996,7 @@
 	}
 
 	p = (PU32) kmalloc (sizeof (U32) + numBuffers * sizeof (singleB),
-			    GFP_DMA|GFP_ATOMIC|GFP_KERNEL);
+			    GFP_DMA | GFP_ATOMIC);
 
 	if (!p) {
 		printk (KERN_WARNING "%s unable to allocate TCB\n",
diff -urN linux-2.5.67-bk7/drivers/net/tokenring/tms380tr.c linux-2.5.67-bk8/drivers/net/tokenring/tms380tr.c
--- linux-2.5.67-bk7/drivers/net/tokenring/tms380tr.c	2003-04-07 10:31:45.000000000 -0700
+++ linux-2.5.67-bk8/drivers/net/tokenring/tms380tr.c	2003-04-17 04:38:37.000000000 -0700
@@ -257,7 +257,7 @@
 	int err;
 	
 	/* init the spinlock */
-	spin_lock_init(tp->lock);
+	spin_lock_init(&tp->lock);
 
 	/* Reset the hardware here. Don't forget to set the station address. */
 
@@ -1458,7 +1458,7 @@
 	if(tms380tr_debug > 3)
 	{
 		printk(KERN_DEBUG "%s: buffer (real): %lx\n", dev->name, (long) &tp->scb);
-		printk(KERN_DEBUG "%s: buffer (virt): %lx\n", dev->name, (long) ((char *)&tp->scb - (char *)tp) + tp->dmabuffer);
+		printk(KERN_DEBUG "%s: buffer (virt): %lx\n", dev->name, (long) ((char *)&tp->scb - (char *)tp) + (long) tp->dmabuffer);
 		printk(KERN_DEBUG "%s: buffer (DMA) : %lx\n", dev->name, (long) tp->dmabuffer);
 		printk(KERN_DEBUG "%s: buffer (tp)  : %lx\n", dev->name, (long) tp);
 	}
diff -urN linux-2.5.67-bk7/drivers/net/tulip/tulip_core.c linux-2.5.67-bk8/drivers/net/tulip/tulip_core.c
--- linux-2.5.67-bk7/drivers/net/tulip/tulip_core.c	2003-04-07 10:31:48.000000000 -0700
+++ linux-2.5.67-bk8/drivers/net/tulip/tulip_core.c	2003-04-17 04:38:37.000000000 -0700
@@ -485,12 +485,9 @@
         struct tulip_private *tp = (struct tulip_private *)dev->priv;
 #endif
 	int retval;
-	MOD_INC_USE_COUNT;
 
-	if ((retval = request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev))) {
-		MOD_DEC_USE_COUNT;
+	if ((retval = request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev)))
 		return retval;
-	}
 
 	tulip_init_ring (dev);
 
@@ -823,8 +820,6 @@
 		tp->tx_buffers[i].mapping = 0;
 	}
 
-	MOD_DEC_USE_COUNT;
-
 	return 0;
 }
 
@@ -1361,6 +1356,7 @@
 		return -ENOMEM;
 	}
 
+	SET_MODULE_OWNER(dev);
 	if (pci_resource_len (pdev, 0) < tulip_tbl[chip_idx].io_size) {
 		printk (KERN_ERR PFX "%s: I/O region (0x%lx@0x%lx) too small, "
 			"aborting\n", pdev->slot_name,
diff -urN linux-2.5.67-bk7/drivers/net/tun.c linux-2.5.67-bk8/drivers/net/tun.c
--- linux-2.5.67-bk7/drivers/net/tun.c	2003-04-07 10:31:14.000000000 -0700
+++ linux-2.5.67-bk8/drivers/net/tun.c	2003-04-17 04:38:37.000000000 -0700
@@ -379,6 +379,7 @@
 		tun->owner = -1;
 		tun->dev.init = tun_net_init;
 		tun->dev.priv = tun;
+		tun->dev.owner = THIS_MODULE;
 
 		err = -EINVAL;
 
@@ -402,8 +403,6 @@
 		if ((err = register_netdevice(&tun->dev)))
 			goto failed;
 	
-		MOD_INC_USE_COUNT;
-
 		tun->name = tun->dev.name;
 	}
 
@@ -553,7 +552,6 @@
 		dev_close(&tun->dev);
 		unregister_netdevice(&tun->dev);
 		kfree(tun);
-		MOD_DEC_USE_COUNT;
 	}
 
 	rtnl_unlock();
diff -urN linux-2.5.67-bk7/drivers/net/wan/pc300_tty.c linux-2.5.67-bk8/drivers/net/wan/pc300_tty.c
--- linux-2.5.67-bk7/drivers/net/wan/pc300_tty.c	2003-04-07 10:31:12.000000000 -0700
+++ linux-2.5.67-bk8/drivers/net/wan/pc300_tty.c	2003-04-17 04:38:37.000000000 -0700
@@ -215,6 +215,7 @@
 		/* initialize tty driver struct */
 		memset(&serial_drv,0,sizeof(struct tty_driver));
 		serial_drv.magic = TTY_DRIVER_MAGIC;
+		serial_drv.owner = THIS_MODULE;
 		serial_drv.driver_name = "pc300_tty";
 		serial_drv.name = "ttyCP";
 		serial_drv.major = CPC_TTY_MAJOR;
diff -urN linux-2.5.67-bk7/drivers/net/wan/sdla_chdlc.c linux-2.5.67-bk8/drivers/net/wan/sdla_chdlc.c
--- linux-2.5.67-bk7/drivers/net/wan/sdla_chdlc.c	2003-04-07 10:31:20.000000000 -0700
+++ linux-2.5.67-bk8/drivers/net/wan/sdla_chdlc.c	2003-04-17 04:38:37.000000000 -0700
@@ -4401,6 +4401,7 @@
 		
 		memset(&serial_driver, 0, sizeof(struct tty_driver));
 		serial_driver.magic = TTY_DRIVER_MAGIC;
+		serial_driver.owner = THIS_MODULE;
 		serial_driver.driver_name = "wanpipe_tty"; 
 		serial_driver.name = "ttyW";
 		serial_driver.major = WAN_TTY_MAJOR;
diff -urN linux-2.5.67-bk7/drivers/s390/net/Kconfig linux-2.5.67-bk8/drivers/s390/net/Kconfig
--- linux-2.5.67-bk7/drivers/s390/net/Kconfig	2003-04-07 10:32:30.000000000 -0700
+++ linux-2.5.67-bk8/drivers/s390/net/Kconfig	2003-04-17 04:38:37.000000000 -0700
@@ -9,7 +9,7 @@
   	   or zSeries. This device driver supports Token Ring (IEEE 802.5),
   	   FDDI (IEEE 802.7) and Ethernet. 
 	   This option is also available as a module which will be
-	   called lcs.o . If you do not know what it is, it's safe to say "Y".
+	   called lcs.ko. If you do not know what it is, it's safe to say "Y".
 
 config CTC
 	tristate "CTC device support"
@@ -20,7 +20,7 @@
 	  coupling using ESCON. It also supports virtual CTCs when running
 	  under VM. It will use the channel device configuration if this is
 	  available.  This option is also available as a module which will be
-	  called ctc.o.  If you do not know what it is, it's safe to say "Y".
+	  called ctc.ko.  If you do not know what it is, it's safe to say "Y".
 
 config IUCV
 	tristate "IUCV device support (VM only)"
@@ -28,7 +28,7 @@
 	help
 	  Select this option if you want to use inter-user communication
 	  vehicle networking under VM or VIF.  This option is also available
-	  as a module which will be called iucv.o. If unsure, say "Y".
+	  as a module which will be called iucv.ko. If unsure, say "Y".
 
 config CCWGROUP
  	tristate
diff -urN linux-2.5.67-bk7/drivers/s390/net/ctcmain.c linux-2.5.67-bk8/drivers/s390/net/ctcmain.c
--- linux-2.5.67-bk7/drivers/s390/net/ctcmain.c	2003-04-07 10:31:04.000000000 -0700
+++ linux-2.5.67-bk8/drivers/s390/net/ctcmain.c	2003-04-17 04:38:37.000000000 -0700
@@ -1,5 +1,5 @@
 /*
- * $Id: ctcmain.c,v 1.36 2003/02/18 09:15:14 mschwide Exp $
+ * $Id: ctcmain.c,v 1.40 2003/04/08 16:00:17 mschwide Exp $
  *
  * CTC / ESCON network driver
  *
@@ -36,13 +36,12 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.36 $
+ * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.40 $
  *
  */
 
 #undef DEBUG
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -273,7 +272,7 @@
 print_banner(void)
 {
 	static int printed = 0;
-	char vbuf[] = "$Revision: 1.36 $";
+	char vbuf[] = "$Revision: 1.40 $";
 	char *version = vbuf;
 
 	if (printed)
@@ -1962,22 +1961,17 @@
 	}
 	
 	priv = cdev->dev.driver_data;
-	ch = (struct channel *) intparm;
-	if ((ch != priv->channel[READ]) && (ch != priv->channel[WRITE]))
-		ch = NULL;
-	
-	if (!ch) {
-		/* Try to extract channel from driver data. */
-		if (priv->channel[READ]->cdev == cdev)
-			ch = priv->channel[READ];
-		else if (priv->channel[WRITE]->cdev == cdev)
-			ch = priv->channel[READ];
-		else {
-			printk(KERN_ERR
-			       "ctc: Can't determine channel for interrupt, "
-			       "device %s\n", cdev->dev.bus_id);
-			return;
-		}
+
+	/* Try to extract channel from driver data. */
+	if (priv->channel[READ]->cdev == cdev)
+		ch = priv->channel[READ];
+	else if (priv->channel[WRITE]->cdev == cdev)
+		ch = priv->channel[READ];
+	else {
+		printk(KERN_ERR
+		       "ctc: Can't determine channel for interrupt, "
+		       "device %s\n", cdev->dev.bus_id);
+		return;
 	}
 	
 	dev = (struct net_device *) (ch->netdev);
@@ -2392,7 +2386,6 @@
 static int
 ctc_open(struct net_device * dev)
 {
-	MOD_INC_USE_COUNT;
 	fsm_event(((struct ctc_priv *) dev->priv)->fsm, DEV_EVENT_START, dev);
 	return 0;
 }
@@ -2409,7 +2402,6 @@
 ctc_close(struct net_device * dev)
 {
 	fsm_event(((struct ctc_priv *) dev->priv)->fsm, DEV_EVENT_STOP, dev);
-	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -2761,6 +2753,7 @@
 	dev->addr_len = 0;
 	dev->type = ARPHRD_SLIP;
 	dev->tx_queue_len = 100;
+	dev->owner = THIS_MODULE;
 	dev->flags = IFF_POINTOPOINT | IFF_NOARP;
 	return dev;
 }
diff -urN linux-2.5.67-bk7/drivers/s390/net/ctctty.c linux-2.5.67-bk8/drivers/s390/net/ctctty.c
--- linux-2.5.67-bk7/drivers/s390/net/ctctty.c	2003-04-07 10:31:44.000000000 -0700
+++ linux-2.5.67-bk8/drivers/s390/net/ctctty.c	2003-04-17 04:38:37.000000000 -0700
@@ -1,5 +1,5 @@
 /*
- * $Id: ctctty.c,v 1.9 2002/12/02 15:25:13 aberg Exp $
+ * $Id: ctctty.c,v 1.10 2003/03/21 18:47:31 aberg Exp $
  *
  * CTC / ESCON network driver, tty interface.
  *
@@ -22,7 +22,6 @@
  *
  */
 
-#define __NO_VERSION__
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/tty.h>
diff -urN linux-2.5.67-bk7/drivers/s390/net/fsm.c linux-2.5.67-bk8/drivers/s390/net/fsm.c
--- linux-2.5.67-bk7/drivers/s390/net/fsm.c	2003-04-07 10:31:19.000000000 -0700
+++ linux-2.5.67-bk8/drivers/s390/net/fsm.c	2003-04-17 04:38:37.000000000 -0700
@@ -1,12 +1,11 @@
 /**
- * $Id: fsm.c,v 1.3 2002/10/08 16:53:45 mschwide Exp $
+ * $Id: fsm.c,v 1.4 2003/03/28 08:54:40 mschwide Exp $
  *
  * A generic FSM based on fsm used in isdn4linux
  *
  */
 
 #include "fsm.h"
-#include <linux/version.h>
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/timer.h>
diff -urN linux-2.5.67-bk7/drivers/s390/net/iucv.c linux-2.5.67-bk8/drivers/s390/net/iucv.c
--- linux-2.5.67-bk7/drivers/s390/net/iucv.c	2003-04-07 10:30:40.000000000 -0700
+++ linux-2.5.67-bk8/drivers/s390/net/iucv.c	2003-04-17 04:38:37.000000000 -0700
@@ -1,5 +1,5 @@
 /* 
- * $Id: iucv.c,v 1.9 2002/11/06 13:37:25 cohuck Exp $
+ * $Id: iucv.c,v 1.10 2003/03/28 08:54:40 mschwide Exp $
  *
  * IUCV network driver
  *
@@ -29,14 +29,13 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * RELEASE-TAG: IUCV lowlevel driver $Revision: 1.9 $
+ * RELEASE-TAG: IUCV lowlevel driver $Revision: 1.10 $
  *
  */
 
 #include <linux/module.h>
 #include <linux/config.h>
 
-#include <linux/version.h>
 #include <linux/spinlock.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
@@ -333,7 +332,7 @@
 static void
 iucv_banner(void)
 {
-	char vbuf[] = "$Revision: 1.9 $";
+	char vbuf[] = "$Revision: 1.10 $";
 	char *version = vbuf;
 
 	if ((version = strchr(version, ':'))) {
diff -urN linux-2.5.67-bk7/drivers/s390/net/lcs.c linux-2.5.67-bk8/drivers/s390/net/lcs.c
--- linux-2.5.67-bk7/drivers/s390/net/lcs.c	2003-04-07 10:30:42.000000000 -0700
+++ linux-2.5.67-bk8/drivers/s390/net/lcs.c	2003-04-17 04:38:37.000000000 -0700
@@ -11,7 +11,7 @@
  *			  Frank Pavlic (pavlic@de.ibm.com) and
  *		 	  Martin Schwidefsky <schwidefsky@de.ibm.com>
  *
- *    $Revision: 1.44 $	 $Date: 2003/02/18 19:49:02 $
+ *    $Revision: 1.51 $	 $Date: 2003/03/28 08:54:40 $
  *
  * 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
@@ -28,7 +28,6 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/if.h>
 #include <linux/netdevice.h>
@@ -59,7 +58,7 @@
 /**
  * initialization string for output
  */
-#define VERSION_LCS_C  "$Revision: 1.44 $"
+#define VERSION_LCS_C  "$Revision: 1.51 $"
 
 static char version[] __initdata = "LCS driver ("VERSION_LCS_C "/" VERSION_LCS_H ")";
 
@@ -335,7 +334,9 @@
 		  (void *)lcs_start_kernel_thread,card);
 	card->thread_mask = 0;
 	spin_lock_init(&card->lock);
+#ifdef CONFIG_IP_MULTICAST
 	INIT_LIST_HEAD(&card->ipm_list);
+#endif
 	INIT_LIST_HEAD(&card->lancmd_waiters);
 	return 0;
 }
@@ -358,6 +359,7 @@
 		kfree(ipm_list);
 	}
 #endif
+	kfree(card->dev);
 	/* Cleanup channels. */
 	lcs_cleanup_channel(&card->write);
 	lcs_cleanup_channel(&card->read);
@@ -556,13 +558,12 @@
 static int
 __lcs_processed_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer)
 {
-	int index, prevprev, prev, next;
+	int index, prev, next;
 
 	if (buffer->state != BUF_STATE_READY)
 		BUG();
 	buffer->state = BUF_STATE_PROCESSED;
 	index = buffer - channel->iob;
-	prevprev = (index - 1) & (LCS_NUM_BUFFS - 1);
 	prev = (index - 1) & (LCS_NUM_BUFFS - 1);
 	next = (index + 1) & (LCS_NUM_BUFFS - 1);
 	/* Set the suspend bit and clear the PCI bit of this buffer. */
@@ -1082,7 +1083,7 @@
 	unsigned long flags;
 	struct lcs_channel *channel;
 	struct lcs_buffer *iob;
-	int buf_idx, io_idx;
+	int buf_idx;
 	int rc;
 
 	channel = (struct lcs_channel *) data;
@@ -1092,9 +1093,7 @@
 	/* Check for processed buffers. */
 	iob = channel->iob;
 	buf_idx = channel->buf_idx;
-	io_idx = channel->io_idx;
-	while (buf_idx != io_idx &&
-	       iob[buf_idx].state == BUF_STATE_PROCESSED) {
+	while (iob[buf_idx].state == BUF_STATE_PROCESSED) {
 		/* Do the callback thing. */
 		if (iob[buf_idx].callback != NULL)
 			iob[buf_idx].callback(channel, iob + buf_idx);
@@ -1434,6 +1433,7 @@
 lcs_lgw_stoplan_thread(void *data)
 {
 	struct lcs_card *card;
+	int rc;
 
 	card = (struct lcs_card *) data;
 	daemonize("lgwstop");
@@ -1446,7 +1446,11 @@
 	else
 		PRINT_ERR("Stoplan %s initiated by LGW failed!\n",
 			  card->dev->name);
-	return 0;
+	/*Try to reset the card, stop it on failure */
+        rc = lcs_resetcard(card);
+        if (rc != 0)
+                rc = lcs_stopcard(card);
+        return rc;
 }
 
 /**
@@ -1462,8 +1466,10 @@
 		kernel_thread(lcs_lgw_startlan_thread, (void *) card, SIGCHLD);
 	if (test_and_clear_bit(2, &card->thread_mask))
 		kernel_thread(lcs_lgw_stoplan_thread, (void *) card, SIGCHLD);
+#ifdef CONFIG_IP_MULTICAST
 	if (test_and_clear_bit(3, &card->thread_mask))
 		kernel_thread(lcs_fix_multicast_list, (void *) card, SIGCHLD);
+#endif
 }
 
 /**
@@ -1599,12 +1605,9 @@
 	LCS_DBF_TEXT(2, trace, "stopdev");
 	card   = (struct lcs_card *) dev->priv;
 	netif_stop_queue(dev);
-	// FIXME: really free the net_device here ?!?
-	kfree(card->dev);
 	rc = lcs_stopcard(card);
 	if (rc)
 		PRINT_ERR("Try it again!\n ");
-	MOD_DEC_USE_COUNT;
 	return rc;
 }
 
@@ -1626,7 +1629,6 @@
 		PRINT_ERR("LCS:Error in opening device!\n");
 
 	} else {
-		MOD_INC_USE_COUNT;
 		netif_wake_queue(dev);
 		card->state = DEV_STATE_UP;
 	}
@@ -1784,6 +1786,7 @@
 		dev->set_multicast_list = lcs_set_multicast_list;
 #endif
 	dev->get_stats = lcs_getstats;
+	dev->owner = THIS_MODULE;
 	netif_stop_queue(dev);
 	lcs_stopcard(card);
 	return 0;
diff -urN linux-2.5.67-bk7/drivers/s390/net/netiucv.c linux-2.5.67-bk8/drivers/s390/net/netiucv.c
--- linux-2.5.67-bk7/drivers/s390/net/netiucv.c	2003-04-07 10:31:45.000000000 -0700
+++ linux-2.5.67-bk8/drivers/s390/net/netiucv.c	2003-04-17 04:38:37.000000000 -0700
@@ -1,5 +1,5 @@
 /*
- * $Id: netiucv.c,v 1.16 2003/02/18 09:15:14 mschwide Exp $
+ * $Id: netiucv.c,v 1.19 2003/04/08 16:00:17 mschwide Exp $
  *
  * IUCV network driver
  *
@@ -30,7 +30,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * RELEASE-TAG: IUCV network driver $Revision: 1.16 $
+ * RELEASE-TAG: IUCV network driver $Revision: 1.19 $
  *
  */
 
@@ -1140,7 +1140,6 @@
  */
 static int
 netiucv_open(struct net_device *dev) {
-	MOD_INC_USE_COUNT;
 	SET_DEVICE_START(dev, 1);
 	fsm_event(((struct netiucv_priv *)dev->priv)->fsm, DEV_EVENT_START, dev);
 	return 0;
@@ -1158,7 +1157,6 @@
 netiucv_close(struct net_device *dev) {
 	SET_DEVICE_START(dev, 0);
 	fsm_event(((struct netiucv_priv *)dev->priv)->fsm, DEV_EVENT_STOP, dev);
-	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -1517,12 +1515,14 @@
 		conn->max_buffsize = NETIUCV_BUFSIZE_DEFAULT;
 		conn->netdev = dev;
 
-		conn->rx_buff = alloc_skb(NETIUCV_BUFSIZE_DEFAULT, GFP_DMA);
+		conn->rx_buff = alloc_skb(NETIUCV_BUFSIZE_DEFAULT,
+					  GFP_KERNEL | GFP_DMA);
 		if (!conn->rx_buff) {
 			kfree(conn);
 			return NULL;
 		}
-		conn->tx_buff = alloc_skb(NETIUCV_BUFSIZE_DEFAULT, GFP_DMA);
+		conn->tx_buff = alloc_skb(NETIUCV_BUFSIZE_DEFAULT,
+					  GFP_KERNEL | GFP_DMA);
 		if (!conn->tx_buff) {
 			kfree_skb(conn->rx_buff);
 			kfree(conn);
@@ -1630,6 +1630,7 @@
 	dev->addr_len            = 0;
 	dev->type                = ARPHRD_SLIP;
 	dev->tx_queue_len        = NETIUCV_QUEUELEN_DEFAULT;
+	dev->owner               = THIS_MODULE;
 	dev->flags	         = IFF_POINTOPOINT | IFF_NOARP;
 	return dev;
 }
@@ -1716,7 +1717,7 @@
 static void
 netiucv_banner(void)
 {
-	char vbuf[] = "$Revision: 1.16 $";
+	char vbuf[] = "$Revision: 1.19 $";
 	char *version = vbuf;
 
 	if ((version = strchr(version, ':'))) {
diff -urN linux-2.5.67-bk7/fs/exec.c linux-2.5.67-bk8/fs/exec.c
--- linux-2.5.67-bk7/fs/exec.c	2003-04-17 04:38:27.000000000 -0700
+++ linux-2.5.67-bk8/fs/exec.c	2003-04-17 04:38:37.000000000 -0700
@@ -491,7 +491,8 @@
 
 	old_fs = get_fs();
 	set_fs(get_ds());
-	result = vfs_read(file, addr, count, &pos);
+	/* The cast to a user pointer is valid due to the set_fs() */
+	result = vfs_read(file, (void __user *)addr, count, &pos);
 	set_fs(old_fs);
 	return result;
 }
diff -urN linux-2.5.67-bk7/fs/namei.c linux-2.5.67-bk8/fs/namei.c
--- linux-2.5.67-bk7/fs/namei.c	2003-04-17 04:38:27.000000000 -0700
+++ linux-2.5.67-bk8/fs/namei.c	2003-04-17 04:38:37.000000000 -0700
@@ -847,6 +847,7 @@
 			read_unlock(&current->fs->lock);
 			if (__emul_lookup_dentry(name,nd))
 				return 0;
+			read_lock(&current->fs->lock);
 		}
 		nd->mnt = mntget(current->fs->rootmnt);
 		nd->dentry = dget(current->fs->root);
diff -urN linux-2.5.67-bk7/fs/namespace.c linux-2.5.67-bk8/fs/namespace.c
--- linux-2.5.67-bk7/fs/namespace.c	2003-04-07 10:31:55.000000000 -0700
+++ linux-2.5.67-bk8/fs/namespace.c	2003-04-17 04:38:37.000000000 -0700
@@ -367,7 +367,7 @@
  * unixes. Our API is identical to OSF/1 to avoid making a mess of AMD
  */
 
-asmlinkage long sys_umount(char * name, int flags)
+asmlinkage long sys_umount(char __user * name, int flags)
 {
 	struct nameidata nd;
 	int retval;
@@ -396,7 +396,7 @@
  *	The 2.0 compatible umount. No flags. 
  */
  
-asmlinkage long sys_oldumount(char * name)
+asmlinkage long sys_oldumount(char __user * name)
 {
 	return sys_umount(name,0);
 }
@@ -664,7 +664,7 @@
 	return err;
 }
 
-static int copy_mount_options (const void *data, unsigned long *where)
+static int copy_mount_options (const void __user *data, unsigned long *where)
 {
 	int i;
 	unsigned long page;
@@ -842,8 +842,9 @@
 	return -ENOMEM;
 }
 
-asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type,
-			  unsigned long flags, void * data)
+asmlinkage long sys_mount(char __user * dev_name, char __user * dir_name,
+			  char __user * type, unsigned long flags,
+			  void __user * data)
 {
 	int retval;
 	unsigned long data_page;
@@ -963,7 +964,7 @@
  *    first.
  */
 
-asmlinkage long sys_pivot_root(const char *new_root, const char *put_old)
+asmlinkage long sys_pivot_root(const char __user *new_root, const char __user *put_old)
 {
 	struct vfsmount *tmp;
 	struct nameidata new_nd, old_nd, parent_nd, root_parent, user_nd;
diff -urN linux-2.5.67-bk7/fs/nfsctl.c linux-2.5.67-bk8/fs/nfsctl.c
--- linux-2.5.67-bk7/fs/nfsctl.c	2003-04-07 10:33:02.000000000 -0700
+++ linux-2.5.67-bk8/fs/nfsctl.c	2003-04-17 04:38:37.000000000 -0700
@@ -87,10 +87,10 @@
 };
 
 long
-asmlinkage sys_nfsservctl(int cmd, struct nfsctl_arg *arg, void *res)
+asmlinkage sys_nfsservctl(int cmd, struct nfsctl_arg __user *arg, void __user *res)
 {
 	struct file *file;
-	void *p = &arg->u;
+	void __user *p = &arg->u;
 	int version;
 	int err;
 
diff -urN linux-2.5.67-bk7/fs/read_write.c linux-2.5.67-bk8/fs/read_write.c
--- linux-2.5.67-bk7/fs/read_write.c	2003-04-17 04:38:27.000000000 -0700
+++ linux-2.5.67-bk8/fs/read_write.c	2003-04-17 04:38:37.000000000 -0700
@@ -335,7 +335,7 @@
 			       const struct iovec __user * uvector,
 			       unsigned long nr_segs, loff_t *pos)
 {
-	typedef ssize_t (*io_fn_t)(struct file *, char *, size_t, loff_t *);
+	typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *);
 	typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
 
 	size_t tot_len;
@@ -423,7 +423,7 @@
 	ret = 0;
 	vector = iov;
 	while (nr_segs > 0) {
-		void * base;
+		void __user * base;
 		size_t len;
 		ssize_t nr;
 
diff -urN linux-2.5.67-bk7/include/asm-parisc/compat.h linux-2.5.67-bk8/include/asm-parisc/compat.h
--- linux-2.5.67-bk7/include/asm-parisc/compat.h	2003-04-07 10:33:03.000000000 -0700
+++ linux-2.5.67-bk8/include/asm-parisc/compat.h	2003-04-17 04:38:38.000000000 -0700
@@ -99,6 +99,8 @@
 	s32		f_spare[6];
 };
 
+#define COMPAT_RLIM_INFINITY 0xffffffff
+
 typedef u32		compat_old_sigset_t;	/* at least 32 bits */
 
 #define _COMPAT_NSIG		64
diff -urN linux-2.5.67-bk7/include/asm-ppc64/compat.h linux-2.5.67-bk8/include/asm-ppc64/compat.h
--- linux-2.5.67-bk7/include/asm-ppc64/compat.h	2003-04-07 10:30:57.000000000 -0700
+++ linux-2.5.67-bk8/include/asm-ppc64/compat.h	2003-04-17 04:38:38.000000000 -0700
@@ -93,6 +93,9 @@
 	int		f_spare[6];
 };
 
+#define COMPAT_RLIM_OLD_INFINITY	0x7fffffff
+#define COMPAT_RLIM_INFINITY		0xffffffff
+
 typedef u32		compat_old_sigset_t;
 
 #define _COMPAT_NSIG		64
diff -urN linux-2.5.67-bk7/include/asm-s390/compat.h linux-2.5.67-bk8/include/asm-s390/compat.h
--- linux-2.5.67-bk7/include/asm-s390/compat.h	2003-04-17 04:38:27.000000000 -0700
+++ linux-2.5.67-bk8/include/asm-s390/compat.h	2003-04-17 04:38:38.000000000 -0700
@@ -96,6 +96,9 @@
 	s32		f_spare[6];
 };
 
+#define COMPAT_RLIM_OLD_INFINITY	0x7fffffff
+#define COMPAT_RLIM_INFINITY		0xffffffff
+
 typedef u32		compat_old_sigset_t;	/* at least 32 bits */
 
 #define _COMPAT_NSIG		64
diff -urN linux-2.5.67-bk7/include/asm-sparc64/compat.h linux-2.5.67-bk8/include/asm-sparc64/compat.h
--- linux-2.5.67-bk7/include/asm-sparc64/compat.h	2003-04-07 10:31:51.000000000 -0700
+++ linux-2.5.67-bk8/include/asm-sparc64/compat.h	2003-04-17 04:38:38.000000000 -0700
@@ -95,6 +95,8 @@
 	int		f_spare[6];
 };
 
+#define COMPAT_RLIM_INFINITY 0x7fffffff
+
 typedef u32		compat_old_sigset_t;
 
 #define _COMPAT_NSIG		64
diff -urN linux-2.5.67-bk7/include/asm-x86_64/compat.h linux-2.5.67-bk8/include/asm-x86_64/compat.h
--- linux-2.5.67-bk7/include/asm-x86_64/compat.h	2003-04-07 10:32:16.000000000 -0700
+++ linux-2.5.67-bk8/include/asm-x86_64/compat.h	2003-04-17 04:38:38.000000000 -0700
@@ -102,6 +102,9 @@
 	int		f_spare[6];
 };
 
+#define COMPAT_RLIM_OLD_INFINITY	0x7fffffff
+#define COMPAT_RLIM_INFINITY		0xffffffff
+
 typedef u32		compat_old_sigset_t;	/* at least 32 bits */
 
 #define _COMPAT_NSIG		64
diff -urN linux-2.5.67-bk7/include/linux/binfmts.h linux-2.5.67-bk8/include/linux/binfmts.h
--- linux-2.5.67-bk7/include/linux/binfmts.h	2003-04-07 10:31:25.000000000 -0700
+++ linux-2.5.67-bk8/include/linux/binfmts.h	2003-04-17 04:38:38.000000000 -0700
@@ -56,7 +56,7 @@
 extern int search_binary_handler(struct linux_binprm *,struct pt_regs *);
 extern int flush_old_exec(struct linux_binprm * bprm);
 extern int setup_arg_pages(struct linux_binprm * bprm);
-extern int copy_strings(int argc,char ** argv,struct linux_binprm *bprm); 
+extern int copy_strings(int argc,char __user * __user * argv,struct linux_binprm *bprm); 
 extern int copy_strings_kernel(int argc,char ** argv,struct linux_binprm *bprm);
 extern void compute_creds(struct linux_binprm *binprm);
 extern int do_coredump(long signr, int exit_code, struct pt_regs * regs);
diff -urN linux-2.5.67-bk7/include/linux/compat.h linux-2.5.67-bk8/include/linux/compat.h
--- linux-2.5.67-bk7/include/linux/compat.h	2003-04-07 10:31:15.000000000 -0700
+++ linux-2.5.67-bk8/include/linux/compat.h	2003-04-17 04:38:38.000000000 -0700
@@ -47,5 +47,29 @@
 	compat_size_t	iov_len;
 };
 
+struct compat_rlimit {
+	compat_ulong_t	rlim_cur;
+	compat_ulong_t	rlim_max;
+};
+
+struct compat_rusage {
+	struct compat_timeval ru_utime;
+	struct compat_timeval ru_stime;
+	compat_long_t	ru_maxrss;
+	compat_long_t	ru_ixrss;
+	compat_long_t	ru_idrss;
+	compat_long_t	ru_isrss;
+	compat_long_t	ru_minflt;
+	compat_long_t	ru_majflt;
+	compat_long_t	ru_nswap;
+	compat_long_t	ru_inblock;
+	compat_long_t	ru_oublock;
+	compat_long_t	ru_msgsnd;
+	compat_long_t	ru_msgrcv;
+	compat_long_t	ru_nsignals;
+	compat_long_t	ru_nvcsw;
+	compat_long_t	ru_nivcsw;
+};
+
 #endif /* CONFIG_COMPAT */
 #endif /* _LINUX_COMPAT_H */
diff -urN linux-2.5.67-bk7/include/linux/fs.h linux-2.5.67-bk8/include/linux/fs.h
--- linux-2.5.67-bk7/include/linux/fs.h	2003-04-17 04:38:27.000000000 -0700
+++ linux-2.5.67-bk8/include/linux/fs.h	2003-04-17 04:38:38.000000000 -0700
@@ -752,11 +752,11 @@
 
 struct seq_file;
 
-extern ssize_t vfs_read(struct file *, char *, size_t, loff_t *);
-extern ssize_t vfs_write(struct file *, const char *, size_t, loff_t *);
-extern ssize_t vfs_readv(struct file *, const struct iovec *,
+extern ssize_t vfs_read(struct file *, char __user *, size_t, loff_t *);
+extern ssize_t vfs_write(struct file *, const char __user *, size_t, loff_t *);
+extern ssize_t vfs_readv(struct file *, const struct iovec __user *,
 		unsigned long, loff_t *);
-extern ssize_t vfs_writev(struct file *, const struct iovec *,
+extern ssize_t vfs_writev(struct file *, const struct iovec __user *,
 		unsigned long, loff_t *);
 
 /*
@@ -1202,16 +1202,16 @@
 extern int generic_file_readonly_mmap(struct file *, struct vm_area_struct *);
 extern int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size);
 extern int file_send_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size);
-extern ssize_t generic_file_read(struct file *, char *, size_t, loff_t *);
+extern ssize_t generic_file_read(struct file *, char __user *, size_t, loff_t *);
 int generic_write_checks(struct inode *inode, struct file *file,
 			loff_t *pos, size_t *count, int isblk);
-extern ssize_t generic_file_write(struct file *, const char *, size_t, loff_t *);
+extern ssize_t generic_file_write(struct file *, const char __user *, size_t, loff_t *);
 extern ssize_t generic_file_aio_read(struct kiocb *, char *, size_t, loff_t);
 extern ssize_t generic_file_aio_write(struct kiocb *, const char *, size_t, loff_t);
 extern ssize_t generic_file_aio_write_nolock(struct kiocb *, const struct iovec *,
 				unsigned long, loff_t *);
-extern ssize_t do_sync_read(struct file *filp, char *buf, size_t len, loff_t *ppos);
-extern ssize_t do_sync_write(struct file *filp, const char *buf, size_t len, loff_t *ppos);
+extern ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos);
+extern ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos);
 ssize_t generic_file_write_nolock(struct file *file, const struct iovec *iov,
 				unsigned long nr_segs, loff_t *ppos);
 extern ssize_t generic_file_sendfile(struct file *, loff_t *, size_t, read_actor_t, void *);
@@ -1247,9 +1247,9 @@
 
 extern struct file_operations generic_ro_fops;
 
-extern int vfs_readlink(struct dentry *, char *, int, const char *);
+extern int vfs_readlink(struct dentry *, char __user *, int, const char *);
 extern int vfs_follow_link(struct nameidata *, const char *);
-extern int page_readlink(struct dentry *, char *, int);
+extern int page_readlink(struct dentry *, char __user *, int);
 extern int page_follow_link(struct dentry *, struct nameidata *);
 extern int page_symlink(struct inode *inode, const char *symname, int len);
 extern struct inode_operations page_symlink_inode_operations;
diff -urN linux-2.5.67-bk7/include/linux/icmpv6.h linux-2.5.67-bk8/include/linux/icmpv6.h
--- linux-2.5.67-bk7/include/linux/icmpv6.h	2003-04-07 10:30:58.000000000 -0700
+++ linux-2.5.67-bk8/include/linux/icmpv6.h	2003-04-17 04:38:38.000000000 -0700
@@ -86,6 +86,19 @@
 #define ICMPV6_MGM_REPORT       	131
 #define ICMPV6_MGM_REDUCTION    	132
 
+/* definitions for MLDv2 */
+
+#define MLD2_MODE_IS_INCLUDE	1
+#define MLD2_MODE_IS_EXCLUDE	2
+#define MLD2_CHANGE_TO_INCLUDE	3
+#define MLD2_CHANGE_TO_EXCLUDE	4
+#define MLD2_ALLOW_NEW_SOURCES	5
+#define MLD2_BLOCK_OLD_SOURCES	6
+
+/* this must be an IANA-assigned value; 206 for testing only */
+#define ICMPV6_MLD2_REPORT		206
+#define MLD2_ALL_MCR_INIT { { { 0xff,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0,0x16 } } }
+
 /*
  *	Codes for Destination Unreachable
  */
diff -urN linux-2.5.67-bk7/include/linux/in.h linux-2.5.67-bk8/include/linux/in.h
--- linux-2.5.67-bk7/include/linux/in.h	2003-04-17 04:38:27.000000000 -0700
+++ linux-2.5.67-bk8/include/linux/in.h	2003-04-17 04:38:38.000000000 -0700
@@ -90,6 +90,13 @@
 #define IP_ADD_SOURCE_MEMBERSHIP	39
 #define IP_DROP_SOURCE_MEMBERSHIP	40
 #define IP_MSFILTER			41
+#define MCAST_JOIN_GROUP		42
+#define MCAST_BLOCK_SOURCE		43
+#define MCAST_UNBLOCK_SOURCE		44
+#define MCAST_LEAVE_GROUP		45
+#define MCAST_JOIN_SOURCE_GROUP		46
+#define MCAST_LEAVE_SOURCE_GROUP	47
+#define MCAST_MSFILTER			48
 
 #define MCAST_EXCLUDE	0
 #define MCAST_INCLUDE	1
@@ -131,6 +138,32 @@
 	(sizeof(struct ip_msfilter) - sizeof(__u32) \
 	+ (numsrc) * sizeof(__u32))
 
+struct group_req
+{
+	__u32			gr_interface;	/* interface index */
+	struct sockaddr_storage	gr_group;	/* group address */
+};
+
+struct group_source_req
+{
+	__u32			gsr_interface;	/* interface index */
+	struct sockaddr_storage	gsr_group;	/* group address */
+	struct sockaddr_storage	gsr_source;	/* source address */
+};
+
+struct group_filter
+{
+	__u32			gf_interface;	/* interface index */
+	struct sockaddr_storage	gf_group;	/* multicast address */
+	__u32			gf_fmode;	/* filter mode */
+	__u32			gf_numsrc;	/* number of sources */
+	struct sockaddr_storage	gf_slist[1];	/* interface index */
+};
+
+#define GROUP_FILTER_SIZE(numsrc) \
+	(sizeof(struct group_filter) - sizeof(struct sockaddr_storage) \
+	+ (numsrc) * sizeof(struct sockaddr_storage))
+
 struct in_pktinfo
 {
 	int		ipi_ifindex;
diff -urN linux-2.5.67-bk7/include/linux/ip.h linux-2.5.67-bk8/include/linux/ip.h
--- linux-2.5.67-bk7/include/linux/ip.h	2003-04-07 10:30:59.000000000 -0700
+++ linux-2.5.67-bk8/include/linux/ip.h	2003-04-17 04:38:38.000000000 -0700
@@ -79,6 +79,7 @@
 #define	IPOPT_TS_PRESPEC	3		/* specified modules only */
 
 #ifdef __KERNEL__
+#include <linux/config.h>
 #include <linux/types.h>
 #include <net/sock.h>
 #include <linux/igmp.h>
diff -urN linux-2.5.67-bk7/include/linux/netfilter_ipv4/ip_conntrack_amanda.h linux-2.5.67-bk8/include/linux/netfilter_ipv4/ip_conntrack_amanda.h
--- linux-2.5.67-bk7/include/linux/netfilter_ipv4/ip_conntrack_amanda.h	2003-04-07 10:30:42.000000000 -0700
+++ linux-2.5.67-bk8/include/linux/netfilter_ipv4/ip_conntrack_amanda.h	2003-04-17 04:38:38.000000000 -0700
@@ -11,14 +11,6 @@
 
 #endif
 
-struct conn {
-	char* match;
-	int matchlen;
-};
-
-#define NUM_MSGS 	3
-
-
 struct ip_ct_amanda_expect
 {
 	u_int16_t port;		/* port number of this expectation */
diff -urN linux-2.5.67-bk7/include/linux/netfilter_ipv4/ip_conntrack_core.h linux-2.5.67-bk8/include/linux/netfilter_ipv4/ip_conntrack_core.h
--- linux-2.5.67-bk7/include/linux/netfilter_ipv4/ip_conntrack_core.h	2003-04-07 10:33:02.000000000 -0700
+++ linux-2.5.67-bk8/include/linux/netfilter_ipv4/ip_conntrack_core.h	2003-04-17 04:38:38.000000000 -0700
@@ -24,9 +24,11 @@
 extern struct ip_conntrack *icmp_error_track(struct sk_buff *skb,
 					     enum ip_conntrack_info *ctinfo,
 					     unsigned int hooknum);
-extern int get_tuple(const struct iphdr *iph, size_t len,
+extern int get_tuple(const struct iphdr *iph,
+		     const struct sk_buff *skb,
+		     unsigned int dataoff,
 		     struct ip_conntrack_tuple *tuple,
-		     struct ip_conntrack_protocol *protocol);
+		     const struct ip_conntrack_protocol *protocol);
 
 /* Find a connection corresponding to a tuple. */
 struct ip_conntrack_tuple_hash *
diff -urN linux-2.5.67-bk7/include/linux/netfilter_ipv4/ip_conntrack_helper.h linux-2.5.67-bk8/include/linux/netfilter_ipv4/ip_conntrack_helper.h
--- linux-2.5.67-bk7/include/linux/netfilter_ipv4/ip_conntrack_helper.h	2003-04-07 10:30:43.000000000 -0700
+++ linux-2.5.67-bk8/include/linux/netfilter_ipv4/ip_conntrack_helper.h	2003-04-17 04:38:38.000000000 -0700
@@ -25,7 +25,7 @@
 	
 	/* Function to call when data passes; return verdict, or -1 to
            invalidate. */
-	int (*help)(const struct iphdr *, size_t len,
+	int (*help)(struct sk_buff *skb,
 		    struct ip_conntrack *ct,
 		    enum ip_conntrack_info conntrackinfo);
 };
diff -urN linux-2.5.67-bk7/include/linux/netfilter_ipv4/ip_conntrack_irc.h linux-2.5.67-bk8/include/linux/netfilter_ipv4/ip_conntrack_irc.h
--- linux-2.5.67-bk7/include/linux/netfilter_ipv4/ip_conntrack_irc.h	2003-04-07 10:31:04.000000000 -0700
+++ linux-2.5.67-bk8/include/linux/netfilter_ipv4/ip_conntrack_irc.h	2003-04-17 04:38:38.000000000 -0700
@@ -37,11 +37,6 @@
 
 #define IRC_PORT	6667
 
-struct dccproto {
-	char* match;
-	int matchlen;
-};
-
 /* Protects irc part of conntracks */
 DECLARE_LOCK_EXTERN(ip_irc_lock);
 
diff -urN linux-2.5.67-bk7/include/linux/netfilter_ipv4/ip_conntrack_protocol.h linux-2.5.67-bk8/include/linux/netfilter_ipv4/ip_conntrack_protocol.h
--- linux-2.5.67-bk7/include/linux/netfilter_ipv4/ip_conntrack_protocol.h	2003-04-07 10:32:51.000000000 -0700
+++ linux-2.5.67-bk8/include/linux/netfilter_ipv4/ip_conntrack_protocol.h	2003-04-17 04:38:38.000000000 -0700
@@ -14,9 +14,11 @@
 	/* Protocol name */
 	const char *name;
 
-	/* Try to fill in the third arg; return true if possible. */
-	int (*pkt_to_tuple)(const void *datah, size_t datalen,
-			    struct ip_conntrack_tuple *tuple);
+	/* Try to fill in the third arg: dataoff is offset past IP
+           hdr.  Return true if possible. */
+	int (*pkt_to_tuple)(const struct sk_buff *skb,
+			   unsigned int dataoff,
+			   struct ip_conntrack_tuple *tuple);
 
 	/* Invert the per-proto part of the tuple: ie. turn xmit into reply.
 	 * Some packets can't be inverted: return 0 in that case.
@@ -34,20 +36,19 @@
 
 	/* Returns verdict for packet, or -1 for invalid. */
 	int (*packet)(struct ip_conntrack *conntrack,
-		      struct iphdr *iph, size_t len,
+		      const struct sk_buff *skb,
 		      enum ip_conntrack_info ctinfo);
 
 	/* Called when a new connection for this protocol found;
 	 * returns TRUE if it's OK.  If so, packet() called next. */
-	int (*new)(struct ip_conntrack *conntrack, struct iphdr *iph,
-		   size_t len);
+	int (*new)(struct ip_conntrack *conntrack, const struct sk_buff *skb);
 
 	/* Called when a conntrack entry is destroyed */
 	void (*destroy)(struct ip_conntrack *conntrack);
 
 	/* Has to decide if a expectation matches one packet or not */
 	int (*exp_matches_pkt)(struct ip_conntrack_expect *exp,
-			       struct sk_buff **pskb);
+			       const struct sk_buff *skb);
 
 	/* Module (if any) which this is connected to. */
 	struct module *me;
diff -urN linux-2.5.67-bk7/include/linux/nfsd/syscall.h linux-2.5.67-bk8/include/linux/nfsd/syscall.h
--- linux-2.5.67-bk7/include/linux/nfsd/syscall.h	2003-04-17 04:38:27.000000000 -0700
+++ linux-2.5.67-bk8/include/linux/nfsd/syscall.h	2003-04-17 04:38:38.000000000 -0700
@@ -116,7 +116,7 @@
 /*
  * Kernel syscall implementation.
  */
-extern asmlinkage long	sys_nfsservctl(int, struct nfsctl_arg *, void *);
+extern asmlinkage long	sys_nfsservctl(int, struct nfsctl_arg __user *, void __user *);
 extern int		exp_addclient(struct nfsctl_client *ncp);
 extern int		exp_delclient(struct nfsctl_client *ncp);
 extern int		exp_export(struct nfsctl_export *nxp);
diff -urN linux-2.5.67-bk7/include/linux/pci_ids.h linux-2.5.67-bk8/include/linux/pci_ids.h
--- linux-2.5.67-bk7/include/linux/pci_ids.h	2003-04-17 04:38:27.000000000 -0700
+++ linux-2.5.67-bk8/include/linux/pci_ids.h	2003-04-17 04:38:38.000000000 -0700
@@ -1753,6 +1753,9 @@
 #define PCI_DEVICE_ID_AKS_ALADDINCARD	0x0100
 #define PCI_DEVICE_ID_AKS_CPC		0x0200
 
+#define PCI_VENDOR_ID_REDCREEK		0x4916
+#define PCI_DEVICE_ID_RC45		0x1960
+
 #define PCI_VENDOR_ID_NETVIN		0x4a14
 #define PCI_DEVICE_ID_NETVIN_NV5000SC	0x5000
 
diff -urN linux-2.5.67-bk7/include/linux/sched.h linux-2.5.67-bk8/include/linux/sched.h
--- linux-2.5.67-bk7/include/linux/sched.h	2003-04-17 04:38:27.000000000 -0700
+++ linux-2.5.67-bk8/include/linux/sched.h	2003-04-17 04:38:38.000000000 -0700
@@ -629,7 +629,7 @@
 extern int allow_signal(int);
 extern task_t *child_reaper;
 
-extern int do_execve(char *, char **, char **, struct pt_regs *);
+extern int do_execve(char *, char __user * __user *, char __user * __user *, struct pt_regs *);
 extern struct task_struct *do_fork(unsigned long, unsigned long, struct pt_regs *, unsigned long, int *, int *);
 
 #ifdef CONFIG_SMP
diff -urN linux-2.5.67-bk7/include/linux/tcp.h linux-2.5.67-bk8/include/linux/tcp.h
--- linux-2.5.67-bk7/include/linux/tcp.h	2003-04-07 10:31:18.000000000 -0700
+++ linux-2.5.67-bk8/include/linux/tcp.h	2003-04-17 04:38:38.000000000 -0700
@@ -17,6 +17,7 @@
 #ifndef _LINUX_TCP_H
 #define _LINUX_TCP_H
 
+#include <linux/config.h>
 #include <linux/skbuff.h>
 #include <asm/byteorder.h>
 #include <net/sock.h>
diff -urN linux-2.5.67-bk7/include/linux/udp.h linux-2.5.67-bk8/include/linux/udp.h
--- linux-2.5.67-bk7/include/linux/udp.h	2003-04-07 10:30:57.000000000 -0700
+++ linux-2.5.67-bk8/include/linux/udp.h	2003-04-17 04:38:38.000000000 -0700
@@ -17,6 +17,7 @@
 #ifndef _LINUX_UDP_H
 #define _LINUX_UDP_H
 
+#include <linux/config.h>
 #include <asm/byteorder.h>
 #include <net/sock.h>
 #include <linux/ip.h>
diff -urN linux-2.5.67-bk7/include/linux/uio.h linux-2.5.67-bk8/include/linux/uio.h
--- linux-2.5.67-bk7/include/linux/uio.h	2003-04-07 10:31:56.000000000 -0700
+++ linux-2.5.67-bk8/include/linux/uio.h	2003-04-17 04:38:38.000000000 -0700
@@ -1,6 +1,7 @@
 #ifndef __LINUX_UIO_H
 #define __LINUX_UIO_H
 
+#include <linux/compiler.h>
 #include <linux/types.h>
 
 /*
@@ -18,7 +19,7 @@
 
 struct iovec
 {
-	void *iov_base;		/* BSD uses caddr_t (1003.1g requires void *) */
+	void __user *iov_base;	/* BSD uses caddr_t (1003.1g requires void *) */
 	__kernel_size_t iov_len; /* Must be size_t (1003.1g) */
 };
 
diff -urN linux-2.5.67-bk7/include/net/addrconf.h linux-2.5.67-bk8/include/net/addrconf.h
--- linux-2.5.67-bk7/include/net/addrconf.h	2003-04-07 10:32:21.000000000 -0700
+++ linux-2.5.67-bk8/include/net/addrconf.h	2003-04-17 04:38:38.000000000 -0700
@@ -76,49 +76,38 @@
 /*
  *	multicast prototypes (mcast.c)
  */
-extern int			ipv6_sock_mc_join(struct sock *sk, 
-						  int ifindex, 
-						  struct in6_addr *addr);
-extern int			ipv6_sock_mc_drop(struct sock *sk,
-						  int ifindex, 
-						  struct in6_addr *addr);
-extern void			ipv6_sock_mc_close(struct sock *sk);
-extern int			inet6_mc_check(struct sock *sk, struct in6_addr *addr);
-
-extern int			ipv6_dev_mc_inc(struct net_device *dev,
-						struct in6_addr *addr);
-extern int			ipv6_dev_mc_dec(struct net_device *dev,
-						struct in6_addr *addr);
-extern void			ipv6_mc_up(struct inet6_dev *idev);
-extern void			ipv6_mc_down(struct inet6_dev *idev);
-extern void			ipv6_mc_init_dev(struct inet6_dev *idev);
-extern void			ipv6_mc_destroy_dev(struct inet6_dev *idev);
-extern void			addrconf_dad_failure(struct inet6_ifaddr *ifp);
+extern int ipv6_sock_mc_join(struct sock *sk, int ifindex, 
+		  struct in6_addr *addr);
+extern int ipv6_sock_mc_drop(struct sock *sk, int ifindex, 
+		  struct in6_addr *addr);
+extern void ipv6_sock_mc_close(struct sock *sk);
+extern int inet6_mc_check(struct sock *sk, struct in6_addr *mc_addr,
+		struct in6_addr *src_addr);
+
+extern int ipv6_dev_mc_inc(struct net_device *dev, struct in6_addr *addr);
+extern int ipv6_dev_mc_dec(struct net_device *dev, struct in6_addr *addr);
+extern void ipv6_mc_up(struct inet6_dev *idev);
+extern void ipv6_mc_down(struct inet6_dev *idev);
+extern void ipv6_mc_init_dev(struct inet6_dev *idev);
+extern void ipv6_mc_destroy_dev(struct inet6_dev *idev);
+extern void addrconf_dad_failure(struct inet6_ifaddr *ifp);
 
-extern int			ipv6_chk_mcast_addr(struct net_device *dev,
-						    struct in6_addr *addr);
+extern int ipv6_chk_mcast_addr(struct net_device *dev, struct in6_addr *group,
+		struct in6_addr *src_addr);
 
-extern void			addrconf_prefix_rcv(struct net_device *dev,
-						    u8 *opt, int len);
+extern void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len);
 
 /*
  *	anycast prototypes (anycast.c)
  */
-extern int			ipv6_sock_ac_join(struct sock *sk, 
-						  int ifindex, 
-						  struct in6_addr *addr);
-extern int			ipv6_sock_ac_drop(struct sock *sk,
-						  int ifindex, 
-						  struct in6_addr *addr);
-extern void			ipv6_sock_ac_close(struct sock *sk);
-extern int			inet6_ac_check(struct sock *sk, struct in6_addr *addr, int ifindex);
-
-extern int			ipv6_dev_ac_inc(struct net_device *dev,
-						struct in6_addr *addr);
-extern int			ipv6_dev_ac_dec(struct net_device *dev,
-						struct in6_addr *addr);
-extern int			ipv6_chk_acast_addr(struct net_device *dev,
-						struct in6_addr *addr);
+extern int ipv6_sock_ac_join(struct sock *sk,int ifindex,struct in6_addr *addr);
+extern int ipv6_sock_ac_drop(struct sock *sk,int ifindex,struct in6_addr *addr);
+extern void ipv6_sock_ac_close(struct sock *sk);
+extern int inet6_ac_check(struct sock *sk, struct in6_addr *addr, int ifindex);
+
+extern int ipv6_dev_ac_inc(struct net_device *dev, struct in6_addr *addr);
+extern int ipv6_dev_ac_dec(struct net_device *dev, struct in6_addr *addr);
+extern int ipv6_chk_acast_addr(struct net_device *dev, struct in6_addr *addr);
 
 
 /* Device notifier */
diff -urN linux-2.5.67-bk7/include/net/dst.h linux-2.5.67-bk8/include/net/dst.h
--- linux-2.5.67-bk7/include/net/dst.h	2003-04-07 10:32:49.000000000 -0700
+++ linux-2.5.67-bk8/include/net/dst.h	2003-04-17 04:38:38.000000000 -0700
@@ -11,6 +11,7 @@
 #include <linux/config.h>
 #include <linux/rtnetlink.h>
 #include <linux/rcupdate.h>
+#include <linux/jiffies.h>
 #include <net/neighbour.h>
 #include <asm/processor.h>
 
@@ -208,7 +209,7 @@
 	if (expires == 0)
 		expires = 1;
 
-	if (dst->expires == 0 || (long)(dst->expires - expires) > 0)
+	if (dst->expires == 0 || time_before(expires, dst->expires))
 		dst->expires = expires;
 }
 
diff -urN linux-2.5.67-bk7/include/net/icmp.h linux-2.5.67-bk8/include/net/icmp.h
--- linux-2.5.67-bk7/include/net/icmp.h	2003-04-07 10:32:26.000000000 -0700
+++ linux-2.5.67-bk8/include/net/icmp.h	2003-04-17 04:38:38.000000000 -0700
@@ -18,6 +18,7 @@
 #ifndef _ICMP_H
 #define	_ICMP_H
 
+#include <linux/config.h>
 #include <linux/icmp.h>
 #include <linux/skbuff.h>
 
diff -urN linux-2.5.67-bk7/include/net/if_inet6.h linux-2.5.67-bk8/include/net/if_inet6.h
--- linux-2.5.67-bk7/include/net/if_inet6.h	2003-04-07 10:32:52.000000000 -0700
+++ linux-2.5.67-bk8/include/net/if_inet6.h	2003-04-17 04:38:38.000000000 -0700
@@ -52,27 +52,58 @@
 	int			dead;
 };
 
+struct ip6_sf_socklist
+{
+	unsigned int		sl_max;
+	unsigned int		sl_count;
+	struct in6_addr		sl_addr[0];
+};
+
+#define IP6_SFLSIZE(count)	(sizeof(struct ip6_sf_socklist) + \
+	(count) * sizeof(struct in6_addr))
+
+#define IP6_SFBLOCK	10	/* allocate this many at once */
+
 struct ipv6_mc_socklist
 {
 	struct in6_addr		addr;
 	int			ifindex;
 	struct ipv6_mc_socklist *next;
+	unsigned int		sfmode;		/* MCAST_{INCLUDE,EXCLUDE} */
+	struct ip6_sf_socklist	*sflist;
+};
+
+struct ip6_sf_list
+{
+	struct ip6_sf_list	*sf_next;
+	struct in6_addr		sf_addr;
+	unsigned long		sf_count[2];	/* include/exclude counts */
+	unsigned char		sf_gsresp;	/* include in g & s response? */
+	unsigned char		sf_oldin;	/* change state */
+	unsigned char		sf_crcount;	/* retrans. left to send */
 };
 
 #define MAF_TIMER_RUNNING	0x01
 #define MAF_LAST_REPORTER	0x02
 #define MAF_LOADED		0x04
+#define MAF_NOREPORT		0x08
+#define MAF_GSQUERY		0x10
 
 struct ifmcaddr6
 {
 	struct in6_addr		mca_addr;
 	struct inet6_dev	*idev;
 	struct ifmcaddr6	*next;
+	struct ip6_sf_list	*mca_sources;
+	struct ip6_sf_list	*mca_tomb;
+	unsigned int		mca_sfmode;
+	unsigned long		mca_sfcount[2];
 	struct timer_list	mca_timer;
 	unsigned		mca_flags;
 	int			mca_users;
 	atomic_t		mca_refcnt;
 	spinlock_t		mca_lock;
+	unsigned char		mca_crcount;
 };
 
 /* Anycast stuff */
@@ -126,7 +157,18 @@
 	struct net_device		*dev;
 
 	struct inet6_ifaddr	*addr_list;
+
 	struct ifmcaddr6	*mc_list;
+	struct ifmcaddr6	*mc_tomb;
+	rwlock_t		mc_lock;
+	unsigned long		mc_v1_seen;
+	unsigned long		mc_maxdelay;
+	unsigned char		mc_qrv;
+	unsigned char		mc_gq_running;
+	unsigned char		mc_ifc_count;
+	struct timer_list	mc_gq_timer;	/* general query timer */
+	struct timer_list	mc_ifc_timer;	/* interface change timer */
+
 	struct ifacaddr6	*ac_list;
 	rwlock_t		lock;
 	atomic_t		refcnt;
diff -urN linux-2.5.67-bk7/include/net/protocol.h linux-2.5.67-bk8/include/net/protocol.h
--- linux-2.5.67-bk7/include/net/protocol.h	2003-04-07 10:31:08.000000000 -0700
+++ linux-2.5.67-bk8/include/net/protocol.h	2003-04-17 04:38:38.000000000 -0700
@@ -44,15 +44,17 @@
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
 struct inet6_protocol 
 {
-	int	(*handler)(struct sk_buff **skbp);
+	int	(*handler)(struct sk_buff **skb, unsigned int *nhoffp);
 
 	void	(*err_handler)(struct sk_buff *skb,
 			       struct inet6_skb_parm *opt,
 			       int type, int code, int offset,
 			       __u32 info);
-	int	no_policy;
+	unsigned int	flags;	/* INET6_PROTO_xxx */
 };
 
+#define INET6_PROTO_NOPOLICY	0x1
+#define INET6_PROTO_FINAL	0x2
 #endif
 
 /* This is used to register socket interfaces for IP protocols.  */
diff -urN linux-2.5.67-bk7/include/net/sock.h linux-2.5.67-bk8/include/net/sock.h
--- linux-2.5.67-bk7/include/net/sock.h	2003-04-07 10:32:16.000000000 -0700
+++ linux-2.5.67-bk8/include/net/sock.h	2003-04-17 04:38:38.000000000 -0700
@@ -453,7 +453,7 @@
 extern void sock_init_data(struct socket *sock, struct sock *sk);
 
 /**
- *	__sk_filter - run a packet through a socket filter
+ *	sk_filter - run a packet through a socket filter
  *	@sk: sock associated with &sk_buff
  *	@skb: buffer to filter
  *	@needlock: set to 1 if the sock is not locked by caller.
@@ -464,14 +464,16 @@
  * wrapper to sk_run_filter. It returns 0 if the packet should
  * be accepted or -EPERM if the packet should be tossed.
  *
- * This function should not be called directly, use sk_filter instead
- * to ensure that the LSM security check is also performed.
  */
 
-static inline int __sk_filter(struct sock *sk, struct sk_buff *skb, int needlock)
+static inline int sk_filter(struct sock *sk, struct sk_buff *skb, int needlock)
 {
-	int err = 0;
-
+	int err;
+	
+	err = security_sock_rcv_skb(sk, skb);
+	if (err)
+		return err;
+	
 	if (sk->filter) {
 		struct sk_filter *filter;
 		
@@ -518,17 +520,6 @@
 	atomic_add(sk_filter_len(fp), &sk->omem_alloc);
 }
 
-static inline int sk_filter(struct sock *sk, struct sk_buff *skb, int needlock)
-{
-	int err;
-	
-	err = security_sock_rcv_skb(sk, skb);
-	if (err)
-		return err;
-	
-	return __sk_filter(sk, skb, needlock);
-}
-
 /*
  * Socket reference counting postulates.
  *
diff -urN linux-2.5.67-bk7/include/net/xfrm.h linux-2.5.67-bk8/include/net/xfrm.h
--- linux-2.5.67-bk7/include/net/xfrm.h	2003-04-17 04:38:28.000000000 -0700
+++ linux-2.5.67-bk8/include/net/xfrm.h	2003-04-17 04:38:38.000000000 -0700
@@ -760,7 +760,7 @@
 extern int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type);
 extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler);
 extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler);
-extern int xfrm6_rcv(struct sk_buff **pskb);
+extern int xfrm6_rcv(struct sk_buff **pskb, unsigned int *nhoffp);
 extern int xfrm6_clear_mutable_options(struct sk_buff *skb, u16 *nh_offset, int dir);
 extern int xfrm_user_policy(struct sock *sk, int optname, u8 *optval, int optlen);
 
diff -urN linux-2.5.67-bk7/kernel/compat.c linux-2.5.67-bk8/kernel/compat.c
--- linux-2.5.67-bk7/kernel/compat.c	2003-04-17 04:38:28.000000000 -0700
+++ linux-2.5.67-bk8/kernel/compat.c	2003-04-17 04:38:38.000000000 -0700
@@ -227,6 +227,152 @@
 	return do_futex((unsigned long)uaddr, op, val, timeout);
 }
 
+asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit *rlim);
+
+asmlinkage long compat_sys_setrlimit(unsigned int resource, struct compat_rlimit *rlim)
+{
+	struct rlimit r;
+	int ret;
+	mm_segment_t old_fs = get_fs ();
+
+	if (resource >= RLIM_NLIMITS) 
+		return -EINVAL;	
+
+	if (!access_ok(VERIFY_READ, rlim, sizeof(*rlim)) ||
+	    __get_user(r.rlim_cur, &rlim->rlim_cur) ||
+	    __get_user(r.rlim_max, &rlim->rlim_max))
+		return -EFAULT;
+
+	if (r.rlim_cur == COMPAT_RLIM_INFINITY)
+		r.rlim_cur = RLIM_INFINITY;
+	if (r.rlim_max == COMPAT_RLIM_INFINITY)
+		r.rlim_max = RLIM_INFINITY;
+	set_fs(KERNEL_DS);
+	ret = sys_setrlimit(resource, &r);
+	set_fs(old_fs);
+	return ret;
+}
+
+#ifdef COMPAT_RLIM_OLD_INFINITY
+asmlinkage long sys_old_getrlimit(unsigned int resource, struct rlimit *rlim);
+
+asmlinkage long compat_sys_old_getrlimit(unsigned int resource, struct compat_rlimit *rlim)
+{
+	struct rlimit r;
+	int ret;
+	mm_segment_t old_fs = get_fs();
+
+	set_fs(KERNEL_DS);
+	ret = sys_old_getrlimit(resource, &r);
+	set_fs(old_fs);
+
+	if (!ret) {
+		if (r.rlim_cur > COMPAT_RLIM_OLD_INFINITY)
+			r.rlim_cur = COMPAT_RLIM_INFINITY;
+		if (r.rlim_max > COMPAT_RLIM_OLD_INFINITY)
+			r.rlim_max = COMPAT_RLIM_INFINITY;
+
+		if (!access_ok(VERIFY_WRITE, rlim, sizeof(*rlim)) ||
+		    __put_user(r.rlim_cur, &rlim->rlim_cur) ||
+		    __put_user(r.rlim_max, &rlim->rlim_max))
+			return -EFAULT;
+	}
+	return ret;
+}
+#endif
+
+asmlinkage long sys_getrlimit (unsigned int resource, struct rlimit *rlim);
+
+asmlinkage long compat_sys_getrlimit (unsigned int resource, struct compat_rlimit *rlim)
+{
+	struct rlimit r;
+	int ret;
+	mm_segment_t old_fs = get_fs();
+
+	set_fs(KERNEL_DS);
+	ret = sys_getrlimit(resource, &r);
+	set_fs(old_fs);
+	if (!ret) {
+		if (r.rlim_cur > COMPAT_RLIM_INFINITY)
+			r.rlim_cur = COMPAT_RLIM_INFINITY;
+		if (r.rlim_max > COMPAT_RLIM_INFINITY)
+			r.rlim_max = COMPAT_RLIM_INFINITY;
+
+		if (!access_ok(VERIFY_WRITE, rlim, sizeof(*rlim)) ||
+		    __put_user(r.rlim_cur, &rlim->rlim_cur) ||
+		    __put_user(r.rlim_max, &rlim->rlim_max))
+			return -EFAULT;
+	}
+	return ret;
+}
+
+static long put_compat_rusage (struct compat_rusage *ru, struct rusage *r)
+{
+	if (!access_ok(VERIFY_WRITE, ru, sizeof(*ru)) ||
+	    __put_user(r->ru_utime.tv_sec, &ru->ru_utime.tv_sec) ||
+	    __put_user(r->ru_utime.tv_usec, &ru->ru_utime.tv_usec) ||
+	    __put_user(r->ru_stime.tv_sec, &ru->ru_stime.tv_sec) ||
+	    __put_user(r->ru_stime.tv_usec, &ru->ru_stime.tv_usec) ||
+	    __put_user(r->ru_maxrss, &ru->ru_maxrss) ||
+	    __put_user(r->ru_ixrss, &ru->ru_ixrss) ||
+	    __put_user(r->ru_idrss, &ru->ru_idrss) ||
+	    __put_user(r->ru_isrss, &ru->ru_isrss) ||
+	    __put_user(r->ru_minflt, &ru->ru_minflt) ||
+	    __put_user(r->ru_majflt, &ru->ru_majflt) ||
+	    __put_user(r->ru_nswap, &ru->ru_nswap) ||
+	    __put_user(r->ru_inblock, &ru->ru_inblock) ||
+	    __put_user(r->ru_oublock, &ru->ru_oublock) ||
+	    __put_user(r->ru_msgsnd, &ru->ru_msgsnd) ||
+	    __put_user(r->ru_msgrcv, &ru->ru_msgrcv) ||
+	    __put_user(r->ru_nsignals, &ru->ru_nsignals) ||
+	    __put_user(r->ru_nvcsw, &ru->ru_nvcsw) ||
+	    __put_user(r->ru_nivcsw, &ru->ru_nivcsw))
+		return -EFAULT;
+	return 0;
+}
+
+asmlinkage long sys_getrusage(int who, struct rusage *ru);
+
+asmlinkage long compat_sys_getrusage(int who, struct compat_rusage *ru)
+{
+	struct rusage r;
+	int ret;
+	mm_segment_t old_fs = get_fs();
+		
+	set_fs(KERNEL_DS);
+	ret = sys_getrusage(who, &r);
+	set_fs(old_fs);
+
+	return ret || put_compat_rusage(ru, &r);
+}
+
+asmlinkage long
+compat_sys_wait4(compat_pid_t pid, compat_uint_t * stat_addr, int options,
+	struct compat_rusage *ru)
+{
+	if (!ru) {
+		return sys_wait4(pid, stat_addr, options, NULL);
+	} else {
+		struct rusage r;
+		int ret;
+		unsigned int status;
+		mm_segment_t old_fs = get_fs();
+
+		set_fs (KERNEL_DS);
+		ret = sys_wait4(pid, stat_addr ? &status : NULL, options, &r);
+		set_fs (old_fs);
+
+		if (!ret)
+		{
+			if (put_compat_rusage(ru, &r)) 
+				return -EFAULT;
+			if (stat_addr && put_user(status, stat_addr))
+				return -EFAULT;
+		}
+		return ret;
+	}
+}
+
 extern asmlinkage long sys_sched_setaffinity(pid_t pid, unsigned int len,
 					    unsigned long *user_mask_ptr);
 
diff -urN linux-2.5.67-bk7/net/ipv4/netfilter/ip_conntrack_amanda.c linux-2.5.67-bk8/net/ipv4/netfilter/ip_conntrack_amanda.c
--- linux-2.5.67-bk7/net/ipv4/netfilter/ip_conntrack_amanda.c	2003-04-07 10:31:56.000000000 -0700
+++ linux-2.5.67-bk8/net/ipv4/netfilter/ip_conntrack_amanda.c	2003-04-17 04:38:38.000000000 -0700
@@ -37,14 +37,8 @@
 MODULE_PARM_DESC(master_timeout, "timeout for the master connection");
 
 DECLARE_LOCK(ip_amanda_lock);
-struct module *ip_conntrack_amanda = THIS_MODULE;
 
-#define MAXMATCHLEN	6
-struct conn conns[NUM_MSGS] = {
-	{"DATA ", 5},
-	{"MESG ", 5},
-	{"INDEX ", 6},
-};
+char *conns[] = { "DATA ", "MESG ", "INDEX " };
 
 #if 0
 #define DEBUGP printk
@@ -52,18 +46,15 @@
 #define DEBUGP(format, args...)
 #endif
 
+/* This is slow, but it's simple. --RR */
+static char amanda_buffer[65536];
 
-/* FIXME: This should be in userspace.  Later. */
-static int help(const struct iphdr *iph, size_t len,
+static int help(struct sk_buff *skb,
 		struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
 {
-	struct udphdr *udph = (void *)iph + iph->ihl * 4;
-	u_int32_t udplen = len - iph->ihl * 4;
-	u_int32_t datalen = udplen - sizeof(struct udphdr);
-	char *data = (char *)udph + sizeof(struct udphdr);
-	char *datap = data;
-	char *data_limit = (char *) data + datalen;
+	char *data, *data_limit;
 	int dir = CTINFO2DIR(ctinfo);
+	unsigned int dataoff, i;
 	struct ip_ct_amanda *info =
 				(struct ip_ct_amanda *)&ct->help.ct_ftp_info;
 
@@ -79,121 +70,121 @@
 	if (dir == IP_CT_DIR_ORIGINAL)
 		return NF_ACCEPT;
 
-	/* Not whole UDP header? */
-	if (udplen < sizeof(struct udphdr)) {
-		printk("ip_conntrack_amanda_help: udplen = %u\n",
-		       (unsigned)udplen);
+	/* No data? */
+	dataoff = skb->nh.iph->ihl*4 + sizeof(struct udphdr);
+	if (dataoff >= skb->len) {
+		if (net_ratelimit())
+			printk("ip_conntrack_amanda_help: skblen = %u\n",
+			       (unsigned)skb->len);
 		return NF_ACCEPT;
 	}
 
-	/* Checksum invalid?  Ignore. */
-	if (csum_tcpudp_magic(iph->saddr, iph->daddr, udplen, IPPROTO_UDP,
-			      csum_partial((char *)udph, udplen, 0))) {
-		DEBUGP("ip_ct_talk_help: bad csum: %p %u %u.%u.%u.%u "
-		       "%u.%u.%u.%u\n",
-		       udph, udplen, NIPQUAD(iph->saddr),
-		       NIPQUAD(iph->daddr));
-		return NF_ACCEPT;
-	}
-	
+	LOCK_BH(&ip_amanda_lock);
+	skb_copy_bits(skb, dataoff, amanda_buffer, skb->len - dataoff);
+	data = amanda_buffer;
+	data_limit = amanda_buffer + skb->len - dataoff;
+	*data_limit = '\0';
+
 	/* Search for the CONNECT string */
-	while (data < data_limit) {
-		if (!memcmp(data, "CONNECT ", 8)) {
-			break;
-		}
-		data++;
-	}
-	if (memcmp(data, "CONNECT ", 8))
-		return NF_ACCEPT;
+	data = strstr(data, "CONNECT ");
+	if (!data)
+		goto out;
 
 	DEBUGP("ip_conntrack_amanda_help: CONNECT found in connection "
 		   "%u.%u.%u.%u:%u %u.%u.%u.%u:%u\n",
 		   NIPQUAD(iph->saddr), htons(udph->source),
 		   NIPQUAD(iph->daddr), htons(udph->dest));
-	data += 8;
-	while (*data != 0x0a && data < data_limit) {
+	data += strlen("CONNECT ");
 
-		int i;
-
-		for (i = 0; i < NUM_MSGS; i++) {
-			if (!memcmp(data, conns[i].match,
-				   conns[i].matchlen)) {
-
-				char *portchr;
-				struct ip_conntrack_expect expect;
-				struct ip_ct_amanda_expect
-				    *exp_amanda_info =
-					&expect.help.exp_amanda_info;
-
-				memset(&expect, 0, sizeof(expect));
-
-				data += conns[i].matchlen;
-				/* this is not really tcp, but let's steal an
-				 * idea from a tcp stream helper :-)
+	/* Only search first line. */	
+	if (strchr(data, '\n'))
+		*strchr(data, '\n') = '\0';
+
+	for (i = 0; i < ARRAY_SIZE(conns); i++) {
+		char *match = strstr(data, conns[i]);
+		if (match) {
+			char *portchr;
+			struct ip_conntrack_expect expect;
+			struct ip_ct_amanda_expect *exp_amanda_info =
+				&expect.help.exp_amanda_info;
+
+			memset(&expect, 0, sizeof(expect));
+
+			data += strlen(conns[i]);
+			/* this is not really tcp, but let's steal an
+			 * idea from a tcp stream helper :-) */
+			// XXX expect.seq = data - amanda_buffer;
+			exp_amanda_info->offset = data - amanda_buffer;
+// XXX DEBUGP("expect.seq = %p - %p = %d\n", data, amanda_buffer, expect.seq);
+DEBUGP("exp_amanda_info->offset = %p - %p = %d\n", data, amanda_buffer, exp_amanda_info->offset);
+			portchr = data;
+			exp_amanda_info->port = simple_strtoul(data, &data,10);
+			exp_amanda_info->len = data - portchr;
+
+			/* eat whitespace */
+			while (*data == ' ')
+				data++;
+			DEBUGP("ip_conntrack_amanda_help: "
+			       "CONNECT %s request with port "
+			       "%u found\n", conns[i],
+			       exp_amanda_info->port);
+
+			expect.tuple = ((struct ip_conntrack_tuple)
+				{ { ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip,
+				    { 0 } },
+				  { ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip,
+				    { htons(exp_amanda_info->port) },
+				    IPPROTO_TCP }});
+			expect.mask = ((struct ip_conntrack_tuple)
+				{ { 0, { 0 } },
+				  { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
+
+			expect.expectfn = NULL;
+
+			DEBUGP ("ip_conntrack_amanda_help: "
+				"expect_related: %u.%u.%u.%u:%u - "
+				"%u.%u.%u.%u:%u\n",
+				NIPQUAD(expect.tuple.src.ip),
+				ntohs(expect.tuple.src.u.tcp.port),
+				NIPQUAD(expect.tuple.dst.ip),
+				ntohs(expect.tuple.dst.u.tcp.port));
+			if (ip_conntrack_expect_related(ct, &expect)
+			    == -EEXIST) {
+				;
+				/* this must be a packet being resent */
+				/* XXX - how do I get the
+				 *       ip_conntrack_expect that
+				 *       already exists so that I can
+				 *       update the .seq so that the
+				 *       nat module rewrites the port
+				 *       numbers?
+				 *       Perhaps I should use the
+				 *       exp_amanda_info instead of
+				 *       .seq.
 				 */
-				// XXX expect.seq = data - datap;
-				exp_amanda_info->offset = data - datap;
-// XXX DEBUGP("expect.seq = %p - %p = %d\n", data, datap, expect.seq);
-DEBUGP("exp_amanda_info->offset = %p - %p = %d\n", data, datap, exp_amanda_info->offset);
-				portchr = data;
-				exp_amanda_info->port =
-				    simple_strtoul(data, &data, 10);
-				exp_amanda_info->len = data - portchr;
-
-				/* eat whitespace */
-				while (*data == ' ')
-					data++;
-				DEBUGP ("ip_conntrack_amanda_help: "
-					"CONNECT %s request with port "
-					"%u found\n", conns[i].match,
-					exp_amanda_info->port);
-
-				LOCK_BH(&ip_amanda_lock);
-
-				expect.tuple = ((struct ip_conntrack_tuple)
-						{ { ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip,
-						  { 0 } },
-				  		{ ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip,
-						  { htons(exp_amanda_info->port) },
-				    	  IPPROTO_TCP }});
-				expect.mask = ((struct ip_conntrack_tuple)
-							   { { 0, { 0 } },
-				  				 { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
-
-				expect.expectfn = NULL;
-
-				DEBUGP ("ip_conntrack_amanda_help: "
-					"expect_related: %u.%u.%u.%u:%u - "
-					"%u.%u.%u.%u:%u\n",
-					NIPQUAD(expect.tuple.src.ip),
-					ntohs(expect.tuple.src.u.tcp.port),
-					NIPQUAD(expect.tuple.dst.ip),
-					ntohs(expect.tuple.dst.u.tcp.port));
-				if (ip_conntrack_expect_related(ct, &expect) ==
-				    -EEXIST) {
-					;
-					/* this must be a packet being resent */
-					/* XXX - how do I get the
-					 *       ip_conntrack_expect that
-					 *       already exists so that I can
-					 *       update the .seq so that the
-					 *       nat module rewrites the port
-					 *       numbers?
-					 *       Perhaps I should use the
-					 *       exp_amanda_info instead of
-					 *       .seq.
-					 */
-				}
-				UNLOCK_BH(&ip_amanda_lock);
-			} /* if memcmp(conns) */
-		} /* for .. NUM_MSGS */
-		data++;
-	} /* while (*data != 0x0a && data < data_limit) */
-
+			}
+		}
+	}
+ out:
+	UNLOCK_BH(&ip_amanda_lock);
 	return NF_ACCEPT;
 }
 
-static struct ip_conntrack_helper amanda_helper;
+static struct ip_conntrack_helper amanda_helper = {
+	.max_expected = ARRAY_SIZE(conns),
+	.timeout = 180,
+	.flags = IP_CT_HELPER_F_REUSE_EXPECT,
+	.me = THIS_MODULE,
+	.help = help,
+	.name = "amanda",
+
+	.tuple = { .src = { .u = { __constant_htons(10080) } },
+		   .dst = { .protonum = IPPROTO_UDP },
+	},
+	.mask = { .src = { .u = { 0xFFFF } },
+		 .dst = { .protonum = 0xFFFF },
+	},
+};
 
 static void fini(void)
 {
@@ -205,20 +196,7 @@
 {
 	int ret;
 
-	memset(&amanda_helper, 0, sizeof(struct ip_conntrack_helper));
-	amanda_helper.tuple.src.u.udp.port = htons(10080);
-	amanda_helper.tuple.dst.protonum = IPPROTO_UDP;
-	amanda_helper.mask.src.u.udp.port = 0xFFFF;
-	amanda_helper.mask.dst.protonum = 0xFFFF;
-	amanda_helper.max_expected = NUM_MSGS;
-	amanda_helper.timeout = 180;
-	amanda_helper.flags = IP_CT_HELPER_F_REUSE_EXPECT;
-	amanda_helper.me = ip_conntrack_amanda;
-	amanda_helper.help = help;
-	amanda_helper.name = "amanda";
-
 	DEBUGP("ip_ct_amanda: registering helper for port 10080\n");
-
 	ret = ip_conntrack_helper_register(&amanda_helper);
 
 	if (ret) {
diff -urN linux-2.5.67-bk7/net/ipv4/netfilter/ip_conntrack_core.c linux-2.5.67-bk8/net/ipv4/netfilter/ip_conntrack_core.c
--- linux-2.5.67-bk7/net/ipv4/netfilter/ip_conntrack_core.c	2003-04-17 04:38:28.000000000 -0700
+++ linux-2.5.67-bk8/net/ipv4/netfilter/ip_conntrack_core.c	2003-04-17 04:38:38.000000000 -0700
@@ -120,31 +120,25 @@
 		% ip_conntrack_htable_size;
 }
 
-inline int
-get_tuple(const struct iphdr *iph, size_t len,
+int
+get_tuple(const struct iphdr *iph,
+	  const struct sk_buff *skb,
+	  unsigned int dataoff,
 	  struct ip_conntrack_tuple *tuple,
-	  struct ip_conntrack_protocol *protocol)
+	  const struct ip_conntrack_protocol *protocol)
 {
-	int ret;
-
 	/* Never happen */
 	if (iph->frag_off & htons(IP_OFFSET)) {
 		printk("ip_conntrack_core: Frag of proto %u.\n",
 		       iph->protocol);
 		return 0;
 	}
-	/* Guarantee 8 protocol bytes: if more wanted, use len param */
-	else if (iph->ihl * 4 + 8 > len)
-		return 0;
 
 	tuple->src.ip = iph->saddr;
 	tuple->dst.ip = iph->daddr;
 	tuple->dst.protonum = iph->protocol;
 
-	ret = protocol->pkt_to_tuple((u_int32_t *)iph + iph->ihl,
-				     len - 4*iph->ihl,
-				     tuple);
-	return ret;
+	return protocol->pkt_to_tuple(skb, dataoff, tuple);
 }
 
 static int
@@ -496,54 +490,40 @@
 		 enum ip_conntrack_info *ctinfo,
 		 unsigned int hooknum)
 {
-	const struct iphdr *iph;
-	struct icmphdr *hdr;
 	struct ip_conntrack_tuple innertuple, origtuple;
-	struct iphdr *inner;
-	size_t datalen;
+	struct {
+		struct icmphdr icmp;
+		struct iphdr ip;
+	} inside;
 	struct ip_conntrack_protocol *innerproto;
 	struct ip_conntrack_tuple_hash *h;
+	int dataoff;
 
-	IP_NF_ASSERT(iph->protocol == IPPROTO_ICMP);
 	IP_NF_ASSERT(skb->nfct == NULL);
 
-	iph = skb->nh.iph;
-	hdr = (struct icmphdr *)((u_int32_t *)iph + iph->ihl);
-	inner = (struct iphdr *)(hdr + 1);
-	datalen = skb->len - iph->ihl*4 - sizeof(*hdr);
-
-	if (skb->len < iph->ihl * 4 + sizeof(*hdr) + sizeof(*iph)) {
-		DEBUGP("icmp_error_track: too short\n");
+	/* Not enough header? */
+	if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &inside, sizeof(inside))!=0)
 		return NULL;
-	}
 
-	if (hdr->type != ICMP_DEST_UNREACH
-	    && hdr->type != ICMP_SOURCE_QUENCH
-	    && hdr->type != ICMP_TIME_EXCEEDED
-	    && hdr->type != ICMP_PARAMETERPROB
-	    && hdr->type != ICMP_REDIRECT)
+	if (inside.icmp.type != ICMP_DEST_UNREACH
+	    && inside.icmp.type != ICMP_SOURCE_QUENCH
+	    && inside.icmp.type != ICMP_TIME_EXCEEDED
+	    && inside.icmp.type != ICMP_PARAMETERPROB
+	    && inside.icmp.type != ICMP_REDIRECT)
 		return NULL;
 
 	/* Ignore ICMP's containing fragments (shouldn't happen) */
-	if (inner->frag_off & htons(IP_OFFSET)) {
+	if (inside.ip.frag_off & htons(IP_OFFSET)) {
 		DEBUGP("icmp_error_track: fragment of proto %u\n",
-		       inner->protocol);
-		return NULL;
-	}
-
-	/* Ignore it if the checksum's bogus. */
-	if (ip_compute_csum((unsigned char *)hdr, sizeof(*hdr) + datalen)) {
-		DEBUGP("icmp_error_track: bad csum\n");
+		       inside.ip.protocol);
 		return NULL;
 	}
 
-	innerproto = ip_ct_find_proto(inner->protocol);
+	innerproto = ip_ct_find_proto(inside.ip.protocol);
+	dataoff = skb->nh.iph->ihl*4 + sizeof(inside.icmp) + inside.ip.ihl*4;
 	/* Are they talking about one of our connections? */
-	if (inner->ihl * 4 + 8 > datalen
-	    || !get_tuple(inner, datalen, &origtuple, innerproto)) {
-		DEBUGP("icmp_error: ! get_tuple p=%u (%u*4+%u dlen=%u)\n",
-		       inner->protocol, inner->ihl, 8,
-		       datalen);
+	if (!get_tuple(&inside.ip, skb, dataoff, &origtuple, innerproto)) {
+		DEBUGP("icmp_error: ! get_tuple p=%u", inside.ip.protocol);
 		return NULL;
 	}
 
@@ -679,7 +659,7 @@
 	for (i=0; i < IP_CT_NUMBER; i++)
 		conntrack->infos[i].master = &conntrack->ct_general;
 
-	if (!protocol->new(conntrack, skb->nh.iph, skb->len)) {
+	if (!protocol->new(conntrack, skb)) {
 		kmem_cache_free(ip_conntrack_cachep, conntrack);
 		return NULL;
 	}
@@ -748,7 +728,7 @@
 
 	IP_NF_ASSERT((skb->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
 
-	if (!get_tuple(skb->nh.iph, skb->len, &tuple, proto))
+	if (!get_tuple(skb->nh.iph, skb, skb->nh.iph->ihl*4, &tuple, proto))
 		return NULL;
 
 	/* look for tuple match */
@@ -823,10 +803,6 @@
 	if ((*pskb)->nfct)
 		return NF_ACCEPT;
 
-	/* FIXME: Push down to extensions --RR */
-	if (skb_is_nonlinear(*pskb) && skb_linearize(*pskb, GFP_ATOMIC) != 0)
-		return NF_DROP;
-
 	/* Gather fragments. */
 	if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
 		*pskb = ip_ct_gather_frags(*pskb);
@@ -851,7 +827,7 @@
 
 	IP_NF_ASSERT((*pskb)->nfct);
 
-	ret = proto->packet(ct, (*pskb)->nh.iph, (*pskb)->len, ctinfo);
+	ret = proto->packet(ct, *pskb, ctinfo);
 	if (ret == -1) {
 		/* Invalid */
 		nf_conntrack_put((*pskb)->nfct);
@@ -860,8 +836,7 @@
 	}
 
 	if (ret != NF_DROP && ct->helper) {
-		ret = ct->helper->help((*pskb)->nh.iph, (*pskb)->len,
-				       ct, ctinfo);
+		ret = ct->helper->help(*pskb, ct, ctinfo);
 		if (ret == -1) {
 			/* Invalid */
 			nf_conntrack_put((*pskb)->nfct);
diff -urN linux-2.5.67-bk7/net/ipv4/netfilter/ip_conntrack_ftp.c linux-2.5.67-bk8/net/ipv4/netfilter/ip_conntrack_ftp.c
--- linux-2.5.67-bk7/net/ipv4/netfilter/ip_conntrack_ftp.c	2003-04-07 10:32:20.000000000 -0700
+++ linux-2.5.67-bk8/net/ipv4/netfilter/ip_conntrack_ftp.c	2003-04-17 04:38:38.000000000 -0700
@@ -11,6 +11,9 @@
 #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
 #include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
 
+/* This is slow, but it's simple. --RR */
+static char ftp_buffer[65536];
+
 DECLARE_LOCK(ip_ftp_lock);
 struct module *ip_conntrack_ftp = THIS_MODULE;
 
@@ -228,18 +231,14 @@
 	return 1;
 }
 
-/* FIXME: This should be in userspace.  Later. */
-static int help(const struct iphdr *iph, size_t len,
+static int help(struct sk_buff *skb,
 		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;
+	unsigned int dataoff, datalen;
+	struct tcphdr tcph;
 	u_int32_t old_seq_aft_nl;
-	int old_seq_aft_nl_set;
+	int old_seq_aft_nl_set, ret;
 	u_int32_t array[6] = { 0 };
 	int dir = CTINFO2DIR(ctinfo);
 	unsigned int matchlen, matchoff;
@@ -257,45 +256,42 @@
 		return NF_ACCEPT;
 	}
 
-	/* Not whole TCP header? */
-	if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff*4) {
-		DEBUGP("ftp: tcplen = %u\n", (unsigned)tcplen);
+	if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &tcph, sizeof(tcph)) != 0)
 		return NF_ACCEPT;
-	}
 
-	/* 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",
-		       tcph, tcplen, NIPQUAD(iph->saddr),
-		       NIPQUAD(iph->daddr));
+	dataoff = skb->nh.iph->ihl*4 + tcph.doff*4;
+	/* No data? */
+	if (dataoff >= skb->len) {
+		DEBUGP("ftp: skblen = %u\n", skb->len);
 		return NF_ACCEPT;
 	}
+	datalen = skb->len - dataoff;
 
 	LOCK_BH(&ip_ftp_lock);
+	skb_copy_bits(skb, dataoff, ftp_buffer, skb->len - dataoff);
+
 	old_seq_aft_nl_set = ct_ftp_info->seq_aft_nl_set[dir];
 	old_seq_aft_nl = ct_ftp_info->seq_aft_nl[dir];
 
 	DEBUGP("conntrack_ftp: datalen %u\n", datalen);
-	if ((datalen > 0) && (data[datalen-1] == '\n')) {
+	if (ftp_buffer[datalen - 1] == '\n') {
 		DEBUGP("conntrack_ftp: datalen %u ends in \\n\n", datalen);
 		if (!old_seq_aft_nl_set
-		    || after(ntohl(tcph->seq) + datalen, old_seq_aft_nl)) {
+		    || after(ntohl(tcph.seq) + datalen, old_seq_aft_nl)) {
 			DEBUGP("conntrack_ftp: updating nl to %u\n",
-			       ntohl(tcph->seq) + datalen);
+			       ntohl(tcph.seq) + datalen);
 			ct_ftp_info->seq_aft_nl[dir] = 
-						ntohl(tcph->seq) + datalen;
+						ntohl(tcph.seq) + datalen;
 			ct_ftp_info->seq_aft_nl_set[dir] = 1;
 		}
 	}
-	UNLOCK_BH(&ip_ftp_lock);
 
 	if(!old_seq_aft_nl_set ||
-			(ntohl(tcph->seq) != old_seq_aft_nl)) {
+			(ntohl(tcph.seq) != old_seq_aft_nl)) {
 		DEBUGP("ip_conntrack_ftp_help: wrong seq pos %s(%u)\n",
 		       old_seq_aft_nl_set ? "":"(UNSET) ", old_seq_aft_nl);
-		return NF_ACCEPT;
+		ret = NF_ACCEPT;
+		goto out;
 	}
 
 	/* Initialize IP array to expected address (it's not mentioned
@@ -308,7 +304,7 @@
 	for (i = 0; i < sizeof(search) / sizeof(search[0]); i++) {
 		if (search[i].dir != dir) continue;
 
-		found = find_pattern(data, datalen,
+		found = find_pattern(ftp_buffer, skb->len - dataoff,
 				     search[i].pattern,
 				     search[i].plen,
 				     search[i].skip,
@@ -326,22 +322,24 @@
 		if (net_ratelimit())
 			printk("conntrack_ftp: partial %s %u+%u\n",
 			       search[i].pattern,
-			       ntohl(tcph->seq), datalen);
-		return NF_DROP;
-	} else if (found == 0) /* No match */
-		return NF_ACCEPT;
+			       ntohl(tcph.seq), datalen);
+		ret = NF_DROP;
+		goto out;
+	} else if (found == 0) { /* No match */
+		ret = NF_ACCEPT;
+		goto out;
+	}
 
 	DEBUGP("conntrack_ftp: match `%.*s' (%u bytes at %u)\n",
 	       (int)matchlen, data + matchoff,
-	       matchlen, ntohl(tcph->seq) + matchoff);
+	       matchlen, ntohl(tcph.seq) + matchoff);
 	       
 	memset(&expect, 0, sizeof(expect));
 
 	/* Update the ftp info */
-	LOCK_BH(&ip_ftp_lock);
 	if (htonl((array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3])
 	    == ct->tuplehash[dir].tuple.src.ip) {
-		exp->seq = ntohl(tcph->seq) + matchoff;
+		exp->seq = ntohl(tcph.seq) + matchoff;
 		exp_ftp_info->len = matchlen;
 		exp_ftp_info->ftptype = search[i].ftptype;
 		exp_ftp_info->port = array[4] << 8 | array[5];
@@ -358,7 +356,10 @@
 		   <lincoln@cesar.org.br> for reporting this potential
 		   problem (DMZ machines opening holes to internal
 		   networks, or the packet filter itself). */
-		if (!loose) goto out;
+		if (!loose) {
+			ret = NF_ACCEPT;
+			goto out;
+		}
 	}
 
 	exp->tuple = ((struct ip_conntrack_tuple)
@@ -376,10 +377,10 @@
 
 	/* Ignore failure; should only happen with NAT */
 	ip_conntrack_expect_related(ct, &expect);
+	ret = NF_ACCEPT;
  out:
 	UNLOCK_BH(&ip_ftp_lock);
-
-	return NF_ACCEPT;
+	return ret;
 }
 
 static struct ip_conntrack_helper ftp[MAX_PORTS];
diff -urN linux-2.5.67-bk7/net/ipv4/netfilter/ip_conntrack_irc.c linux-2.5.67-bk8/net/ipv4/netfilter/ip_conntrack_irc.c
--- linux-2.5.67-bk7/net/ipv4/netfilter/ip_conntrack_irc.c	2003-04-07 10:32:18.000000000 -0700
+++ linux-2.5.67-bk8/net/ipv4/netfilter/ip_conntrack_irc.c	2003-04-17 04:38:38.000000000 -0700
@@ -38,6 +38,8 @@
 static int ports_c = 0;
 static int max_dcc_channels = 8;
 static unsigned int dcc_timeout = 300;
+/* This is slow, but it's simple. --RR */
+static char irc_buffer[65536];
 
 MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
 MODULE_DESCRIPTION("IRC (DCC) connection tracking module");
@@ -51,14 +53,7 @@
 MODULE_PARM_DESC(dcc_timeout, "timeout on for unestablished DCC channels");
 #endif
 
-#define NUM_DCCPROTO 	5
-struct dccproto dccprotos[NUM_DCCPROTO] = {
-	{"SEND ", 5},
-	{"CHAT ", 5},
-	{"MOVE ", 5},
-	{"TSEND ", 6},
-	{"SCHAT ", 6}
-};
+static char *dccprotos[] = { "SEND ", "CHAT ", "MOVE ", "TSEND ", "SCHAT " };
 #define MAXMATCHLEN	6
 
 DECLARE_LOCK(ip_irc_lock);
@@ -102,18 +97,12 @@
 	return 0;
 }
 
-
-/* FIXME: This should be in userspace.  Later. */
-static int help(const struct iphdr *iph, size_t len,
+static int help(struct sk_buff *skb,
 		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;
-	const char *_data = data;
-	char *data_limit;
-	u_int32_t tcplen = len - iph->ihl * 4;
-	u_int32_t datalen = tcplen - tcph->doff * 4;
+	unsigned int dataoff;
+	struct tcphdr tcph;
+	char *data, *data_limit;
 	int dir = CTINFO2DIR(ctinfo);
 	struct ip_conntrack_expect expect, *exp = &expect;
 	struct ip_ct_irc_expect *exp_irc_info = &exp->help.exp_irc_info;
@@ -136,23 +125,20 @@
 		return NF_ACCEPT;
 	}
 
-	/* Not whole TCP header? */
-	if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) {
-		DEBUGP("tcplen = %u\n", (unsigned) tcplen);
+	/* Not a full tcp header? */
+	if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &tcph, sizeof(tcph)) != 0)
 		return NF_ACCEPT;
-	}
 
-	/* 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("bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
-		     tcph, tcplen, NIPQUAD(iph->saddr),
-		     NIPQUAD(iph->daddr));
+	/* No data? */
+	dataoff = skb->nh.iph->ihl*4 + tcph.doff*4;
+	if (dataoff >= skb->len)
 		return NF_ACCEPT;
-	}
 
-	data_limit = (char *) data + datalen;
+	LOCK_BH(&ip_irc_lock);
+	skb_copy_bits(skb, dataoff, irc_buffer, skb->len - dataoff);
+
+	data = irc_buffer;
+	data_limit = irc_buffer + skb->len - dataoff;
 	while (data < (data_limit - (22 + MAXMATCHLEN))) {
 		if (memcmp(data, "\1DCC ", 5)) {
 			data++;
@@ -162,19 +148,18 @@
 		data += 5;
 
 		DEBUGP("DCC found in master %u.%u.%u.%u:%u %u.%u.%u.%u:%u...\n",
-			NIPQUAD(iph->saddr), ntohs(tcph->source),
-			NIPQUAD(iph->daddr), ntohs(tcph->dest));
+			NIPQUAD(iph->saddr), ntohs(tcph.source),
+			NIPQUAD(iph->daddr), ntohs(tcph.dest));
 
-		for (i = 0; i < NUM_DCCPROTO; i++) {
-			if (memcmp(data, dccprotos[i].match,
-				   dccprotos[i].matchlen)) {
+		for (i = 0; i < ARRAY_SIZE(dccprotos); i++) {
+			if (memcmp(data, dccprotos[i], strlen(dccprotos[i]))) {
 				/* no match */
 				continue;
 			}
 
-			DEBUGP("DCC %s detected\n", dccprotos[i].match);
-			data += dccprotos[i].matchlen;
-			if (parse_dcc((char *) data, data_limit, &dcc_ip,
+			DEBUGP("DCC %s detected\n", dccprotos[i]);
+			data += strlen(dccprotos[i]);
+			if (parse_dcc((char *)data, data_limit, &dcc_ip,
 				       &dcc_port, &addr_beg_p, &addr_end_p)) {
 				/* unable to parse */
 				DEBUGP("unable to parse dcc command\n");
@@ -196,12 +181,10 @@
 			
 			memset(&expect, 0, sizeof(expect));
 
-			LOCK_BH(&ip_irc_lock);
-
 			/* save position of address in dcc string,
 			 * necessary for NAT */
-			DEBUGP("tcph->seq = %u\n", tcph->seq);
-			exp->seq = ntohl(tcph->seq) + (addr_beg_p - _data);
+			DEBUGP("tcph->seq = %u\n", tcph.seq);
+			exp->seq = ntohl(tcph.seq) + (addr_beg_p - irc_buffer);
 			exp_irc_info->len = (addr_end_p - addr_beg_p);
 			exp_irc_info->port = dcc_port;
 			DEBUGP("wrote info seq=%u (ofs=%u), len=%d\n",
@@ -224,12 +207,13 @@
 				ntohs(exp->tuple.dst.u.tcp.port));
 
 			ip_conntrack_expect_related(ct, &expect);
-			UNLOCK_BH(&ip_irc_lock);
 
-			return NF_ACCEPT;
+			goto out;
 		} /* for .. NUM_DCCPROTO */
 	} /* while data < ... */
 
+ out:
+	UNLOCK_BH(&ip_irc_lock);
 	return NF_ACCEPT;
 }
 
diff -urN linux-2.5.67-bk7/net/ipv4/netfilter/ip_conntrack_proto_generic.c linux-2.5.67-bk8/net/ipv4/netfilter/ip_conntrack_proto_generic.c
--- linux-2.5.67-bk7/net/ipv4/netfilter/ip_conntrack_proto_generic.c	2003-04-07 10:31:02.000000000 -0700
+++ linux-2.5.67-bk8/net/ipv4/netfilter/ip_conntrack_proto_generic.c	2003-04-17 04:38:38.000000000 -0700
@@ -6,7 +6,8 @@
 
 #define GENERIC_TIMEOUT (600*HZ)
 
-static int generic_pkt_to_tuple(const void *datah, size_t datalen,
+static int generic_pkt_to_tuple(const struct sk_buff *skb,
+				unsigned int dataoff,
 				struct ip_conntrack_tuple *tuple)
 {
 	tuple->src.u.all = 0;
@@ -39,17 +40,16 @@
 }
 
 /* Returns verdict for packet, or -1 for invalid. */
-static int established(struct ip_conntrack *conntrack,
-		       struct iphdr *iph, size_t len,
-		       enum ip_conntrack_info conntrackinfo)
+static int packet(struct ip_conntrack *conntrack,
+		  const struct sk_buff *skb,
+		  enum ip_conntrack_info conntrackinfo)
 {
 	ip_ct_refresh(conntrack, GENERIC_TIMEOUT);
 	return NF_ACCEPT;
 }
 
 /* Called when a new connection for this protocol found. */
-static int
-new(struct ip_conntrack *conntrack, struct iphdr *iph, size_t len)
+static int new(struct ip_conntrack *conntrack, const struct sk_buff *skb)
 {
 	return 1;
 }
@@ -57,5 +57,5 @@
 struct ip_conntrack_protocol ip_conntrack_generic_protocol
 = { { NULL, NULL }, 0, "unknown",
     generic_pkt_to_tuple, generic_invert_tuple, generic_print_tuple,
-    generic_print_conntrack, established, new, NULL, NULL, NULL };
+    generic_print_conntrack, packet, new, NULL, NULL, NULL };
 
diff -urN linux-2.5.67-bk7/net/ipv4/netfilter/ip_conntrack_proto_icmp.c linux-2.5.67-bk8/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
--- linux-2.5.67-bk7/net/ipv4/netfilter/ip_conntrack_proto_icmp.c	2003-04-07 10:30:34.000000000 -0700
+++ linux-2.5.67-bk8/net/ipv4/netfilter/ip_conntrack_proto_icmp.c	2003-04-17 04:38:38.000000000 -0700
@@ -14,14 +14,18 @@
 #define DEBUGP(format, args...)
 #endif
 
-static int icmp_pkt_to_tuple(const void *datah, size_t datalen,
+static int icmp_pkt_to_tuple(const struct sk_buff *skb,
+			     unsigned int dataoff,
 			     struct ip_conntrack_tuple *tuple)
 {
-	const struct icmphdr *hdr = datah;
+	struct icmphdr hdr;
 
-	tuple->dst.u.icmp.type = hdr->type;
-	tuple->src.u.icmp.id = hdr->un.echo.id;
-	tuple->dst.u.icmp.code = hdr->code;
+	if (skb_copy_bits(skb, dataoff, &hdr, sizeof(hdr)) != 0)
+		return 0;
+
+	tuple->dst.u.icmp.type = hdr.type;
+	tuple->src.u.icmp.id = hdr.un.echo.id;
+	tuple->dst.u.icmp.code = hdr.code;
 
 	return 1;
 }
@@ -69,7 +73,7 @@
 
 /* Returns verdict for packet, or -1 for invalid. */
 static int icmp_packet(struct ip_conntrack *ct,
-		       struct iphdr *iph, size_t len,
+		       const struct sk_buff *skb,
 		       enum ip_conntrack_info ctinfo)
 {
 	/* Try to delete connection immediately after all replies:
@@ -90,7 +94,7 @@
 
 /* Called when a new connection for this protocol found. */
 static int icmp_new(struct ip_conntrack *conntrack,
-		    struct iphdr *iph, size_t len)
+		    const struct sk_buff *skb)
 {
 	static u_int8_t valid_new[]
 		= { [ICMP_ECHO] = 1,
diff -urN linux-2.5.67-bk7/net/ipv4/netfilter/ip_conntrack_proto_tcp.c linux-2.5.67-bk8/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
--- linux-2.5.67-bk7/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	2003-04-07 10:32:58.000000000 -0700
+++ linux-2.5.67-bk8/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	2003-04-17 04:38:38.000000000 -0700
@@ -96,13 +96,18 @@
 	}
 };
 
-static int tcp_pkt_to_tuple(const void *datah, size_t datalen,
-			    struct ip_conntrack_tuple *tuple)
+static int tcp_pkt_to_tuple(const struct sk_buff *skb,
+			     unsigned int dataoff,
+			     struct ip_conntrack_tuple *tuple)
 {
-	const struct tcphdr *hdr = datah;
+	struct tcphdr hdr;
 
-	tuple->src.u.tcp.port = hdr->source;
-	tuple->dst.u.tcp.port = hdr->dest;
+	/* Actually only need first 8 bytes. */
+	if (skb_copy_bits(skb, dataoff, &hdr, 8) != 0)
+		return 0;
+
+	tuple->src.u.tcp.port = hdr.source;
+	tuple->dst.u.tcp.port = hdr.dest;
 
 	return 1;
 }
@@ -148,30 +153,26 @@
 
 /* Returns verdict for packet, or -1 for invalid. */
 static int tcp_packet(struct ip_conntrack *conntrack,
-		      struct iphdr *iph, size_t len,
+		      const struct sk_buff *skb,
 		      enum ip_conntrack_info ctinfo)
 {
 	enum tcp_conntrack newconntrack, oldtcpstate;
-	struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph + iph->ihl);
+	struct tcphdr tcph;
 
-	/* We're guaranteed to have the base header, but maybe not the
-           options. */
-	if (len < (iph->ihl + tcph->doff) * 4) {
-		DEBUGP("ip_conntrack_tcp: Truncated packet.\n");
+	if (skb_copy_bits(skb, skb->nh.iph->ihl * 4, &tcph, sizeof(tcph)) != 0)
 		return -1;
-	}
 
 	WRITE_LOCK(&tcp_lock);
 	oldtcpstate = conntrack->proto.tcp.state;
 	newconntrack
 		= tcp_conntracks
 		[CTINFO2DIR(ctinfo)]
-		[get_conntrack_index(tcph)][oldtcpstate];
+		[get_conntrack_index(&tcph)][oldtcpstate];
 
 	/* Invalid */
 	if (newconntrack == TCP_CONNTRACK_MAX) {
 		DEBUGP("ip_conntrack_tcp: Invalid dir=%i index=%u conntrack=%u\n",
-		       CTINFO2DIR(ctinfo), get_conntrack_index(tcph),
+		       CTINFO2DIR(ctinfo), get_conntrack_index(&tcph),
 		       conntrack->proto.tcp.state);
 		WRITE_UNLOCK(&tcp_lock);
 		return -1;
@@ -182,15 +183,15 @@
 	/* Poor man's window tracking: record SYN/ACK for handshake check */
 	if (oldtcpstate == TCP_CONNTRACK_SYN_SENT
 	    && CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY
-	    && tcph->syn && tcph->ack)
+	    && tcph.syn && tcph.ack)
 		conntrack->proto.tcp.handshake_ack
-			= htonl(ntohl(tcph->seq) + 1);
+			= htonl(ntohl(tcph.seq) + 1);
 
 	/* If only reply is a RST, we can consider ourselves not to
 	   have an established connection: this is a fairly common
 	   problem case, so we can delete the conntrack
 	   immediately.  --RR */
-	if (!test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status) && tcph->rst) {
+	if (!test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status) && tcph.rst) {
 		WRITE_UNLOCK(&tcp_lock);
 		if (del_timer(&conntrack->timeout))
 			conntrack->timeout.function((unsigned long)conntrack);
@@ -198,8 +199,8 @@
 		/* Set ASSURED if we see see valid ack in ESTABLISHED after SYN_RECV */
 		if (oldtcpstate == TCP_CONNTRACK_SYN_RECV
 		    && CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL
-		    && tcph->ack && !tcph->syn
-		    && tcph->ack_seq == conntrack->proto.tcp.handshake_ack)
+		    && tcph.ack && !tcph.syn
+		    && tcph.ack_seq == conntrack->proto.tcp.handshake_ack)
 			set_bit(IPS_ASSURED_BIT, &conntrack->status);
 
 		WRITE_UNLOCK(&tcp_lock);
@@ -210,15 +211,17 @@
 }
 
 /* Called when a new connection for this protocol found. */
-static int tcp_new(struct ip_conntrack *conntrack,
-		   struct iphdr *iph, size_t len)
+static int tcp_new(struct ip_conntrack *conntrack, const struct sk_buff *skb)
 {
 	enum tcp_conntrack newconntrack;
-	struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph + iph->ihl);
+	struct tcphdr tcph;
+
+	if (skb_copy_bits(skb, skb->nh.iph->ihl * 4, &tcph, sizeof(tcph)) != 0)
+		return -1;
 
 	/* Don't need lock here: this conntrack not in circulation yet */
 	newconntrack
-		= tcp_conntracks[0][get_conntrack_index(tcph)]
+		= tcp_conntracks[0][get_conntrack_index(&tcph)]
 		[TCP_CONNTRACK_NONE];
 
 	/* Invalid: delete conntrack */
@@ -232,15 +235,17 @@
 }
 
 static int tcp_exp_matches_pkt(struct ip_conntrack_expect *exp,
-			       struct sk_buff **pskb)
+			       const struct sk_buff *skb)
 {
-	struct iphdr *iph = (*pskb)->nh.iph;
-	struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph + iph->ihl);
+	const struct iphdr *iph = skb->nh.iph;
+	struct tcphdr tcph;
 	unsigned int datalen;
 
-	datalen = (*pskb)->len - iph->ihl*4 - tcph->doff*4;
+	if (skb_copy_bits(skb, skb->nh.iph->ihl * 4, &tcph, sizeof(tcph)) != 0)
+		return 0;
+	datalen = skb->len - iph->ihl*4 - tcph.doff*4;
 
-	return between(exp->seq, ntohl(tcph->seq), ntohl(tcph->seq) + datalen);
+	return between(exp->seq, ntohl(tcph.seq), ntohl(tcph.seq) + datalen);
 }
 
 struct ip_conntrack_protocol ip_conntrack_protocol_tcp
diff -urN linux-2.5.67-bk7/net/ipv4/netfilter/ip_conntrack_proto_udp.c linux-2.5.67-bk8/net/ipv4/netfilter/ip_conntrack_proto_udp.c
--- linux-2.5.67-bk7/net/ipv4/netfilter/ip_conntrack_proto_udp.c	2003-04-07 10:30:32.000000000 -0700
+++ linux-2.5.67-bk8/net/ipv4/netfilter/ip_conntrack_proto_udp.c	2003-04-17 04:38:38.000000000 -0700
@@ -9,13 +9,18 @@
 #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)
-{
-	const struct udphdr *hdr = datah;
+static int udp_pkt_to_tuple(const struct sk_buff *skb,
+			     unsigned int dataoff,
+			     struct ip_conntrack_tuple *tuple)
+{
+	struct udphdr hdr;
+
+	/* Actually only need first 8 bytes. */
+	if (skb_copy_bits(skb, dataoff, &hdr, 8) != 0)
+		return 0;
 
-	tuple->src.u.udp.port = hdr->source;
-	tuple->dst.u.udp.port = hdr->dest;
+	tuple->src.u.udp.port = hdr.source;
+	tuple->dst.u.udp.port = hdr.dest;
 
 	return 1;
 }
@@ -46,7 +51,7 @@
 
 /* Returns verdict for packet, and may modify conntracktype */
 static int udp_packet(struct ip_conntrack *conntrack,
-		      struct iphdr *iph, size_t len,
+		      const struct sk_buff *skb,
 		      enum ip_conntrack_info conntrackinfo)
 {
 	/* If we've seen traffic both ways, this is some kind of UDP
@@ -62,8 +67,7 @@
 }
 
 /* Called when a new connection for this protocol found. */
-static int udp_new(struct ip_conntrack *conntrack,
-			     struct iphdr *iph, size_t len)
+static int udp_new(struct ip_conntrack *conntrack, const struct sk_buff *skb)
 {
 	return 1;
 }
diff -urN linux-2.5.67-bk7/net/ipv4/netfilter/ip_conntrack_standalone.c linux-2.5.67-bk8/net/ipv4/netfilter/ip_conntrack_standalone.c
--- linux-2.5.67-bk7/net/ipv4/netfilter/ip_conntrack_standalone.c	2003-04-17 04:38:28.000000000 -0700
+++ linux-2.5.67-bk8/net/ipv4/netfilter/ip_conntrack_standalone.c	2003-04-07 10:31:13.000000000 -0700
@@ -192,10 +192,6 @@
 {
 	struct rtable *rt = (struct rtable *)(*pskb)->dst;
 
-	/* FIXME: Push down to extensions --RR */
-	if (skb_is_nonlinear(*pskb) && skb_linearize(*pskb, GFP_ATOMIC) != 0)
-		return NF_DROP;
-
 	/* We've seen it coming out the other side: confirm */
 	if (ip_confirm(hooknum, pskb, in, out, okfn) != NF_ACCEPT)
 		return NF_DROP;
@@ -217,10 +213,6 @@
 				       const struct net_device *out,
 				       int (*okfn)(struct sk_buff *))
 {
-	/* FIXME: Push down to extensions --RR */
-	if (skb_is_nonlinear(*pskb) && skb_linearize(*pskb, GFP_ATOMIC) != 0)
-		return NF_DROP;
-
 	/* root is playing with raw sockets. */
 	if ((*pskb)->len < sizeof(struct iphdr)
 	    || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) {
diff -urN linux-2.5.67-bk7/net/ipv4/netfilter/ip_conntrack_tftp.c linux-2.5.67-bk8/net/ipv4/netfilter/ip_conntrack_tftp.c
--- linux-2.5.67-bk7/net/ipv4/netfilter/ip_conntrack_tftp.c	2003-04-07 10:31:00.000000000 -0700
+++ linux-2.5.67-bk8/net/ipv4/netfilter/ip_conntrack_tftp.c	2003-04-17 04:38:38.000000000 -0700
@@ -35,15 +35,18 @@
 #define DEBUGP(format, args...)
 #endif
 
-static int tftp_help(const struct iphdr *iph, size_t len,
-	struct ip_conntrack *ct,
-	enum ip_conntrack_info ctinfo)
+static int tftp_help(struct sk_buff *skb,
+		     struct ip_conntrack *ct,
+		     enum ip_conntrack_info ctinfo)
 {
-	struct udphdr *udph = (void *)iph + iph->ihl * 4;
-	struct tftphdr *tftph = (void *)udph + 8;
+	struct tftphdr tftph;
 	struct ip_conntrack_expect exp;
-	
-	switch (ntohs(tftph->opcode)) {
+
+	if (skb_copy_bits(skb, skb->nh.iph->ihl * 4 + sizeof(struct udphdr),
+			  &tftph, sizeof(tftph)) != 0)
+		return -1;
+
+	switch (ntohs(tftph.opcode)) {
 	/* RRQ and WRQ works the same way */
 	case TFTP_OPCODE_READ:
 	case TFTP_OPCODE_WRITE:
diff -urN linux-2.5.67-bk7/net/ipv4/netfilter/ip_fw_compat_masq.c linux-2.5.67-bk8/net/ipv4/netfilter/ip_fw_compat_masq.c
--- linux-2.5.67-bk7/net/ipv4/netfilter/ip_fw_compat_masq.c	2003-04-07 10:32:23.000000000 -0700
+++ linux-2.5.67-bk8/net/ipv4/netfilter/ip_fw_compat_masq.c	2003-04-17 04:38:38.000000000 -0700
@@ -146,6 +146,12 @@
 			   server here (== DNAT).  Do SNAT icmp manips
 			   in POST_ROUTING handling. */
 			if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) {
+				/* FIXME: Remove once NAT handled non-linear.
+				 */
+				if (skb_is_nonlinear(*pskb)
+				    && skb_linearize(*pskb, GFP_ATOMIC) != 0)
+					return NF_DROP;
+
 				icmp_reply_translation(*pskb, ct,
 						       NF_IP_PRE_ROUTING,
 						       CTINFO2DIR(ctinfo));
@@ -160,7 +166,7 @@
 	case IPPROTO_UDP:
 		IP_NF_ASSERT(((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
 
-		if (!get_tuple(iph, (*pskb)->len, &tuple, protocol)) {
+		if (!get_tuple(iph, *pskb, iph->ihl*4, &tuple, protocol)) {
 			if (net_ratelimit())
 				printk("ip_fw_compat_masq: Can't get tuple\n");
 			return NF_ACCEPT;
diff -urN linux-2.5.67-bk7/net/ipv4/netfilter/ip_nat_core.c linux-2.5.67-bk8/net/ipv4/netfilter/ip_nat_core.c
--- linux-2.5.67-bk7/net/ipv4/netfilter/ip_nat_core.c	2003-04-07 10:30:43.000000000 -0700
+++ linux-2.5.67-bk8/net/ipv4/netfilter/ip_nat_core.c	2003-04-17 04:38:38.000000000 -0700
@@ -730,15 +730,15 @@
 }
 
 static inline int exp_for_packet(struct ip_conntrack_expect *exp,
-			         struct sk_buff **pskb)
+			         struct sk_buff *skb)
 {
 	struct ip_conntrack_protocol *proto;
 	int ret = 1;
 
 	MUST_BE_READ_LOCKED(&ip_conntrack_lock);
-	proto = __ip_ct_find_proto((*pskb)->nh.iph->protocol);
+	proto = __ip_ct_find_proto(skb->nh.iph->protocol);
 	if (proto->exp_matches_pkt)
-		ret = proto->exp_matches_pkt(exp, pskb);
+		ret = proto->exp_matches_pkt(exp, skb);
 
 	return ret;
 }
@@ -813,7 +813,7 @@
 			if (exp->sibling)
 				continue;
 
-			if (exp_for_packet(exp, pskb)) {
+			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);
diff -urN linux-2.5.67-bk7/net/ipv4/netfilter/ip_nat_tftp.c linux-2.5.67-bk8/net/ipv4/netfilter/ip_nat_tftp.c
--- linux-2.5.67-bk7/net/ipv4/netfilter/ip_nat_tftp.c	2003-04-07 10:31:00.000000000 -0700
+++ linux-2.5.67-bk8/net/ipv4/netfilter/ip_nat_tftp.c	2003-04-17 04:38:38.000000000 -0700
@@ -153,7 +153,7 @@
 
 static int __init init(void)
 {
-	int i, ret;
+	int i, ret = 0;
 	char *tmpname;
 
 	if (!ports[0])
diff -urN linux-2.5.67-bk7/net/ipv6/af_inet6.c linux-2.5.67-bk8/net/ipv6/af_inet6.c
--- linux-2.5.67-bk7/net/ipv6/af_inet6.c	2003-04-17 04:38:28.000000000 -0700
+++ linux-2.5.67-bk8/net/ipv6/af_inet6.c	2003-04-17 04:38:38.000000000 -0700
@@ -805,7 +805,6 @@
 	sit_init();
 
 	/* Init v6 extension headers. */
-	ipv6_hopopts_init();
 	ipv6_rthdr_init();
 	ipv6_frag_init();
 	ipv6_nodata_init();
diff -urN linux-2.5.67-bk7/net/ipv6/ah6.c linux-2.5.67-bk8/net/ipv6/ah6.c
--- linux-2.5.67-bk7/net/ipv6/ah6.c	2003-04-17 04:38:28.000000000 -0700
+++ linux-2.5.67-bk8/net/ipv6/ah6.c	2003-04-17 04:38:38.000000000 -0700
@@ -330,7 +330,7 @@
 static struct inet6_protocol ah6_protocol = {
 	.handler	=	xfrm6_rcv,
 	.err_handler	=	ah6_err,
-	.no_policy	=	1,
+	.flags		=	INET6_PROTO_NOPOLICY,
 };
 
 int __init ah6_init(void)
diff -urN linux-2.5.67-bk7/net/ipv6/esp6.c linux-2.5.67-bk8/net/ipv6/esp6.c
--- linux-2.5.67-bk7/net/ipv6/esp6.c	2003-04-17 04:38:28.000000000 -0700
+++ linux-2.5.67-bk8/net/ipv6/esp6.c	2003-04-17 04:38:38.000000000 -0700
@@ -501,7 +501,7 @@
 static struct inet6_protocol esp6_protocol = {
 	.handler 	=	xfrm6_rcv,
 	.err_handler	=	esp6_err,
-	.no_policy	=	1,
+	.flags		=	INET6_PROTO_NOPOLICY,
 };
 
 int __init esp6_init(void)
diff -urN linux-2.5.67-bk7/net/ipv6/exthdrs.c linux-2.5.67-bk8/net/ipv6/exthdrs.c
--- linux-2.5.67-bk7/net/ipv6/exthdrs.c	2003-04-07 10:30:38.000000000 -0700
+++ linux-2.5.67-bk8/net/ipv6/exthdrs.c	2003-04-17 04:38:38.000000000 -0700
@@ -18,9 +18,9 @@
 /* Changes:
  *	yoshfuji		: ensure not to overrun while parsing 
  *				  tlv options.
- *	Mitsuru KANDA @USAGI	: Remove ipv6_parse_exthdrs().
- *				: Register inbound extention header
- *				: handlers as inet6_protocol{}.
+ *	Mitsuru KANDA @USAGI and: Remove ipv6_parse_exthdrs().
+ *	YOSHIFUJI Hideaki @USAGI  Register inbound extention header
+ *				  handlers as inet6_protocol{}.
  */
 
 #include <linux/errno.h>
@@ -153,38 +153,37 @@
 	{-1,			NULL}
 };
 
-static int ipv6_destopt_rcv(struct sk_buff **skbp) 
+static int ipv6_destopt_rcv(struct sk_buff **skbp, unsigned int *nhoffp)
 {
 	struct sk_buff *skb = *skbp;
 	struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
-	u8 nexthdr = 0;
 
 	if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||
 	    !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
 		kfree_skb(skb);
-		return 0;
+		return -1;
 	}
 
-	nexthdr = ((struct ipv6_destopt_hdr *)skb->h.raw)->nexthdr;
-	
 	opt->dst1 = skb->h.raw - skb->nh.raw;
 
 	if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) {
 		skb->h.raw += ((skb->h.raw[1]+1)<<3);
-		return -nexthdr;
+		*nhoffp = opt->dst1;
+		return 1;
 	}
-						
-	return 0;
+
+	return -1;
 }
 
 static struct inet6_protocol destopt_protocol =
 {
-	.handler 	= 	ipv6_destopt_rcv,
+	.handler	=	ipv6_destopt_rcv,
+	.flags		=	INET6_PROTO_NOPOLICY,
 };
 
 void __init ipv6_destopt_init(void)
 {
-	if (inet6_add_protocol(&destopt_protocol, IPPROTO_DSTOPTS) < 0) 
+	if (inet6_add_protocol(&destopt_protocol, IPPROTO_DSTOPTS) < 0)
 		printk(KERN_ERR "ipv6_destopt_init: Could not register protocol\n");
 }
 
@@ -192,7 +191,7 @@
   NONE header. No data in packet.
  ********************************/
 
-static int ipv6_nodata_rcv(struct sk_buff **skbp)
+static int ipv6_nodata_rcv(struct sk_buff **skbp, unsigned int *nhoffp)
 {
 	struct sk_buff *skb = *skbp;
 
@@ -203,6 +202,7 @@
 static struct inet6_protocol nodata_protocol =
 {
 	.handler	=	ipv6_nodata_rcv,
+	.flags		=	INET6_PROTO_NOPOLICY,
 };
 
 void __init ipv6_nodata_init(void)
@@ -215,7 +215,7 @@
   Routing header.
  ********************************/
 
-static int ipv6_rthdr_rcv(struct sk_buff **skbp)
+static int ipv6_rthdr_rcv(struct sk_buff **skbp, unsigned int *nhoffp)
 {
 	struct sk_buff *skb = *skbp;
 	struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
@@ -223,7 +223,6 @@
 	struct in6_addr daddr;
 	int addr_type;
 	int n, i;
-	u8 nexthdr = 0;
 
 	struct ipv6_rt_hdr *hdr;
 	struct rt0_hdr *rthdr;
@@ -232,16 +231,15 @@
 	    !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
 		IP6_INC_STATS_BH(Ip6InHdrErrors);
 		kfree_skb(skb);
-		return 0;
+		return -1;
 	}
 
 	hdr = (struct ipv6_rt_hdr *) skb->h.raw;
-	nexthdr = hdr->nexthdr;
 
 	if ((ipv6_addr_type(&skb->nh.ipv6h->daddr)&IPV6_ADDR_MULTICAST) ||
 	    skb->pkt_type != PACKET_HOST) {
 		kfree_skb(skb);
-		return 0;
+		return -1;
 	}
 
 looped_back:
@@ -250,12 +248,13 @@
 		skb->h.raw += (hdr->hdrlen + 1) << 3;
 		opt->dst0 = opt->dst1;
 		opt->dst1 = 0;
-		return -nexthdr;
+		*nhoffp = (&hdr->nexthdr) - skb->nh.raw;
+		return 1;
 	}
 
 	if (hdr->type != IPV6_SRCRT_TYPE_0 || (hdr->hdrlen & 0x01)) {
 		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, hdr->type != IPV6_SRCRT_TYPE_0 ? 2 : 1);
-		return 0;
+		return -1;
 	}
 
 	/*
@@ -267,7 +266,7 @@
 
 	if (hdr->segments_left > n) {
 		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->segments_left) - skb->nh.raw);
-		return 0;
+		return -1;
 	}
 
 	/* We are about to mangle packet header. Be careful!
@@ -277,7 +276,7 @@
 		struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
 		kfree_skb(skb);
 		if (skb2 == NULL)
-			return 0;
+			return -1;
 		*skbp = skb = skb2;
 		opt = (struct inet6_skb_parm *)skb2->cb;
 		hdr = (struct ipv6_rt_hdr *) skb2->h.raw;
@@ -296,7 +295,7 @@
 
 	if (addr_type&IPV6_ADDR_MULTICAST) {
 		kfree_skb(skb);
-		return 0;
+		return -1;
 	}
 
 	ipv6_addr_copy(&daddr, addr);
@@ -307,26 +306,27 @@
 	ip6_route_input(skb);
 	if (skb->dst->error) {
 		dst_input(skb);
-		return 0;
+		return -1;
 	}
 	if (skb->dst->dev->flags&IFF_LOOPBACK) {
 		if (skb->nh.ipv6h->hop_limit <= 1) {
 			icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
 				    0, skb->dev);
 			kfree_skb(skb);
-			return 0;
+			return -1;
 		}
 		skb->nh.ipv6h->hop_limit--;
 		goto looped_back;
 	}
 
 	dst_input(skb);
-	return 0;
+	return -1;
 }
 
 static struct inet6_protocol rthdr_protocol =
 {
 	.handler	=	ipv6_rthdr_rcv,
+	.flags		=	INET6_PROTO_NOPOLICY,
 };
 
 void __init ipv6_rthdr_init(void)
@@ -470,34 +470,6 @@
 	return -1;
 }
 
-/* This is fake. We have already parsed hopopts in ipv6_rcv(). -mk */
-static int ipv6_hopopts_rcv(struct sk_buff **skbp)
-{
-	struct sk_buff *skb = *skbp;
-	u8 nexthdr = 0;
-
-	if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||
-	    !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
-		kfree_skb(skb);
-		return 0;
-	}
-	nexthdr = ((struct ipv6_hopopt_hdr *)skb->h.raw)->nexthdr;
-	skb->h.raw += (skb->h.raw[1]+1)<<3;
-
-       return -nexthdr;
-}
-
-static struct inet6_protocol hopopts_protocol =
-{
-	.handler	=	ipv6_hopopts_rcv,
-};
-
-void __init ipv6_hopopts_init(void)
-{
-	if (inet6_add_protocol(&hopopts_protocol, IPPROTO_HOPOPTS) < 0)
-		printk(KERN_ERR "ipv6_hopopts_init: Could not register protocol\n");
-}
-
 /*
  *	Creating outbound headers.
  *
diff -urN linux-2.5.67-bk7/net/ipv6/icmp.c linux-2.5.67-bk8/net/ipv6/icmp.c
--- linux-2.5.67-bk7/net/ipv6/icmp.c	2003-04-07 10:30:59.000000000 -0700
+++ linux-2.5.67-bk8/net/ipv6/icmp.c	2003-04-17 04:38:38.000000000 -0700
@@ -74,10 +74,11 @@
 static struct socket *__icmpv6_socket[NR_CPUS];
 #define icmpv6_socket	__icmpv6_socket[smp_processor_id()]
 
-static int icmpv6_rcv(struct sk_buff **pskb);
+static int icmpv6_rcv(struct sk_buff **pskb, unsigned int *nhoffp);
 
 static struct inet6_protocol icmpv6_protocol = {
 	.handler	=	icmpv6_rcv,
+	.flags		=	INET6_PROTO_FINAL,
 };
 
 struct icmpv6_msg {
@@ -459,7 +460,7 @@
  *	Handle icmp messages
  */
 
-static int icmpv6_rcv(struct sk_buff **pskb)
+static int icmpv6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
 {
 	struct sk_buff *skb = *pskb;
 	struct net_device *dev = skb->dev;
diff -urN linux-2.5.67-bk7/net/ipv6/ip6_input.c linux-2.5.67-bk8/net/ipv6/ip6_input.c
--- linux-2.5.67-bk7/net/ipv6/ip6_input.c	2003-04-07 10:32:17.000000000 -0700
+++ linux-2.5.67-bk8/net/ipv6/ip6_input.c	2003-04-17 04:38:38.000000000 -0700
@@ -17,7 +17,8 @@
  */
 /* Changes
  *
- * 	Mitsuru KANDA @USAGI	: Remove ipv6_parse_exthdrs().
+ * 	Mitsuru KANDA @USAGI and
+ * 	YOSHIFUJI Hideaki @USAGI: Remove ipv6_parse_exthdrs().
  */
 
 #include <linux/errno.h>
@@ -128,22 +129,34 @@
 
 static inline int ip6_input_finish(struct sk_buff *skb)
 {
-	struct ipv6hdr *hdr = skb->nh.ipv6h;
 	struct inet6_protocol *ipprot;
 	struct sock *raw_sk;
-	int nexthdr = hdr->nexthdr;
+	unsigned int nhoff;
+	int nexthdr;
 	u8 hash;
+	int cksum_sub = 0;
 
 	skb->h.raw = skb->nh.raw + sizeof(struct ipv6hdr);
 
-	if (!pskb_pull(skb, skb->h.raw - skb->data))
-		goto discard;
+	/*
+	 *	Parse extension headers
+	 */
 
-	if (skb->ip_summed == CHECKSUM_HW)
-		skb->csum = csum_sub(skb->csum,
-				     csum_partial(skb->nh.raw, skb->h.raw-skb->nh.raw, 0));
+	nexthdr = skb->nh.ipv6h->nexthdr;
+	nhoff = offsetof(struct ipv6hdr, nexthdr);
+
+	/* Skip  hop-by-hop options, they are already parsed. */
+	if (nexthdr == NEXTHDR_HOP) {
+		nhoff = sizeof(struct ipv6hdr);
+		nexthdr = skb->h.raw[0];
+		skb->h.raw += (skb->h.raw[1]+1)<<3;
+	}
 
 resubmit:
+	if (!pskb_pull(skb, skb->h.raw - skb->data))
+		goto discard;
+	nexthdr = skb->nh.raw[nhoff];
+
 	raw_sk = raw_v6_htable[nexthdr & (MAX_INET_PROTOS - 1)];
 	if (raw_sk)
 		ipv6_raw_deliver(skb, nexthdr);
@@ -152,23 +165,29 @@
 	if ((ipprot = inet6_protos[hash]) != NULL) {
 		int ret;
 		
-		if (!ipprot->no_policy &&
+		if (ipprot->flags & INET6_PROTO_FINAL) {
+			if (!cksum_sub && skb->ip_summed == CHECKSUM_HW) {
+				skb->csum = csum_sub(skb->csum,
+						     csum_partial(skb->nh.raw, skb->h.raw-skb->nh.raw, 0));
+				cksum_sub++;
+			}
+		}
+		if (!(ipprot->flags & INET6_PROTO_NOPOLICY) &&
 		    !xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
 			kfree_skb(skb);
 			return 0;
 		}
-		ret = ipprot->handler(&skb);
-		if (ret < 0) {
-			nexthdr = -ret;
+		
+		ret = ipprot->handler(&skb, &nhoff);
+		if (ret > 0)
 			goto resubmit;
-		}
-		IP6_INC_STATS_BH(Ip6InDelivers);
+		else if (ret == 0)
+			IP6_INC_STATS_BH(Ip6InDelivers);
 	} else {
 		if (!raw_sk) {
 			if (xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
 				IP6_INC_STATS_BH(Ip6InUnknownProtos);
-				icmpv6_param_prob(skb, ICMPV6_UNK_NEXTHDR,
-						  offsetof(struct ipv6hdr, nexthdr));
+				icmpv6_param_prob(skb, ICMPV6_UNK_NEXTHDR, nhoff);
 			}
 		} else {
 			IP6_INC_STATS_BH(Ip6InDelivers);
@@ -198,7 +217,7 @@
 	IP6_INC_STATS_BH(Ip6InMcastPkts);
 
 	hdr = skb->nh.ipv6h;
-	if (ipv6_chk_mcast_addr(skb->dev, &hdr->daddr))
+	if (ipv6_chk_mcast_addr(skb->dev, &hdr->daddr, &hdr->saddr))
 		deliver = 1;
 
 	/*
diff -urN linux-2.5.67-bk7/net/ipv6/ip6_output.c linux-2.5.67-bk8/net/ipv6/ip6_output.c
--- linux-2.5.67-bk7/net/ipv6/ip6_output.c	2003-04-07 10:30:39.000000000 -0700
+++ linux-2.5.67-bk8/net/ipv6/ip6_output.c	2003-04-17 04:38:38.000000000 -0700
@@ -110,7 +110,8 @@
 		struct ipv6_pinfo* np = skb->sk ? inet6_sk(skb->sk) : NULL;
 
 		if (!(dev->flags & IFF_LOOPBACK) && (!np || np->mc_loop) &&
-		    ipv6_chk_mcast_addr(dev, &skb->nh.ipv6h->daddr)) {
+		    ipv6_chk_mcast_addr(dev, &skb->nh.ipv6h->daddr,
+				&skb->nh.ipv6h->saddr)) {
 			struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC);
 
 			/* Do not check for IFF_ALLMULTI; multicast routing
@@ -154,6 +155,7 @@
 	if (dst->error) {
 		if (net_ratelimit())
 			printk(KERN_DEBUG "ip6_route_me_harder: No more route.\n");
+		dst_release(dst);
 		return -EINVAL;
 	}
 
diff -urN linux-2.5.67-bk7/net/ipv6/ipv6_sockglue.c linux-2.5.67-bk8/net/ipv6/ipv6_sockglue.c
--- linux-2.5.67-bk7/net/ipv6/ipv6_sockglue.c	2003-04-17 04:38:28.000000000 -0700
+++ linux-2.5.67-bk8/net/ipv6/ipv6_sockglue.c	2003-04-17 04:38:38.000000000 -0700
@@ -19,6 +19,10 @@
  *	o	Return -EINVAL for setsockopt of short lengths
  *	o	Truncate getsockopt returns
  *	o	Return an optlen of the truncated length if need be
+ *
+ *	Changes:
+ *	David L Stevens <dlstevens@us.ibm.com>:
+ *		- added multicast source filtering API for MLDv2
  */
 
 #include <linux/module.h>
@@ -375,6 +379,89 @@
 			retv = ipv6_sock_ac_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_acaddr);
 		break;
 	}
+	case MCAST_JOIN_GROUP:
+	case MCAST_LEAVE_GROUP:
+	{
+		struct group_req greq;
+		struct sockaddr_in6 *psin6;
+
+		retv = -EFAULT;
+		if (copy_from_user(&greq, optval, sizeof(struct group_req)))
+			break;
+		if (greq.gr_group.ss_family != AF_INET6) {
+			retv = -EADDRNOTAVAIL;
+			break;
+		}
+		psin6 = (struct sockaddr_in6 *)&greq.gr_group;
+		if (optname == IPV6_ADD_MEMBERSHIP)
+			retv = ipv6_sock_mc_join(sk, greq.gr_interface,
+				&psin6->sin6_addr);
+		else
+			retv = ipv6_sock_mc_drop(sk, greq.gr_interface,
+				&psin6->sin6_addr);
+	}
+	case MCAST_JOIN_SOURCE_GROUP:
+	case MCAST_LEAVE_SOURCE_GROUP:
+	case MCAST_BLOCK_SOURCE:
+	case MCAST_UNBLOCK_SOURCE:
+	{
+		struct group_source_req greqs;
+		int omode, add;
+
+		if (optlen != sizeof(struct group_source_req))
+			goto e_inval;
+		if (copy_from_user(&greqs, optval, sizeof(greqs))) {
+			retv = -EFAULT;
+			break;
+		}
+		if (greqs.gsr_group.ss_family != AF_INET6) {
+			retv = -EADDRNOTAVAIL;
+			break;
+		}
+		if (optname == MCAST_BLOCK_SOURCE) {
+			omode = MCAST_EXCLUDE;
+			add = 1;
+		} else if (optname == MCAST_UNBLOCK_SOURCE) {
+			omode = MCAST_EXCLUDE;
+			add = 0;
+		} else if (optname == MCAST_JOIN_SOURCE_GROUP) {
+			struct sockaddr_in6 *psin6;
+
+			psin6 = (struct sockaddr_in6 *)&greqs.gsr_group;
+			retv = ipv6_sock_mc_join(sk, greqs.gsr_interface,
+				&psin6->sin6_addr);
+			if (retv)
+				break;
+			omode = MCAST_INCLUDE;
+			add = 1;
+		} else /*IP_DROP_SOURCE_MEMBERSHIP */ {
+			omode = MCAST_INCLUDE;
+			add = 0;
+		}
+		retv = ip6_mc_source(add, omode, sk, &greqs);
+		break;
+	}
+	case MCAST_MSFILTER:
+	{
+		struct group_filter *gsf;
+
+		if (optlen < GROUP_FILTER_SIZE(0))
+			goto e_inval;
+		gsf = (struct group_filter *)kmalloc(optlen,GFP_KERNEL);
+		if (gsf == 0) {
+			retv = -ENOBUFS;
+			break;
+		}
+		retv = -EFAULT;
+		if (copy_from_user(gsf, optval, optlen)) {
+			kfree(gsf);
+			break;
+		}
+		retv = ip6_mc_msfilter(sk, gsf);
+		kfree(gsf);
+
+		break;
+	}
 	case IPV6_ROUTER_ALERT:
 		retv = ip6_ra_control(sk, val, NULL);
 		break;
@@ -448,6 +535,21 @@
 			return -ENOTCONN;
 		val = sk->family;
 		break;
+	case MCAST_MSFILTER:
+	{
+		struct group_filter gsf;
+		int err;
+
+		if (len < GROUP_FILTER_SIZE(0))
+			return -EINVAL;
+		if (copy_from_user(&gsf, optval, GROUP_FILTER_SIZE(0)))
+			return -EFAULT;
+		lock_sock(sk);
+		err = ip6_mc_msfget(sk, &gsf,
+			(struct group_filter *)optval, optlen);
+		release_sock(sk);
+		return err;
+	}
 
 	case IPV6_PKTOPTIONS:
 	{
diff -urN linux-2.5.67-bk7/net/ipv6/mcast.c linux-2.5.67-bk8/net/ipv6/mcast.c
--- linux-2.5.67-bk7/net/ipv6/mcast.c	2003-04-07 10:32:28.000000000 -0700
+++ linux-2.5.67-bk8/net/ipv6/mcast.c	2003-04-17 04:38:38.000000000 -0700
@@ -24,6 +24,8 @@
  *	YOSHIFUJI Hideaki @USAGI:
  *		- Ignore Queries for invalid addresses.
  *		- MLD for link-local addresses.
+ *	David L Stevens <dlstevens@us.ibm.com>:
+ *		- MLDv2 support
  */
 
 #include <linux/config.h>
@@ -35,6 +37,7 @@
 #include <linux/sockios.h>
 #include <linux/jiffies.h>
 #include <linux/net.h>
+#include <linux/in.h>
 #include <linux/in6.h>
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
@@ -63,6 +66,58 @@
 #define MDBG(x)
 #endif
 
+/*
+ *  These header formats should be in a separate include file, but icmpv6.h
+ *  doesn't have in6_addr defined in all cases, there is no __u128, and no
+ *  other files reference these.
+ *
+ *  			+-DLS 4/14/03
+ */
+
+/* Multicast Listener Discovery version 2 headers */
+
+struct mld2_grec {
+	__u8		grec_type;
+	__u8		grec_auxwords;
+	__u16		grec_nsrcs;
+	struct in6_addr	grec_mca;
+	struct in6_addr	grec_src[0];
+};
+
+struct mld2_report {
+	__u8	type;
+	__u8	resv1;
+	__u16	csum;
+	__u16	resv2;
+	__u16	ngrec;
+	struct mld2_grec grec[0];
+};
+
+struct mld2_query {
+	__u8 type;
+	__u8 code;
+	__u16 csum;
+	__u16 mrc;
+	__u16 resv1;
+	struct in6_addr mca;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	__u8 qrv:3,
+	     suppress:1,
+	     resv2:4;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+	__u8 resv2:4,
+	     suppress:1,
+	     qrv:3;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	__u8 qqic;
+	__u16 nsrcs;
+	struct in6_addr srcs[0];
+};
+
+struct in6_addr mld2_all_mcr = MLD2_ALL_MCR_INIT;
+
 /* Big mc list lock for all the sockets */
 static rwlock_t ipv6_sk_mc_lock = RW_LOCK_UNLOCKED;
 
@@ -72,7 +127,37 @@
 static void igmp6_leave_group(struct ifmcaddr6 *ma);
 static void igmp6_timer_handler(unsigned long data);
 
+static void mld_gq_timer_expire(unsigned long data);
+static void mld_ifc_timer_expire(unsigned long data);
+static void mld_ifc_event(struct inet6_dev *idev);
+static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *pmc);
+static void mld_del_delrec(struct inet6_dev *idev, struct in6_addr *addr);
+static void mld_clear_delrec(struct inet6_dev *idev);
+static int sf_setstate(struct ifmcaddr6 *pmc);
+static void sf_markstate(struct ifmcaddr6 *pmc);
+static void ip6_mc_clear_src(struct ifmcaddr6 *pmc);
+int ip6_mc_del_src(struct inet6_dev *idev, struct in6_addr *pmca, int sfmode,
+	int sfcount, struct in6_addr *psfsrc, int delta);
+int ip6_mc_add_src(struct inet6_dev *idev, struct in6_addr *pmca, int sfmode,
+	int sfcount, struct in6_addr *psfsrc, int delta);
+int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml,
+	struct inet6_dev *idev);
+
+
 #define IGMP6_UNSOLICITED_IVAL	(10*HZ)
+#define MLD_QRV_DEFAULT		2
+
+#define MLD_V1_SEEN(idev) ((idev)->mc_v1_seen && \
+		time_before(jiffies, (idev)->mc_v1_seen))
+
+#define MLDV2_MASK(value, nb) ((nb)>=32 ? (value) : ((1<<(nb))-1) & (value))
+#define MLDV2_EXP(thresh, nbmant, nbexp, value) \
+	((value) < (thresh) ? (value) : \
+	((MLDV2_MASK(value, nbmant) | (1<<(nbmant+nbexp))) << \
+	(MLDV2_MASK((value) >> (nbmant), nbexp) + (nbexp))))
+
+#define MLDV2_QQIC(value) MLDV2_EXP(0x80, 4, 3, value)
+#define MLDV2_MRC(value) MLDV2_EXP(0x8000, 12, 3, value)
 
 /*
  *	socket join on multicast group
@@ -113,6 +198,8 @@
 	}
 
 	mc_lst->ifindex = dev->ifindex;
+	mc_lst->sfmode = MCAST_EXCLUDE;
+	mc_lst->sflist = 0;
 
 	/*
 	 *	now add/increase the group membership on the device
@@ -154,6 +241,12 @@
 			write_unlock_bh(&ipv6_sk_mc_lock);
 
 			if ((dev = dev_get_by_index(mc_lst->ifindex)) != NULL) {
+				struct inet6_dev *idev = in6_dev_get(dev);
+
+				if (idev) {
+					(void) ip6_mc_leave_src(sk,mc_lst,idev);
+					in6_dev_put(idev);
+				}
 				ipv6_dev_mc_dec(dev, &mc_lst->addr);
 				dev_put(dev);
 			}
@@ -166,6 +259,40 @@
 	return -ENOENT;
 }
 
+struct inet6_dev *ip6_mc_find_dev(struct in6_addr *group, int ifindex)
+{
+	struct net_device *dev = 0;
+	struct inet6_dev *idev = 0;
+
+	if (ifindex == 0) {
+		struct rt6_info *rt;
+
+		rt = rt6_lookup(group, NULL, 0, 0);
+		if (rt) {
+			dev = rt->rt6i_dev;
+			dev_hold(dev);
+			dst_release(&rt->u.dst);
+		}
+	} else
+		dev = dev_get_by_index(ifindex);
+
+	if (!dev)
+		return 0;
+	idev = in6_dev_get(dev);
+	if (!idev) {
+		dev_put(dev);
+		return 0;
+	}
+	read_lock_bh(&idev->lock);
+	if (idev->dead) {
+		read_unlock_bh(&idev->lock);
+		in6_dev_put(idev);
+		dev_put(dev);
+		return 0;
+	}
+	return idev;
+}
+
 void ipv6_sock_mc_close(struct sock *sk)
 {
 	struct ipv6_pinfo *np = inet6_sk(sk);
@@ -180,6 +307,12 @@
 
 		dev = dev_get_by_index(mc_lst->ifindex);
 		if (dev) {
+			struct inet6_dev *idev = in6_dev_get(dev);
+
+			if (idev) {
+				(void) ip6_mc_leave_src(sk, mc_lst, idev);
+				in6_dev_put(idev);
+			}
 			ipv6_dev_mc_dec(dev, &mc_lst->addr);
 			dev_put(dev);
 		}
@@ -191,21 +324,291 @@
 	write_unlock_bh(&ipv6_sk_mc_lock);
 }
 
-int inet6_mc_check(struct sock *sk, struct in6_addr *addr)
+int ip6_mc_source(int add, int omode, struct sock *sk,
+	struct group_source_req *pgsr)
+{
+	struct in6_addr *source, *group;
+	struct ipv6_mc_socklist *pmc;
+	struct net_device *dev;
+	struct inet6_dev *idev;
+	struct ipv6_pinfo *inet6 = inet6_sk(sk);
+	struct ip6_sf_socklist *psl;
+	int i, j, rv;
+	int err;
+
+	if (pgsr->gsr_group.ss_family != AF_INET6 ||
+	    pgsr->gsr_source.ss_family != AF_INET6)
+		return -EINVAL;
+
+	source = &((struct sockaddr_in6 *)&pgsr->gsr_source)->sin6_addr;
+	group = &((struct sockaddr_in6 *)&pgsr->gsr_group)->sin6_addr;
+
+	if (!(ipv6_addr_type(group) & IPV6_ADDR_MULTICAST))
+		return -EINVAL;
+
+	idev = ip6_mc_find_dev(group, pgsr->gsr_interface);
+	if (!idev)
+		return -ENODEV;
+	dev = idev->dev;
+
+	err = -EADDRNOTAVAIL;
+
+	for (pmc=inet6->ipv6_mc_list; pmc; pmc=pmc->next) {
+		if (pmc->ifindex != pgsr->gsr_interface)
+			continue;
+		if (ipv6_addr_cmp(&pmc->addr, group) == 0)
+			break;
+	}
+	if (!pmc)		/* must have a prior join */
+		goto done;
+	/* if a source filter was set, must be the same mode as before */
+	if (pmc->sflist) {
+		if (pmc->sfmode != omode)
+			goto done;
+	} else if (pmc->sfmode != omode) {
+		/* allow mode switches for empty-set filters */
+		ip6_mc_del_src(idev, group, pmc->sfmode, 0, 0, 0);
+		pmc->sfmode = omode;
+		ip6_mc_del_src(idev, group, pmc->sfmode, 0, 0, 0);
+	}
+
+	psl = pmc->sflist;
+	if (!add) {
+		if (!psl)
+			goto done;
+		rv = !0;
+		for (i=0; i<psl->sl_count; i++) {
+			rv = memcmp(&psl->sl_addr, group,
+				sizeof(struct in6_addr));
+			if (rv >= 0)
+				break;
+		}
+		if (!rv)	/* source not found */
+			goto done;
+
+		/* update the interface filter */
+		ip6_mc_del_src(idev, group, omode, 1, source, 1);
+
+		for (j=i+1; j<psl->sl_count; j++)
+			psl->sl_addr[j-1] = psl->sl_addr[j];
+		psl->sl_count--;
+		err = 0;
+		goto done;
+	}
+	/* else, add a new source to the filter */
+
+	if (!psl || psl->sl_count == psl->sl_max) {
+		struct ip6_sf_socklist *newpsl;
+		int count = IP6_SFBLOCK;
+
+		if (psl)
+			count += psl->sl_max;
+		newpsl = (struct ip6_sf_socklist *)sock_kmalloc(sk,
+			IP6_SFLSIZE(count), GFP_ATOMIC);
+		if (!newpsl) {
+			err = -ENOBUFS;
+			goto done;
+		}
+		newpsl->sl_max = count;
+		newpsl->sl_count = count - IP6_SFBLOCK;
+		if (psl) {
+			for (i=0; i<psl->sl_count; i++)
+				newpsl->sl_addr[i] = psl->sl_addr[i];
+			sock_kfree_s(sk, psl, IP6_SFLSIZE(psl->sl_max));
+		}
+		pmc->sflist = psl = newpsl;
+	}
+	rv = 1;	/* > 0 for insert logic below if sl_count is 0 */
+	for (i=0; i<psl->sl_count; i++) {
+		rv = memcmp(&psl->sl_addr, group, sizeof(struct in6_addr));
+		if (rv >= 0)
+			break;
+	}
+	if (rv == 0)		/* address already there is an error */
+		goto done;
+	for (j=psl->sl_count-1; j>=i; j--)
+		psl->sl_addr[j+1] = psl->sl_addr[j];
+	psl->sl_addr[i] = *source;
+	psl->sl_count++;
+	err = 0;
+	/* update the interface list */
+	ip6_mc_add_src(idev, group, omode, 1, source, 1);
+done:
+	read_unlock_bh(&idev->lock);
+	in6_dev_put(idev);
+	dev_put(dev);
+	return err;
+}
+
+int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf)
+{
+	struct in6_addr *group;
+	struct ipv6_mc_socklist *pmc;
+	struct net_device *dev;
+	struct inet6_dev *idev;
+	struct ipv6_pinfo *inet6 = inet6_sk(sk);
+	struct ip6_sf_socklist *newpsl, *psl;
+	int i, err;
+
+	group = &((struct sockaddr_in6 *)&gsf->gf_group)->sin6_addr;
+
+	if (!(ipv6_addr_type(group) & IPV6_ADDR_MULTICAST))
+		return -EINVAL;
+	if (gsf->gf_fmode != MCAST_INCLUDE &&
+	    gsf->gf_fmode != MCAST_EXCLUDE)
+		return -EINVAL;
+
+	idev = ip6_mc_find_dev(group, gsf->gf_interface);
+
+	if (!idev)
+		return -ENODEV;
+	dev = idev->dev;
+	err = -EADDRNOTAVAIL;
+
+	for (pmc=inet6->ipv6_mc_list; pmc; pmc=pmc->next) {
+		if (pmc->ifindex != gsf->gf_interface)
+			continue;
+		if (ipv6_addr_cmp(&pmc->addr, group) == 0)
+			break;
+	}
+	if (!pmc)		/* must have a prior join */
+		goto done;
+	if (gsf->gf_numsrc) {
+		newpsl = (struct ip6_sf_socklist *)sock_kmalloc(sk,
+				IP6_SFLSIZE(gsf->gf_numsrc), GFP_ATOMIC);
+		if (!newpsl) {
+			err = -ENOBUFS;
+			goto done;
+		}
+		newpsl->sl_max = newpsl->sl_count = gsf->gf_numsrc;
+		for (i=0; i<newpsl->sl_count; ++i) {
+			struct sockaddr_in6 *psin6;
+
+			psin6 = (struct sockaddr_in6 *)&gsf->gf_slist[i];
+			newpsl->sl_addr[i] = psin6->sin6_addr;
+		}
+		err = ip6_mc_add_src(idev, group, gsf->gf_fmode,
+			newpsl->sl_count, newpsl->sl_addr, 0);
+		if (err) {
+			sock_kfree_s(sk, newpsl, IP6_SFLSIZE(newpsl->sl_max));
+			goto done;
+		}
+	} else
+		newpsl = 0;
+	psl = pmc->sflist;
+	if (psl) {
+		(void) ip6_mc_del_src(idev, group, pmc->sfmode,
+			psl->sl_count, psl->sl_addr, 0);
+		sock_kfree_s(sk, psl, IP6_SFLSIZE(psl->sl_max));
+	} else
+		(void) ip6_mc_del_src(idev, group, pmc->sfmode, 0, 0, 0);
+	pmc->sflist = newpsl;
+	pmc->sfmode = gsf->gf_fmode;
+done:
+	read_unlock_bh(&idev->lock);
+	in6_dev_put(idev);
+	dev_put(dev);
+	return err;
+}
+
+int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
+	struct group_filter *optval, int *optlen)
+{
+	int err, i, count, copycount;
+	struct in6_addr *group;
+	struct ipv6_mc_socklist *pmc;
+	struct inet6_dev *idev;
+	struct net_device *dev;
+	struct ipv6_pinfo *inet6 = inet6_sk(sk);
+	struct ip6_sf_socklist *psl;
+
+	group = &((struct sockaddr_in6 *)&gsf->gf_group)->sin6_addr;
+
+	if (!(ipv6_addr_type(group) & IPV6_ADDR_MULTICAST))
+		return -EINVAL;
+
+	idev = ip6_mc_find_dev(group, gsf->gf_interface);
+
+	if (!idev)
+		return -ENODEV;
+
+	dev = idev->dev;
+
+	err = -EADDRNOTAVAIL;
+
+	for (pmc=inet6->ipv6_mc_list; pmc; pmc=pmc->next) {
+		if (pmc->ifindex != gsf->gf_interface)
+			continue;
+		if (ipv6_addr_cmp(group, &pmc->addr) == 0)
+			break;
+	}
+	if (!pmc)		/* must have a prior join */
+		goto done;
+	gsf->gf_fmode = pmc->sfmode;
+	psl = pmc->sflist;
+	count = psl ? psl->sl_count : 0;
+	read_unlock_bh(&idev->lock);
+	in6_dev_put(idev);
+	dev_put(dev);
+
+	copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc;
+	gsf->gf_numsrc = count;
+	if (put_user(GROUP_FILTER_SIZE(copycount), optlen) ||
+	    copy_to_user((void *)optval, gsf, GROUP_FILTER_SIZE(0))) {
+		return -EFAULT;
+	}
+	for (i=0; i<copycount; i++) {
+		struct sockaddr_in6 *psin6;
+		struct sockaddr_storage ss;
+
+		psin6 = (struct sockaddr_in6 *)&ss;
+		memset(&ss, 0, sizeof(ss));
+		psin6->sin6_family = AF_INET6;
+		psin6->sin6_addr = psl->sl_addr[i];
+	    	if (copy_to_user((void *)&optval->gf_slist[i], &ss, sizeof(ss)))
+			return -EFAULT;
+	}
+	return 0;
+done:
+	read_unlock_bh(&idev->lock);
+	in6_dev_put(idev);
+	dev_put(dev);
+	return err;
+}
+
+int inet6_mc_check(struct sock *sk, struct in6_addr *mc_addr,
+	struct in6_addr *src_addr)
 {
 	struct ipv6_pinfo *np = inet6_sk(sk);
 	struct ipv6_mc_socklist *mc;
+	struct ip6_sf_socklist *psl;
+	int rv = 0;
 
 	read_lock(&ipv6_sk_mc_lock);
 	for (mc = np->ipv6_mc_list; mc; mc = mc->next) {
-		if (ipv6_addr_cmp(&mc->addr, addr) == 0) {
-			read_unlock(&ipv6_sk_mc_lock);
-			return 1;
+		if (ipv6_addr_cmp(&mc->addr, mc_addr) == 0)
+			break;
+	}
+	if (!mc) {
+		read_unlock(&ipv6_sk_mc_lock);
+		return 0;
+	}
+	psl = mc->sflist;
+	if (!psl) {
+		rv = mc->sfmode == MCAST_EXCLUDE;
+	} else {
+		int i;
+
+		for (i=0; i<psl->sl_count; i++) {
+			if (ipv6_addr_cmp(&psl->sl_addr[i], src_addr) == 0)
+				break;
 		}
+		rv = (mc->sfmode == MCAST_INCLUDE && i < psl->sl_count);
+		rv |= (mc->sfmode == MCAST_EXCLUDE && i >= psl->sl_count);
 	}
 	read_unlock(&ipv6_sk_mc_lock);
 
-	return 0;
+	return rv;
 }
 
 static void ma_put(struct ifmcaddr6 *mc)
@@ -216,7 +619,7 @@
 	}
 }
 
-static int igmp6_group_added(struct ifmcaddr6 *mc)
+static void igmp6_group_added(struct ifmcaddr6 *mc)
 {
 	struct net_device *dev = mc->idev->dev;
 	char buf[MAX_ADDR_LEN];
@@ -229,12 +632,20 @@
 	}
 	spin_unlock_bh(&mc->mca_lock);
 
-	if (dev->flags&IFF_UP)
+	if (!(dev->flags & IFF_UP) || (mc->mca_flags & MAF_NOREPORT))
+		return;
+
+	if (MLD_V1_SEEN(mc->idev)) {
 		igmp6_join_group(mc);
-	return 0;
+		return;
+	}
+	/* else v2 */
+
+	mc->mca_crcount = mc->idev->mc_qrv;
+	mld_ifc_event(mc->idev);
 }
 
-static int igmp6_group_dropped(struct ifmcaddr6 *mc)
+static void igmp6_group_dropped(struct ifmcaddr6 *mc)
 {
 	struct net_device *dev = mc->idev->dev;
 	char buf[MAX_ADDR_LEN];
@@ -247,9 +658,122 @@
 	}
 	spin_unlock_bh(&mc->mca_lock);
 
+	if (mc->mca_flags & MAF_NOREPORT)
+		goto done;
+
 	if (dev->flags&IFF_UP)
 		igmp6_leave_group(mc);
-	return 0;
+
+	spin_lock_bh(&mc->mca_lock);
+	if (del_timer(&mc->mca_timer))
+		atomic_dec(&mc->mca_refcnt);
+	spin_unlock_bh(&mc->mca_lock);
+
+done:
+	ip6_mc_clear_src(mc);
+}
+
+/*
+ * deleted ifmcaddr6 manipulation
+ */
+static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im)
+{
+	struct ifmcaddr6 *pmc;
+
+	/* this is an "ifmcaddr6" for convenience; only the fields below
+	 * are actually used. In particular, the refcnt and users are not
+	 * used for management of the delete list. Using the same structure
+	 * for deleted items allows change reports to use common code with
+	 * non-deleted or query-response MCA's.
+	 */
+	pmc = (struct ifmcaddr6 *)kmalloc(sizeof(*pmc), GFP_ATOMIC);
+	if (!pmc)
+		return;
+	memset(pmc, 0, sizeof(*pmc));
+	spin_lock_bh(&im->mca_lock);
+	pmc->mca_lock = SPIN_LOCK_UNLOCKED;
+	pmc->idev = im->idev;
+	in6_dev_hold(idev);
+	pmc->mca_addr = im->mca_addr;
+	pmc->mca_crcount = idev->mc_qrv;
+	pmc->mca_sfmode = im->mca_sfmode;
+	if (pmc->mca_sfmode == MCAST_INCLUDE) {
+		struct ip6_sf_list *psf;
+
+		pmc->mca_tomb = im->mca_tomb;
+		pmc->mca_sources = im->mca_sources;
+		im->mca_tomb = im->mca_sources = 0;
+		for (psf=pmc->mca_sources; psf; psf=psf->sf_next)
+			psf->sf_crcount = pmc->mca_crcount;
+	}
+	spin_unlock_bh(&im->mca_lock);
+
+	write_lock_bh(&idev->mc_lock);
+	pmc->next = idev->mc_tomb;
+	idev->mc_tomb = pmc;
+	write_unlock_bh(&idev->mc_lock);
+}
+
+static void mld_del_delrec(struct inet6_dev *idev, struct in6_addr *pmca)
+{
+	struct ifmcaddr6 *pmc, *pmc_prev;
+	struct ip6_sf_list *psf, *psf_next;
+
+	write_lock_bh(&idev->mc_lock);
+	pmc_prev = 0;
+	for (pmc=idev->mc_tomb; pmc; pmc=pmc->next) {
+		if (ipv6_addr_cmp(&pmc->mca_addr, pmca) == 0)
+			break;
+		pmc_prev = pmc;
+	}
+	if (pmc) {
+		if (pmc_prev)
+			pmc_prev->next = pmc->next;
+		else
+			idev->mc_tomb = pmc->next;
+	}
+	write_unlock_bh(&idev->mc_lock);
+	if (pmc) {
+		for (psf=pmc->mca_tomb; psf; psf=psf_next) {
+			psf_next = psf->sf_next;
+			kfree(psf);
+		}
+		in6_dev_put(pmc->idev);
+		kfree(pmc);
+	}
+}
+
+static void mld_clear_delrec(struct inet6_dev *idev)
+{
+	struct ifmcaddr6 *pmc, *nextpmc;
+
+	write_lock_bh(&idev->mc_lock);
+	pmc = idev->mc_tomb;
+	idev->mc_tomb = 0;
+	write_unlock_bh(&idev->mc_lock);
+
+	for (; pmc; pmc = nextpmc) {
+		nextpmc = pmc->next;
+		ip6_mc_clear_src(pmc);
+		in6_dev_put(pmc->idev);
+		kfree(pmc);
+	}
+
+	/* clear dead sources, too */
+	read_lock_bh(&idev->lock);
+	for (pmc=idev->mc_list; pmc; pmc=pmc->next) {
+		struct ip6_sf_list *psf, *psf_next;
+
+		spin_lock_bh(&pmc->mca_lock);
+		psf = pmc->mca_tomb;
+		pmc->mca_tomb = 0;
+		spin_unlock_bh(&pmc->mca_lock);
+		for (psf=pmc->mca_tomb; psf; psf=psf_next) {
+			psf_next = psf->sf_next;
+			kfree(psf);
+		}
+	}
+	read_unlock_bh(&idev->lock);
 }
 
 
@@ -277,6 +801,8 @@
 		if (ipv6_addr_cmp(&mc->mca_addr, addr) == 0) {
 			mc->mca_users++;
 			write_unlock_bh(&idev->lock);
+			ip6_mc_add_src(idev, &mc->mca_addr, MCAST_EXCLUDE, 0,
+				0, 0);
 			in6_dev_put(idev);
 			return 0;
 		}
@@ -305,10 +831,19 @@
 	atomic_set(&mc->mca_refcnt, 2);
 	mc->mca_lock = SPIN_LOCK_UNLOCKED;
 
+	/* initial mode is (EX, empty) */
+	mc->mca_sfmode = MCAST_EXCLUDE;
+	mc->mca_sfcount[MCAST_EXCLUDE] = 1;
+
+	if (ipv6_addr_is_ll_all_nodes(&mc->mca_addr) ||
+	    IPV6_ADDR_MC_SCOPE(&mc->mca_addr) < IPV6_ADDR_SCOPE_LINKLOCAL)
+		mc->mca_flags |= MAF_NOREPORT;
+
 	mc->next = idev->mc_list;
 	idev->mc_list = mc;
 	write_unlock_bh(&idev->lock);
 
+	mld_del_delrec(idev, &mc->mca_addr);
 	igmp6_group_added(mc);
 	ma_put(mc);
 	return 0;
@@ -353,25 +888,57 @@
 /*
  *	check if the interface/address pair is valid
  */
-int ipv6_chk_mcast_addr(struct net_device *dev, struct in6_addr *addr)
+int ipv6_chk_mcast_addr(struct net_device *dev, struct in6_addr *group,
+	struct in6_addr *src_addr)
 {
 	struct inet6_dev *idev;
 	struct ifmcaddr6 *mc;
+	int rv = 0;
 
 	idev = in6_dev_get(dev);
 	if (idev) {
 		read_lock_bh(&idev->lock);
 		for (mc = idev->mc_list; mc; mc=mc->next) {
-			if (ipv6_addr_cmp(&mc->mca_addr, addr) == 0) {
-				read_unlock_bh(&idev->lock);
-				in6_dev_put(idev);
-				return 1;
+			if (ipv6_addr_cmp(&mc->mca_addr, group) == 0)
+				break;
+		}
+		if (mc) {
+			struct ip6_sf_list *psf;
+
+			spin_lock_bh(&mc->mca_lock);
+			for (psf=mc->mca_sources; psf; psf=psf->sf_next) {
+				if (ipv6_addr_cmp(&psf->sf_addr, src_addr) == 0)
+					break;
 			}
+			if (psf)
+				rv = psf->sf_count[MCAST_INCLUDE] ||
+					psf->sf_count[MCAST_EXCLUDE] !=
+					mc->mca_sfcount[MCAST_EXCLUDE];
+			else
+				rv = mc->mca_sfcount[MCAST_EXCLUDE] != 0;
+			spin_unlock_bh(&mc->mca_lock);
 		}
 		read_unlock_bh(&idev->lock);
 		in6_dev_put(idev);
 	}
-	return 0;
+	return rv;
+}
+
+static void mld_gq_start_timer(struct inet6_dev *idev)
+{
+	int tv = net_random() % idev->mc_maxdelay;
+
+	idev->mc_gq_running = 1;
+	if (!mod_timer(&idev->mc_gq_timer, jiffies+tv+2))
+		atomic_inc(&idev->refcnt);
+}
+
+static void mld_ifc_start_timer(struct inet6_dev *idev, int delay)
+{
+	int tv = net_random() % delay;
+
+	if (!mod_timer(&idev->mc_ifc_timer, jiffies+tv+2))
+		atomic_inc(&idev->refcnt);
 }
 
 /*
@@ -386,7 +953,6 @@
 	if (ipv6_addr_type(&ma->mca_addr)&(IPV6_ADDR_LINKLOCAL|IPV6_ADDR_LOOPBACK))
 		return;
 
-	spin_lock(&ma->mca_lock);
 	if (del_timer(&ma->mca_timer)) {
 		atomic_dec(&ma->mca_refcnt);
 		delay = ma->mca_timer.expires - jiffies;
@@ -398,60 +964,137 @@
 		else
 			delay = 1;
 	}
-
 	ma->mca_timer.expires = jiffies + delay;
 	if (!mod_timer(&ma->mca_timer, jiffies + delay))
 		atomic_inc(&ma->mca_refcnt);
-	spin_unlock(&ma->mca_lock);
+}
+
+static void mld_marksources(struct ifmcaddr6 *pmc, int nsrcs,
+	struct in6_addr *srcs)
+{
+	struct ip6_sf_list *psf;
+	int i, scount;
+
+	scount = 0;
+	for (psf=pmc->mca_sources; psf; psf=psf->sf_next) {
+		if (scount == nsrcs)
+			break;
+		for (i=0; i<nsrcs; i++)
+			if (ipv6_addr_cmp(&srcs[i], &psf->sf_addr) == 0) {
+				psf->sf_gsresp = 1;
+				scount++;
+				break;
+			}
+	}
 }
 
 int igmp6_event_query(struct sk_buff *skb)
 {
+	struct mld2_query *mlh2 = (struct mld2_query *) skb->h.raw;
 	struct ifmcaddr6 *ma;
-	struct in6_addr *addrp;
-	unsigned long resptime;
+	struct in6_addr *group;
+	unsigned long max_delay;
 	struct inet6_dev *idev;
 	struct icmp6hdr *hdr;
-	int addr_type;
+	int group_type;
+	int mark = 0;
+	int len;
 
 	if (!pskb_may_pull(skb, sizeof(struct in6_addr)))
 		return -EINVAL;
 
-	hdr = (struct icmp6hdr*) skb->h.raw;
+	len = ntohs(skb->nh.ipv6h->payload_len);
 
 	/* Drop queries with not link local source */
 	if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr)&IPV6_ADDR_LINKLOCAL))
 		return -EINVAL;
 
-	resptime = ntohs(hdr->icmp6_maxdelay);
-	/* Translate milliseconds to jiffies */
-	resptime = (resptime<<10)/(1024000/HZ);
-
-	addrp = (struct in6_addr *) (hdr + 1);
-	addr_type = ipv6_addr_type(addrp);
-
-	if (addr_type != IPV6_ADDR_ANY &&
-	    !(addr_type&IPV6_ADDR_MULTICAST))
-		return -EINVAL;
-
 	idev = in6_dev_get(skb->dev);
 
 	if (idev == NULL)
 		return 0;
 
-	read_lock(&idev->lock);
-	if (addr_type == IPV6_ADDR_ANY) {
-		for (ma = idev->mc_list; ma; ma=ma->next)
-			igmp6_group_queried(ma, resptime);
+	hdr = (struct icmp6hdr *) skb->h.raw;
+	group = (struct in6_addr *) (hdr + 1);
+	group_type = ipv6_addr_type(group);
+
+	if (group_type != IPV6_ADDR_ANY &&
+	    !(group_type&IPV6_ADDR_MULTICAST)) {
+		in6_dev_put(idev);
+		return -EINVAL;
+	}
+
+	if (len == 24) {
+		int switchback;
+		/* MLDv1 router present */
+
+		/* Translate milliseconds to jiffies */
+		max_delay = ntohs(hdr->icmp6_maxdelay)*(HZ/10);
+
+		switchback = (idev->mc_qrv + 1) * max_delay;
+		idev->mc_v1_seen = jiffies + switchback;
+
+		/* cancel the interface change timer */
+		idev->mc_ifc_count = 0;
+		if (del_timer(&idev->mc_ifc_timer))
+			atomic_dec(&idev->refcnt);
+		/* clear deleted report items */
+		mld_clear_delrec(idev);
+	} else if (len >= 28) {
+		max_delay = MLDV2_MRC(ntohs(mlh2->mrc))*(HZ/10);
+		idev->mc_maxdelay = max_delay;
+		if (mlh2->qrv)
+			idev->mc_qrv = mlh2->qrv;
+		if (group_type == IPV6_ADDR_ANY) { /* general query */
+			if (mlh2->nsrcs) {
+				in6_dev_put(idev);
+				return -EINVAL; /* no sources allowed */
+			}
+			mld_gq_start_timer(idev);
+			in6_dev_put(idev);
+			return 0;
+		}
+		/* mark sources to include, if group & source-specific */
+		mark = mlh2->nsrcs != 0;
 	} else {
+		in6_dev_put(idev);
+		return -EINVAL;
+	}
+
+	read_lock_bh(&idev->lock);
+	if (group_type == IPV6_ADDR_ANY) {
 		for (ma = idev->mc_list; ma; ma=ma->next) {
-			if (ipv6_addr_cmp(addrp, &ma->mca_addr) == 0) {
-				igmp6_group_queried(ma, resptime);
-				break;
+			spin_lock_bh(&ma->mca_lock);
+			igmp6_group_queried(ma, max_delay);
+			spin_unlock_bh(&ma->mca_lock);
+		}
+	} else {
+		for (ma = idev->mc_list; ma; ma=ma->next) {
+			if (group_type != IPV6_ADDR_ANY &&
+			    ipv6_addr_cmp(group, &ma->mca_addr) != 0)
+				continue;
+			spin_lock_bh(&ma->mca_lock);
+			if (ma->mca_flags & MAF_TIMER_RUNNING) {
+				/* gsquery <- gsquery && mark */
+				if (!mark)
+					ma->mca_flags &= ~MAF_GSQUERY;
+			} else {
+				/* gsquery <- mark */
+				if (mark)
+					ma->mca_flags |= MAF_GSQUERY;
+				else
+					ma->mca_flags &= ~MAF_GSQUERY;
 			}
+			if (ma->mca_flags & MAF_GSQUERY)
+				mld_marksources(ma, ntohs(mlh2->nsrcs),
+					mlh2->srcs);
+			igmp6_group_queried(ma, max_delay);
+			spin_unlock_bh(&ma->mca_lock);
+			if (group_type != IPV6_ADDR_ANY)
+				break;
 		}
 	}
-	read_unlock(&idev->lock);
+	read_unlock_bh(&idev->lock);
 	in6_dev_put(idev);
 
 	return 0;
@@ -491,7 +1134,7 @@
 	 *	Cancel the timer for this group
 	 */
 
-	read_lock(&idev->lock);
+	read_lock_bh(&idev->lock);
 	for (ma = idev->mc_list; ma; ma=ma->next) {
 		if (ipv6_addr_cmp(&ma->mca_addr, addrp) == 0) {
 			spin_lock(&ma->mca_lock);
@@ -502,11 +1145,376 @@
 			break;
 		}
 	}
-	read_unlock(&idev->lock);
+	read_unlock_bh(&idev->lock);
 	in6_dev_put(idev);
 	return 0;
 }
 
+static int is_in(struct ifmcaddr6 *pmc, struct ip6_sf_list *psf, int type,
+	int gdeleted, int sdeleted)
+{
+	switch (type) {
+	case MLD2_MODE_IS_INCLUDE:
+	case MLD2_MODE_IS_EXCLUDE:
+		if (gdeleted || sdeleted)
+			return 0;
+		return !((pmc->mca_flags & MAF_GSQUERY) && !psf->sf_gsresp);
+	case MLD2_CHANGE_TO_INCLUDE:
+		if (gdeleted || sdeleted)
+			return 0;
+		return psf->sf_count[MCAST_INCLUDE] != 0;
+	case MLD2_CHANGE_TO_EXCLUDE:
+		if (gdeleted || sdeleted)
+			return 0;
+		if (pmc->mca_sfcount[MCAST_EXCLUDE] == 0 ||
+		    psf->sf_count[MCAST_INCLUDE])
+			return 0;
+		return pmc->mca_sfcount[MCAST_EXCLUDE] ==
+			psf->sf_count[MCAST_EXCLUDE];
+	case MLD2_ALLOW_NEW_SOURCES:
+		if (gdeleted || !psf->sf_crcount)
+			return 0;
+		return (pmc->mca_sfmode == MCAST_INCLUDE) ^ sdeleted;
+	case MLD2_BLOCK_OLD_SOURCES:
+		if (pmc->mca_sfmode == MCAST_INCLUDE)
+			return gdeleted || (psf->sf_crcount && sdeleted);
+		return psf->sf_crcount && !gdeleted && !sdeleted;
+	}
+	return 0;
+}
+
+static int
+mld_scount(struct ifmcaddr6 *pmc, int type, int gdeleted, int sdeleted)
+{
+	struct ip6_sf_list *psf;
+	int scount = 0;
+
+	for (psf=pmc->mca_sources; psf; psf=psf->sf_next) {
+		if (!is_in(pmc, psf, type, gdeleted, sdeleted))
+			continue;
+		scount++;
+	}
+	return scount;
+}
+
+static struct sk_buff *mld_newpack(struct net_device *dev, int size)
+{
+	struct sock *sk = igmp6_socket->sk;
+	struct sk_buff *skb;
+	struct mld2_report *pmr;
+	struct in6_addr addr_buf;
+	int err;
+	u8 ra[8] = { IPPROTO_ICMPV6, 0,
+		     IPV6_TLV_ROUTERALERT, 2, 0, 0,
+		     IPV6_TLV_PADN, 0 };
+
+	skb = sock_alloc_send_skb(sk, size + dev->hard_header_len+15, 0, &err);
+
+	if (skb == 0)
+		return 0;
+
+	skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
+	if (dev->hard_header) {
+		unsigned char ha[MAX_ADDR_LEN];
+
+		ndisc_mc_map(&mld2_all_mcr, ha, dev, 1);
+		if (dev->hard_header(skb, dev, ETH_P_IPV6,ha,NULL,size) < 0) {
+			kfree_skb(skb);
+			return 0;
+		}
+	}
+
+	if (ipv6_get_lladdr(dev, &addr_buf)) {
+		/* <draft-ietf-magma-mld-source-02.txt>:
+		 * use unspecified address as the source address 
+		 * when a valid link-local address is not available.
+		 */
+		memset(&addr_buf, 0, sizeof(addr_buf));
+	}
+
+	ip6_nd_hdr(sk, skb, dev, &addr_buf, &mld2_all_mcr, NEXTHDR_HOP, 0);
+
+	memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra));
+
+	pmr =(struct mld2_report *)skb_put(skb, sizeof(*pmr));
+	skb->h.raw = (unsigned char *)pmr;
+	pmr->type = ICMPV6_MLD2_REPORT;
+	pmr->resv1 = 0;
+	pmr->csum = 0;
+	pmr->resv2 = 0;
+	pmr->ngrec = 0;
+	return skb;
+}
+
+static void mld_sendpack(struct sk_buff *skb)
+{
+	struct ipv6hdr *pip6 = skb->nh.ipv6h;
+	struct mld2_report *pmr = (struct mld2_report *)skb->h.raw;
+	int payload_len, mldlen;
+
+	payload_len = skb->tail - (unsigned char *)skb->nh.ipv6h -
+		sizeof(struct ipv6hdr);
+	mldlen = skb->tail - skb->h.raw;
+	pip6->payload_len = htons(payload_len);
+
+	pmr->csum = csum_ipv6_magic(&pip6->saddr, &pip6->daddr, mldlen,
+		IPPROTO_ICMPV6, csum_partial(skb->h.raw, mldlen, 0));
+	dev_queue_xmit(skb);
+	ICMP6_INC_STATS(Icmp6OutMsgs);
+}
+
+static int grec_size(struct ifmcaddr6 *pmc, int type, int gdel, int sdel)
+{
+	return sizeof(struct mld2_grec) + 4*mld_scount(pmc,type,gdel,sdel);
+}
+
+static struct sk_buff *add_grhead(struct sk_buff *skb, struct ifmcaddr6 *pmc,
+	int type, struct mld2_grec **ppgr)
+{
+	struct net_device *dev = pmc->idev->dev;
+	struct mld2_report *pmr;
+	struct mld2_grec *pgr;
+
+	if (!skb)
+		skb = mld_newpack(dev, dev->mtu);
+	if (!skb)
+		return 0;
+	pgr = (struct mld2_grec *)skb_put(skb, sizeof(struct mld2_grec));
+	pgr->grec_type = type;
+	pgr->grec_auxwords = 0;
+	pgr->grec_nsrcs = 0;
+	pgr->grec_mca = pmc->mca_addr;	/* structure copy */
+	pmr = (struct mld2_report *)skb->h.raw;
+	pmr->ngrec = htons(ntohs(pmr->ngrec)+1);
+	*ppgr = pgr;
+	return skb;
+}
+
+#define AVAILABLE(skb) ((skb) ? ((skb)->dev ? (skb)->dev->mtu - (skb)->len : \
+	skb_tailroom(skb)) : 0)
+
+static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc,
+	int type, int gdeleted, int sdeleted)
+{
+	struct net_device *dev = pmc->idev->dev;
+	struct mld2_report *pmr;
+	struct mld2_grec *pgr = 0;
+	struct ip6_sf_list *psf, *psf_next, *psf_prev, *psf_list;
+	int scount, first, isquery, truncate;
+
+	if (pmc->mca_flags & MAF_NOREPORT)
+		return skb;
+
+	isquery = type == MLD2_MODE_IS_INCLUDE ||
+		  type == MLD2_MODE_IS_EXCLUDE;
+	truncate = type == MLD2_MODE_IS_EXCLUDE ||
+		    type == MLD2_CHANGE_TO_EXCLUDE;
+
+	psf_list = sdeleted ? pmc->mca_tomb : pmc->mca_sources;
+
+	if (!psf_list) {
+		if (type == MLD2_ALLOW_NEW_SOURCES ||
+		    type == MLD2_BLOCK_OLD_SOURCES)
+			return skb;
+		if (pmc->mca_crcount || isquery)
+			skb = add_grhead(skb, pmc, type, &pgr);
+		return skb;
+	}
+	pmr = skb ? (struct mld2_report *)skb->h.raw : 0;
+
+	/* EX and TO_EX get a fresh packet, if needed */
+	if (truncate) {
+		if (pmr && pmr->ngrec &&
+		    AVAILABLE(skb) < grec_size(pmc, type, gdeleted, sdeleted)) {
+			if (skb)
+				mld_sendpack(skb);
+			skb = mld_newpack(dev, dev->mtu);
+		}
+	}
+	first = 1;
+	scount = 0;
+	psf_prev = 0;
+	for (psf=psf_list; psf; psf=psf_next) {
+		struct in6_addr *psrc;
+
+		psf_next = psf->sf_next;
+
+		if (!is_in(pmc, psf, type, gdeleted, sdeleted)) {
+			psf_prev = psf;
+			continue;
+		}
+
+		/* clear marks on query responses */
+		if (isquery)
+			psf->sf_gsresp = 0;
+
+		if (AVAILABLE(skb) < sizeof(*psrc) +
+		    first*sizeof(struct mld2_grec)) {
+			if (truncate && !first)
+				break;	 /* truncate these */
+			if (pgr)
+				pgr->grec_nsrcs = htons(scount);
+			if (skb)
+				mld_sendpack(skb);
+			skb = mld_newpack(dev, dev->mtu);
+			first = 1;
+			scount = 0;
+		}
+		if (first) {
+			skb = add_grhead(skb, pmc, type, &pgr);
+			first = 0;
+		}
+		psrc = (struct in6_addr *)skb_put(skb, sizeof(*psrc));
+		*psrc = psf->sf_addr;
+		scount++;
+		if ((type == MLD2_ALLOW_NEW_SOURCES ||
+		     type == MLD2_BLOCK_OLD_SOURCES) && psf->sf_crcount) {
+			psf->sf_crcount--;
+			if ((sdeleted || gdeleted) && psf->sf_crcount == 0) {
+				if (psf_prev)
+					psf_prev->sf_next = psf->sf_next;
+				else
+					pmc->mca_tomb = psf->sf_next;
+				kfree(psf);
+				continue;
+			}
+		}
+		psf_prev = psf;
+	}
+	if (pgr)
+		pgr->grec_nsrcs = htons(scount);
+
+	if (isquery)
+		pmc->mca_flags &= ~MAF_GSQUERY;	/* clear query state */
+	return skb;
+}
+
+static void mld_send_report(struct inet6_dev *idev, struct ifmcaddr6 *pmc)
+{
+	struct sk_buff *skb = 0;
+	int type;
+
+	if (!pmc) {
+		read_lock_bh(&idev->lock);
+		for (pmc=idev->mc_list; pmc; pmc=pmc->next) {
+			if (pmc->mca_flags & MAF_NOREPORT)
+				continue;
+			spin_lock_bh(&pmc->mca_lock);
+			if (pmc->mca_sfcount[MCAST_EXCLUDE])
+				type = MLD2_MODE_IS_EXCLUDE;
+			else
+				type = MLD2_MODE_IS_INCLUDE;
+			skb = add_grec(skb, pmc, type, 0, 0);
+			spin_unlock_bh(&pmc->mca_lock);
+		}
+		read_unlock_bh(&idev->lock);
+	} else {
+		spin_lock_bh(&pmc->mca_lock);
+		if (pmc->mca_sfcount[MCAST_EXCLUDE])
+			type = MLD2_MODE_IS_EXCLUDE;
+		else
+			type = MLD2_MODE_IS_INCLUDE;
+		skb = add_grec(skb, pmc, type, 0, 0);
+		spin_unlock_bh(&pmc->mca_lock);
+	}
+	if (skb)
+		mld_sendpack(skb);
+}
+
+/*
+ * remove zero-count source records from a source filter list
+ */
+static void mld_clear_zeros(struct ip6_sf_list **ppsf)
+{
+	struct ip6_sf_list *psf_prev, *psf_next, *psf;
+
+	psf_prev = 0;
+	for (psf=*ppsf; psf; psf = psf_next) {
+		psf_next = psf->sf_next;
+		if (psf->sf_crcount == 0) {
+			if (psf_prev)
+				psf_prev->sf_next = psf->sf_next;
+			else
+				*ppsf = psf->sf_next;
+			kfree(psf);
+		} else
+			psf_prev = psf;
+	}
+}
+
+static void mld_send_cr(struct inet6_dev *idev)
+{
+	struct ifmcaddr6 *pmc, *pmc_prev, *pmc_next;
+	struct sk_buff *skb = 0;
+	int type, dtype;
+
+	read_lock_bh(&idev->lock);
+	write_lock_bh(&idev->mc_lock);
+
+	/* deleted MCA's */
+	pmc_prev = 0;
+	for (pmc=idev->mc_tomb; pmc; pmc=pmc_next) {
+		pmc_next = pmc->next;
+		if (pmc->mca_sfmode == MCAST_INCLUDE) {
+			type = MLD2_BLOCK_OLD_SOURCES;
+			dtype = MLD2_BLOCK_OLD_SOURCES;
+			skb = add_grec(skb, pmc, type, 1, 0);
+			skb = add_grec(skb, pmc, dtype, 1, 1);
+		}
+		if (pmc->mca_crcount) {
+			pmc->mca_crcount--;
+			if (pmc->mca_sfmode == MCAST_EXCLUDE) {
+				type = MLD2_CHANGE_TO_INCLUDE;
+				skb = add_grec(skb, pmc, type, 1, 0);
+			}
+			if (pmc->mca_crcount == 0) {
+				mld_clear_zeros(&pmc->mca_tomb);
+				mld_clear_zeros(&pmc->mca_sources);
+			}
+		}
+		if (pmc->mca_crcount == 0 && !pmc->mca_tomb &&
+		    !pmc->mca_sources) {
+			if (pmc_prev)
+				pmc_prev->next = pmc_next;
+			else
+				idev->mc_tomb = pmc_next;
+			in6_dev_put(pmc->idev);
+			kfree(pmc);
+		} else
+			pmc_prev = pmc;
+	}
+	write_unlock_bh(&idev->mc_lock);
+
+	/* change recs */
+	for (pmc=idev->mc_list; pmc; pmc=pmc->next) {
+		spin_lock_bh(&pmc->mca_lock);
+		if (pmc->mca_sfcount[MCAST_EXCLUDE]) {
+			type = MLD2_BLOCK_OLD_SOURCES;
+			dtype = MLD2_ALLOW_NEW_SOURCES;
+		} else {
+			type = MLD2_ALLOW_NEW_SOURCES;
+			dtype = MLD2_BLOCK_OLD_SOURCES;
+		}
+		skb = add_grec(skb, pmc, type, 0, 0);
+		skb = add_grec(skb, pmc, dtype, 0, 1);	/* deleted sources */
+
+		/* filter mode changes */
+		if (pmc->mca_crcount) {
+			pmc->mca_crcount--;
+			if (pmc->mca_sfmode == MCAST_EXCLUDE)
+				type = MLD2_CHANGE_TO_EXCLUDE;
+			else
+				type = MLD2_CHANGE_TO_INCLUDE;
+			skb = add_grec(skb, pmc, type, 0, 0);
+		}
+		spin_unlock_bh(&pmc->mca_lock);
+	}
+	read_unlock_bh(&idev->lock);
+	if (!skb)
+		return;
+	(void) mld_sendpack(skb);
+}
+
 static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
 {
 	struct sock *sk = igmp6_socket->sk;
@@ -579,12 +1587,251 @@
 	kfree_skb(skb);
 }
 
+static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode,
+	struct in6_addr *psfsrc)
+{
+	struct ip6_sf_list *psf, *psf_prev;
+	int rv = 0;
+
+	psf_prev = 0;
+	for (psf=pmc->mca_sources; psf; psf=psf->sf_next) {
+		if (ipv6_addr_cmp(&psf->sf_addr, psfsrc) == 0)
+			break;
+		psf_prev = psf;
+	}
+	if (!psf || psf->sf_count[sfmode] == 0) {
+		/* source filter not found, or count wrong =>  bug */
+		return -ESRCH;
+	}
+	psf->sf_count[sfmode]--;
+	if (!psf->sf_count[MCAST_INCLUDE] && !psf->sf_count[MCAST_EXCLUDE]) {
+		struct inet6_dev *idev = pmc->idev;
+
+		/* no more filters for this source */
+		if (psf_prev)
+			psf_prev->sf_next = psf->sf_next;
+		else
+			pmc->mca_sources = psf->sf_next;
+		if (psf->sf_oldin && !(pmc->mca_flags & MAF_NOREPORT) &&
+		    !MLD_V1_SEEN(idev)) {
+			psf->sf_crcount = idev->mc_qrv;
+			psf->sf_next = pmc->mca_tomb;
+			pmc->mca_tomb = psf;
+			rv = 1;
+		} else
+			kfree(psf);
+	}
+	return rv;
+}
+
+int ip6_mc_del_src(struct inet6_dev *idev, struct in6_addr *pmca, int sfmode,
+	int sfcount, struct in6_addr *psfsrc, int delta)
+{
+	struct ifmcaddr6 *pmc;
+	int	changerec = 0;
+	int	i, err;
+
+	if (!idev)
+		return -ENODEV;
+	read_lock_bh(&idev->lock);
+	for (pmc=idev->mc_list; pmc; pmc=pmc->next) {
+		if (ipv6_addr_cmp(pmca, &pmc->mca_addr) == 0)
+			break;
+	}
+	if (!pmc) {
+		/* MCA not found?? bug */
+		read_unlock_bh(&idev->lock);
+		return -ESRCH;
+	}
+	spin_lock_bh(&pmc->mca_lock);
+	read_unlock_bh(&idev->lock);
+	sf_markstate(pmc);
+	if (!delta) {
+		if (!pmc->mca_sfcount[sfmode]) {
+			spin_unlock_bh(&pmc->mca_lock);
+			return -EINVAL;
+		}
+		pmc->mca_sfcount[sfmode]--;
+	}
+	err = 0;
+	for (i=0; i<sfcount; i++) {
+		int rv = ip6_mc_del1_src(pmc, sfmode, &psfsrc[i]);
+
+		changerec |= rv > 0;
+		if (!err && rv < 0)
+			err = rv;
+	}
+	if (pmc->mca_sfmode == MCAST_EXCLUDE &&
+	    pmc->mca_sfcount[MCAST_EXCLUDE] == 0 &&
+	    pmc->mca_sfcount[MCAST_INCLUDE]) {
+		struct ip6_sf_list *psf;
+
+		/* filter mode change */
+		pmc->mca_sfmode = MCAST_INCLUDE;
+		pmc->mca_crcount = idev->mc_qrv;
+		idev->mc_ifc_count = pmc->mca_crcount;
+		for (psf=pmc->mca_sources; psf; psf = psf->sf_next)
+			psf->sf_crcount = 0;
+		mld_ifc_event(pmc->idev);
+	} else if (sf_setstate(pmc) || changerec)
+		mld_ifc_event(pmc->idev);
+	spin_unlock_bh(&pmc->mca_lock);
+	return err;
+}
+
+/*
+ * Add multicast single-source filter to the interface list
+ */
+static int ip6_mc_add1_src(struct ifmcaddr6 *pmc, int sfmode,
+	struct in6_addr *psfsrc, int delta)
+{
+	struct ip6_sf_list *psf, *psf_prev;
+
+	psf_prev = 0;
+	for (psf=pmc->mca_sources; psf; psf=psf->sf_next) {
+		if (ipv6_addr_cmp(&psf->sf_addr, psfsrc) == 0)
+			break;
+		psf_prev = psf;
+	}
+	if (!psf) {
+		psf = (struct ip6_sf_list *)kmalloc(sizeof(*psf), GFP_ATOMIC);
+		if (!psf)
+			return -ENOBUFS;
+		memset(psf, 0, sizeof(*psf));
+		psf->sf_addr = *psfsrc;
+		if (psf_prev) {
+			psf_prev->sf_next = psf;
+		} else
+			pmc->mca_sources = psf;
+	}
+	psf->sf_count[sfmode]++;
+	return 0;
+}
+
+static void sf_markstate(struct ifmcaddr6 *pmc)
+{
+	struct ip6_sf_list *psf;
+	int mca_xcount = pmc->mca_sfcount[MCAST_EXCLUDE];
+
+	for (psf=pmc->mca_sources; psf; psf=psf->sf_next)
+		if (pmc->mca_sfcount[MCAST_EXCLUDE]) {
+			psf->sf_oldin = mca_xcount ==
+				psf->sf_count[MCAST_EXCLUDE] &&
+				!psf->sf_count[MCAST_INCLUDE];
+		} else
+			psf->sf_oldin = psf->sf_count[MCAST_INCLUDE] != 0;
+}
+
+static int sf_setstate(struct ifmcaddr6 *pmc)
+{
+	struct ip6_sf_list *psf;
+	int mca_xcount = pmc->mca_sfcount[MCAST_EXCLUDE];
+	int qrv = pmc->idev->mc_qrv;
+	int new_in, rv;
+
+	rv = 0;
+	for (psf=pmc->mca_sources; psf; psf=psf->sf_next) {
+		if (pmc->mca_sfcount[MCAST_EXCLUDE]) {
+			new_in = mca_xcount == psf->sf_count[MCAST_EXCLUDE] &&
+				!psf->sf_count[MCAST_INCLUDE];
+		} else
+			new_in = psf->sf_count[MCAST_INCLUDE] != 0;
+		if (new_in != psf->sf_oldin) {
+			psf->sf_crcount = qrv;
+			rv++;
+		}
+	}
+	return rv;
+}
+
+/*
+ * Add multicast source filter list to the interface list
+ */
+int ip6_mc_add_src(struct inet6_dev *idev, struct in6_addr *pmca, int sfmode,
+	int sfcount, struct in6_addr *psfsrc, int delta)
+{
+	struct ifmcaddr6 *pmc;
+	int	isexclude;
+	int	i, err;
+
+	if (!idev)
+		return -ENODEV;
+	read_lock_bh(&idev->lock);
+	for (pmc=idev->mc_list; pmc; pmc=pmc->next) {
+		if (ipv6_addr_cmp(pmca, &pmc->mca_addr) == 0)
+			break;
+	}
+	if (!pmc) {
+		/* MCA not found?? bug */
+		read_unlock_bh(&idev->lock);
+		return -ESRCH;
+	}
+	spin_lock_bh(&pmc->mca_lock);
+	read_unlock_bh(&idev->lock);
+
+	sf_markstate(pmc);
+	isexclude = pmc->mca_sfmode == MCAST_EXCLUDE;
+	if (!delta)
+		pmc->mca_sfcount[sfmode]++;
+	err = 0;
+	for (i=0; i<sfcount; i++) {
+		err = ip6_mc_add1_src(pmc, sfmode, &psfsrc[i], delta);
+		if (err)
+			break;
+	}
+	if (err) {
+		int j;
+
+		pmc->mca_sfcount[sfmode]--;
+		for (j=0; j<i; j++)
+			(void) ip6_mc_del1_src(pmc, sfmode, &psfsrc[i]);
+	} else if (isexclude != (pmc->mca_sfcount[MCAST_EXCLUDE] != 0)) {
+		struct inet6_dev *idev = pmc->idev;
+		struct ip6_sf_list *psf;
+
+		/* filter mode change */
+		if (pmc->mca_sfcount[MCAST_EXCLUDE])
+			pmc->mca_sfmode = MCAST_EXCLUDE;
+		else if (pmc->mca_sfcount[MCAST_INCLUDE])
+			pmc->mca_sfmode = MCAST_INCLUDE;
+		/* else no filters; keep old mode for reports */
+
+		pmc->mca_crcount = idev->mc_qrv;
+		idev->mc_ifc_count = pmc->mca_crcount;
+		for (psf=pmc->mca_sources; psf; psf = psf->sf_next)
+			psf->sf_crcount = 0;
+		mld_ifc_event(idev);
+	} else if (sf_setstate(pmc))
+		mld_ifc_event(idev);
+	spin_unlock_bh(&pmc->mca_lock);
+	return err;
+}
+
+static void ip6_mc_clear_src(struct ifmcaddr6 *pmc)
+{
+	struct ip6_sf_list *psf, *nextpsf;
+
+	for (psf=pmc->mca_tomb; psf; psf=nextpsf) {
+		nextpsf = psf->sf_next;
+		kfree(psf);
+	}
+	pmc->mca_tomb = 0;
+	for (psf=pmc->mca_sources; psf; psf=nextpsf) {
+		nextpsf = psf->sf_next;
+		kfree(psf);
+	}
+	pmc->mca_sources = 0;
+	pmc->mca_sfmode = MCAST_EXCLUDE;
+	pmc->mca_sfcount[MCAST_EXCLUDE] = 0;
+	pmc->mca_sfcount[MCAST_EXCLUDE] = 1;
+}
+
+
 static void igmp6_join_group(struct ifmcaddr6 *ma)
 {
 	unsigned long delay;
 
-	if (IPV6_ADDR_MC_SCOPE(&ma->mca_addr) < IPV6_ADDR_SCOPE_LINKLOCAL ||
-	    ipv6_addr_is_ll_all_nodes(&ma->mca_addr))
+	if (ma->mca_flags & MAF_NOREPORT)
 		return;
 
 	igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REPORT);
@@ -603,26 +1850,71 @@
 	spin_unlock_bh(&ma->mca_lock);
 }
 
+int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml,
+	struct inet6_dev *idev)
+{
+	int err;
+
+	if (iml->sflist == 0) {
+		/* any-source empty exclude case */
+		return ip6_mc_del_src(idev, &iml->addr, iml->sfmode, 0, 0, 0);
+	}
+	err = ip6_mc_del_src(idev, &iml->addr, iml->sfmode,
+		iml->sflist->sl_count, iml->sflist->sl_addr, 0);
+	sock_kfree_s(sk, iml->sflist, IP6_SFLSIZE(iml->sflist->sl_max));
+	iml->sflist = 0;
+	return err;
+}
+
 static void igmp6_leave_group(struct ifmcaddr6 *ma)
 {
-	if (IPV6_ADDR_MC_SCOPE(&ma->mca_addr) < IPV6_ADDR_SCOPE_LINKLOCAL ||
-	    ipv6_addr_is_ll_all_nodes(&ma->mca_addr))
-		return;
+	if (MLD_V1_SEEN(ma->idev)) {
+		if (ma->mca_flags & MAF_LAST_REPORTER)
+			igmp6_send(&ma->mca_addr, ma->idev->dev,
+				ICMPV6_MGM_REDUCTION);
+	} else {
+		mld_add_delrec(ma->idev, ma);
+		mld_ifc_event(ma->idev);
+	}
+}
 
-	if (ma->mca_flags & MAF_LAST_REPORTER)
-		igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REDUCTION);
+static void mld_gq_timer_expire(unsigned long data)
+{
+	struct inet6_dev *idev = (struct inet6_dev *)data;
 
-	spin_lock_bh(&ma->mca_lock);
-	if (del_timer(&ma->mca_timer))
-		atomic_dec(&ma->mca_refcnt);
-	spin_unlock_bh(&ma->mca_lock);
+	idev->mc_gq_running = 0;
+	mld_send_report(idev, 0);
+}
+
+static void mld_ifc_timer_expire(unsigned long data)
+{
+	struct inet6_dev *idev = (struct inet6_dev *)data;
+
+	mld_send_cr(idev);
+	if (idev->mc_ifc_count) {
+		idev->mc_ifc_count--;
+		if (idev->mc_ifc_count)
+			mld_ifc_start_timer(idev, idev->mc_maxdelay);
+	}
+}
+
+static void mld_ifc_event(struct inet6_dev *idev)
+{
+	if (MLD_V1_SEEN(idev))
+		return;
+	idev->mc_ifc_count = idev->mc_qrv;
+	mld_ifc_start_timer(idev, 1);
 }
 
+
 static void igmp6_timer_handler(unsigned long data)
 {
 	struct ifmcaddr6 *ma = (struct ifmcaddr6 *) data;
 
-	igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REPORT);
+	if (MLD_V1_SEEN(ma->idev))
+		igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REPORT);
+	else
+		mld_send_report(ma->idev, ma);
 
 	spin_lock(&ma->mca_lock);
 	ma->mca_flags |=  MAF_LAST_REPORTER;
@@ -640,9 +1932,18 @@
 	/* Withdraw multicast list */
 
 	read_lock_bh(&idev->lock);
+	idev->mc_ifc_count = 0;
+	if (del_timer(&idev->mc_ifc_timer))
+		atomic_dec(&idev->refcnt);
+	idev->mc_gq_running = 0;
+	if (del_timer(&idev->mc_gq_timer))
+		atomic_dec(&idev->refcnt);
+
 	for (i = idev->mc_list; i; i=i->next)
 		igmp6_group_dropped(i);
 	read_unlock_bh(&idev->lock);
+
+	mld_clear_delrec(idev);
 }
 
 
@@ -666,6 +1967,22 @@
 {
 	struct in6_addr maddr;
 
+	write_lock_bh(&idev->lock);
+	idev->mc_lock = RW_LOCK_UNLOCKED;
+	idev->mc_gq_running = 0;
+	init_timer(&idev->mc_gq_timer);
+	idev->mc_gq_timer.data = (unsigned long) idev;
+	idev->mc_gq_timer.function = &mld_gq_timer_expire;
+	idev->mc_tomb = 0;
+	idev->mc_ifc_count = 0;
+	init_timer(&idev->mc_ifc_timer);
+	idev->mc_ifc_timer.data = (unsigned long) idev;
+	idev->mc_ifc_timer.function = &mld_ifc_timer_expire;
+	idev->mc_qrv = MLD_QRV_DEFAULT;
+	idev->mc_maxdelay = IGMP6_UNSOLICITED_IVAL;
+	idev->mc_v1_seen = 0;
+	write_unlock_bh(&idev->lock);
+
 	/* Add all-nodes address. */
 	ipv6_addr_all_nodes(&maddr);
 	ipv6_dev_mc_inc(idev->dev, &maddr);
@@ -755,6 +2072,113 @@
 		len=0;
 	return len;
 }
+
+static int ip6_mcf_read_proc(char *buffer, char **start, off_t offset,
+			   int length, int *eof, void *data)
+{
+	off_t pos=0, begin=0;
+	int len=0;
+	int first=1;
+	struct net_device *dev;
+	
+	read_lock(&dev_base_lock);
+	for (dev=dev_base; dev; dev=dev->next) {
+		struct inet6_dev *idev = in6_dev_get(dev);
+		struct ifmcaddr6 *imc;
+
+		if (idev == NULL)
+			continue;
+
+		read_lock_bh(&idev->lock);
+
+		for (imc=idev->mc_list; imc; imc=imc->next) {
+			struct ip6_sf_list *psf;
+			unsigned long icount, xcount, i;
+
+			spin_lock_bh(&imc->mca_lock);
+			icount = imc->mca_sfcount[MCAST_INCLUDE];
+			xcount = imc->mca_sfcount[MCAST_EXCLUDE];
+			for (psf=imc->mca_sources; psf; psf=psf->sf_next) {
+				if (first) {
+					len += sprintf(buffer+len, "%3s %6s "
+						"%32s %32s %6s %6s\n", "Idx",
+						"Device", "Multicast Address",
+						"Source Address", "INC", "EXC");
+					first = 0;
+				}
+				len += sprintf(buffer+len,"%3d %6.6s ",
+					dev->ifindex, dev->name);
+
+				for (i=0; i<16; i++)
+					len += sprintf(buffer+len, "%02x",
+						imc->mca_addr.s6_addr[i]);
+				buffer[len++] = ' ';
+				for (i=0; i<16; i++)
+					len += sprintf(buffer+len, "%02x",
+						psf->sf_addr.s6_addr[i]);
+				len += sprintf(buffer+len, " %6lu %6lu\n",
+					psf->sf_count[MCAST_INCLUDE],
+					psf->sf_count[MCAST_EXCLUDE]);
+				pos = begin+len;
+				if (pos < offset) {
+					len=0;
+					begin=pos;
+				}
+				if (pos > offset+length) {
+					spin_unlock_bh(&imc->mca_lock);
+					read_unlock_bh(&idev->lock);
+					in6_dev_put(idev);
+					goto done;
+				}
+				icount -= psf->sf_count[MCAST_INCLUDE];
+				xcount -= psf->sf_count[MCAST_EXCLUDE];
+			}
+			if (icount > 0 || xcount > 0) {
+				if (first) {
+					len += sprintf(buffer+len, "%3s %6s "
+						"%32s %32s %6s %6s\n", "Idx",
+						"Device", "Multicast Address",
+						"Source Address", "INC", "EXC");
+					first = 0;
+				}
+				len += sprintf(buffer+len,"%3d %6.6s ",
+					dev->ifindex, dev->name);
+
+				for (i=0; i<16; i++)
+					len += sprintf(buffer+len, "%02x",
+						imc->mca_addr.s6_addr[i]);
+				len += sprintf(buffer+len, " %32s %6lu %6lu\n",
+					"NONE", icount, xcount);
+				pos = begin+len;
+				if (pos < offset) {
+					len=0;
+					begin=pos;
+				}
+				if (pos > offset+length) {
+					spin_unlock_bh(&imc->mca_lock);
+					read_unlock_bh(&idev->lock);
+					in6_dev_put(idev);
+					goto done;
+				}
+			}
+			spin_unlock_bh(&imc->mca_lock);
+		}
+		read_unlock_bh(&idev->lock);
+		in6_dev_put(idev);
+	}
+	*eof = 1;
+
+done:
+	read_unlock(&dev_base_lock);
+
+	*start=buffer+(offset-begin);
+	len-=(offset-begin);
+	if(len>length)
+		len=length;
+	if (len<0)
+		len=0;
+	return len;
+}
 #endif
 
 int __init igmp6_init(struct net_proto_family *ops)
@@ -780,6 +2204,7 @@
 	np->hop_limit = 1;
 #ifdef CONFIG_PROC_FS
 	create_proc_read_entry("net/igmp6", 0, 0, igmp6_read_proc, NULL);
+	create_proc_read_entry("net/mcfilter6", 0, 0, ip6_mcf_read_proc, NULL);
 #endif
 
 	return 0;
diff -urN linux-2.5.67-bk7/net/ipv6/ndisc.c linux-2.5.67-bk8/net/ipv6/ndisc.c
--- linux-2.5.67-bk7/net/ipv6/ndisc.c	2003-04-17 04:38:28.000000000 -0700
+++ linux-2.5.67-bk8/net/ipv6/ndisc.c	2003-04-17 04:38:38.000000000 -0700
@@ -462,7 +462,7 @@
 	}
 
 	skb = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15,
-				  0, &err);
+				  1, &err);
 
 	if (skb == NULL) {
 		ND_PRINTK1("send_na: alloc skb failed\n");
@@ -546,7 +546,7 @@
 		len += NDISC_OPT_SPACE(dev->addr_len);
 
 	skb = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15,
-				  0, &err);
+				  1, &err);
 	if (skb == NULL) {
 		ND_PRINTK1("send_ns: alloc skb failed\n");
 		return;
@@ -616,7 +616,7 @@
 		len += NDISC_OPT_SPACE(dev->addr_len);
 
         skb = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15,
-				  0, &err);
+				  1, &err);
 	if (skb == NULL) {
 		ND_PRINTK1("send_ns: alloc skb failed\n");
 		return;
@@ -1328,7 +1328,7 @@
 	len += rd_len;
 
 	buff = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15,
-				   0, &err);
+				   1, &err);
 	if (buff == NULL) {
 		ND_PRINTK1("ndisc_send_redirect: alloc_skb failed\n");
 		return;
diff -urN linux-2.5.67-bk7/net/ipv6/netfilter/Makefile linux-2.5.67-bk8/net/ipv6/netfilter/Makefile
--- linux-2.5.67-bk7/net/ipv6/netfilter/Makefile	2003-04-07 10:31:47.000000000 -0700
+++ linux-2.5.67-bk8/net/ipv6/netfilter/Makefile	2003-04-17 04:38:38.000000000 -0700
@@ -21,4 +21,4 @@
 obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o
 obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o
 obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
-obj-$(CONFIG_IP_NF_MATCH_HL) += ip6t_hl.o
+obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o
diff -urN linux-2.5.67-bk7/net/ipv6/raw.c linux-2.5.67-bk8/net/ipv6/raw.c
--- linux-2.5.67-bk7/net/ipv6/raw.c	2003-04-07 10:31:05.000000000 -0700
+++ linux-2.5.67-bk8/net/ipv6/raw.c	2003-04-17 04:38:38.000000000 -0700
@@ -99,7 +99,7 @@
 				if (!ipv6_addr_cmp(&np->rcv_saddr, loc_addr))
 					break;
 				if ((addr_type & IPV6_ADDR_MULTICAST) &&
-				    inet6_mc_check(s, loc_addr))
+				    inet6_mc_check(s, loc_addr, rmt_addr))
 					break;
 				continue;
 			}
diff -urN linux-2.5.67-bk7/net/ipv6/reassembly.c linux-2.5.67-bk8/net/ipv6/reassembly.c
--- linux-2.5.67-bk7/net/ipv6/reassembly.c	2003-04-07 10:31:00.000000000 -0700
+++ linux-2.5.67-bk8/net/ipv6/reassembly.c	2003-04-17 04:38:38.000000000 -0700
@@ -520,13 +520,13 @@
  *	the last and the first frames arrived and all the bits are here.
  */
 static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
+			  unsigned int *nhoffp,
 			  struct net_device *dev)
 {
 	struct sk_buff *fp, *head = fq->fragments;
 	int    remove_fraghdr = 0;
 	int    payload_len;
-	int    nhoff;
-	u8     nexthdr = 0;
+	unsigned int nhoff;
 
 	fq_kill(fq);
 
@@ -537,8 +537,6 @@
 	payload_len = (head->data - head->nh.raw) - sizeof(struct ipv6hdr) + fq->len;
 	nhoff = head->h.raw - head->nh.raw;
 
-	nexthdr = ((struct frag_hdr*)head->h.raw)->nexthdr;
-
 	if (payload_len > 65535) {
 		payload_len -= 8;
 		if (payload_len > 65535)
@@ -613,12 +611,10 @@
 	if (head->ip_summed == CHECKSUM_HW)
 		head->csum = csum_partial(head->nh.raw, head->h.raw-head->nh.raw, head->csum);
 
-	if (!pskb_pull(head, head->h.raw - head->data))
-		goto out_fail;
-
 	IP6_INC_STATS_BH(Ip6ReasmOKs);
 	fq->fragments = NULL;
-	return nexthdr;
+	*nhoffp = nhoff;
+	return 1;
 
 out_oversize:
 	if (net_ratelimit())
@@ -629,18 +625,16 @@
 		printk(KERN_DEBUG "ip6_frag_reasm: no memory for reassembly\n");
 out_fail:
 	IP6_INC_STATS_BH(Ip6ReasmFails);
-	return 0;
+	return -1;
 }
 
-static int ipv6_frag_rcv(struct sk_buff **skbp)
+static int ipv6_frag_rcv(struct sk_buff **skbp, unsigned int *nhoffp)
 {
 	struct sk_buff *skb = *skbp; 
 	struct net_device *dev = skb->dev;
 	struct frag_hdr *fhdr;
 	struct frag_queue *fq;
 	struct ipv6hdr *hdr;
-	int nhoff = skb->h.raw - skb->nh.raw;
-	u8 nexthdr = 0;
 
 	hdr = skb->nh.ipv6h;
 
@@ -649,23 +643,23 @@
 	/* Jumbo payload inhibits frag. header */
 	if (hdr->payload_len==0) {
 		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw-skb->nh.raw);
-		goto discard;
+		return -1;
 	}
 	if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+sizeof(struct frag_hdr))) {
 		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw-skb->nh.raw);
-		goto discard;
+		return -1;
 	}
 
 	hdr = skb->nh.ipv6h;
 	fhdr = (struct frag_hdr *)skb->h.raw;
-	nexthdr = fhdr->nexthdr;
 
 	if (!(fhdr->frag_off & htons(0xFFF9))) {
 		/* It is not a fragmented frame */
 		skb->h.raw += sizeof(struct frag_hdr);
 		IP6_INC_STATS_BH(Ip6ReasmOKs);
 
-		return (u8*)fhdr - skb->nh.raw;
+		*nhoffp = (u8*)fhdr - skb->nh.raw;
+		return 1;
 	}
 
 	if (atomic_read(&ip6_frag_mem) > sysctl_ip6frag_high_thresh)
@@ -676,26 +670,26 @@
 
 		spin_lock(&fq->lock);
 
-		ip6_frag_queue(fq, skb, fhdr, nhoff);
+		ip6_frag_queue(fq, skb, fhdr, *nhoffp);
 
 		if (fq->last_in == (FIRST_IN|LAST_IN) &&
 		    fq->meat == fq->len)
-			ret = ip6_frag_reasm(fq, skbp, dev);
+			ret = ip6_frag_reasm(fq, skbp, nhoffp, dev);
 
 		spin_unlock(&fq->lock);
 		fq_put(fq);
-		return -ret;
+		return ret;
 	}
 
-discard:
 	IP6_INC_STATS_BH(Ip6ReasmFails);
 	kfree_skb(skb);
-	return 0;
+	return -1;
 }
 
 static struct inet6_protocol frag_protocol =
 {
 	.handler	=	ipv6_frag_rcv,
+	.flags		=	INET6_PROTO_NOPOLICY,
 };
 
 void __init ipv6_frag_init(void)
diff -urN linux-2.5.67-bk7/net/ipv6/tcp_ipv6.c linux-2.5.67-bk8/net/ipv6/tcp_ipv6.c
--- linux-2.5.67-bk7/net/ipv6/tcp_ipv6.c	2003-04-07 10:31:45.000000000 -0700
+++ linux-2.5.67-bk8/net/ipv6/tcp_ipv6.c	2003-04-17 04:38:38.000000000 -0700
@@ -1591,7 +1591,7 @@
 	return 0;
 }
 
-static int tcp_v6_rcv(struct sk_buff **pskb)
+static int tcp_v6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
 {
 	struct sk_buff *skb = *pskb;
 	struct tcphdr *th;	
@@ -1657,7 +1657,7 @@
 	bh_unlock_sock(sk);
 
 	sock_put(sk);
-	return ret;
+	return ret ? -1 : 0;
 
 no_tcp_socket:
 	if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
@@ -2193,7 +2193,7 @@
 static struct inet6_protocol tcpv6_protocol = {
 	.handler	=	tcp_v6_rcv,
 	.err_handler	=	tcp_v6_err,
-	.no_policy	=	1,
+	.flags		=	INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
 };
 
 extern struct proto_ops inet6_stream_ops;
diff -urN linux-2.5.67-bk7/net/ipv6/udp.c linux-2.5.67-bk8/net/ipv6/udp.c
--- linux-2.5.67-bk7/net/ipv6/udp.c	2003-04-07 10:32:26.000000000 -0700
+++ linux-2.5.67-bk8/net/ipv6/udp.c	2003-04-17 04:38:38.000000000 -0700
@@ -592,7 +592,7 @@
 				if (!ipv6_addr_cmp(&np->rcv_saddr, loc_addr))
 					return s;
 			}
-			if(!inet6_mc_check(s, loc_addr))
+			if(!inet6_mc_check(s, loc_addr, rmt_addr))
 				continue;
 			return s;
 		}
@@ -640,7 +640,7 @@
 	read_unlock(&udp_hash_lock);
 }
 
-static int udpv6_rcv(struct sk_buff **pskb)
+static int udpv6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
 {
 	struct sk_buff *skb = *pskb;
 	struct sock *sk;
@@ -954,7 +954,7 @@
 static struct inet6_protocol udpv6_protocol = {
 	.handler	=	udpv6_rcv,
 	.err_handler	=	udpv6_err,
-	.no_policy	=	1,
+	.flags		=	INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
 };
 
 #define LINE_LEN 190
diff -urN linux-2.5.67-bk7/net/ipv6/xfrm6_input.c linux-2.5.67-bk8/net/ipv6/xfrm6_input.c
--- linux-2.5.67-bk7/net/ipv6/xfrm6_input.c	2003-04-17 04:38:28.000000000 -0700
+++ linux-2.5.67-bk8/net/ipv6/xfrm6_input.c	2003-04-17 04:38:38.000000000 -0700
@@ -123,7 +123,7 @@
 	return nexthdr;
 }
 
-int xfrm6_rcv(struct sk_buff **pskb)
+int xfrm6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
 {
 	struct sk_buff *skb = *pskb;
 	int err;
@@ -233,6 +233,7 @@
 
 	memcpy(skb->sp->x+skb->sp->len, xfrm_vec, xfrm_nr*sizeof(struct sec_decap_state));
 	skb->sp->len += xfrm_nr;
+	skb->ip_summed = CHECKSUM_NONE;
 
 	if (decaps) {
 		if (!(skb->dev->flags&IFF_LOOPBACK)) {
@@ -240,9 +241,10 @@
 			skb->dst = NULL;
 		}
 		netif_rx(skb);
-		return 0;
+		return -1;
 	} else {
-		return -nexthdr;
+		*nhoffp = nh_offset;
+		return 1;
 	}
 
 drop_unlock:
@@ -253,7 +255,7 @@
 	while (--xfrm_nr >= 0)
 		xfrm_state_put(xfrm_vec[xfrm_nr].xvec);
 	kfree_skb(skb);
-	return 0;
+	return -1;
 }
 
 void __init xfrm6_input_init(void)
diff -urN linux-2.5.67-bk7/net/sched/cls_rsvp.h linux-2.5.67-bk8/net/sched/cls_rsvp.h
--- linux-2.5.67-bk7/net/sched/cls_rsvp.h	2003-04-07 10:30:41.000000000 -0700
+++ linux-2.5.67-bk8/net/sched/cls_rsvp.h	2003-04-17 04:38:38.000000000 -0700
@@ -149,11 +149,6 @@
 	struct iphdr *nhptr = skb->nh.iph;
 #endif
 
-#if !defined( __i386__) && !defined(__mc68000__)
-	if ((unsigned long)nhptr & 3)
-		return -1;
-#endif
-
 restart:
 
 #if RSVP_DST_LEN == 4
diff -urN linux-2.5.67-bk7/net/sched/cls_u32.c linux-2.5.67-bk8/net/sched/cls_u32.c
--- linux-2.5.67-bk7/net/sched/cls_u32.c	2003-04-07 10:30:59.000000000 -0700
+++ linux-2.5.67-bk8/net/sched/cls_u32.c	2003-04-17 04:38:38.000000000 -0700
@@ -112,11 +112,6 @@
 	int sel = 0;
 	int i;
 
-#if !defined(__i386__) && !defined(__mc68000__)
-	if ((unsigned long)ptr & 3)
-		return -1;
-#endif
-
 next_ht:
 	n = ht->ht[sel];
 
diff -urN linux-2.5.67-bk7/net/sctp/ipv6.c linux-2.5.67-bk8/net/sctp/ipv6.c
--- linux-2.5.67-bk7/net/sctp/ipv6.c	2003-04-07 10:31:49.000000000 -0700
+++ linux-2.5.67-bk8/net/sctp/ipv6.c	2003-04-17 04:38:38.000000000 -0700
@@ -776,18 +776,18 @@
 	.ops           = &inet6_seqpacket_ops,
 	.capability    = -1,
 	.no_check      = 0,
-	.flags         = SCTP_PROTOSW_FLAG
+	.flags         = SCTP_PROTOSW_FLAG,
 };
 
-static int sctp6_rcv(struct sk_buff **pskb)
+static int sctp6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
 {
-	return sctp_rcv(*pskb);
+	return sctp_rcv(*pskb) ? -1 : 0;
 }
 
 static struct inet6_protocol sctpv6_protocol = {
 	.handler      = sctp6_rcv,
 	.err_handler  = sctp_v6_err,
-	.no_policy    = 1,
+	.flags        = INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL,
 };
 
 static struct sctp_af sctp_ipv6_specific = {
