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

diff -urN linux-2.5.67-bk9/Makefile linux-2.5.67-bk10/Makefile
--- linux-2.5.67-bk9/Makefile	2003-04-19 04:35:27.000000000 -0700
+++ linux-2.5.67-bk10/Makefile	2003-04-19 04:35:36.000000000 -0700
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 5
 SUBLEVEL = 67
-EXTRAVERSION = -bk9
+EXTRAVERSION = -bk10
 
 # *DOCUMENTATION*
 # To see a list of typical targets execute "make help"
diff -urN linux-2.5.67-bk9/arch/sparc64/kernel/ioctl32.c linux-2.5.67-bk10/arch/sparc64/kernel/ioctl32.c
--- linux-2.5.67-bk9/arch/sparc64/kernel/ioctl32.c	2003-04-19 04:35:28.000000000 -0700
+++ linux-2.5.67-bk10/arch/sparc64/kernel/ioctl32.c	2003-04-19 04:35:36.000000000 -0700
@@ -54,9 +54,6 @@
 #include <linux/elevator.h>
 #include <linux/rtc.h>
 #include <linux/pci.h>
-#if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE)
-#include <linux/lvm.h>
-#endif /* LVM */
 #include <linux/dm-ioctl.h>
 
 #include <scsi/scsi.h>
@@ -2766,443 +2763,6 @@
         return -EINVAL;
 }
 
-#if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE)
-/* Ugh, LVM. Pitty it was not cleaned up before accepted :((. */
-typedef struct {
-	uint8_t vg_name[NAME_LEN];
-	uint32_t vg_number;
-	uint32_t vg_access;
-	uint32_t vg_status;
-	uint32_t lv_max;
-	uint32_t lv_cur;
-	uint32_t lv_open;
-	uint32_t pv_max;
-	uint32_t pv_cur;
-	uint32_t pv_act;
-	uint32_t dummy;
-	uint32_t vgda;
-	uint32_t pe_size;
-	uint32_t pe_total;
-	uint32_t pe_allocated;
-	uint32_t pvg_total;
-	u32 proc;
-	u32 pv[ABS_MAX_PV + 1];
-	u32 lv[ABS_MAX_LV + 1];
-    	uint8_t vg_uuid[UUID_LEN+1];	/* volume group UUID */
-	uint8_t dummy1[200];
-} vg32_t;
-
-typedef struct {
-	uint8_t id[2];
-	uint16_t version;
-	lvm_disk_data_t pv_on_disk;
-	lvm_disk_data_t vg_on_disk;
-	lvm_disk_data_t pv_namelist_on_disk;
-	lvm_disk_data_t lv_on_disk;
-	lvm_disk_data_t pe_on_disk;
-	uint8_t pv_name[NAME_LEN];
-	uint8_t vg_name[NAME_LEN];
-	uint8_t system_id[NAME_LEN];
-	kdev_t pv_dev;
-	uint32_t pv_number;
-	uint32_t pv_status;
-	uint32_t pv_allocatable;
-	uint32_t pv_size;
-	uint32_t lv_cur;
-	uint32_t pe_size;
-	uint32_t pe_total;
-	uint32_t pe_allocated;
-	uint32_t pe_stale;
-	u32 pe;
-	u32 inode;
-	uint8_t pv_uuid[UUID_LEN+1];
-} pv32_t;
-
-typedef struct {
-	char lv_name[NAME_LEN];
-	u32 lv;
-} lv_req32_t;
-
-typedef struct {
-	u32 lv_index;
-	u32 lv;
-	/* Transfer size because user space and kernel space differ */
-	uint16_t size;
-} lv_status_byindex_req32_t;
-
-typedef struct {
-	compat_dev_t dev;
-	u32   lv;
-} lv_status_bydev_req32_t;
-
-typedef struct {
-	uint8_t lv_name[NAME_LEN];
-	kdev_t old_dev;
-	kdev_t new_dev;
-	u32 old_pe;
-	u32 new_pe;
-} le_remap_req32_t;
-
-typedef struct {
-	char pv_name[NAME_LEN];
-	u32 pv;
-} pv_status_req32_t;
-
-typedef struct {
-	uint8_t lv_name[NAME_LEN];
-	uint8_t vg_name[NAME_LEN];
-	uint32_t lv_access;
-	uint32_t lv_status;
-	uint32_t lv_open;
-	kdev_t lv_dev;
-	uint32_t lv_number;
-	uint32_t lv_mirror_copies;
-	uint32_t lv_recovery;
-	uint32_t lv_schedule;
-	uint32_t lv_size;
-	u32 lv_current_pe;
-	uint32_t lv_current_le;
-	uint32_t lv_allocated_le;
-	uint32_t lv_stripes;
-	uint32_t lv_stripesize;
-	uint32_t lv_badblock;
-	uint32_t lv_allocation;
-	uint32_t lv_io_timeout;
-	uint32_t lv_read_ahead;
-	/* delta to version 1 starts here */
-	u32 lv_snapshot_org;
-	u32 lv_snapshot_prev;
-	u32 lv_snapshot_next;
-	u32 lv_block_exception;
-	uint32_t lv_remap_ptr;
-	uint32_t lv_remap_end;
-	uint32_t lv_chunk_size;
-	uint32_t lv_snapshot_minor;
-	char dummy[200];
-} lv32_t;
-
-typedef struct {
-	u32 hash[2];
-	u32 rsector_org;
-	kdev_t rdev_org;
-	u32 rsector_new;
-	kdev_t rdev_new;
-} lv_block_exception32_t;
-
-static void put_lv_t(lv_t *l)
-{
-	if (l->lv_current_pe) vfree(l->lv_current_pe);
-	if (l->lv_block_exception) vfree(l->lv_block_exception);
-	kfree(l);
-}
-
-static lv_t *get_lv_t(u32 p, int *errp)
-{
-	int err, i;
-	u32 ptr1, ptr2;
-	size_t size;
-	lv_block_exception32_t __user *lbe32;
-	lv_block_exception_t *lbe;
-	lv32_t __user *ul = A(p);
-	lv_t *l = (lv_t *) kmalloc(sizeof(lv_t), GFP_KERNEL);
-
-	if (!l) {
-		*errp = -ENOMEM;
-		return NULL;
-	}
-	memset(l, 0, sizeof(lv_t));
-	err = copy_from_user(l, ul, (long)&((lv32_t *)0)->lv_current_pe);
-	err |= __copy_from_user(&l->lv_current_le, &ul->lv_current_le,
-				((long)&ul->lv_snapshot_org) - ((long)&ul->lv_current_le));
-	err |= __copy_from_user(&l->lv_remap_ptr, &ul->lv_remap_ptr,
-				((long)&ul->dummy[0]) - ((long)&ul->lv_remap_ptr));
-	err |= __get_user(ptr1, &ul->lv_current_pe);
-	err |= __get_user(ptr2, &ul->lv_block_exception);
-	if (err) {
-		kfree(l);
-		*errp = -EFAULT;
-		return NULL;
-	}
-	if (ptr1) {
-		size = l->lv_allocated_le * sizeof(pe_t);
-		l->lv_current_pe = vmalloc(size);
-		if (l->lv_current_pe)
-			err = copy_from_user(l->lv_current_pe, A(ptr1), size);
-	}
-	if (!err && ptr2) {
-		size = l->lv_remap_end * sizeof(lv_block_exception_t);
-		l->lv_block_exception = lbe = vmalloc(size);
-		if (l->lv_block_exception) {
-			lbe32 = A(ptr2);
-			memset(lbe, 0, size);
-			for (i = 0; i < l->lv_remap_end; i++, lbe++, lbe32++) {
-				err |= get_user(lbe->rsector_org, &lbe32->rsector_org);
-				err |= __get_user(lbe->rdev_org, &lbe32->rdev_org);
-				err |= __get_user(lbe->rsector_new, &lbe32->rsector_new);
-				err |= __get_user(lbe->rdev_new, &lbe32->rdev_new);
-			}
-		}
-	}
-	if (err || (ptr1 && !l->lv_current_pe) || (ptr2 && !l->lv_block_exception)) {
-		if (!err)
-			*errp = -ENOMEM;
-		else
-			*errp = -EFAULT;
-		put_lv_t(l);
-		return NULL;
-	}
-	return l;
-}
-
-static int copy_lv_t(u32 ptr, lv_t *l)
-{
-	int err;
-	lv32_t __user *ul = A(ptr);
-	u32 ptr1;
-	size_t size;
-
-	err = get_user(ptr1, &ul->lv_current_pe);
-	if (err)
-		return -EFAULT;
-	err = copy_to_user(ul, l, (long)&((lv32_t *)0)->lv_current_pe);
-	err |= __copy_to_user(&ul->lv_current_le, &l->lv_current_le,
-				((long)&ul->lv_snapshot_org) - ((long)&ul->lv_current_le));
-	err |= __copy_to_user(&ul->lv_remap_ptr, &l->lv_remap_ptr,
-				((long)&ul->dummy[0]) - ((long)&ul->lv_remap_ptr));
-	size = l->lv_allocated_le * sizeof(pe_t);
-	if (ptr1)
-		err |= __copy_to_user(A(ptr1), l->lv_current_pe, size);
-	return err ? -EFAULT : 0;
-}
-
-static int do_lvm_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	vg_t *v = NULL;
-	union {
-		lv_req_t lv_req;
-		le_remap_req_t le_remap;
-		lv_status_byindex_req_t lv_byindex;
-	        lv_status_bydev_req_t lv_bydev;
-		pv_status_req_t pv_status;
-	} u;
-	pv_t p;
-	int err;
-	u32 ptr = 0;
-	int i;
-	mm_segment_t old_fs;
-	void *karg = &u;
-
-	switch (cmd) {
-	case VG_STATUS:
-		v = kmalloc(sizeof(vg_t), GFP_KERNEL);
-		if (!v)
-			return -ENOMEM;
-		karg = v;
-		break;
-
-	case VG_CREATE_OLD:
-	case VG_CREATE:
-		v = kmalloc(sizeof(vg_t), GFP_KERNEL);
-		if (!v)
-			return -ENOMEM;
-		if (copy_from_user(v, (void *)arg, (long)&((vg32_t *)0)->proc)) {
-			kfree(v);
-			return -EFAULT;
-		}
-		/* 'proc' field is unused, just NULL it out. */
-		v->proc = NULL;
-		if (copy_from_user(v->vg_uuid, ((vg32_t *)arg)->vg_uuid, UUID_LEN+1)) {
-			kfree(v);
-			return -EFAULT;
-		}
-		    
-		karg = v;
-		memset(v->pv, 0, sizeof(v->pv) + sizeof(v->lv));
-		if (v->pv_max > ABS_MAX_PV || v->lv_max > ABS_MAX_LV)
-			return -EPERM;
-		for (i = 0; i < v->pv_max; i++) {
-			err = __get_user(ptr, &((vg32_t *)arg)->pv[i]);
-			if (err)
-				break;
-			if (ptr) {
-				v->pv[i] = kmalloc(sizeof(pv_t), GFP_KERNEL);
-				if (!v->pv[i]) {
-					err = -ENOMEM;
-					break;
-				}
-				err = copy_from_user(v->pv[i], A(ptr),
-						     sizeof(pv32_t) - 8 - UUID_LEN+1);
-				if (err) {
-					err = -EFAULT;
-					break;
-				}
-				err = copy_from_user(&v->pv[i]->pv_uuid[0],
-						     &((pv32_t __user *)A(ptr))->pv_uuid[0],
-						     UUID_LEN+1);
-				if (err) {
-				        err = -EFAULT;
-					break;
-				}
-
-				v->pv[i]->pe = NULL;
-				v->pv[i]->bd = NULL;
-			}
-		}
-		if (!err) {
-			for (i = 0; i < v->lv_max; i++) {
-				err = __get_user(ptr, &((vg32_t *)arg)->lv[i]);
-				if (err)
-					break;
-				if (ptr) {
-					v->lv[i] = get_lv_t(ptr, &err);
-					if (err)
-						break;
-				}
-			}
-		}
-		break;
-
-	case LV_CREATE:
-	case LV_EXTEND:
-	case LV_REDUCE:
-	case LV_REMOVE:
-	case LV_RENAME:
-	case LV_STATUS_BYNAME:
-	        err = copy_from_user(&u.pv_status, arg, sizeof(u.pv_status.pv_name));
-		if (err)
-			return -EFAULT;
-		if (cmd != LV_REMOVE) {
-			err = __get_user(ptr, &((lv_req32_t *)arg)->lv);
-			if (err)
-				return err;
-			u.lv_req.lv = get_lv_t(ptr, &err);
-		} else
-			u.lv_req.lv = NULL;
-		break;
-
-	case LV_STATUS_BYINDEX:
-		err = get_user(u.lv_byindex.lv_index,
-			       &((lv_status_byindex_req32_t *)arg)->lv_index);
-		err |= __get_user(ptr, &((lv_status_byindex_req32_t *)arg)->lv);
-		if (err)
-			return err;
-		u.lv_byindex.lv = get_lv_t(ptr, &err);
-		break;
-
-	case LV_STATUS_BYDEV:
-	        err = get_user(u.lv_bydev.dev, &((lv_status_bydev_req32_t *)arg)->dev);
-		err |= __get_user(ptr, &((lv_status_bydev_req32_t *)arg)->lv);
-		if (err)
-			return err;
-		u.lv_bydev.lv = get_lv_t(ptr, &err);
-		break;
-
-	case VG_EXTEND:
-		err = copy_from_user(&p, (void *)arg, sizeof(pv32_t) - 8 - UUID_LEN+1);
-		if (err)
-			return -EFAULT;
-		err = copy_from_user(p.pv_uuid, ((pv32_t *)arg)->pv_uuid, UUID_LEN+1);
-		if (err)
-			return -EFAULT;
-		p.pe = NULL;
-		p.bd = NULL;
-		karg = &p;
-		break;
-
-	case PV_CHANGE:
-	case PV_STATUS:
-		err = copy_from_user(&u.pv_status, arg, sizeof(u.lv_req.lv_name));
-		if (err)
-			return -EFAULT;
-		err = __get_user(ptr, &((pv_status_req32_t *)arg)->pv);
-		if (err)
-			return err;
-		u.pv_status.pv = &p;
-		if (cmd == PV_CHANGE) {
-			err = copy_from_user(&p, A(ptr),
-					     sizeof(pv32_t) - 8 - UUID_LEN+1);
-			if (err)
-				return -EFAULT;
-			p.pe = NULL;
-			p.bd = NULL;
-		}
-		break;
-	};
-
-        old_fs = get_fs(); set_fs (KERNEL_DS);
-        err = sys_ioctl (fd, cmd, (unsigned long)karg);
-        set_fs (old_fs);
-
-	switch (cmd) {
-	case VG_STATUS:
-		if (!err) {
-			if (copy_to_user((void *)arg, v, (long)&((vg32_t *)0)->proc) ||
-			    clear_user(&((vg32_t *)arg)->proc, sizeof(vg32_t) - (long)&((vg32_t *)0)->proc))
-				err = -EFAULT;
-		}
-		if (copy_to_user(((vg32_t *)arg)->vg_uuid, v->vg_uuid, UUID_LEN+1)) {
-		        err = -EFAULT;
-		}
-		kfree(v);
-		break;
-
-	case VG_CREATE_OLD:
-	case VG_CREATE:
-		for (i = 0; i < v->pv_max; i++) {
-			if (v->pv[i])
-				kfree(v->pv[i]);
-		}
-		for (i = 0; i < v->lv_max; i++) {
-			if (v->lv[i])
-				put_lv_t(v->lv[i]);
-		}
-		kfree(v);
-		break;
-
-	case LV_STATUS_BYNAME:
-		if (!err && u.lv_req.lv)
-			err = copy_lv_t(ptr, u.lv_req.lv);
-		/* Fall through */
-
-        case LV_CREATE:
-	case LV_EXTEND:
-	case LV_REDUCE:
-		if (u.lv_req.lv)
-			put_lv_t(u.lv_req.lv);
-		break;
-
-	case LV_STATUS_BYINDEX:
-		if (u.lv_byindex.lv) {
-			if (!err)
-				err = copy_lv_t(ptr, u.lv_byindex.lv);
-			put_lv_t(u.lv_byindex.lv);
-		}
-		break;
-
-	case LV_STATUS_BYDEV:
-	        if (u.lv_bydev.lv) {
-			if (!err)
-				err = copy_lv_t(ptr, u.lv_bydev.lv);
-			put_lv_t(u.lv_byindex.lv);
-	        }
-	        break;
-
-	case PV_STATUS:
-		if (!err) {
-			err = copy_to_user(A(ptr), &p, sizeof(pv32_t) - 8 - UUID_LEN+1);
-			if (err)
-				return -EFAULT;
-			err = copy_to_user(&((pv_t __user *)A(ptr))->pv_uuid[0], &p.pv_uuid[0], UUID_LEN + 1);
-			if (err)
-				return -EFAULT;
-		}
-		break;
-	};
-
-	return err;
-}
-#endif
-
 #if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
 /* This really belongs in include/linux/drm.h -DaveM */
 #include "../../../drivers/char/drm/drm.h"
@@ -4887,28 +4447,6 @@
 COMPATIBLE_IOCTL(ATMTCP_REMOVE)
 COMPATIBLE_IOCTL(ATMMPC_CTRL)
 COMPATIBLE_IOCTL(ATMMPC_DATA)
-#if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE)
-/* 0xfe - lvm */
-COMPATIBLE_IOCTL(VG_SET_EXTENDABLE)
-COMPATIBLE_IOCTL(VG_STATUS_GET_COUNT)
-COMPATIBLE_IOCTL(VG_STATUS_GET_NAMELIST)
-COMPATIBLE_IOCTL(VG_REMOVE)
-COMPATIBLE_IOCTL(VG_RENAME)
-COMPATIBLE_IOCTL(VG_REDUCE)
-COMPATIBLE_IOCTL(PE_LOCK_UNLOCK)
-COMPATIBLE_IOCTL(PV_FLUSH)
-COMPATIBLE_IOCTL(LVM_LOCK_LVM)
-COMPATIBLE_IOCTL(LVM_GET_IOP_VERSION)
-#ifdef LVM_TOTAL_RESET
-COMPATIBLE_IOCTL(LVM_RESET)
-#endif
-COMPATIBLE_IOCTL(LV_SET_ACCESS)
-COMPATIBLE_IOCTL(LV_SET_STATUS)
-COMPATIBLE_IOCTL(LV_SET_ALLOCATION)
-COMPATIBLE_IOCTL(LE_REMAP)
-COMPATIBLE_IOCTL(LV_BMAP)
-COMPATIBLE_IOCTL(LV_SNAPSHOT_USE_RATE)
-#endif /* LVM */
 #if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
 COMPATIBLE_IOCTL(DRM_IOCTL_GET_MAGIC)
 COMPATIBLE_IOCTL(DRM_IOCTL_IRQ_BUSID)
@@ -5172,22 +4710,6 @@
 HANDLE_IOCTL(SONET_SETFRAMING, do_atm_ioctl)
 HANDLE_IOCTL(SONET_GETFRAMING, do_atm_ioctl)
 HANDLE_IOCTL(SONET_GETFRSENSE, do_atm_ioctl)
-#if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE)
-HANDLE_IOCTL(VG_STATUS, do_lvm_ioctl)
-HANDLE_IOCTL(VG_CREATE_OLD, do_lvm_ioctl)
-HANDLE_IOCTL(VG_CREATE, do_lvm_ioctl)
-HANDLE_IOCTL(VG_EXTEND, do_lvm_ioctl)
-HANDLE_IOCTL(LV_CREATE, do_lvm_ioctl)
-HANDLE_IOCTL(LV_REMOVE, do_lvm_ioctl)
-HANDLE_IOCTL(LV_EXTEND, do_lvm_ioctl)
-HANDLE_IOCTL(LV_REDUCE, do_lvm_ioctl)
-HANDLE_IOCTL(LV_RENAME, do_lvm_ioctl)
-HANDLE_IOCTL(LV_STATUS_BYNAME, do_lvm_ioctl)
-HANDLE_IOCTL(LV_STATUS_BYINDEX, do_lvm_ioctl)
-HANDLE_IOCTL(LV_STATUS_BYDEV, do_lvm_ioctl)
-HANDLE_IOCTL(PV_CHANGE, do_lvm_ioctl)
-HANDLE_IOCTL(PV_STATUS, do_lvm_ioctl)
-#endif /* LVM */
 #if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
 HANDLE_IOCTL(DRM32_IOCTL_VERSION, drm32_version)
 HANDLE_IOCTL(DRM32_IOCTL_GET_UNIQUE, drm32_getsetunique)
diff -urN linux-2.5.67-bk9/arch/sparc64/kernel/sys_sunos32.c linux-2.5.67-bk10/arch/sparc64/kernel/sys_sunos32.c
--- linux-2.5.67-bk9/arch/sparc64/kernel/sys_sunos32.c	2003-04-07 10:31:51.000000000 -0700
+++ linux-2.5.67-bk10/arch/sparc64/kernel/sys_sunos32.c	2003-04-19 04:35:36.000000000 -0700
@@ -800,15 +800,16 @@
 }
 
 /* So stupid... */
-extern asmlinkage int sys32_wait4(compat_pid_t pid,
-				  u32 stat_addr, int options, u32 ru);
+extern long compat_sys_wait4(compat_pid_t, compat_uint_t *, int,
+			     struct compat_rusage *);
 
 asmlinkage int sunos_wait4(compat_pid_t pid, u32 stat_addr, int options, u32 ru)
 {
 	int ret;
 
-	ret = sys32_wait4((pid ? pid : ((compat_pid_t)-1)),
-			  stat_addr, options, ru);
+	ret = compat_sys_wait4((pid ? pid : ((compat_pid_t)-1)),
+			       (compat_uint_t *)A(stat_addr), options,
+			       (struct compat_rusage *)A(ru));
 	return ret;
 }
 
diff -urN linux-2.5.67-bk9/arch/sparc64/kernel/systbls.S linux-2.5.67-bk10/arch/sparc64/kernel/systbls.S
--- linux-2.5.67-bk9/arch/sparc64/kernel/systbls.S	2003-04-19 04:35:28.000000000 -0700
+++ linux-2.5.67-bk10/arch/sparc64/kernel/systbls.S	2003-04-19 04:35:36.000000000 -0700
@@ -180,7 +180,7 @@
 	.word sys_listen, sunos_nosys, sunos_sigaction
 	.word sunos_sigblock, sunos_sigsetmask, sys_sigpause
 	.word sys32_sigstack, compat_sys_recvmsg, compat_sys_sendmsg
-	.word sunos_nosys, sys32_gettimeofday, sys32_getrusage
+	.word sunos_nosys, sys32_gettimeofday, compat_sys_getrusage
 	.word sunos_getsockopt, sunos_nosys, sunos_readv
 	.word sunos_writev, sys32_settimeofday, sys32_fchown16
 	.word sys_fchmod, sys32_recvfrom, sys32_setreuid16
@@ -189,8 +189,8 @@
 	.word sys32_sendto, sys_shutdown, sys_socketpair
 	.word sys_mkdir, sys_rmdir, sys32_utimes
 	.word sys32_sigreturn, sunos_nosys, sys_getpeername
-	.word sunos_gethostid, sunos_nosys, sys32_getrlimit
-	.word sys32_setrlimit, sunos_killpg, sunos_nosys
+	.word sunos_gethostid, sunos_nosys, compat_sys_getrlimit
+	.word compat_sys_setrlimit, sunos_killpg, sunos_nosys
 	.word sunos_nosys, sunos_nosys
 /*150*/	.word sys_getsockname, sunos_nosys, sunos_nosys
 	.word sys_poll, sunos_nosys, sunos_nosys
diff -urN linux-2.5.67-bk9/drivers/block/cpqarray.c linux-2.5.67-bk10/drivers/block/cpqarray.c
--- linux-2.5.67-bk9/drivers/block/cpqarray.c	2003-04-07 10:30:43.000000000 -0700
+++ linux-2.5.67-bk10/drivers/block/cpqarray.c	2003-04-19 04:35:36.000000000 -0700
@@ -400,7 +400,6 @@
 			sprintf(disk->disk_name, "ida/c%dd%d", i, j);
 			disk->major = COMPAQ_SMART2_MAJOR + i;
 			disk->first_minor = j<<NWD_SHIFT;
-			disk->flags = GENHD_FL_DEVFS;
 			disk->fops = &ida_fops; 
 			if (!drv->nr_blks)
 				continue;
@@ -1678,10 +1677,9 @@
                 			return;
 
 				}
-				if (!disk->de) {
-					disk->de = devfs_mk_dir("ida/c%dd%d",
-							ctlr, log_unit);
-				}
+
+				sprintf(disk->devfs_name, "ida/c%dd%d", ctlr, log_unit);
+
 				info_p->phys_drives =
 				    sense_config_buf->ctlr_phys_drv;
 				info_p->drv_assign_map
diff -urN linux-2.5.67-bk9/drivers/block/loop.c linux-2.5.67-bk10/drivers/block/loop.c
--- linux-2.5.67-bk9/drivers/block/loop.c	2003-04-07 10:31:46.000000000 -0700
+++ linux-2.5.67-bk10/drivers/block/loop.c	2003-04-19 04:35:36.000000000 -0700
@@ -120,13 +120,13 @@
 	return 0;
 }
 
-static int none_status(struct loop_device *lo, struct loop_info *info)
+static int none_status(struct loop_device *lo, const struct loop_info64 *info)
 {
 	lo->lo_flags |= LO_FLAGS_BH_REMAP;
 	return 0;
 }
 
-static int xor_status(struct loop_device *lo, struct loop_info *info)
+static int xor_status(struct loop_device *lo, const struct loop_info64 *info)
 {
 	if (info->lo_encrypt_key_size <= 0)
 		return -EINVAL;
@@ -215,7 +215,8 @@
 			 * The transfer failed, but we still write the data to
 			 * keep prepare/commit calls balanced.
 			 */
-			printk(KERN_ERR "loop: transfer error block %llu\n", (unsigned long long)index);
+			printk(KERN_ERR "loop: transfer error block %llu\n",
+			       (unsigned long long)index);
 			memset(kaddr + offset, 0, size);
 		}
 		flush_dcache_page(page);
@@ -270,7 +271,9 @@
 	int bsize;
 };
 
-static int lo_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size)
+static int
+lo_read_actor(read_descriptor_t *desc, struct page *page,
+	      unsigned long offset, unsigned long size)
 {
 	char *kaddr;
 	unsigned long count = desc->count;
@@ -284,7 +287,8 @@
 	kaddr = kmap(page);
 	if (lo_do_transfer(lo, READ, kaddr + offset, p->data, size, IV)) {
 		size = 0;
-		printk(KERN_ERR "loop: transfer error block %ld\n",page->index);
+		printk(KERN_ERR "loop: transfer error block %ld\n",
+		       page->index);
 		desc->error = -EINVAL;
 	}
 	kunmap(page);
@@ -297,7 +301,7 @@
 
 static int
 do_lo_receive(struct loop_device *lo,
-		struct bio_vec *bvec, int bsize, loff_t pos)
+	      struct bio_vec *bvec, int bsize, loff_t pos)
 {
 	struct lo_read_data cookie;
 	struct file *file;
@@ -330,8 +334,8 @@
 	return ret;
 }
 
-static inline unsigned long loop_get_iv(struct loop_device *lo,
-					unsigned long sector)
+static inline unsigned long
+loop_get_iv(struct loop_device *lo, unsigned long sector)
 {
 	int bs = lo->lo_blocksize;
 	unsigned long offset, IV;
@@ -358,6 +362,7 @@
 }
 
 static int loop_end_io_transfer(struct bio *, unsigned int, int);
+
 static void loop_put_buffer(struct bio *bio)
 {
 	/*
@@ -764,7 +769,8 @@
 	return err;
 }
 
-static int loop_init_xfer(struct loop_device *lo, int type,struct loop_info *i)
+static int
+loop_init_xfer(struct loop_device *lo, int type, const struct loop_info64 *i)
 {
 	int err = 0; 
 	if (type) {
@@ -822,9 +828,9 @@
 	return 0;
 }
 
-static int loop_set_status(struct loop_device *lo, struct loop_info *arg)
+static int
+loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
 {
-	struct loop_info info; 
 	int err;
 	unsigned int type;
 	loff_t offset;
@@ -834,23 +840,21 @@
 		return -EPERM;
 	if (lo->lo_state != Lo_bound)
 		return -ENXIO;
-	if (copy_from_user(&info, arg, sizeof (struct loop_info)))
-		return -EFAULT; 
-	if ((unsigned int) info.lo_encrypt_key_size > LO_KEY_SIZE)
+	if ((unsigned int) info->lo_encrypt_key_size > LO_KEY_SIZE)
 		return -EINVAL;
-	type = info.lo_encrypt_type; 
+	type = info->lo_encrypt_type; 
 	if (type >= MAX_LO_CRYPT || xfer_funcs[type] == NULL)
 		return -EINVAL;
-	if (type == LO_CRYPT_XOR && info.lo_encrypt_key_size == 0)
+	if (type == LO_CRYPT_XOR && info->lo_encrypt_key_size == 0)
 		return -EINVAL;
 
 	err = loop_release_xfer(lo);
 	if (!err) 
-		err = loop_init_xfer(lo, type, &info);
+		err = loop_init_xfer(lo, type, info);
 
 	offset = lo->lo_offset;
-	if (offset != info.lo_offset) {
-		lo->lo_offset = info.lo_offset;
+	if (offset != info->lo_offset) {
+		lo->lo_offset = info->lo_offset;
 		if (figure_loop_size(lo)){
 			err = -EFBIG;
 			lo->lo_offset = offset;
@@ -860,51 +864,147 @@
 	if (err)
 		return err;	
 
-	strncpy(lo->lo_name, info.lo_name, LO_NAME_SIZE);
+	strncpy(lo->lo_name, info->lo_name, LO_NAME_SIZE);
 
 	lo->transfer = xfer_funcs[type]->transfer;
 	lo->ioctl = xfer_funcs[type]->ioctl;
-	lo->lo_encrypt_key_size = info.lo_encrypt_key_size;
-	lo->lo_init[0] = info.lo_init[0];
-	lo->lo_init[1] = info.lo_init[1];
-	if (info.lo_encrypt_key_size) {
-		memcpy(lo->lo_encrypt_key, info.lo_encrypt_key, 
-		       info.lo_encrypt_key_size);
+	lo->lo_encrypt_key_size = info->lo_encrypt_key_size;
+	lo->lo_init[0] = info->lo_init[0];
+	lo->lo_init[1] = info->lo_init[1];
+	if (info->lo_encrypt_key_size) {
+		memcpy(lo->lo_encrypt_key, info->lo_encrypt_key, 
+		       info->lo_encrypt_key_size);
 		lo->lo_key_owner = current->uid; 
 	}	
 
 	return 0;
 }
 
-static int loop_get_status(struct loop_device *lo, struct loop_info *arg)
+static int
+loop_get_status(struct loop_device *lo, struct loop_info64 *info)
 {
 	struct file *file = lo->lo_backing_file;
-	struct loop_info info;
 	struct kstat stat;
 	int error;
 
 	if (lo->lo_state != Lo_bound)
 		return -ENXIO;
-	if (!arg)
-		return -EINVAL;
 	error = vfs_getattr(file->f_vfsmnt, file->f_dentry, &stat);
 	if (error)
 		return error;
-	memset(&info, 0, sizeof(info));
-	info.lo_number = lo->lo_number;
-	info.lo_device = stat.dev;
-	info.lo_inode = stat.ino;
-	info.lo_rdevice = lo->lo_device ? stat.rdev : stat.dev;
-	info.lo_offset = lo->lo_offset;
-	info.lo_flags = lo->lo_flags;
-	strncpy(info.lo_name, lo->lo_name, LO_NAME_SIZE);
-	info.lo_encrypt_type = lo->lo_encrypt_type;
+	memset(info, 0, sizeof(*info));
+	info->lo_number = lo->lo_number;
+	info->lo_device = stat.dev;
+	info->lo_inode = stat.ino;
+	info->lo_rdevice = lo->lo_device ? stat.rdev : stat.dev;
+	info->lo_offset = lo->lo_offset;
+	info->lo_flags = lo->lo_flags;
+	strncpy(info->lo_name, lo->lo_name, LO_NAME_SIZE);
+	info->lo_encrypt_type = lo->lo_encrypt_type;
 	if (lo->lo_encrypt_key_size && capable(CAP_SYS_ADMIN)) {
-		info.lo_encrypt_key_size = lo->lo_encrypt_key_size;
-		memcpy(info.lo_encrypt_key, lo->lo_encrypt_key,
+		info->lo_encrypt_key_size = lo->lo_encrypt_key_size;
+		memcpy(info->lo_encrypt_key, lo->lo_encrypt_key,
 		       lo->lo_encrypt_key_size);
 	}
-	return copy_to_user(arg, &info, sizeof(info)) ? -EFAULT : 0;
+	return 0;
+}
+
+static void
+loop_info64_from_old(const struct loop_info *info, struct loop_info64 *info64)
+{
+	info64->lo_number = info->lo_number;
+	info64->lo_device = info->lo_device;
+	info64->lo_inode = info->lo_inode;
+	info64->lo_rdevice = info->lo_rdevice;
+	info64->lo_offset = info->lo_offset;
+	info64->lo_encrypt_type = info->lo_encrypt_type;
+	info64->lo_encrypt_key_size = info->lo_encrypt_key_size;
+	info64->lo_flags = info->lo_flags;
+	info64->lo_init[0] = info->lo_init[0];
+	info64->lo_init[1] = info->lo_init[1];
+	memcpy(info64->lo_name, info->lo_name, LO_NAME_SIZE);
+	memcpy(info64->lo_encrypt_key, info->lo_encrypt_key, LO_KEY_SIZE);
+}
+
+static int
+loop_info64_to_old(const struct loop_info64 *info64, struct loop_info *info)
+{
+	info->lo_number = info64->lo_number;
+	info->lo_device = info64->lo_device;
+	info->lo_inode = info64->lo_inode;
+	info->lo_rdevice = info64->lo_rdevice;
+	info->lo_offset = info64->lo_offset;
+	info->lo_encrypt_type = info64->lo_encrypt_type;
+	info->lo_encrypt_key_size = info64->lo_encrypt_key_size;
+	info->lo_flags = info64->lo_flags;
+	info->lo_init[0] = info64->lo_init[0];
+	info->lo_init[1] = info64->lo_init[1];
+	memcpy(info->lo_name, info64->lo_name, LO_NAME_SIZE);
+	memcpy(info->lo_encrypt_key,info64->lo_encrypt_key,LO_KEY_SIZE);
+
+	/* error in case values were truncated */
+	if (info->lo_device != info64->lo_device ||
+	    info->lo_rdevice != info64->lo_rdevice ||
+	    info->lo_inode != info64->lo_inode ||
+	    info->lo_offset != info64->lo_offset)
+		return -EOVERFLOW;
+
+	return 0;
+}
+
+static int
+loop_set_status_old(struct loop_device *lo, const struct loop_info *arg)
+{
+	struct loop_info info;
+	struct loop_info64 info64;
+
+	if (copy_from_user(&info, arg, sizeof (struct loop_info)))
+		return -EFAULT;
+	loop_info64_from_old(&info, &info64);
+	return loop_set_status(lo, &info64);
+}
+
+static int
+loop_set_status64(struct loop_device *lo, const struct loop_info64 *arg)
+{
+	struct loop_info64 info64;
+
+	if (copy_from_user(&info64, arg, sizeof (struct loop_info64)))
+		return -EFAULT;
+	return loop_set_status(lo, &info64);
+}
+
+static int
+loop_get_status_old(struct loop_device *lo, struct loop_info *arg) {
+	struct loop_info info;
+	struct loop_info64 info64;
+	int err = 0;
+
+	if (!arg)
+		err = -EINVAL;
+	if (!err)
+		err = loop_get_status(lo, &info64);
+	if (!err)
+		err = loop_info64_to_old(&info64, &info);
+	if (!err && copy_to_user(arg, &info, sizeof(info)))
+		err = -EFAULT;
+
+	return err;
+}
+
+static int
+loop_get_status64(struct loop_device *lo, struct loop_info64 *arg) {
+	struct loop_info64 info64;
+	int err = 0;
+
+	if (!arg)
+		err = -EINVAL;
+	if (!err)
+		err = loop_get_status(lo, &info64);
+	if (!err && copy_to_user(arg, &info64, sizeof(info64)))
+		err = -EFAULT;
+
+	return err;
 }
 
 static int lo_ioctl(struct inode * inode, struct file * file,
@@ -922,10 +1022,16 @@
 		err = loop_clr_fd(lo, inode->i_bdev);
 		break;
 	case LOOP_SET_STATUS:
-		err = loop_set_status(lo, (struct loop_info *) arg);
+		err = loop_set_status_old(lo, (struct loop_info *) arg);
 		break;
 	case LOOP_GET_STATUS:
-		err = loop_get_status(lo, (struct loop_info *) arg);
+		err = loop_get_status_old(lo, (struct loop_info *) arg);
+		break;
+	case LOOP_SET_STATUS64:
+		err = loop_set_status64(lo, (struct loop_info64 *) arg);
+		break;
+	case LOOP_GET_STATUS64:
+		err = loop_get_status64(lo, (struct loop_info64 *) arg);
 		break;
 	default:
 		err = lo->ioctl ? lo->ioctl(lo, cmd, arg) : -EINVAL;
diff -urN linux-2.5.67-bk9/drivers/cdrom/sbpcd.c linux-2.5.67-bk10/drivers/cdrom/sbpcd.c
--- linux-2.5.67-bk9/drivers/cdrom/sbpcd.c	2003-04-07 10:30:44.000000000 -0700
+++ linux-2.5.67-bk10/drivers/cdrom/sbpcd.c	2003-04-19 04:35:36.000000000 -0700
@@ -5645,7 +5645,6 @@
 int __init sbpcd_init(void)
 #endif
 {
-	char nbuff[16];
 	int i=0, j=0;
 	int addr[2]={1, CDROM_PORT};
 	int port_index;
@@ -5869,8 +5868,7 @@
 		disk->fops = &sbpcd_bdops;
 		strcpy(disk->disk_name, sbpcd_infop->name);
 		disk->flags = GENHD_FL_CD;
-		sprintf(nbuff, "sbp/c0t%d", p->drv_id);
-		disk->de = devfs_mk_dir(NULL, nbuff, NULL);
+		sprintf(disk->devfs_name, "sbp/c0t%d", p->drv_id);
 		p->disk = disk;
 		if (register_cdrom(sbpcd_infop))
 		{
diff -urN linux-2.5.67-bk9/drivers/char/misc.c linux-2.5.67-bk10/drivers/char/misc.c
--- linux-2.5.67-bk9/drivers/char/misc.c	2003-04-07 10:32:50.000000000 -0700
+++ linux-2.5.67-bk10/drivers/char/misc.c	2003-04-19 04:35:36.000000000 -0700
@@ -166,8 +166,8 @@
  
 int misc_register(struct miscdevice * misc)
 {
-	static devfs_handle_t devfs_handle, dir;
 	struct miscdevice *c;
+	char buf[256];
 	
 	if (misc->next || misc->prev)
 		return -EBUSY;
@@ -195,14 +195,16 @@
 	}
 	if (misc->minor < DYNAMIC_MINORS)
 		misc_minors[misc->minor >> 3] |= 1 << (misc->minor & 7);
-	if (!devfs_handle)
-		devfs_handle = devfs_mk_dir("misc");
-	dir = strchr (misc->name, '/') ? NULL : devfs_handle;
-	misc->devfs_handle =
-		devfs_register (dir, misc->name, DEVFS_FL_NONE,
-				MISC_MAJOR, misc->minor,
-				S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
-				misc->fops, NULL);
+
+
+	/* yuck, yet another stupid special-casing.  We should rather
+	   add ->devfs_name to avoid this mess. */
+	snprintf(buf, sizeof(buf), strchr(misc->name, '/') ?
+			"%s" : "misc/%s", misc->name);
+	misc->devfs_handle = devfs_register(NULL, buf, 0,
+			MISC_MAJOR, misc->minor,
+			S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
+			misc->fops, NULL);
 
 	/*
 	 * Add it to the front, so that later devices can "override"
diff -urN linux-2.5.67-bk9/drivers/ide/ide-cd.c linux-2.5.67-bk10/drivers/ide/ide-cd.c
--- linux-2.5.67-bk9/drivers/ide/ide-cd.c	2003-04-07 10:31:13.000000000 -0700
+++ linux-2.5.67-bk10/drivers/ide/ide-cd.c	2003-04-19 04:35:36.000000000 -0700
@@ -3366,7 +3366,7 @@
 	DRIVER(drive)->busy++;
 	g->minors = 1;
 	g->minor_shift = 0;
-	g->de = drive->de;
+	strcpy(g->devfs_name, drive->devfs_name);
 	g->driverfs_dev = &drive->gendev;
 	g->flags = GENHD_FL_CD;
 	if (ide_cdrom_setup(drive)) {
diff -urN linux-2.5.67-bk9/drivers/ide/ide-disk.c linux-2.5.67-bk10/drivers/ide/ide-disk.c
--- linux-2.5.67-bk9/drivers/ide/ide-disk.c	2003-04-07 10:31:06.000000000 -0700
+++ linux-2.5.67-bk10/drivers/ide/ide-disk.c	2003-04-19 04:35:36.000000000 -0700
@@ -1816,10 +1816,9 @@
 	DRIVER(drive)->busy--;
 	g->minors = 1 << PARTN_BITS;
 	g->minor_shift = PARTN_BITS;
-	g->de = drive->de;
+	strcpy(g->devfs_name, drive->devfs_name);
 	g->driverfs_dev = &drive->gendev;
 	g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0;
-	g->flags |= GENHD_FL_DEVFS;
 	set_capacity(g, current_capacity(drive));
 	g->fops = &idedisk_ops;
 	add_disk(g);
diff -urN linux-2.5.67-bk9/drivers/ide/ide-floppy.c linux-2.5.67-bk10/drivers/ide/ide-floppy.c
--- linux-2.5.67-bk9/drivers/ide/ide-floppy.c	2003-04-07 10:31:20.000000000 -0700
+++ linux-2.5.67-bk10/drivers/ide/ide-floppy.c	2003-04-19 04:35:36.000000000 -0700
@@ -2059,9 +2059,8 @@
 	g->minors = 1 << PARTN_BITS;
 	g->minor_shift = PARTN_BITS;
 	g->driverfs_dev = &drive->gendev;
-	g->de = drive->de;
+	strcpy(g->devfs_name, drive->devfs_name);
 	g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0;
-	g->flags |= GENHD_FL_DEVFS;
 	g->fops = &idefloppy_ops;
 	add_disk(g);
 	return 0;
diff -urN linux-2.5.67-bk9/drivers/ide/ide-io.c linux-2.5.67-bk10/drivers/ide/ide-io.c
--- linux-2.5.67-bk9/drivers/ide/ide-io.c	2003-04-07 10:32:26.000000000 -0700
+++ linux-2.5.67-bk10/drivers/ide/ide-io.c	2003-04-19 04:35:36.000000000 -0700
@@ -41,7 +41,6 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/ide.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/completion.h>
 #include <linux/reboot.h>
 #include <linux/cdrom.h>
diff -urN linux-2.5.67-bk9/drivers/ide/ide-probe.c linux-2.5.67-bk10/drivers/ide/ide-probe.c
--- linux-2.5.67-bk9/drivers/ide/ide-probe.c	2003-04-19 04:35:28.000000000 -0700
+++ linux-2.5.67-bk10/drivers/ide/ide-probe.c	2003-04-19 04:35:36.000000000 -0700
@@ -1289,7 +1289,6 @@
 
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		ide_drive_t * drive = &hwif->drives[unit];
-		char name[64];
 		ide_add_generic_settings(drive);
 		snprintf(drive->gendev.bus_id,BUS_ID_SIZE,"%u.%u",
 			 hwif->index,unit);
@@ -1298,13 +1297,12 @@
 		drive->gendev.parent = &hwif->gendev;
 		drive->gendev.bus = &ide_bus_type;
 		drive->gendev.driver_data = drive;
-		sprintf (name, "ide/host%d/bus%d/target%d/lun%d",
-			(hwif->channel && hwif->mate) ?
-			hwif->mate->index : hwif->index,
-			hwif->channel, unit, drive->lun);
 		if (drive->present) {
 			device_register(&drive->gendev);
-			drive->de = devfs_mk_dir(name);
+			sprintf(drive->devfs_name, "ide/host%d/bus%d/target%d/lun%d",
+				(hwif->channel && hwif->mate) ?
+				hwif->mate->index : hwif->index,
+				hwif->channel, unit, drive->lun);
 		}
 	}
 	blk_register_region(MKDEV(hwif->major, 0), MAX_DRIVES << PARTN_BITS,
diff -urN linux-2.5.67-bk9/drivers/ide/ide-tape.c linux-2.5.67-bk10/drivers/ide/ide-tape.c
--- linux-2.5.67-bk9/drivers/ide/ide-tape.c	2003-04-07 10:31:00.000000000 -0700
+++ linux-2.5.67-bk10/drivers/ide/ide-tape.c	2003-04-19 04:35:36.000000000 -0700
@@ -866,8 +866,6 @@
  */
 typedef struct {
 	ide_drive_t *drive;
-	devfs_handle_t de_r, de_n;
-
 	/*
 	 *	Since a typical character device operation requires more
 	 *	than one packet command, we provide here enough memory
@@ -6170,8 +6168,8 @@
 	DRIVER(drive)->busy = 0;
 	(void) ide_unregister_subdriver(drive);
 	drive->driver_data = NULL;
-	devfs_unregister(tape->de_r);
-	devfs_unregister(tape->de_n);
+	devfs_remove("%s/mt");
+	devfs_remove("%s/mtn");
 	devfs_unregister_tape(drive->disk->number);
 	kfree (tape);
 	drive->disk->fops = ide_fops;
@@ -6272,6 +6270,7 @@
 static int idetape_attach (ide_drive_t *drive)
 {
 	idetape_tape_t *tape;
+	char devfs_name[64];
 	int minor;
 
 	if (!strstr("ide-tape", drive->driver_req))
@@ -6306,17 +6305,20 @@
 		;
 	idetape_setup(drive, tape, minor);
 	idetape_chrdevs[minor].drive = drive;
-	tape->de_r =
-	    devfs_register (drive->de, "mt", DEVFS_FL_DEFAULT,
-			    HWIF(drive)->major, minor,
-			    S_IFCHR | S_IRUGO | S_IWUGO,
-			    &idetape_fops, NULL);
-	tape->de_n =
-	    devfs_register (drive->de, "mtn", DEVFS_FL_DEFAULT,
-			    HWIF(drive)->major, minor + 128,
-			    S_IFCHR | S_IRUGO | S_IWUGO,
-			    &idetape_fops, NULL);
-	drive->disk->number = devfs_register_tape(drive->de);
+
+	sprintf(devfs_name, "%s/mt", drive->devfs_name);
+	tape->de_r = devfs_register (NULL, devfs_name, 0,
+			HWIF(drive)->major, minor,
+			S_IFCHR | S_IRUGO | S_IWUGO,
+			&idetape_fops, NULL);
+
+	sprintf(devfs_name, "%s/mtn", drive->devfs_name);
+	tape->de_n = devfs_register (NULL, devfs_name, 0,
+			HWIF(drive)->major, minor + 128,
+			S_IFCHR | S_IRUGO | S_IWUGO,
+			&idetape_fops, NULL);
+
+	drive->disk->number = devfs_register_tape(drive->devfs_name);
 	drive->disk->fops = &idetape_block_ops;
 	return 0;
 failed:
diff -urN linux-2.5.67-bk9/drivers/ide/ide.c linux-2.5.67-bk10/drivers/ide/ide.c
--- linux-2.5.67-bk9/drivers/ide/ide.c	2003-04-07 10:30:59.000000000 -0700
+++ linux-2.5.67-bk10/drivers/ide/ide.c	2003-04-19 04:35:36.000000000 -0700
@@ -650,9 +650,9 @@
 	 */
 	for (i = 0; i < MAX_DRIVES; ++i) {
 		drive = &hwif->drives[i];
-		if (drive->de) {
-			devfs_unregister(drive->de);
-			drive->de = NULL;
+		if (drive->devfs_name[0] != '\0') {
+			devfs_remove(drive->devfs_name);
+			drive->devfs_name[0] = '\0';
 		}
 		if (!drive->present)
 			continue;
diff -urN linux-2.5.67-bk9/drivers/s390/block/dasd.c linux-2.5.67-bk10/drivers/s390/block/dasd.c
--- linux-2.5.67-bk9/drivers/s390/block/dasd.c	2003-04-19 04:35:30.000000000 -0700
+++ linux-2.5.67-bk10/drivers/s390/block/dasd.c	2003-04-19 04:35:38.000000000 -0700
@@ -157,9 +157,10 @@
 
 #ifdef CONFIG_DEVFS_FS
 	/* Add a proc directory and the dasd device entry to devfs. */
- 	device->gdp->de = devfs_mk_dir("dasd/%04x",
+ 	sprintf(device->gdp->devfs_name, "dasd/%04x",
 		_ccw_device_get_device_number(device->cdev));
 #endif
+
 	if (device->ro_flag)
 		devfs_perm = S_IFBLK | S_IRUSR;
 	else
diff -urN linux-2.5.67-bk9/drivers/s390/block/dasd_genhd.c linux-2.5.67-bk10/drivers/s390/block/dasd_genhd.c
--- linux-2.5.67-bk9/drivers/s390/block/dasd_genhd.c	2003-04-19 04:35:30.000000000 -0700
+++ linux-2.5.67-bk10/drivers/s390/block/dasd_genhd.c	2003-04-19 04:35:39.000000000 -0700
@@ -137,7 +137,6 @@
 	gdp->major = mi->major;
 	gdp->first_minor = index << DASD_PARTN_BITS;
 	gdp->fops = &dasd_device_operations;
-	gdp->flags |= GENHD_FL_DEVFS;
 
 	/*
 	 * Set device name.
diff -urN linux-2.5.67-bk9/drivers/scsi/osst.c linux-2.5.67-bk10/drivers/scsi/osst.c
--- linux-2.5.67-bk9/drivers/scsi/osst.c	2003-04-07 10:31:18.000000000 -0700
+++ linux-2.5.67-bk10/drivers/scsi/osst.c	2003-04-19 04:35:40.000000000 -0700
@@ -47,6 +47,7 @@
 #include <linux/vmalloc.h>
 #include <linux/version.h>
 #include <linux/blk.h>
+#include <linux/devfs_fs_kernel.h>
 #include <asm/uaccess.h>
 #include <asm/dma.h>
 #include <asm/system.h>
@@ -99,6 +100,8 @@
 };
 #endif
 
+static char *osst_formats[ST_NBR_MODES] ={"", "l", "m", "a"};
+
 /* Some default definitions have been moved to osst_options.h */
 #define OSST_BUFFER_SIZE (OSST_BUFFER_BLOCKS * ST_KILOBYTE)
 #define OSST_WRITE_THRESHOLD (OSST_WRITE_THRESHOLD_BLOCKS * ST_KILOBYTE)
@@ -5524,11 +5527,12 @@
 	write_unlock(&os_scsi_tapes_lock);
 
 	for (mode = 0; mode < ST_NBR_MODES; ++mode) {
-		char name[8];
-		static char *formats[ST_NBR_MODES] ={"", "l", "m", "a"};
-		
+		char name[8], devfs_name[64];
+
 		/*  Rewind entry  */
-		sprintf (name, "ot%s", formats[mode]);
+		sprintf(name, "ot%s", osst_formats[mode]);
+		sprintf(devfs_name, "%s/ot%s", SDp->devfs_name, osst_formats[mode]);
+
 		sprintf(tpnt->driverfs_dev_r[mode].bus_id, "%s:%s", 
 				SDp->sdev_driverfs_dev.bus_id, name);
 		sprintf(tpnt->driverfs_dev_r[mode].name, "%s%s", 
@@ -5541,13 +5545,14 @@
 		device_create_file(&tpnt->driverfs_dev_r[mode], 
 				&dev_attr_type);
 		device_create_file(&tpnt->driverfs_dev_r[mode], &dev_attr_kdev);
-		tpnt->de_r[mode] =
-			devfs_register (SDp->de, name, DEVFS_FL_DEFAULT,
+		devfs_register(NULL, devfs_name, 0,
 					OSST_MAJOR, dev_num + (mode << 5),
 					S_IFCHR | S_IRUGO | S_IWUGO,
 					&osst_fops, NULL);
 		/*  No-rewind entry  */
-		sprintf (name, "ot%sn", formats[mode]);
+		sprintf (name, "ot%sn", osst_formats[mode]);
+		sprintf(devfs_name, "%s/ot%sn", SDp->devfs_name, osst_formats[mode]);
+
 		sprintf(tpnt->driverfs_dev_n[mode].bus_id, "%s:%s", 
 				SDp->sdev_driverfs_dev.bus_id, name);
 		sprintf(tpnt->driverfs_dev_n[mode].name, "%s%s", 
@@ -5561,13 +5566,12 @@
 				&dev_attr_type);
 		device_create_file(&tpnt->driverfs_dev_n[mode], 
 				&dev_attr_kdev);
-		tpnt->de_n[mode] =
-			devfs_register (SDp->de, name, DEVFS_FL_DEFAULT,
+		devfs_register(NULL, devfs_name, 0,
 					OSST_MAJOR, dev_num + (mode << 5) + 128,
 					S_IFCHR | S_IRUGO | S_IWUGO,
 					&osst_fops, NULL);
 	}
-	drive->number = devfs_register_tape (SDp->de);
+	drive->number = devfs_register_tape(SDp->devfs_name);
 
 	printk(KERN_INFO
 		"osst :I: Attached OnStream %.5s tape at scsi%d, channel %d, id %d, lun %d as %s\n",
@@ -5595,10 +5599,8 @@
 	if((tpnt = os_scsi_tapes[i]) && (tpnt->device == SDp)) {
 		tpnt->device = NULL;
 		for (mode = 0; mode < ST_NBR_MODES; ++mode) {
-			devfs_unregister (tpnt->de_r[mode]);
-			tpnt->de_r[mode] = NULL;
-			devfs_unregister (tpnt->de_n[mode]);
-			tpnt->de_n[mode] = NULL;
+			devfs_remove("%s/ot%s", SDp->devfs_name, osst_formats[mode]);
+			devfs_remove("%s/ot%sn", SDp->devfs_name, osst_formats[mode]);
 		}
 		devfs_unregister_tape(tpnt->drive->number);
 		put_disk(tpnt->drive);
diff -urN linux-2.5.67-bk9/drivers/scsi/osst.h linux-2.5.67-bk10/drivers/scsi/osst.h
--- linux-2.5.67-bk9/drivers/scsi/osst.h	2003-04-07 10:31:54.000000000 -0700
+++ linux-2.5.67-bk10/drivers/scsi/osst.h	2003-04-19 04:35:40.000000000 -0700
@@ -5,9 +5,7 @@
 #include <asm/byteorder.h>
 #include <linux/config.h>
 #include <linux/completion.h>
-#ifdef CONFIG_DEVFS_FS
-#include <linux/devfs_fs_kernel.h>
-#endif
+
 
 /*	FIXME - rename and use the following two types or delete them!
  *              and the types really should go to st.h anyway...
@@ -557,8 +555,6 @@
   /* Mode characteristics */
   ST_mode modes[ST_NBR_MODES];
   int current_mode;
-  devfs_handle_t de_r[ST_NBR_MODES];  /*  Rewind entries     */
-  devfs_handle_t de_n[ST_NBR_MODES];  /*  No-rewind entries  */
   struct device driverfs_dev_r[ST_NBR_MODES];
   struct device driverfs_dev_n[ST_NBR_MODES];
 
diff -urN linux-2.5.67-bk9/drivers/scsi/scsi.h linux-2.5.67-bk10/drivers/scsi/scsi.h
--- linux-2.5.67-bk9/drivers/scsi/scsi.h	2003-04-19 04:35:30.000000000 -0700
+++ linux-2.5.67-bk10/drivers/scsi/scsi.h	2003-04-19 04:35:40.000000000 -0700
@@ -16,7 +16,6 @@
 #define _SCSI_H
 
 #include <linux/config.h>	    /* for CONFIG_SCSI_LOGGING */
-#include <linux/devfs_fs_kernel.h>  /* some morons don't know struct pointers */
 #include <scsi/scsi.h>
 
 
@@ -588,7 +587,7 @@
 	int access_count;	/* Count of open channels/mounts */
 
 	void *hostdata;		/* available to low-level driver */
-	devfs_handle_t de;      /* directory for the device      */
+	char devfs_name[256];	/* devfs junk */
 	char type;
 	char scsi_level;
 	unsigned char inquiry_len;	/* valid bytes in 'inquiry' */
diff -urN linux-2.5.67-bk9/drivers/scsi/scsi_scan.c linux-2.5.67-bk10/drivers/scsi/scsi_scan.c
--- linux-2.5.67-bk9/drivers/scsi/scsi_scan.c	2003-04-19 04:35:30.000000000 -0700
+++ linux-2.5.67-bk10/drivers/scsi/scsi_scan.c	2003-04-19 04:35:40.000000000 -0700
@@ -1244,7 +1244,7 @@
 	
 	scsi_device_register(sdev);
 
-	sdev->de = devfs_mk_dir("scsi/host%d/bus%d/target%d/lun%d",
+	sprintf(sdev->devfs_name, "scsi/host%d/bus%d/target%d/lun%d",
 				sdev->host->host_no, sdev->channel,
 				sdev->id, sdev->lun);
 
@@ -1733,7 +1733,7 @@
 	if (sdev->attached)
 		return -EINVAL;
 
-	devfs_unregister(sdev->de);
+	devfs_remove(sdev->devfs_name);
 	scsi_device_unregister(sdev);
 
 	scsi_free_sdev(sdev);
diff -urN linux-2.5.67-bk9/drivers/scsi/sd.c linux-2.5.67-bk10/drivers/scsi/sd.c
--- linux-2.5.67-bk9/drivers/scsi/sd.c	2003-04-19 04:35:30.000000000 -0700
+++ linux-2.5.67-bk10/drivers/scsi/sd.c	2003-04-19 04:35:40.000000000 -0700
@@ -1327,7 +1327,6 @@
 	sdkp->disk = gd;
 	sdkp->index = index;
 
-	gd->de = sdp->de;
 	gd->major = sd_major(index >> 4);
 	gd->first_minor = (index & 15) << 4;
 	gd->minors = 16;
@@ -1340,10 +1339,12 @@
 		sprintf(gd->disk_name, "sd%c", 'a' + index % 26);
 	}
 
+	strcpy(gd->devfs_name, sdp->devfs_name);
+
 	sd_init_onedisk(sdkp, gd);
 
 	gd->driverfs_dev = &sdp->sdev_driverfs_dev;
-	gd->flags = GENHD_FL_DRIVERFS | GENHD_FL_DEVFS;
+	gd->flags = GENHD_FL_DRIVERFS;
 	if (sdp->removable)
 		gd->flags |= GENHD_FL_REMOVABLE;
 	gd->private_data = &sdkp->driver;
diff -urN linux-2.5.67-bk9/drivers/scsi/sg.c linux-2.5.67-bk10/drivers/scsi/sg.c
--- linux-2.5.67-bk9/drivers/scsi/sg.c	2003-04-07 10:31:14.000000000 -0700
+++ linux-2.5.67-bk10/drivers/scsi/sg.c	2003-04-19 04:35:40.000000000 -0700
@@ -182,7 +182,6 @@
 	wait_queue_head_t o_excl_wait;	/* queue open() when O_EXCL in use */
 	int sg_tablesize;	/* adapter's max scatter-gather table size */
 	Sg_fd *headfp;		/* first open fd belonging to this device */
-	devfs_handle_t de;
 	volatile char detached;	/* 0->attached, 1->detached pending removal */
 	volatile char exclude;	/* opened for exclusive access */
 	char sgdebug;		/* 0->off, 1->sense, 9->dump dev, 10-> all devs */
@@ -1350,6 +1349,7 @@
 	struct gendisk *disk;
 	Sg_device *sdp = NULL;
 	unsigned long iflags;
+	char devfs_name[64];
 	int k, error;
 
 	disk = alloc_disk(1);
@@ -1447,10 +1447,13 @@
 	device_register(&sdp->sg_driverfs_dev);
 	device_create_file(&sdp->sg_driverfs_dev, &dev_attr_type);
 	device_create_file(&sdp->sg_driverfs_dev, &dev_attr_kdev);
-	sdp->de = devfs_register(scsidp->de, "generic", DEVFS_FL_DEFAULT,
-				 SCSI_GENERIC_MAJOR, k,
-				 S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
-				 &sg_fops, sdp);
+
+	sprintf(devfs_name, "%s/generic", scsidp->devfs_name);
+	devfs_register(NULL, devfs_name, 0,
+			SCSI_GENERIC_MAJOR, k,
+			S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
+			&sg_fops, sdp);
+
 	switch (scsidp->type) {
 	case TYPE_DISK:
 	case TYPE_MOD:
@@ -1527,8 +1530,7 @@
 	write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
 
 	if (sdp) {
-		devfs_unregister(sdp->de);
-		sdp->de = NULL;
+		devfs_remove("%s/generic", scsidp->devfs_name);
 		device_remove_file(&sdp->sg_driverfs_dev, &dev_attr_type);
 		device_remove_file(&sdp->sg_driverfs_dev, &dev_attr_kdev);
 		device_unregister(&sdp->sg_driverfs_dev);
diff -urN linux-2.5.67-bk9/drivers/scsi/sr.c linux-2.5.67-bk10/drivers/scsi/sr.c
--- linux-2.5.67-bk9/drivers/scsi/sr.c	2003-04-07 10:30:57.000000000 -0700
+++ linux-2.5.67-bk10/drivers/scsi/sr.c	2003-04-19 04:35:40.000000000 -0700
@@ -569,7 +569,7 @@
 	get_capabilities(cd);
 	sr_vendor_init(cd);
 
-	disk->de = sdev->de;
+	strcpy(disk->devfs_name, sdev->devfs_name);
 	disk->driverfs_dev = &sdev->sdev_driverfs_dev;
 	register_cdrom(&cd->cdi);
 	set_capacity(disk, cd->capacity);
diff -urN linux-2.5.67-bk9/drivers/scsi/st.c linux-2.5.67-bk10/drivers/scsi/st.c
--- linux-2.5.67-bk9/drivers/scsi/st.c	2003-04-19 04:35:30.000000000 -0700
+++ linux-2.5.67-bk10/drivers/scsi/st.c	2003-04-19 04:35:40.000000000 -0700
@@ -35,6 +35,7 @@
 #include <linux/spinlock.h>
 #include <linux/blk.h>
 #include <linux/moduleparam.h>
+#include <linux/devfs_fs_kernel.h>
 #include <asm/uaccess.h>
 #include <asm/dma.h>
 #include <asm/system.h>
@@ -116,6 +117,7 @@
 };
 #endif
 
+static char *st_formats[ST_NBR_MODES] ={"", "l", "m", "a"};
 
 /* The default definitions have been moved to st_options.h */
 
@@ -3863,11 +3865,12 @@
 	write_unlock(&st_dev_arr_lock);
 
 	for (mode = 0; mode < ST_NBR_MODES; ++mode) {
-	    char name[8];
-	    static char *formats[ST_NBR_MODES] ={"", "l", "m", "a"};
+	    char name[8], devfs_name[64];
 
 	    /*  Rewind entry  */
-	    sprintf (name, "mt%s", formats[mode]);
+	    sprintf(name, "mt%s", st_formats[mode]);
+	    sprintf(devfs_name, "%s/mt%s", SDp->devfs_name, st_formats[mode]);
+	    
 	    sprintf(tpnt->driverfs_dev_r[mode].bus_id, "%s:%s", 
 		    SDp->sdev_driverfs_dev.bus_id, name);
 	    sprintf(tpnt->driverfs_dev_r[mode].name, "%s%s", 
@@ -3880,13 +3883,14 @@
 	    device_create_file(&tpnt->driverfs_dev_r[mode], 
 			       &dev_attr_type);
 	    device_create_file(&tpnt->driverfs_dev_r[mode], &dev_attr_kdev);
-	    tpnt->de_r[mode] =
-		devfs_register (SDp->de, name, DEVFS_FL_DEFAULT,
+	    devfs_register(NULL, devfs_name, 0,
 				SCSI_TAPE_MAJOR, dev_num + (mode << 5),
 				S_IFCHR | S_IRUGO | S_IWUGO,
 				&st_fops, NULL);
 	    /*  No-rewind entry  */
-	    sprintf (name, "mt%sn", formats[mode]);
+	    sprintf (name, "mt%sn", st_formats[mode]);
+	    sprintf(devfs_name, "%s/mt%sn", SDp->devfs_name, st_formats[mode]);
+
 	    sprintf(tpnt->driverfs_dev_n[mode].bus_id, "%s:%s", 
 		    SDp->sdev_driverfs_dev.bus_id, name);
 	    sprintf(tpnt->driverfs_dev_n[mode].name, "%s%s", 
@@ -3900,13 +3904,12 @@
 			       &dev_attr_type);
 	    device_create_file(&tpnt->driverfs_dev_n[mode], 
 			       &dev_attr_kdev);
-	    tpnt->de_n[mode] =
-		devfs_register (SDp->de, name, DEVFS_FL_DEFAULT,
+	    devfs_register(NULL, devfs_name, 0,
 				SCSI_TAPE_MAJOR, dev_num + (mode << 5) + 128,
 				S_IFCHR | S_IRUGO | S_IWUGO,
 				&st_fops, NULL);
 	}
-	disk->number = devfs_register_tape(SDp->de);
+	disk->number = devfs_register_tape(SDp->devfs_name);
 
 	printk(KERN_WARNING
 	"Attached scsi tape %s at scsi%d, channel %d, id %d, lun %d\n",
@@ -3939,10 +3942,8 @@
 			write_unlock(&st_dev_arr_lock);
 			devfs_unregister_tape(tpnt->disk->number);
 			for (mode = 0; mode < ST_NBR_MODES; ++mode) {
-				devfs_unregister (tpnt->de_r[mode]);
-				tpnt->de_r[mode] = NULL;
-				devfs_unregister (tpnt->de_n[mode]);
-				tpnt->de_n[mode] = NULL;
+				devfs_remove("%s/mt%s", SDp->devfs_name, st_formats[mode]);
+				devfs_remove("%s/mt%sn", SDp->devfs_name, st_formats[mode]);
 				device_remove_file(&tpnt->driverfs_dev_r[mode],
 						   &dev_attr_type);
 				device_remove_file(&tpnt->driverfs_dev_r[mode],
diff -urN linux-2.5.67-bk9/drivers/scsi/st.h linux-2.5.67-bk10/drivers/scsi/st.h
--- linux-2.5.67-bk9/drivers/scsi/st.h	2003-04-19 04:35:30.000000000 -0700
+++ linux-2.5.67-bk10/drivers/scsi/st.h	2003-04-19 04:35:40.000000000 -0700
@@ -5,7 +5,6 @@
 #ifndef _SCSI_H
 #include "scsi.h"
 #endif
-#include <linux/devfs_fs_kernel.h>
 #include <linux/completion.h>
 
 /* The tape buffer descriptor. */
@@ -104,8 +103,6 @@
 	/* Mode characteristics */
 	ST_mode modes[ST_NBR_MODES];
 	int current_mode;
-	devfs_handle_t de_r[ST_NBR_MODES];  /*  Rewind entries     */
-	devfs_handle_t de_n[ST_NBR_MODES];  /*  No-rewind entries  */
 	struct device driverfs_dev_r[ST_NBR_MODES];
 	struct device driverfs_dev_n[ST_NBR_MODES];
 
diff -urN linux-2.5.67-bk9/fs/devfs/base.c linux-2.5.67-bk10/fs/devfs/base.c
--- linux-2.5.67-bk9/fs/devfs/base.c	2003-04-19 04:35:31.000000000 -0700
+++ linux-2.5.67-bk10/fs/devfs/base.c	2003-04-19 04:35:41.000000000 -0700
@@ -1377,7 +1377,6 @@
  *	@uid: The user ID.
  *	@gid: The group ID.
  *	@fs_info: The filesystem info.
- *	@atomic: If TRUE, an atomic allocation is required.
  *
  *	Returns %TRUE if an event was queued and devfsd woken up, else %FALSE.
  */
@@ -1423,7 +1422,7 @@
 static void devfsd_notify (struct devfs_entry *de,unsigned short type)
 {
 	devfsd_notify_de(de, type, de->mode, current->euid,
-			 current->egid, &fs_info, 0);
+			 current->egid, &fs_info);
 } 
 
 
@@ -1456,8 +1455,8 @@
     dev_t devnum = 0, dev = MKDEV(major, minor);
     struct devfs_entry *de;
 
-    if (flags)
-	printk(KERN_ERR "%s called with flags != 0, please fix!\n");
+    /* we don't accept any flags anymore.  prototype will change soon. */
+    WARN_ON(flags);
 
     if (name == NULL)
     {
@@ -1748,7 +1747,7 @@
  *	else a negative error code.
  */
 
-int devfs_generate_path (devfs_handle_t de, char *path, int buflen)
+static int devfs_generate_path (devfs_handle_t de, char *path, int buflen)
 {
     int pos;
 #define NAMEOF(de) ( (de)->mode ? (de)->name : (de)->u.name )
@@ -1868,7 +1867,6 @@
 EXPORT_SYMBOL(devfs_mk_symlink);
 EXPORT_SYMBOL(devfs_mk_dir);
 EXPORT_SYMBOL(devfs_remove);
-EXPORT_SYMBOL(devfs_generate_path);
 
 
 /**
diff -urN linux-2.5.67-bk9/fs/devfs/util.c linux-2.5.67-bk10/fs/devfs/util.c
--- linux-2.5.67-bk9/fs/devfs/util.c	2003-04-07 10:31:42.000000000 -0700
+++ linux-2.5.67-bk10/fs/devfs/util.c	2003-04-19 04:35:41.000000000 -0700
@@ -77,28 +77,18 @@
 #define PRINTK(format, args...) \
    {printk (KERN_ERR "%s" format, __FUNCTION__ , ## args);}
 
+int devfs_register_tape(const char *name)
+{
+	char tname[32], dest[64];
+	static unsigned int tape_counter;
+	unsigned int n = tape_counter++;
 
-/*  Private functions follow  */
-
-/**
- *	devfs_register_tape - Register a tape device in the "/dev/tapes" hierarchy.
- *	@de: Any tape device entry in the device directory.
- */
+	sprintf(dest, "../%s", name);
+	sprintf(tname, "tapes/tape%u", n);
+	devfs_mk_symlink(tname, dest);
 
-int devfs_register_tape (devfs_handle_t de)
-{
-    int pos;
-    char name[32], dest[64];
-    static unsigned int tape_counter;
-    int n = tape_counter++;
-
-    pos = devfs_generate_path (de, dest + 3, sizeof dest - 3);
-    if (pos < 0) return -1;
-    strncpy (dest + pos, "../", 3);
-    sprintf (name, "tapes/tape%u", n);
-    devfs_mk_symlink (name, dest + pos);
-    return n;
-}   /*  End Function devfs_register_tape  */
+	return n;
+}
 EXPORT_SYMBOL(devfs_register_tape);
 
 void devfs_unregister_tape(int num)
@@ -356,78 +346,71 @@
 static struct unique_numspace disc_numspace = UNIQUE_NUMBERSPACE_INITIALISER;
 static struct unique_numspace cdrom_numspace = UNIQUE_NUMBERSPACE_INITIALISER;
 
-void devfs_create_partitions(struct gendisk *dev)
+void devfs_create_partitions(struct gendisk *disk)
 {
-	int pos = 0;
-	devfs_handle_t dir;
-	char dirname[64], symlink[16];
-
-	if (dev->flags & GENHD_FL_DEVFS) {
-		dir = dev->de;
-		if (!dir)  /*  Aware driver wants to block disc management  */
-			return;
-		pos = devfs_generate_path(dir, dirname + 3, sizeof dirname-3);
-		if (pos < 0)
-			return;
-		strncpy(dirname + pos, "../", 3);
-	} else {
-		/*  Unaware driver: construct "real" directory  */
-		sprintf(dirname, "../%s/disc%d", dev->disk_name,
-			dev->first_minor >> dev->minor_shift);
-		dir = devfs_mk_dir(dirname + 3);
-		dev->de = dir;
-	}
-	dev->number = devfs_alloc_unique_number (&disc_numspace);
-	sprintf(symlink, "discs/disc%d", dev->number);
-	devfs_mk_symlink(symlink, dirname + pos);
-	dev->disk_de = devfs_register(dir, "disc", 0,
-			    dev->major, dev->first_minor,
-			    S_IFBLK | S_IRUSR | S_IWUSR, dev->fops, NULL);
+	char dirname[64], diskname[64], symlink[16];
+
+	if (!disk->devfs_name)
+		sprintf(disk->devfs_name, "%s/disc%d", disk->disk_name,
+				disk->first_minor >> disk->minor_shift);
+
+	devfs_mk_dir(disk->devfs_name);
+	disk->number = devfs_alloc_unique_number(&disc_numspace);
+
+	sprintf(diskname, "%s/disc", disk->devfs_name);
+	devfs_register(NULL, diskname, 0,
+			disk->major, disk->first_minor,
+			S_IFBLK | S_IRUSR | S_IWUSR,
+			disk->fops, NULL);
+
+	sprintf(symlink, "discs/disc%d", disk->number);
+	sprintf(dirname, "../%s", disk->devfs_name);
+	devfs_mk_symlink(symlink, dirname);
+
 }
 
-void devfs_create_cdrom(struct gendisk *dev)
+void devfs_create_cdrom(struct gendisk *disk)
 {
-	char vname[23];
+	char dirname[64], cdname[64], symlink[16];
 
-	dev->number = devfs_alloc_unique_number(&cdrom_numspace);
-	sprintf(vname, "cdroms/cdrom%d", dev->number);
-	if (dev->de) {
-		int pos;
-		char rname[64];
-
-		dev->disk_de = devfs_register(dev->de, "cd", DEVFS_FL_DEFAULT,
-				     dev->major, dev->first_minor,
-				     S_IFBLK | S_IRUGO | S_IWUGO,
-				     dev->fops, NULL);
-
-		pos = devfs_generate_path(dev->disk_de, rname+3, sizeof(rname)-3);
-		if (pos >= 0) {
-			strncpy(rname + pos, "../", 3);
-			devfs_mk_symlink(vname, rname + pos);
-		}
-	} else {
-		dev->disk_de = devfs_register (NULL, vname, DEVFS_FL_DEFAULT,
-				    dev->major, dev->first_minor,
-				    S_IFBLK | S_IRUGO | S_IWUGO,
-				    dev->fops, NULL);
-	}
+	if (!disk->devfs_name)
+		strcat(disk->devfs_name, disk->disk_name);
+
+	devfs_mk_dir(disk->devfs_name);
+	disk->number = devfs_alloc_unique_number(&cdrom_numspace);
+
+	sprintf(cdname, "%s/cd", disk->devfs_name);
+	devfs_register(NULL, cdname, 0,
+			disk->major, disk->first_minor,
+			S_IFBLK | S_IRUGO | S_IWUGO,
+			disk->fops, NULL);
+
+	sprintf(symlink, "cdroms/cdrom%d", disk->number);
+	sprintf(dirname, "../%s", disk->devfs_name);
+	devfs_mk_symlink(symlink, dirname);
 }
 
-void devfs_remove_partitions(struct gendisk *dev)
+void devfs_register_partition(struct gendisk *dev, int part)
 {
-	devfs_unregister(dev->disk_de);
-	dev->disk_de = NULL;
+	char devname[64];
 
-	if (dev->flags & GENHD_FL_CD) {
-		if (dev->de)
-			devfs_remove("cdroms/cdrom%d", dev->number);
-		devfs_dealloc_unique_number(&cdrom_numspace, dev->number);
-	} else {
-		devfs_remove("discs/disc%d", dev->number);
-		if (!(dev->flags & GENHD_FL_DEVFS)) {
-			devfs_unregister(dev->de);
-			dev->de = NULL;
-		}
-		devfs_dealloc_unique_number(&disc_numspace, dev->number);
-	}
+	sprintf(devname, "%s/part%d", dev->devfs_name, part);
+	devfs_register(NULL, devname, 0,
+			dev->major, dev->first_minor + part,
+			S_IFBLK | S_IRUSR | S_IWUSR,
+			dev->fops, NULL);
+}
+
+void devfs_remove_partitions(struct gendisk *disk)
+{
+	devfs_remove("discs/disc%d", disk->number);
+	devfs_remove(disk->devfs_name);
+	devfs_dealloc_unique_number(&disc_numspace, disk->number);
+}
+
+void devfs_remove_cdrom(struct gendisk *disk)
+{
+	devfs_remove("cdroms/cdrom%d", disk->number);
+	devfs_remove(disk->devfs_name);
+	devfs_dealloc_unique_number(&cdrom_numspace, disk->number);
 }
diff -urN linux-2.5.67-bk9/fs/partitions/check.c linux-2.5.67-bk10/fs/partitions/check.c
--- linux-2.5.67-bk9/fs/partitions/check.c	2003-04-19 04:35:31.000000000 -0700
+++ linux-2.5.67-bk10/fs/partitions/check.c	2003-04-19 04:35:41.000000000 -0700
@@ -94,25 +94,26 @@
 
 char *disk_name(struct gendisk *hd, int part, char *buf)
 {
-	int pos;
 	if (!part) {
-		if (hd->disk_de) {
-			pos = devfs_generate_path(hd->disk_de, buf, 64);
-			if (pos >= 0)
-				return buf + pos;
-		}
-		sprintf(buf, "%s", hd->disk_name);
+#ifdef CONFIG_DEVFS_FS
+		if (hd->devfs_name)
+			sprintf(buf, "%s/%s", hd->devfs_name,
+				(hd->flags & GENHD_FL_CD) ? "cd" : "disc");
+		else
+#endif
+			sprintf(buf, "%s", hd->disk_name);
 	} else {
-		if (hd->part[part-1].de) {
-			pos = devfs_generate_path(hd->part[part-1].de, buf, 64);
-			if (pos >= 0)
-				return buf + pos;
-		}
+#ifdef CONFIG_DEVFS_FS
+		if (hd->devfs_name)
+			sprintf(buf, "%s/part%d", hd->devfs_name, part);
+		else
+#endif
 		if (isdigit(hd->disk_name[strlen(hd->disk_name)-1]))
 			sprintf(buf, "%sp%d", hd->disk_name, part);
 		else
 			sprintf(buf, "%s%d", hd->disk_name, part);
 	}
+
 	return buf;
 }
 
@@ -120,21 +121,19 @@
 check_partition(struct gendisk *hd, struct block_device *bdev)
 {
 	struct parsed_partitions *state;
-	devfs_handle_t de = NULL;
-	char buf[64];
 	int i, res;
 
 	state = kmalloc(sizeof(struct parsed_partitions), GFP_KERNEL);
 	if (!state)
 		return NULL;
 
-	if (hd->flags & GENHD_FL_DEVFS)
-		de = hd->de;
-	i = devfs_generate_path (de, buf, sizeof buf);
-	if (i >= 0) {
-		printk(KERN_INFO " /dev/%s:", buf + i);
+#ifdef CONFIG_DEVFS_FS
+	if (hd->devfs_name) {
+		printk(KERN_INFO " /dev/%s:", hd->devfs_name);
 		sprintf(state->name, "p");
-	} else {
+	}
+#endif
+	else {
 		disk_name(hd, 0, state->name);
 		printk(KERN_INFO " %s:", state->name);
 		if (isdigit(state->name[strlen(state->name)-1]))
@@ -156,26 +155,6 @@
 	return NULL;
 }
 
-static void devfs_register_partition(struct gendisk *dev, int part)
-{
-#ifdef CONFIG_DEVFS_FS
-	devfs_handle_t dir;
-	struct hd_struct *p = dev->part;
-	char devname[16];
-
-	if (p[part-1].de)
-		return;
-	dir = dev->de;
-	if (!dir)
-		return;
-	sprintf(devname, "part%d", part);
-	p[part-1].de = devfs_register (dir, devname, 0,
-				    dev->major, dev->first_minor + part,
-				    S_IFBLK | S_IRUSR | S_IWUSR,
-				    dev->fops, NULL);
-#endif
-}
-
 /*
  * sysfs bindings for partitions
  */
@@ -261,8 +240,7 @@
 	p->start_sect = 0;
 	p->nr_sects = 0;
 	p->reads = p->writes = p->read_sectors = p->write_sectors = 0;
-	devfs_unregister(p->de);
-	p->de = NULL;
+	devfs_remove("%s/part%d", disk->devfs_name, part);
 	kobject_unregister(&p->kobj);
 }
 
@@ -414,7 +392,10 @@
 	unlink_gendisk(disk);
 	disk_stat_set_all(disk, 0);
 	disk->stamp = disk->stamp_idle = 0;
-	devfs_remove_partitions(disk);
+	if (disk->flags & GENHD_FL_CD)
+		devfs_remove_cdrom(disk);
+	else
+		devfs_remove_partitions(disk);
 	if (disk->driverfs_dev) {
 		sysfs_remove_link(&disk->kobj, "device");
 		sysfs_remove_link(&disk->driverfs_dev->kobj, "block");
diff -urN linux-2.5.67-bk9/include/asm-alpha/posix_types.h linux-2.5.67-bk10/include/asm-alpha/posix_types.h
--- linux-2.5.67-bk9/include/asm-alpha/posix_types.h	2003-04-07 10:32:13.000000000 -0700
+++ linux-2.5.67-bk10/include/asm-alpha/posix_types.h	2003-04-19 04:35:41.000000000 -0700
@@ -40,6 +40,8 @@
 typedef __kernel_uid_t __kernel_uid32_t;
 typedef __kernel_gid_t __kernel_gid32_t;
 
+typedef unsigned int	__kernel_old_dev_t;
+
 #ifdef __KERNEL__
 
 #ifndef __GNUC__
diff -urN linux-2.5.67-bk9/include/asm-arm/posix_types.h linux-2.5.67-bk10/include/asm-arm/posix_types.h
--- linux-2.5.67-bk9/include/asm-arm/posix_types.h	2003-04-07 10:30:39.000000000 -0700
+++ linux-2.5.67-bk10/include/asm-arm/posix_types.h	2003-04-19 04:35:41.000000000 -0700
@@ -45,6 +45,7 @@
 
 typedef unsigned short		__kernel_old_uid_t;
 typedef unsigned short		__kernel_old_gid_t;
+typedef unsigned short		__kernel_old_dev_t;
 
 #ifdef __GNUC__
 typedef long long		__kernel_loff_t;
diff -urN linux-2.5.67-bk9/include/asm-cris/posix_types.h linux-2.5.67-bk10/include/asm-cris/posix_types.h
--- linux-2.5.67-bk9/include/asm-cris/posix_types.h	2003-04-07 10:30:46.000000000 -0700
+++ linux-2.5.67-bk10/include/asm-cris/posix_types.h	2003-04-19 04:35:41.000000000 -0700
@@ -38,6 +38,7 @@
 
 typedef unsigned short  __kernel_old_uid_t;
 typedef unsigned short  __kernel_old_gid_t;
+typedef unsigned short	__kernel_old_dev_t;
 
 #ifdef __GNUC__
 typedef long long	__kernel_loff_t;
diff -urN linux-2.5.67-bk9/include/asm-i386/posix_types.h linux-2.5.67-bk10/include/asm-i386/posix_types.h
--- linux-2.5.67-bk9/include/asm-i386/posix_types.h	2003-04-07 10:32:51.000000000 -0700
+++ linux-2.5.67-bk10/include/asm-i386/posix_types.h	2003-04-19 04:35:41.000000000 -0700
@@ -33,6 +33,7 @@
 
 typedef unsigned short	__kernel_old_uid_t;
 typedef unsigned short	__kernel_old_gid_t;
+typedef unsigned short	__kernel_old_dev_t;
 
 #ifdef __GNUC__
 typedef long long	__kernel_loff_t;
diff -urN linux-2.5.67-bk9/include/asm-ia64/posix_types.h linux-2.5.67-bk10/include/asm-ia64/posix_types.h
--- linux-2.5.67-bk9/include/asm-ia64/posix_types.h	2003-04-07 10:31:00.000000000 -0700
+++ linux-2.5.67-bk10/include/asm-ia64/posix_types.h	2003-04-19 04:35:42.000000000 -0700
@@ -43,6 +43,8 @@
 typedef __kernel_uid_t __kernel_uid32_t;
 typedef __kernel_gid_t __kernel_gid32_t;
 
+typedef unsigned int	__kernel_old_dev_t;
+
 # ifdef __KERNEL__
 
 #  ifndef __GNUC__
diff -urN linux-2.5.67-bk9/include/asm-m68k/posix_types.h linux-2.5.67-bk10/include/asm-m68k/posix_types.h
--- linux-2.5.67-bk9/include/asm-m68k/posix_types.h	2003-04-07 10:30:42.000000000 -0700
+++ linux-2.5.67-bk10/include/asm-m68k/posix_types.h	2003-04-19 04:35:42.000000000 -0700
@@ -33,6 +33,7 @@
 
 typedef unsigned short	__kernel_old_uid_t;
 typedef unsigned short	__kernel_old_gid_t;
+typedef unsigned short	__kernel_old_dev_t;
 
 #ifdef __GNUC__
 typedef long long	__kernel_loff_t;
diff -urN linux-2.5.67-bk9/include/asm-mips/posix_types.h linux-2.5.67-bk10/include/asm-mips/posix_types.h
--- linux-2.5.67-bk9/include/asm-mips/posix_types.h	2003-04-07 10:31:52.000000000 -0700
+++ linux-2.5.67-bk10/include/asm-mips/posix_types.h	2003-04-19 04:35:42.000000000 -0700
@@ -39,6 +39,7 @@
 typedef int		__kernel_gid32_t;
 typedef __kernel_uid_t	__kernel_old_uid_t;
 typedef __kernel_gid_t	__kernel_old_gid_t;
+typedef unsigned int	__kernel_old_dev_t;
 
 #ifdef __GNUC__
 typedef long long      __kernel_loff_t;
diff -urN linux-2.5.67-bk9/include/asm-mips64/posix_types.h linux-2.5.67-bk10/include/asm-mips64/posix_types.h
--- linux-2.5.67-bk9/include/asm-mips64/posix_types.h	2003-04-07 10:30:58.000000000 -0700
+++ linux-2.5.67-bk10/include/asm-mips64/posix_types.h	2003-04-19 04:35:42.000000000 -0700
@@ -39,6 +39,7 @@
 typedef int		__kernel_gid32_t;
 typedef __kernel_uid_t	__kernel_old_uid_t;
 typedef __kernel_gid_t	__kernel_old_gid_t;
+typedef unsigned int	__kernel_old_dev_t;
 
 #ifdef __GNUC__
 typedef long long      __kernel_loff_t;
diff -urN linux-2.5.67-bk9/include/asm-parisc/posix_types.h linux-2.5.67-bk10/include/asm-parisc/posix_types.h
--- linux-2.5.67-bk9/include/asm-parisc/posix_types.h	2003-04-07 10:32:27.000000000 -0700
+++ linux-2.5.67-bk10/include/asm-parisc/posix_types.h	2003-04-19 04:35:42.000000000 -0700
@@ -45,6 +45,8 @@
 typedef unsigned long long	__kernel_ino64_t;
 #endif
 
+typedef unsigned int		__kernel_old_dev_t;
+
 typedef struct {
 #if defined(__KERNEL__) || defined(__USE_ALL)
 	int	val[2];
diff -urN linux-2.5.67-bk9/include/asm-ppc/posix_types.h linux-2.5.67-bk10/include/asm-ppc/posix_types.h
--- linux-2.5.67-bk9/include/asm-ppc/posix_types.h	2003-04-07 10:31:10.000000000 -0700
+++ linux-2.5.67-bk10/include/asm-ppc/posix_types.h	2003-04-19 04:35:42.000000000 -0700
@@ -33,6 +33,7 @@
 
 typedef unsigned int	__kernel_old_uid_t;
 typedef unsigned int	__kernel_old_gid_t;
+typedef unsigned int	__kernel_old_dev_t;
 
 #ifdef __GNUC__
 typedef long long	__kernel_loff_t;
diff -urN linux-2.5.67-bk9/include/asm-ppc64/posix_types.h linux-2.5.67-bk10/include/asm-ppc64/posix_types.h
--- linux-2.5.67-bk9/include/asm-ppc64/posix_types.h	2003-04-07 10:33:03.000000000 -0700
+++ linux-2.5.67-bk10/include/asm-ppc64/posix_types.h	2003-04-19 04:35:42.000000000 -0700
@@ -39,6 +39,7 @@
 
 typedef unsigned int	__kernel_old_uid_t;
 typedef unsigned int	__kernel_old_gid_t;
+typedef unsigned long	__kernel_old_dev_t;
 
 typedef struct {
 	int	val[2];
diff -urN linux-2.5.67-bk9/include/asm-s390/posix_types.h linux-2.5.67-bk10/include/asm-s390/posix_types.h
--- linux-2.5.67-bk9/include/asm-s390/posix_types.h	2003-04-19 04:35:31.000000000 -0700
+++ linux-2.5.67-bk10/include/asm-s390/posix_types.h	2003-04-19 04:35:42.000000000 -0700
@@ -47,6 +47,7 @@
 typedef unsigned int	__kernel_gid32_t;
 typedef unsigned short	__kernel_old_uid_t;
 typedef unsigned short	__kernel_old_gid_t;
+typedef unsigned short	__kernel_old_dev_t;
 
 #else /* __s390x__ */
 
diff -urN linux-2.5.67-bk9/include/asm-sh/posix_types.h linux-2.5.67-bk10/include/asm-sh/posix_types.h
--- linux-2.5.67-bk9/include/asm-sh/posix_types.h	2003-04-07 10:31:13.000000000 -0700
+++ linux-2.5.67-bk10/include/asm-sh/posix_types.h	2003-04-19 04:35:42.000000000 -0700
@@ -31,6 +31,7 @@
 
 typedef unsigned short	__kernel_old_uid_t;
 typedef unsigned short	__kernel_old_gid_t;
+typedef unsigned short	__kernel_old_dev_t;
 
 #ifdef __GNUC__
 typedef long long	__kernel_loff_t;
diff -urN linux-2.5.67-bk9/include/asm-sparc/posix_types.h linux-2.5.67-bk10/include/asm-sparc/posix_types.h
--- linux-2.5.67-bk9/include/asm-sparc/posix_types.h	2003-04-07 10:31:00.000000000 -0700
+++ linux-2.5.67-bk10/include/asm-sparc/posix_types.h	2003-04-19 04:35:42.000000000 -0700
@@ -31,6 +31,7 @@
 typedef unsigned int	       __kernel_gid32_t;
 typedef unsigned short	       __kernel_old_uid_t;
 typedef unsigned short	       __kernel_old_gid_t;
+typedef unsigned short	       __kernel_old_dev_t;
 typedef int                    __kernel_clockid_t;
 typedef int                    __kernel_timer_t;
 
diff -urN linux-2.5.67-bk9/include/asm-sparc64/posix_types.h linux-2.5.67-bk10/include/asm-sparc64/posix_types.h
--- linux-2.5.67-bk9/include/asm-sparc64/posix_types.h	2003-04-07 10:32:28.000000000 -0700
+++ linux-2.5.67-bk10/include/asm-sparc64/posix_types.h	2003-04-19 04:35:42.000000000 -0700
@@ -34,6 +34,8 @@
 typedef __kernel_uid_t	       __kernel_uid32_t;
 typedef __kernel_gid_t	       __kernel_gid32_t;
 
+typedef unsigned int	       __kernel_old_dev_t;
+
 /* Note this piece of asymmetry from the v9 ABI.  */
 typedef int		       __kernel_suseconds_t;
 
diff -urN linux-2.5.67-bk9/include/asm-v850/posix_types.h linux-2.5.67-bk10/include/asm-v850/posix_types.h
--- linux-2.5.67-bk9/include/asm-v850/posix_types.h	2003-04-19 04:35:31.000000000 -0700
+++ linux-2.5.67-bk10/include/asm-v850/posix_types.h	2003-04-19 04:35:42.000000000 -0700
@@ -42,7 +42,7 @@
 
 /* Some bogus code depends on this; we don't care.  */
 typedef __kernel_uid_t __kernel_old_uid_t;
-
+typedef unsigned int	__kernel_old_dev_t;
 
 typedef struct {
 #if defined(__KERNEL__) || defined(__USE_ALL)
diff -urN linux-2.5.67-bk9/include/asm-x86_64/posix_types.h linux-2.5.67-bk10/include/asm-x86_64/posix_types.h
--- linux-2.5.67-bk9/include/asm-x86_64/posix_types.h	2003-04-07 10:32:55.000000000 -0700
+++ linux-2.5.67-bk10/include/asm-x86_64/posix_types.h	2003-04-19 04:35:42.000000000 -0700
@@ -22,8 +22,8 @@
 typedef long		__kernel_time_t;
 typedef long		__kernel_suseconds_t;
 typedef long		__kernel_clock_t;
-typedef int            __kernel_timer_t;
-typedef int            __kernel_clockid_t;
+typedef int		__kernel_timer_t;
+typedef int		__kernel_clockid_t;
 typedef int		__kernel_daddr_t;
 typedef char *		__kernel_caddr_t;
 typedef unsigned short	__kernel_uid16_t;
@@ -42,6 +42,8 @@
 typedef __kernel_uid_t __kernel_uid32_t;
 typedef __kernel_gid_t __kernel_gid32_t;
 
+typedef unsigned long	__kernel_old_dev_t;
+
 #ifdef __KERNEL__
 
 #undef __FD_SET
diff -urN linux-2.5.67-bk9/include/linux/devfs_fs_kernel.h linux-2.5.67-bk10/include/linux/devfs_fs_kernel.h
--- linux-2.5.67-bk9/include/linux/devfs_fs_kernel.h	2003-04-19 04:35:31.000000000 -0700
+++ linux-2.5.67-bk10/include/linux/devfs_fs_kernel.h	2003-04-19 04:35:42.000000000 -0700
@@ -31,13 +31,14 @@
 	__attribute__((format (printf, 1, 2)));
 extern void devfs_remove(const char *fmt, ...)
 	__attribute__((format (printf, 1, 2)));
-extern int devfs_generate_path (devfs_handle_t de, char *path, int buflen);
-extern int devfs_register_tape (devfs_handle_t de);
+extern int devfs_register_tape(const char *name);
 extern void devfs_unregister_tape(int num);
 extern void devfs_create_partitions(struct gendisk *dev);
 extern void devfs_create_cdrom(struct gendisk *dev);
 extern void devfs_remove_partitions(struct gendisk *dev);
-extern void mount_devfs_fs (void);
+extern void devfs_remove_cdrom(struct gendisk *dev);
+extern void devfs_register_partition(struct gendisk *dev, int part);
+extern void mount_devfs_fs(void);
 #else  /*  CONFIG_DEVFS_FS  */
 static inline devfs_handle_t devfs_register (devfs_handle_t dir,
 					     const char *name,
@@ -64,11 +65,6 @@
 static inline void devfs_remove(const char *fmt, ...)
 {
 }
-static inline int devfs_generate_path (devfs_handle_t de, char *path,
-				       int buflen)
-{
-    return -ENOSYS;
-}
 static inline int devfs_register_tape (devfs_handle_t de)
 {
     return -1;
@@ -85,6 +81,12 @@
 static inline void devfs_remove_partitions(struct gendisk *dev)
 {
 }
+static inline void devfs_remove_cdrom(struct gendisk *dev)
+{
+}
+static inline void devfs_register_partition(struct gendisk *dev, int part)
+{
+}
 static inline void mount_devfs_fs (void)
 {
     return;
diff -urN linux-2.5.67-bk9/include/linux/genhd.h linux-2.5.67-bk10/include/linux/genhd.h
--- linux-2.5.67-bk9/include/linux/genhd.h	2003-04-07 10:30:43.000000000 -0700
+++ linux-2.5.67-bk10/include/linux/genhd.h	2003-04-19 04:35:42.000000000 -0700
@@ -55,12 +55,13 @@
 } __attribute__((packed));
 
 #ifdef __KERNEL__
-#  include <linux/devfs_fs_kernel.h>
-
+#include <linux/devfs_fs_kernel.h>	/* we don't need any devfs crap
+					   here, but some of the implicitly
+					   included headers.   will clean
+					   this mess up later.	--hch */
 struct hd_struct {
 	sector_t start_sect;
 	sector_t nr_sects;
-	devfs_handle_t de;              /* primary (master) devfs entry  */
 	struct kobject kobj;
 	unsigned reads, read_sectors, writes, write_sectors;
 	int policy;
@@ -68,7 +69,6 @@
 
 #define GENHD_FL_REMOVABLE  1
 #define GENHD_FL_DRIVERFS  2
-#define GENHD_FL_DEVFS	4
 #define GENHD_FL_CD	8
 #define GENHD_FL_UP	16
 
@@ -96,9 +96,8 @@
 	sector_t capacity;
 
 	int flags;
-	int number;			/* devfs crap */
-	devfs_handle_t de;		/* more of the same */
-	devfs_handle_t disk_de;		/* piled higher and deeper */
+	char devfs_name[64];		/* devfs crap */
+	int number;			/* more of the same */
 	struct device *driverfs_dev;
 	struct kobject kobj;
 
diff -urN linux-2.5.67-bk9/include/linux/ide.h linux-2.5.67-bk10/include/linux/ide.h
--- linux-2.5.67-bk9/include/linux/ide.h	2003-04-07 10:31:04.000000000 -0700
+++ linux-2.5.67-bk10/include/linux/ide.h	2003-04-19 04:35:42.000000000 -0700
@@ -13,7 +13,6 @@
 #include <linux/hdsmart.h>
 #include <linux/blkdev.h>
 #include <linux/proc_fs.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/interrupt.h>
 #include <linux/bitops.h>
 #include <linux/bio.h>
@@ -699,7 +698,7 @@
 	struct hd_driveid	*id;	/* drive model identification info */
 	struct proc_dir_entry *proc;	/* /proc/ide/ directory entry */
 	struct ide_settings_s *settings;/* /proc/ide/ drive settings */
-	devfs_handle_t		de;	/* directory for device */
+	char		devfs_name[64];	/* devfs crap */
 
 	struct hwif_s		*hwif;	/* actually (ide_hwif_t *) */
 
diff -urN linux-2.5.67-bk9/include/linux/if.h linux-2.5.67-bk10/include/linux/if.h
--- linux-2.5.67-bk9/include/linux/if.h	2003-04-07 10:31:14.000000000 -0700
+++ linux-2.5.67-bk10/include/linux/if.h	2003-04-19 04:35:42.000000000 -0700
@@ -50,7 +50,7 @@
 
 /* Private (from user) interface flags (netdevice->priv_flags). */
 #define IFF_802_1Q_VLAN 0x1             /* 802.1Q VLAN device.          */
-
+#define IFF_EBRIDGE	0x2		/* Ethernet bridging device.	*/
 
 #define IF_GET_IFACE	0x0001		/* for querying only */
 #define IF_GET_PROTO	0x0002
diff -urN linux-2.5.67-bk9/include/linux/if_vlan.h linux-2.5.67-bk10/include/linux/if_vlan.h
--- linux-2.5.67-bk9/include/linux/if_vlan.h	2003-04-07 10:30:44.000000000 -0700
+++ linux-2.5.67-bk10/include/linux/if_vlan.h	2003-04-19 04:35:42.000000000 -0700
@@ -54,8 +54,8 @@
 
 #define VLAN_VID_MASK	0xfff
 
-/* found in af_inet.c */
-extern int (*vlan_ioctl_hook)(unsigned long arg);
+/* found in socket.c */
+extern void vlan_ioctl_set(int (*hook)(unsigned long));
 
 #define VLAN_NAME "vlan"
 
diff -urN linux-2.5.67-bk9/include/linux/loop.h linux-2.5.67-bk10/include/linux/loop.h
--- linux-2.5.67-bk9/include/linux/loop.h	2003-04-07 10:33:02.000000000 -0700
+++ linux-2.5.67-bk10/include/linux/loop.h	2003-04-19 04:35:42.000000000 -0700
@@ -1,8 +1,6 @@
 #ifndef _LINUX_LOOP_H
 #define _LINUX_LOOP_H
 
-#include <linux/kdev_t.h>
-
 /*
  * include/linux/loop.h
  *
@@ -74,34 +72,37 @@
 #define LO_FLAGS_READ_ONLY	2
 #define LO_FLAGS_BH_REMAP	4
 
-/* 
- * Note that this structure gets the wrong offsets when directly used
- * from a glibc program, because glibc has a 32bit dev_t.
- * Prevent people from shooting in their own foot.  
- */
-#if __GLIBC__ >= 2 && !defined(dev_t)
-#error "Wrong dev_t in loop.h"
-#endif 
-
-/*
- *	This uses kdev_t because glibc currently has no appropiate
- *	conversion version for the loop ioctls. 
- * 	The situation is very unpleasant	
- */
+#include <asm/posix_types.h>	/* for __kernel_old_dev_t */
+#include <asm/types.h>		/* for __u64 */
 
+/* Backwards compatibility version */
 struct loop_info {
-	int		lo_number;	/* ioctl r/o */
-	dev_t		lo_device; 	/* ioctl r/o */
-	unsigned long	lo_inode; 	/* ioctl r/o */
-	dev_t		lo_rdevice; 	/* ioctl r/o */
-	int		lo_offset;
-	int		lo_encrypt_type;
-	int		lo_encrypt_key_size; 	/* ioctl w/o */
-	int		lo_flags;	/* ioctl r/o */
-	char		lo_name[LO_NAME_SIZE];
-	unsigned char	lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
-	unsigned long	lo_init[2];
-	char		reserved[4];
+	int		   lo_number;		/* ioctl r/o */
+	__kernel_old_dev_t lo_device; 		/* ioctl r/o */
+	unsigned long	   lo_inode; 		/* ioctl r/o */
+	__kernel_old_dev_t lo_rdevice; 		/* ioctl r/o */
+	int		   lo_offset;
+	int		   lo_encrypt_type;
+	int		   lo_encrypt_key_size; 	/* ioctl w/o */
+	int		   lo_flags;			/* ioctl r/o */
+	char		   lo_name[LO_NAME_SIZE];
+	unsigned char	   lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
+	unsigned long	   lo_init[2];
+	char		   reserved[4];
+};
+
+struct loop_info64 {
+	__u64		   lo_device; 		/* ioctl r/o */
+	__u64		   lo_inode; 		/* ioctl r/o */
+	__u64		   lo_rdevice; 		/* ioctl r/o */
+	__u64		   lo_offset;
+	__u32		   lo_number;		/* ioctl r/o */
+	__u32		   lo_encrypt_type;
+	__u32		   lo_encrypt_key_size; 	/* ioctl w/o */
+	__u32		   lo_flags;			/* ioctl r/o */
+	__u8		   lo_name[LO_NAME_SIZE];
+	__u8		   lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
+	__u64		   lo_init[2];
 };
 
 /*
@@ -125,7 +126,7 @@
 	int number; 	/* filter type */ 
 	int (*transfer)(struct loop_device *lo, int cmd, char *raw_buf,
 			char *loop_buf, int size, sector_t real_block);
-	int (*init)(struct loop_device *, struct loop_info *); 
+	int (*init)(struct loop_device *, const struct loop_info64 *); 
 	/* release is called from loop_unregister_transfer or clr_fd */
 	int (*release)(struct loop_device *); 
 	int (*ioctl)(struct loop_device *, int cmd, unsigned long arg);
@@ -134,7 +135,7 @@
 	void (*unlock)(struct loop_device *);
 }; 
 
-int  loop_register_transfer(struct loop_func_table *funcs);
+int loop_register_transfer(struct loop_func_table *funcs);
 int loop_unregister_transfer(int number); 
 
 #endif
@@ -142,9 +143,11 @@
  * IOCTL commands --- we will commandeer 0x4C ('L')
  */
 
-#define LOOP_SET_FD	0x4C00
-#define LOOP_CLR_FD	0x4C01
-#define LOOP_SET_STATUS	0x4C02
-#define LOOP_GET_STATUS	0x4C03
+#define LOOP_SET_FD		0x4C00
+#define LOOP_CLR_FD		0x4C01
+#define LOOP_SET_STATUS		0x4C02
+#define LOOP_GET_STATUS		0x4C03
+#define LOOP_SET_STATUS64	0x4C04
+#define LOOP_GET_STATUS64	0x4C05
 
 #endif
diff -urN linux-2.5.67-bk9/include/net/dn.h linux-2.5.67-bk10/include/net/dn.h
--- linux-2.5.67-bk9/include/net/dn.h	2003-04-07 10:31:56.000000000 -0700
+++ linux-2.5.67-bk10/include/net/dn.h	2003-04-19 04:35:42.000000000 -0700
@@ -171,17 +171,17 @@
 	int iif;
 };
 
-static __inline__ dn_address dn_eth2dn(unsigned char *ethaddr)
+static inline dn_address dn_eth2dn(unsigned char *ethaddr)
 {
 	return ethaddr[4] | (ethaddr[5] << 8);
 }
 
-static __inline__ dn_address dn_saddr2dn(struct sockaddr_dn *saddr)
+static inline dn_address dn_saddr2dn(struct sockaddr_dn *saddr)
 {
 	return *(dn_address *)saddr->sdn_nodeaddr;
 }
 
-static __inline__ void dn_dn2eth(unsigned char *ethaddr, dn_address addr)
+static inline void dn_dn2eth(unsigned char *ethaddr, dn_address addr)
 {
 	ethaddr[0] = 0xAA;
 	ethaddr[1] = 0x00;
@@ -191,6 +191,19 @@
 	ethaddr[5] = (unsigned char)(addr >> 8);
 }
 
+static inline void dn_sk_ports_copy(struct flowi *fl, struct dn_scp *scp)
+{
+	fl->uli_u.dnports.sport = scp->addrloc;
+	fl->uli_u.dnports.dport = scp->addrrem;
+	fl->uli_u.dnports.objnum = scp->addr.sdn_objnum;
+	if (fl->uli_u.dnports.objnum == 0) {
+		fl->uli_u.dnports.objnamel = scp->addr.sdn_objnamel;
+		memcpy(fl->uli_u.dnports.objname, scp->addr.sdn_objname, 16);
+	}
+}
+
+extern unsigned dn_mss_from_pmtu(struct net_device *dev, int mtu);
+
 #define DN_MENUVER_ACC 0x01
 #define DN_MENUVER_USR 0x02
 #define DN_MENUVER_PRX 0x04
diff -urN linux-2.5.67-bk9/include/net/dn_dev.h linux-2.5.67-bk10/include/net/dn_dev.h
--- linux-2.5.67-bk9/include/net/dn_dev.h	2003-04-07 10:30:34.000000000 -0700
+++ linux-2.5.67-bk10/include/net/dn_dev.h	2003-04-19 04:35:42.000000000 -0700
@@ -8,6 +8,7 @@
 	struct dn_ifaddr *ifa_next;
 	struct dn_dev    *ifa_dev;
 	dn_address       ifa_local;
+	dn_address       ifa_address;
 	unsigned char    ifa_flags;
 	unsigned char    ifa_scope;
 	char             ifa_label[IFNAMSIZ];
@@ -171,7 +172,10 @@
 extern struct net_device *dn_dev_get_default(void);
 extern int dn_dev_bind_default(dn_address *addr);
 
-static __inline__ int dn_dev_islocal(struct net_device *dev, dn_address addr)
+extern int register_dnaddr_notifier(struct notifier_block *nb);
+extern int unregister_dnaddr_notifier(struct notifier_block *nb);
+
+static inline int dn_dev_islocal(struct net_device *dev, dn_address addr)
 {
 	struct dn_dev *dn_db = dev->dn_ptr;
 	struct dn_ifaddr *ifa;
diff -urN linux-2.5.67-bk9/include/net/dn_fib.h linux-2.5.67-bk10/include/net/dn_fib.h
--- linux-2.5.67-bk9/include/net/dn_fib.h	2003-04-07 10:31:20.000000000 -0700
+++ linux-2.5.67-bk10/include/net/dn_fib.h	2003-04-19 04:35:42.000000000 -0700
@@ -1,12 +1,6 @@
 #ifndef _NET_DN_FIB_H
 #define _NET_DN_FIB_H
 
-#include <linux/config.h>
-
-#ifdef CONFIG_DECNET_ROUTER
-
-#include <linux/rtnetlink.h>
-
 struct dn_kern_rta
 {
         void            *rta_dst;
@@ -23,15 +17,6 @@
         struct rta_cacheinfo *rta_ci;
 };
 
-struct dn_fib_key {
-	dn_address src;
-	dn_address dst;
-	int iif;
-	int oif;
-	u32 fwmark;
-	unsigned char scope;
-};
-
 struct dn_fib_res {
 	struct dn_fib_rule *r;
 	struct dn_fib_info *fi;
@@ -60,16 +45,23 @@
 	unsigned		fib_flags;
 	int			fib_protocol;
 	dn_address		fib_prefsrc;
-	u32			fib_priority;
+	__u32			fib_priority;
+	__u32			fib_metrics[RTAX_MAX];
+#define dn_fib_mtu  fib_metrics[RTAX_MTU-1]
+#define dn_fib_window fib_metrics[RTAX_WINDOW-1]
+#define dn_fib_rtt fib_metrics[RTAX_RTT-1]
+#define dn_fib_advmss fib_metrics[RTAX_ADVMSS-1]
 	int			fib_nhs;
 	int			fib_power;
 	struct dn_fib_nh	fib_nh[0];
-#define fib_dev		fib_nh[0].nh_dev
+#define dn_fib_dev		fib_nh[0].nh_dev
 };
 
 
-#define DN_FIB_RES_NH(res)	((res).fi->fib_nh[(res).nh_sel])
 #define DN_FIB_RES_RESET(res)	((res).nh_sel = 0)
+#define DN_FIB_RES_NH(res)	((res).fi->fib_nh[(res).nh_sel])
+
+#define DN_FIB_RES_PREFSRC(res)	((res).fi->fib_prefsrc ? : __dn_fib_res_prefsrc(&res))
 #define DN_FIB_RES_GW(res)	(DN_FIB_RES_NH(res).nh_gw)
 #define DN_FIB_RES_DEV(res)	(DN_FIB_RES_NH(res).nh_dev)
 #define DN_FIB_RES_OIF(res)	(DN_FIB_RES_NH(res).nh_oif)
@@ -106,7 +98,7 @@
 	int (*delete)(struct dn_fib_table *t, struct rtmsg *r,
 			struct dn_kern_rta *rta, struct nlmsghdr *n,
 			struct netlink_skb_parms *req);
-	int (*lookup)(struct dn_fib_table *t, const struct dn_fib_key *key, 
+	int (*lookup)(struct dn_fib_table *t, const struct flowi *fl,
 			struct dn_fib_res *res);
 	int (*flush)(struct dn_fib_table *t);
 #ifdef CONFIG_PROC_FS
@@ -118,7 +110,7 @@
 	unsigned char data[0];
 };
 
-
+#ifdef CONFIG_DECNET_ROUTER
 /*
  * dn_fib.c
  */
@@ -132,11 +124,12 @@
 				struct dn_kern_rta *rta, 
 				const struct nlmsghdr *nlh, int *errp);
 extern int dn_fib_semantic_match(int type, struct dn_fib_info *fi, 
-			const struct dn_fib_key *key, struct dn_fib_res *res);
+			const struct flowi *fl,
+			struct dn_fib_res *res);
 extern void dn_fib_release_info(struct dn_fib_info *fi);
 extern u16 dn_fib_get_attr16(struct rtattr *attr, int attrlen, int type);
 extern void dn_fib_flush(void);
-extern void dn_fib_select_multipath(const struct dn_fib_key *key, 
+extern void dn_fib_select_multipath(const struct flowi *fl,
 					struct dn_fib_res *res);
 extern int dn_fib_sync_down(dn_address local, struct net_device *dev, 
 				int force);
@@ -156,7 +149,9 @@
 extern void dn_fib_rules_init(void);
 extern void dn_fib_rules_cleanup(void);
 extern void dn_fib_rule_put(struct dn_fib_rule *);
-extern int dn_fib_lookup(struct dn_fib_key *key, struct dn_fib_res *res);
+extern __u16 dn_fib_rules_policy(__u16 saddr, struct dn_fib_res *res, unsigned *flags);
+extern unsigned dnet_addr_type(__u16 addr);
+extern int dn_fib_lookup(const struct flowi *fl, struct dn_fib_res *res);
 
 /*
  * rtnetlink interface
@@ -169,21 +164,15 @@
 extern int dn_fib_rtm_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
 extern int dn_fib_dump_rules(struct sk_buff *skb, struct netlink_callback *cb);
 
-#define DN_NUM_TABLES 255
-#define DN_MIN_TABLE 1
-#define DN_DEFAULT_TABLE 1
-#define DN_L1_TABLE 1
-#define DN_L2_TABLE 2
-
 extern void dn_fib_free_info(struct dn_fib_info *fi);
 
-static __inline__ void dn_fib_info_put(struct dn_fib_info *fi)
+static inline void dn_fib_info_put(struct dn_fib_info *fi)
 {
 	if (atomic_dec_and_test(&fi->fib_clntref))
 		dn_fib_free_info(fi);
 }
 
-static __inline__ void dn_fib_res_put(struct dn_fib_res *res)
+static inline void dn_fib_res_put(struct dn_fib_res *res)
 {
 	if (res->fi)
 		dn_fib_info_put(res->fi);
@@ -191,13 +180,23 @@
 		dn_fib_rule_put(res->r);
 }
 
-static __inline__ u16 dnet_make_mask(int n)
+extern struct dn_fib_table *dn_fib_tables[];
+
+#else /* Endnode */
+
+#define dn_fib_lookup(fl, res) (-ESRCH)
+#define dn_fib_info_put(fi) do { } while(0)
+#define dn_fib_select_multipath(fl, res) do { } while(0)
+#define dn_fib_rules_policy(saddr,res,flags) (0)
+#define dn_fib_res_put(res) do { } while(0)
+
+#endif /* CONFIG_DECNET_ROUTER */
+
+static inline u16 dnet_make_mask(int n)
 {
         if (n)
                 return htons(~((1<<(16-n))-1));
         return 0;
 }
 
-#endif /* CONFIG_DECNET_ROUTER */
-
 #endif /* _NET_DN_FIB_H */
diff -urN linux-2.5.67-bk9/include/net/dn_neigh.h linux-2.5.67-bk10/include/net/dn_neigh.h
--- linux-2.5.67-bk9/include/net/dn_neigh.h	2003-04-07 10:31:19.000000000 -0700
+++ linux-2.5.67-bk10/include/net/dn_neigh.h	2003-04-19 04:35:42.000000000 -0700
@@ -18,7 +18,7 @@
 
 extern void dn_neigh_init(void);
 extern void dn_neigh_cleanup(void);
-extern struct neighbour *dn_neigh_lookup(struct neigh_table *tbl, void *ptr);
+extern struct neighbour *dn_neigh_lookup(struct neigh_table *tbl, const void *ptr);
 extern int dn_neigh_router_hello(struct sk_buff *skb);
 extern int dn_neigh_endnode_hello(struct sk_buff *skb);
 extern void dn_neigh_pointopoint_hello(struct sk_buff *skb);
diff -urN linux-2.5.67-bk9/include/net/dn_nsp.h linux-2.5.67-bk10/include/net/dn_nsp.h
--- linux-2.5.67-bk9/include/net/dn_nsp.h	2003-04-07 10:32:18.000000000 -0700
+++ linux-2.5.67-bk10/include/net/dn_nsp.h	2003-04-19 04:35:42.000000000 -0700
@@ -204,4 +204,6 @@
         return atomic_read(&sk->rmem_alloc) > (sk->rcvbuf >> 1);
 }
 
+#define DN_MAX_NSP_DATA_HEADER (11)
+
 #endif /* _NET_DN_NSP_H */
diff -urN linux-2.5.67-bk9/include/net/dn_route.h linux-2.5.67-bk10/include/net/dn_route.h
--- linux-2.5.67-bk9/include/net/dn_route.h	2003-04-07 10:30:38.000000000 -0700
+++ linux-2.5.67-bk10/include/net/dn_route.h	2003-04-19 04:35:42.000000000 -0700
@@ -16,7 +16,7 @@
 *******************************************************************************/
 
 extern struct sk_buff *dn_alloc_skb(struct sock *sk, int size, int pri);
-extern int dn_route_output(struct dst_entry **pprt, dn_address dst, dn_address src, int flags);
+extern int dn_route_output_sock(struct dst_entry **pprt, struct flowi *, struct sock *sk, int flags);
 extern int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb);
 extern int dn_cache_getroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
 extern void dn_rt_cache_flush(int delay);
@@ -59,10 +59,10 @@
 #define DN_RT_INFO_BLKR 0x40 /* Blocking Requested            */
 
 /*
- * The key structure is what we used to look up the route.
+ * The fl structure is what we used to look up the route.
  * The rt_saddr & rt_daddr entries are the same as key.saddr & key.daddr
- * except for local input routes, where the rt_saddr = key.daddr and
- * rt_daddr = key.saddr to allow the route to be used for returning
+ * except for local input routes, where the rt_saddr = fl.fld_dst and
+ * rt_daddr = fl.fld_src to allow the route to be used for returning
  * packets to the originating host.
  */
 struct dn_route {
@@ -70,19 +70,18 @@
 		struct dst_entry dst;
 		struct dn_route *rt_next;
 	} u;
-	struct {
-		unsigned short saddr;
-		unsigned short daddr;
-		int iif;
-		int oif;
-		u32 fwmark;
-	} key;
-	unsigned short rt_saddr;
-	unsigned short rt_daddr;
-	unsigned char rt_type;
-	unsigned char rt_scope;
-	unsigned char rt_protocol;
-	unsigned char rt_table;
+
+	__u16 rt_saddr;
+	__u16 rt_daddr;
+	__u16 rt_gateway;
+	__u16 __padding;
+	__u16 rt_src_map;
+	__u16 rt_dst_map;
+
+	unsigned rt_flags;
+	unsigned rt_type;
+
+	struct flowi fl;
 };
 
 extern void dn_route_init(void);
@@ -110,32 +109,4 @@
 		kfree_skb(skb);
 }
 
-static inline void dn_nsp_send(struct sk_buff *skb)
-{
-	struct sock *sk = skb->sk;
-	struct dn_scp *scp = DN_SK(sk);
-	struct dst_entry *dst;
-
-	skb->h.raw = skb->data;
-	scp->stamp = jiffies;
-
-	if ((dst = sk->dst_cache) && !dst->obsolete) {
-try_again:
-		skb->dst = dst_clone(dst);
-		dst_output(skb);
-		return;
-	}
-
-	dst_release(xchg(&sk->dst_cache, NULL));
-
-	if (dn_route_output(&sk->dst_cache, dn_saddr2dn(&scp->peer), dn_saddr2dn(&scp->addr), 0) == 0) {
-		dst = sk->dst_cache;
-		goto try_again;
-	}
-
-	sk->err = EHOSTUNREACH;
-	if (!test_bit(SOCK_DEAD, &sk->flags))
-		sk->state_change(sk);
-}
-
 #endif /* _NET_DN_ROUTE_H */
diff -urN linux-2.5.67-bk9/include/net/flow.h linux-2.5.67-bk10/include/net/flow.h
--- linux-2.5.67-bk9/include/net/flow.h	2003-04-07 10:32:28.000000000 -0700
+++ linux-2.5.67-bk10/include/net/flow.h	2003-04-19 04:35:42.000000000 -0700
@@ -25,7 +25,18 @@
 			struct in6_addr *	saddr;
 			__u32			flowlabel;
 		} ip6_u;
+
+		struct {
+			__u16			daddr;
+			__u16			saddr;
+			__u32			fwmark;
+			__u8			scope;
+		} dn_u;
 	} nl_u;
+#define fld_dst		nl_u.dn_u.daddr
+#define fld_src		nl_u.dn_u.saddr
+#define fld_fwmark	nl_u.dn_u.fwmark
+#define fld_scope	nl_u.dn_u.scope
 #define fl6_dst		nl_u.ip6_u.daddr
 #define fl6_src		nl_u.ip6_u.saddr
 #define fl6_flowlabel	nl_u.ip6_u.flowlabel
@@ -48,8 +59,20 @@
 			__u8	code;
 		} icmpt;
 
+		struct {
+			__u16	sport;
+			__u16	dport;
+			__u8	objnum;
+			__u8	objnamel; /* Not 16 bits since max val is 16 */
+			__u8	objname[16]; /* Not zero terminated */
+		} dnports;
+
 		__u32		spi;
 	} uli_u;
+#define fl_ip_sport	uli_u.ports.sport
+#define fl_ip_dport	uli_u.ports.dport
+#define fl_icmp_type	uli_u.icmpt.type
+#define fl_icmp_code	uli_u.icmpt.code
+#define fl_ipsec_spi	uli_u.spi
 };
-
 #endif
diff -urN linux-2.5.67-bk9/include/net/route.h linux-2.5.67-bk10/include/net/route.h
--- linux-2.5.67-bk9/include/net/route.h	2003-04-07 10:30:33.000000000 -0700
+++ linux-2.5.67-bk10/include/net/route.h	2003-04-19 04:35:42.000000000 -0700
@@ -173,13 +173,13 @@
 static inline int ip_route_newports(struct rtable **rp, u16 sport, u16 dport,
 				    struct sock *sk)
 {
-	if (sport != (*rp)->fl.uli_u.ports.sport ||
-	    dport != (*rp)->fl.uli_u.ports.dport) {
+	if (sport != (*rp)->fl.fl_ip_sport ||
+	    dport != (*rp)->fl.fl_ip_dport) {
 		struct flowi fl;
 
 		memcpy(&fl, &(*rp)->fl, sizeof(fl));
-		fl.uli_u.ports.sport = sport;
-		fl.uli_u.ports.dport = dport;
+		fl.fl_ip_sport = sport;
+		fl.fl_ip_dport = dport;
 		ip_rt_put(*rp);
 		*rp = NULL;
 		return ip_route_output_flow(rp, &fl, sk, 0);
diff -urN linux-2.5.67-bk9/include/net/sock.h linux-2.5.67-bk10/include/net/sock.h
--- linux-2.5.67-bk9/include/net/sock.h	2003-04-19 04:35:31.000000000 -0700
+++ linux-2.5.67-bk10/include/net/sock.h	2003-04-19 04:35:42.000000000 -0700
@@ -859,6 +859,9 @@
  * 	schedule();
  * SOCK_SLEEP_POST(sk)
  *
+ * N.B. These are now obsolete and were, afaik, only ever used in DECnet
+ * and when the last use of them in DECnet has gone, I'm intending to
+ * remove them.
  */
 
 #define SOCK_SLEEP_PRE(sk) 	{ struct task_struct *tsk = current; \
diff -urN linux-2.5.67-bk9/include/net/xfrm.h linux-2.5.67-bk10/include/net/xfrm.h
--- linux-2.5.67-bk9/include/net/xfrm.h	2003-04-19 04:35:31.000000000 -0700
+++ linux-2.5.67-bk10/include/net/xfrm.h	2003-04-19 04:35:42.000000000 -0700
@@ -295,11 +295,11 @@
 
 static inline u32 __flow_hash4(struct flowi *fl)
 {
-	u32 hash = fl->fl4_src ^ fl->uli_u.ports.sport;
+	u32 hash = fl->fl4_src ^ fl->fl_ip_sport;
 
 	hash = ((hash & 0xF0F0F0F0) >> 4) | ((hash & 0x0F0F0F0F) << 4);
 
-	hash ^= fl->fl4_dst ^ fl->uli_u.ports.dport;
+	hash ^= fl->fl4_dst ^ fl->fl_ip_dport;
 	hash ^= (hash >> 10);
 	hash ^= (hash >> 20);
 	return hash & (XFRM_FLOWCACHE_HASH_SIZE-1);
@@ -309,13 +309,13 @@
 {
 	u32 hash = fl->fl6_src->s6_addr32[2] ^
 		   fl->fl6_src->s6_addr32[3] ^ 
-		   fl->uli_u.ports.sport;
+		   fl->fl_ip_sport;
 
 	hash = ((hash & 0xF0F0F0F0) >> 4) | ((hash & 0x0F0F0F0F) << 4);
 
 	hash ^= fl->fl6_dst->s6_addr32[2] ^
 		fl->fl6_dst->s6_addr32[3] ^ 
-		fl->uli_u.ports.dport;
+		fl->fl_ip_dport;
 	hash ^= (hash >> 10);
 	hash ^= (hash >> 20);
 	return hash & (XFRM_FLOWCACHE_HASH_SIZE-1);
@@ -454,8 +454,8 @@
 {
 	return  addr_match(&fl->fl4_dst, &sel->daddr, sel->prefixlen_d) &&
 		addr_match(&fl->fl4_src, &sel->saddr, sel->prefixlen_s) &&
-		!((fl->uli_u.ports.dport^sel->dport)&sel->dport_mask) &&
-		!((fl->uli_u.ports.sport^sel->sport)&sel->sport_mask) &&
+		!((fl->fl_ip_dport^sel->dport)&sel->dport_mask) &&
+		!((fl->fl_ip_sport^sel->sport)&sel->sport_mask) &&
 		(fl->proto == sel->proto || !sel->proto) &&
 		(fl->oif == sel->ifindex || !sel->ifindex);
 }
@@ -465,8 +465,8 @@
 {
 	return  addr_match(fl->fl6_dst, &sel->daddr, sel->prefixlen_d) &&
 		addr_match(fl->fl6_src, &sel->saddr, sel->prefixlen_s) &&
-		!((fl->uli_u.ports.dport^sel->dport)&sel->dport_mask) &&
-		!((fl->uli_u.ports.sport^sel->sport)&sel->sport_mask) &&
+		!((fl->fl_ip_dport^sel->dport)&sel->dport_mask) &&
+		!((fl->fl_ip_sport^sel->sport)&sel->sport_mask) &&
 		(fl->proto == sel->proto || !sel->proto) &&
 		(fl->oif == sel->ifindex || !sel->ifindex);
 }
diff -urN linux-2.5.67-bk9/net/8021q/vlan.c linux-2.5.67-bk10/net/8021q/vlan.c
--- linux-2.5.67-bk9/net/8021q/vlan.c	2003-04-19 04:35:31.000000000 -0700
+++ linux-2.5.67-bk10/net/8021q/vlan.c	2003-04-19 04:35:43.000000000 -0700
@@ -49,6 +49,8 @@
 static char vlan_buggyright[] = "David S. Miller <davem@redhat.com>";
 
 static int vlan_device_event(struct notifier_block *, unsigned long, void *);
+static int vlan_ioctl_handler(unsigned long);
+static int unregister_vlan_dev(struct net_device *, unsigned short );
 
 struct notifier_block vlan_notifier_block = {
 	.notifier_call = vlan_device_event,
@@ -100,11 +102,32 @@
 	/* Register us to receive netdevice events */
 	register_netdevice_notifier(&vlan_notifier_block);
 
-	vlan_ioctl_hook = vlan_ioctl_handler;
+	vlan_ioctl_set(vlan_ioctl_handler);
 
 	return 0;
 }
 
+/* Cleanup all vlan devices 
+ * Note: devices that have been registered that but not
+ * brought up will exist but have no module ref count.
+ */
+static void __exit vlan_cleanup_devices(void)
+{
+	struct net_device *dev, *nxt;
+
+	rtnl_lock();
+	for (dev = dev_base; dev; dev = nxt) {
+		nxt = dev->next;
+		if (dev->priv_flags & IFF_802_1Q_VLAN) {
+			unregister_vlan_dev(VLAN_DEV_INFO(dev)->real_dev,
+					    VLAN_DEV_INFO(dev)->vlan_id);
+
+			unregister_netdevice(dev);
+		}
+	}
+	rtnl_unlock();
+}
+
 /*
  *     Module 'remove' entry point.
  *     o delete /proc/net/router directory and static entries.
@@ -113,6 +136,14 @@
 {
 	int i;
 
+	vlan_ioctl_set(NULL);
+
+	/* Un-register us from receiving netdevice events */
+	unregister_netdevice_notifier(&vlan_notifier_block);
+
+	dev_remove_pack(&vlan_packet_type);
+	vlan_cleanup_devices();
+
 	/* This table must be empty if there are no module
 	 * references left.
 	 */
@@ -120,13 +151,9 @@
 		if (vlan_group_hash[i] != NULL)
 			BUG();
 	}
-
-	/* Un-register us from receiving netdevice events */
-	unregister_netdevice_notifier(&vlan_notifier_block);
-
-	dev_remove_pack(&vlan_packet_type);
 	vlan_proc_cleanup();
-	vlan_ioctl_hook = NULL;
+
+	synchronize_net();
 }
 
 module_init(vlan_proto_init);
@@ -262,8 +289,6 @@
 
 				ret = 1;
 			}
-
-			module_put(THIS_MODULE);
 		}
 	}
 
@@ -504,12 +529,6 @@
 	if (register_netdevice(new_dev))
 		goto out_free_newdev_priv;
 
-	/* NOTE:  We have a reference to the real device,
-	 * so hold on to the reference. May fail if we are being removed
-	 */
-	if (!try_module_get(THIS_MODULE))
-		goto out_free_unregister;
-
 	/* So, got the sucker initialized, now lets place
 	 * it into our local structure.
 	 */
@@ -523,7 +542,7 @@
 	if (!grp) { /* need to add a new group */
 		grp = kmalloc(sizeof(struct vlan_group), GFP_KERNEL);
 		if (!grp)
-			goto out_free_put;
+			goto out_free_unregister;
 					
 		/* printk(KERN_ALERT "VLAN REGISTER:  Allocated new group.\n"); */
 		memset(grp, 0, sizeof(struct vlan_group));
@@ -551,8 +570,6 @@
 	printk(VLAN_DBG "Allocated new device successfully, returning.\n");
 #endif
 	return new_dev;
-out_free_put:
-	module_put(THIS_MODULE);
 
 out_free_unregister:
 	unregister_netdev(new_dev);
@@ -658,7 +675,7 @@
  *	o execute requested action or pass command to the device driver
  *   arg is really a void* to a vlan_ioctl_args structure.
  */
-int vlan_ioctl_handler(unsigned long arg)
+static int vlan_ioctl_handler(unsigned long arg)
 {
 	int err = 0;
 	struct vlan_ioctl_args args;
diff -urN linux-2.5.67-bk9/net/8021q/vlan.h linux-2.5.67-bk10/net/8021q/vlan.h
--- linux-2.5.67-bk9/net/8021q/vlan.h	2003-04-07 10:31:55.000000000 -0700
+++ linux-2.5.67-bk10/net/8021q/vlan.h	2003-04-19 04:35:43.000000000 -0700
@@ -30,8 +30,6 @@
 
 extern unsigned short vlan_name_type;
 
-int vlan_ioctl_handler(unsigned long arg);
-
 #define VLAN_GRP_HASH_SHIFT	5
 #define VLAN_GRP_HASH_SIZE	(1 << VLAN_GRP_HASH_SHIFT)
 #define VLAN_GRP_HASH_MASK	(VLAN_GRP_HASH_SIZE - 1)
diff -urN linux-2.5.67-bk9/net/bridge/br.c linux-2.5.67-bk10/net/bridge/br.c
--- linux-2.5.67-bk9/net/bridge/br.c	2003-04-19 04:35:31.000000000 -0700
+++ linux-2.5.67-bk10/net/bridge/br.c	2003-04-19 04:35:43.000000000 -0700
@@ -21,7 +21,6 @@
 #include <linux/etherdevice.h>
 #include <linux/init.h>
 #include <linux/if_bridge.h>
-#include <linux/brlock.h>
 #include <asm/uaccess.h>
 #include "br_private.h"
 
@@ -31,16 +30,6 @@
 
 int (*br_should_route_hook) (struct sk_buff **pskb) = NULL;
 
-void br_dec_use_count()
-{
-	module_put(THIS_MODULE);
-}
-
-void br_inc_use_count()
-{
-	try_module_get(THIS_MODULE);
-}
-
 static int __init br_init(void)
 {
 	printk(KERN_INFO "NET4: Ethernet Bridge 008 for NET4.0\n");
@@ -67,15 +56,17 @@
 	br_netfilter_fini();
 #endif
 	unregister_netdevice_notifier(&br_device_notifier);
-
 	brioctl_set(NULL);
 	br_handle_frame_hook = NULL;
 
 #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
-	/* FIX ME. move into hook structure with ref count */
 	br_fdb_get_hook = NULL;
 	br_fdb_put_hook = NULL;
 #endif
+
+	br_cleanup_bridges();
+
+	synchronize_net();
 }
 
 EXPORT_SYMBOL(br_should_route_hook);
diff -urN linux-2.5.67-bk9/net/bridge/br_device.c linux-2.5.67-bk10/net/bridge/br_device.c
--- linux-2.5.67-bk9/net/bridge/br_device.c	2003-04-07 10:30:33.000000000 -0700
+++ linux-2.5.67-bk10/net/bridge/br_device.c	2003-04-19 04:35:43.000000000 -0700
@@ -16,6 +16,7 @@
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
 #include <linux/if_bridge.h>
+#include <linux/module.h>
 #include <asm/uaccess.h>
 #include "br_private.h"
 
@@ -91,9 +92,9 @@
 	netif_start_queue(dev);
 
 	br = dev->priv;
-	read_lock(&br->lock);
+	write_lock(&br->lock);
 	br_stp_enable_bridge(br);
-	read_unlock(&br->lock);
+	write_unlock(&br->lock);
 
 	return 0;
 }
@@ -107,9 +108,9 @@
 	struct net_bridge *br;
 
 	br = dev->priv;
-	read_lock(&br->lock);
+	write_lock(&br->lock);
 	br_stp_disable_bridge(br);
-	read_unlock(&br->lock);
+	write_unlock(&br->lock);
 
 	netif_stop_queue(dev);
 
@@ -121,6 +122,11 @@
 	return -1;
 }
 
+static void br_dev_destruct(struct net_device *dev) 
+{
+	kfree(dev->priv);
+}
+
 void br_dev_setup(struct net_device *dev)
 {
 	memset(dev->dev_addr, 0, ETH_ALEN);
@@ -130,6 +136,8 @@
 	dev->hard_start_xmit = br_dev_xmit;
 	dev->open = br_dev_open;
 	dev->set_multicast_list = br_dev_set_multicast_list;
+	dev->destructor = br_dev_destruct;
+	dev->owner = THIS_MODULE;
 	dev->stop = br_dev_stop;
 	dev->accept_fastpath = br_dev_accept_fastpath;
 	dev->tx_queue_len = 0;
diff -urN linux-2.5.67-bk9/net/bridge/br_fdb.c linux-2.5.67-bk10/net/bridge/br_fdb.c
--- linux-2.5.67-bk9/net/bridge/br_fdb.c	2003-04-07 10:30:40.000000000 -0700
+++ linux-2.5.67-bk10/net/bridge/br_fdb.c	2003-04-19 04:35:43.000000000 -0700
@@ -94,6 +94,7 @@
 {
 	struct net_bridge *br;
 	int i;
+	int newhash = br_mac_hash(newaddr);
 
 	br = p->br;
 	write_lock_bh(&br->hash_lock);
@@ -103,9 +104,11 @@
 		f = br->hash[i];
 		while (f != NULL) {
 			if (f->dst == p && f->is_local) {
-				__hash_unlink(f);
 				memcpy(f->addr.addr, newaddr, ETH_ALEN);
-				__hash_link(br, f, br_mac_hash(newaddr));
+				if (newhash != i) {
+					__hash_unlink(f);
+					__hash_link(br, f, newhash);
+				}
 				write_unlock_bh(&br->hash_lock);
 				return;
 			}
@@ -212,21 +215,15 @@
 	for (i=0;i<BR_HASH_SIZE;i++) {
 		struct net_bridge_fdb_entry *f;
 
-		f = br->hash[i];
-		while (f != NULL && num < maxnum) {
+		for (f = br->hash[i]; f != NULL && num < maxnum;
+		     f = f->next_hash) {
 			struct __fdb_entry ent;
-			int err;
-			struct net_bridge_fdb_entry *g;
-			struct net_bridge_fdb_entry **pp; 
 
-			if (has_expired(br, f)) {
-				f = f->next_hash;
+			if (has_expired(br, f)) 
 				continue;
-			}
 
 			if (offset) {
 				offset--;
-				f = f->next_hash;
 				continue;
 			}
 
@@ -234,37 +231,33 @@
 
 			atomic_inc(&f->use_count);
 			read_unlock_bh(&br->hash_lock);
-			err = copy_to_user(walk, &ent, sizeof(struct __fdb_entry));
-			read_lock_bh(&br->hash_lock);
-
-			g = f->next_hash;
-			pp = f->pprev_hash;
-			br_fdb_put(f);
+			
+			if (copy_to_user(walk, &ent, sizeof(struct __fdb_entry)))
+				return -EFAULT;
 
-			if (err)
-				goto out_fault;
+			read_lock_bh(&br->hash_lock);
+			
+			/* entry was deleted during copy_to_user */
+			if (atomic_dec_and_test(&f->use_count)) {
+				kfree(f);
+				num = -EAGAIN;
+				goto out;
+			}
 
-			if (g == NULL && pp == NULL)
-				goto out_disappeared;
+			/* entry changed address hash while copying */
+			if (br_mac_hash(f->addr.addr) != i) {
+				num = -EAGAIN;
+				goto out;
+			}
 
 			num++;
 			walk++;
-
-			f = g;
 		}
 	}
 
  out:
 	read_unlock_bh(&br->hash_lock);
 	return num;
-
- out_disappeared:
-	num = -EAGAIN;
-	goto out;
-
- out_fault:
-	num = -EFAULT;
-	goto out;
 }
 
 static __inline__ void __fdb_possibly_replace(struct net_bridge_fdb_entry *fdb,
diff -urN linux-2.5.67-bk9/net/bridge/br_if.c linux-2.5.67-bk10/net/bridge/br_if.c
--- linux-2.5.67-bk9/net/bridge/br_if.c	2003-04-19 04:35:31.000000000 -0700
+++ linux-2.5.67-bk10/net/bridge/br_if.c	2003-04-19 04:35:43.000000000 -0700
@@ -17,14 +17,13 @@
 #include <linux/if_arp.h>
 #include <linux/if_bridge.h>
 #include <linux/inetdevice.h>
+#include <linux/module.h>
 #include <linux/rtnetlink.h>
 #include <linux/brlock.h>
+#include <net/sock.h>
 #include <asm/uaccess.h>
 #include "br_private.h"
 
-static struct net_bridge *bridge_list;
-static spinlock_t bridge_lock = SPIN_LOCK_UNLOCKED;
-
 static int br_initial_port_cost(struct net_device *dev)
 {
 	if (!strncmp(dev->name, "lec", 3))
@@ -70,23 +69,6 @@
 	return 0;
 }
 
-/* called with bridge_lock */
-static struct net_bridge **__find_br(char *name)
-{
-	struct net_bridge **b;
-	struct net_bridge *br;
-
-	b = &bridge_list;
-	while ((br = *b) != NULL) {
-		if (!strncmp(br->dev.name, name, IFNAMSIZ))
-			return b;
-
-		b = &(br->next);
-	}
-
-	return NULL;
-}
-
 static void del_ifs(struct net_bridge *br)
 {
 	br_write_lock_bh(BR_NETPROTO_LOCK);
@@ -97,7 +79,7 @@
 	br_write_unlock_bh(BR_NETPROTO_LOCK);
 }
 
-static struct net_bridge *new_nb(char *name)
+static struct net_bridge *new_nb(const char *name)
 {
 	struct net_bridge *br;
 	struct net_device *dev;
@@ -112,6 +94,7 @@
 
 	strncpy(dev->name, name, IFNAMSIZ);
 	dev->priv = br;
+	dev->priv_flags = IFF_EBRIDGE;
 	ether_setup(dev);
 	br_dev_setup(dev);
 
@@ -178,56 +161,47 @@
 	return p;
 }
 
-int br_add_bridge(char *name)
+int br_add_bridge(const char *name)
 {
 	struct net_bridge *br;
+	int ret;
 
-	if ((br = new_nb(name)) == NULL)
+	if ((br = new_nb(name)) == NULL) 
 		return -ENOMEM;
 
-	if (__dev_get_by_name(name) != NULL) {
+	ret = register_netdev(&br->dev);
+	if (ret)
 		kfree(br);
-		return -EEXIST;
-	}
-
-	spin_lock(&bridge_lock);
-	br->next = bridge_list;
-	bridge_list = br;
-	spin_unlock(&bridge_lock);
-
-	br_inc_use_count();
-	register_netdev(&br->dev);
-
-	return 0;
+	return ret;
 }
 
-int br_del_bridge(char *name)
+int br_del_bridge(const char *name)
 {
-	struct net_bridge **b;
-	struct net_bridge *br;
+	struct net_device *dev;
+	int ret = 0;
 
-	spin_lock(&bridge_lock);
-	if ((b = __find_br(name)) == NULL) {
-		spin_unlock(&bridge_lock);
-		return -ENXIO;
+	dev = dev_get_by_name(name);
+	if (dev == NULL) 
+		return -ENXIO; 	/* Could not find device */
+
+	if (!(dev->priv_flags & IFF_EBRIDGE)) {
+		/* Attempt to delete non bridge device! */
+		ret = -EPERM;
 	}
 
-	br = *b;
-	if (br->dev.flags & IFF_UP) {
-		spin_unlock(&bridge_lock);
-		return -EBUSY;
+	else if (dev->flags & IFF_UP) {
+		/* Not shutdown yet. */
+		ret = -EBUSY;
+	} 
+
+	else {
+		del_ifs((struct net_bridge *) dev->priv);
+	
+		unregister_netdev(dev);
 	}
 
-	*b = br->next;
-	spin_unlock(&bridge_lock);
-
-	del_ifs(br);
-
-	unregister_netdev(&br->dev);
-	kfree(br);
-	br_dec_use_count();
-
-	return 0;
+	dev_put(dev);
+	return ret;
 }
 
 int br_add_if(struct net_bridge *br, struct net_device *dev)
@@ -278,24 +252,19 @@
 
 int br_get_bridge_ifindices(int *indices, int num)
 {
-	struct net_bridge *br;
-	int i;
-
-	spin_lock(&bridge_lock);
-	br = bridge_list;
-	for (i=0;i<num;i++) {
-		if (br == NULL)
-			break;
+	struct net_device *dev;
+	int i = 0;
 
-		indices[i] = br->dev.ifindex;
-		br = br->next;
+	rtnl_shlock();
+	for (dev = dev_base; dev && i < num; dev = dev->next) {
+		if (dev->priv_flags & IFF_EBRIDGE) 
+			indices[i++] = dev->ifindex;
 	}
-	spin_unlock(&bridge_lock);
+	rtnl_shunlock();
 
 	return i;
 }
 
-/* called under ioctl_lock */
 void br_get_port_ifindices(struct net_bridge *br, int *ifindices)
 {
 	struct net_bridge_port *p;
@@ -308,3 +277,24 @@
 	}
 	read_unlock(&br->lock);
 }
+
+
+void __exit br_cleanup_bridges(void)
+{
+	struct net_device *dev, *nxt;
+
+	rtnl_lock();
+	for (dev = dev_base; dev; dev = nxt) {
+		nxt = dev->next;
+		if ((dev->priv_flags & IFF_EBRIDGE)
+		    && dev->owner == THIS_MODULE) {
+			pr_debug("cleanup %s\n", dev->name);
+
+			del_ifs((struct net_bridge *) dev->priv);
+			
+			unregister_netdevice(dev);
+		}
+	}
+	rtnl_unlock();
+
+}
diff -urN linux-2.5.67-bk9/net/bridge/br_private.h linux-2.5.67-bk10/net/bridge/br_private.h
--- linux-2.5.67-bk9/net/bridge/br_private.h	2003-04-07 10:30:57.000000000 -0700
+++ linux-2.5.67-bk10/net/bridge/br_private.h	2003-04-19 04:35:43.000000000 -0700
@@ -79,7 +79,6 @@
 
 struct net_bridge
 {
-	struct net_bridge		*next;
 	rwlock_t			lock;
 	struct net_bridge_port		*port_list;
 	struct net_device		dev;
@@ -115,10 +114,6 @@
 extern struct notifier_block br_device_notifier;
 extern unsigned char bridge_ula[6];
 
-/* br.c */
-extern void br_dec_use_count(void);
-extern void br_inc_use_count(void);
-
 /* br_device.c */
 extern void br_dev_setup(struct net_device *dev);
 extern int br_dev_xmit(struct sk_buff *skb, struct net_device *dev);
@@ -156,8 +151,9 @@
 		      int clone);
 
 /* br_if.c */
-extern int br_add_bridge(char *name);
-extern int br_del_bridge(char *name);
+extern int br_add_bridge(const char *name);
+extern int br_del_bridge(const char *name);
+extern void br_cleanup_bridges(void);
 extern int br_add_if(struct net_bridge *br,
 	      struct net_device *dev);
 extern int br_del_if(struct net_bridge *br,
@@ -172,7 +168,6 @@
 extern int br_handle_frame(struct sk_buff *skb);
 
 /* br_ioctl.c */
-extern void br_call_ioctl_atomic(void (*fn)(void));
 extern int br_ioctl(struct net_bridge *br,
 	     unsigned int cmd,
 	     unsigned long arg0,
diff -urN linux-2.5.67-bk9/net/bridge/br_stp_if.c linux-2.5.67-bk10/net/bridge/br_stp_if.c
--- linux-2.5.67-bk9/net/bridge/br_stp_if.c	2003-04-07 10:32:31.000000000 -0700
+++ linux-2.5.67-bk10/net/bridge/br_stp_if.c	2003-04-19 04:35:43.000000000 -0700
@@ -85,7 +85,7 @@
 		p = p->next;
 	}
 
-	del_timer(&br->tick);
+	del_timer_sync(&br->tick);
 }
 
 /* called under bridge lock */
diff -urN linux-2.5.67-bk9/net/decnet/TODO linux-2.5.67-bk10/net/decnet/TODO
--- linux-2.5.67-bk9/net/decnet/TODO	2003-04-07 10:32:16.000000000 -0700
+++ linux-2.5.67-bk10/net/decnet/TODO	2003-04-19 04:35:43.000000000 -0700
@@ -26,25 +26,16 @@
  o Start to hack together user level software and add more DECnet support
    in ifconfig for example. 
 
- o Test adding/deleting of routes
-
- o Test route lookup
-
- o Test /proc/net/decnet_route route listing works correctly (maybe I'll
-   change the format of this file... atm its very similar to the IPv4 route
-   file)
-
  o Find all the commonality between DECnet and IPv4 routing code and extract 
    it into a small library of routines. [probably a project for 2.7.xx]
 
- o Test ip_gre tunneling works... it did the last time I tested it and it
-   will have to if I'm to test routing properly.
-
  o Add the routing message grabbing netfilter module [written, tested,
    awaiting merge]
 
- o Add perfect socket hashing - an idea suggested by Paul Koning [part written,
-   awaiting debugging and merge]
+ o Add perfect socket hashing - an idea suggested by Paul Koning. Currently
+   we have a half-way house scheme which seems to work reasonably well, but
+   the full scheme is still worth implementing, its not not top of my list
+   right now.
 
  o Add session control message flow control
 
@@ -54,3 +45,5 @@
 
  o AIO for DECnet
 
+ o Eliminate dn_db->parms.blksize
+
diff -urN linux-2.5.67-bk9/net/decnet/af_decnet.c linux-2.5.67-bk10/net/decnet/af_decnet.c
--- linux-2.5.67-bk9/net/decnet/af_decnet.c	2003-04-07 10:31:24.000000000 -0700
+++ linux-2.5.67-bk10/net/decnet/af_decnet.c	2003-04-19 04:35:43.000000000 -0700
@@ -118,6 +118,7 @@
 #include <linux/netfilter.h>
 #include <net/sock.h>
 #include <net/tcp.h>
+#include <net/flow.h>
 #include <asm/system.h>
 #include <asm/ioctls.h>
 #include <linux/mm.h>
@@ -146,6 +147,7 @@
 #define DN_SK_HASH_SIZE (1 << DN_SK_HASH_SHIFT)
 #define DN_SK_HASH_MASK (DN_SK_HASH_SIZE - 1)
 
+
 static kmem_cache_t *dn_sk_cachep;
 static struct proto_ops dn_proto_ops;
 static rwlock_t dn_hash_lock = RW_LOCK_UNLOCKED;
@@ -273,7 +275,7 @@
 
 	if (hash == 0) {
 		hash = addr->sdn_objnamel;
-		for(i = 0; i < addr->sdn_objnamel; i++) {
+		for(i = 0; i < dn_ntohs(addr->sdn_objnamel); i++) {
 			hash ^= addr->sdn_objname[i];
 			hash ^= (hash << 3);
 		}
@@ -512,8 +514,7 @@
 	scp->services_loc = 1 | NSP_FC_NONE;
 	scp->info_rem = 0;
 	scp->info_loc = 0x03; /* NSP version 4.1 */
-	scp->segsize_rem = 230; /* Default: Updated by remote segsize */
-	scp->segsize_loc = 1450; /* Best guess for ethernet */
+	scp->segsize_rem = 230 - DN_MAX_NSP_DATA_HEADER; /* Default: Updated by remote segsize */
 	scp->nonagle = 0;
 	scp->multi_ireq = 1;
 	scp->accept_mode = ACC_IMMED;
@@ -788,8 +789,8 @@
 		return -EINVAL;
 
 #if 1
-	if ((!capable(CAP_NET_BIND_SERVICE) && saddr->sdn_objnum) ||
-	    (saddr->sdn_flags & SDF_WILD))
+	if (!capable(CAP_NET_BIND_SERVICE) && (saddr->sdn_objnum ||
+	    (saddr->sdn_flags & SDF_WILD)))
 		return -EACCES;
 #else
 	/*
@@ -877,18 +878,18 @@
 static int dn_confirm_accept(struct sock *sk, long *timeo, int allocation)
 {
 	struct dn_scp *scp = DN_SK(sk);
-	DECLARE_WAITQUEUE(wait, current);
+	DEFINE_WAIT(wait);
 	int err;
 
 	if (scp->state != DN_CR)
 		return -EINVAL;
 
 	scp->state = DN_CC;
+	scp->segsize_loc = dst_path_metric(__sk_dst_get(sk), RTAX_ADVMSS);
 	dn_send_conn_conf(sk, allocation);
 
-	add_wait_queue(sk->sleep, &wait);
+	prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE);
 	for(;;) {
-		set_current_state(TASK_INTERRUPTIBLE);
 		release_sock(sk);
 		if (scp->state == DN_CC)
 			*timeo = schedule_timeout(*timeo);
@@ -905,16 +906,21 @@
 		err = -EAGAIN;
 		if (!*timeo)
 			break;
+		prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE);
+	}
+	finish_wait(sk->sleep, &wait);
+	if (err == 0) {
+		sk->socket->state = SS_CONNECTED;
+	} else if (scp->state != DN_CC) {
+		sk->socket->state = SS_UNCONNECTED;
 	}
-	remove_wait_queue(sk->sleep, &wait);
-	current->state = TASK_RUNNING;
 	return err;
 }
 
 static int dn_wait_run(struct sock *sk, long *timeo)
 {
 	struct dn_scp *scp = DN_SK(sk);
-	DECLARE_WAITQUEUE(wait, current);
+	DEFINE_WAIT(wait);
 	int err = 0;
 
 	if (scp->state == DN_RUN)
@@ -923,9 +929,8 @@
 	if (!*timeo)
 		return -EALREADY;
 
-	add_wait_queue(sk->sleep, &wait);
+	prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE);
 	for(;;) {
-		set_current_state(TASK_INTERRUPTIBLE);
 		release_sock(sk);
 		if (scp->state == DN_CI || scp->state == DN_CC)
 			*timeo = schedule_timeout(*timeo);
@@ -942,12 +947,14 @@
 		err = -ETIMEDOUT;
 		if (!*timeo)
 			break;
+		prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE);
 	}
-	remove_wait_queue(sk->sleep, &wait);
-	current->state = TASK_RUNNING;
+	finish_wait(sk->sleep, &wait);
 out:
 	if (err == 0) {
 		sk->socket->state = SS_CONNECTED;
+	} else if (scp->state != DN_CI && scp->state != DN_CC) {
+		sk->socket->state = SS_UNCONNECTED;
 	}
 	return err;
 }
@@ -957,6 +964,7 @@
 	struct socket *sock = sk->socket;
 	struct dn_scp *scp = DN_SK(sk);
 	int err = -EISCONN;
+	struct flowi fl;
 
 	if (sock->state == SS_CONNECTED)
 		goto out;
@@ -995,12 +1003,17 @@
 	memcpy(&scp->peer, addr, sizeof(struct sockaddr_dn));
 
 	err = -EHOSTUNREACH;
-	if (dn_route_output(&sk->dst_cache, dn_saddr2dn(&scp->peer),
-			    dn_saddr2dn(&scp->addr), flags & MSG_TRYHARD) < 0)
+	memset(&fl, 0, sizeof(fl));
+	fl.oif = sk->bound_dev_if;
+	fl.fld_dst = dn_saddr2dn(&scp->peer);
+	fl.fld_src = dn_saddr2dn(&scp->addr);
+	dn_sk_ports_copy(&fl, scp);
+	if (dn_route_output_sock(&sk->dst_cache, &fl, sk, flags) < 0)
 		goto out;
-
+	sk->route_caps = sk->dst_cache->dev->features;
 	sock->state = SS_CONNECTING;
 	scp->state = DN_CI;
+	scp->segsize_loc = dst_path_metric(sk->dst_cache, RTAX_ADVMSS);
 
 	dn_nsp_send_conninit(sk, NSP_CI);
 	err = -EINPROGRESS;
@@ -1077,13 +1090,12 @@
 
 static struct sk_buff *dn_wait_for_connect(struct sock *sk, long *timeo)
 {
-	DECLARE_WAITQUEUE(wait, current);
+	DEFINE_WAIT(wait);
 	struct sk_buff *skb = NULL;
 	int err = 0;
 
-	add_wait_queue_exclusive(sk->sleep, &wait);
+	prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE);
 	for(;;) {
-		set_current_state(TASK_INTERRUPTIBLE);
 		release_sock(sk);
 		skb = skb_dequeue(&sk->receive_queue);
 		if (skb == NULL) {
@@ -1102,9 +1114,10 @@
 		err = -EAGAIN;
 		if (!*timeo)
 			break;
+		prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE);
 	}
-	remove_wait_queue(sk->sleep, &wait);
-	current->state = TASK_RUNNING;
+	finish_wait(sk->sleep, &wait);
+
 	return skb == NULL ? ERR_PTR(err) : skb;
 }
 
@@ -1276,12 +1289,6 @@
 		release_sock(sk);
 		return val;
 
-#ifdef CONFIG_DECNET_ROUTER
-	case SIOCADDRT:
-	case SIOCDELRT:
-		return dn_fib_ioctl(sock, cmd, arg);
-#endif /* CONFIG_DECNET_ROUTER */
-
 	case TIOCOUTQ:
 		amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
 		if (amount < 0)
@@ -1888,6 +1895,64 @@
 	return 0;
 }
 
+/*
+ * The DECnet spec requires the the "routing layer" accepts packets which
+ * are at least 230 bytes in size. This excludes any headers which the NSP
+ * layer might add, so we always assume that we'll be using the maximal
+ * length header on data packets. The variation in length is due to the
+ * inclusion (or not) of the two 16 bit acknowledgement fields so it doesn't
+ * make much practical difference.
+ */
+unsigned dn_mss_from_pmtu(struct net_device *dev, int mtu)
+{
+	unsigned mss = 230 - DN_MAX_NSP_DATA_HEADER;
+	if (dev) {
+		struct dn_dev *dn_db = dev->dn_ptr;
+		mtu -= LL_RESERVED_SPACE(dev);
+		if (dn_db->use_long)
+			mtu -= 21;
+		else
+			mtu -= 6;
+		mtu -= DN_MAX_NSP_DATA_HEADER;
+	} else {
+		/*
+		 * 21 = long header, 16 = guess at MAC header length
+		 */
+		mtu -= (21 + DN_MAX_NSP_DATA_HEADER + 16);
+	}
+	if (mtu > mss)
+		mss = mtu;
+	return mss;
+}
+
+static inline unsigned int dn_current_mss(struct sock *sk, int flags)
+{
+	struct dst_entry *dst = __sk_dst_get(sk);
+	struct dn_scp *scp = DN_SK(sk);
+	int mss_now = min_t(int, scp->segsize_loc, scp->segsize_rem);
+
+	/* Other data messages are limited to 16 bytes per packet */
+	if (flags & MSG_OOB)
+		return 16;
+
+	/* This works out the maximum size of segment we can send out */
+	if (dst) {
+		u32 mtu = dst_pmtu(dst);
+		mss_now = min_t(int, dn_mss_from_pmtu(dst->dev, mtu), mss_now);
+	}
+
+	return mss_now;
+}
+
+static int dn_error(struct sock *sk, int flags, int err)
+{
+	if (err == -EPIPE)
+		err = sock_error(sk) ? : -EPIPE;
+	if (err == -EPIPE && !(flags & MSG_NOSIGNAL))
+		send_sig(SIGPIPE, current, 0);
+	return err;
+}
+
 static int dn_sendmsg(struct kiocb *iocb, struct socket *sock,
 	   struct msghdr *msg, int size)
 {
@@ -1902,9 +1967,6 @@
 	struct sockaddr_dn *addr = (struct sockaddr_dn *)msg->msg_name;
 	struct sk_buff *skb = NULL;
 	struct dn_skb_cb *cb;
-	unsigned char msgflg;
-	unsigned char *ptr;
-	unsigned short ack;
 	int len;
 	unsigned char fctype;
 	long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
@@ -1915,17 +1977,26 @@
 	if (addr_len && (addr_len != sizeof(struct sockaddr_dn)))
 		return -EINVAL;
 
+	/*
+	 * The only difference between stream sockets and sequenced packet
+	 * sockets is that the stream sockets always behave as if MSG_EOR
+	 * has been set.
+	 */
+	if (sock->type == SOCK_STREAM) {
+		if (flags & MSG_EOR)
+			return -EINVAL;
+		flags |= MSG_EOR;
+	}
+
 	lock_sock(sk);
 
 	err = dn_check_state(sk, addr, addr_len, &timeo, flags);
 	if (err)
-		goto out;
+		goto out_err;
 
 	if (sk->shutdown & SEND_SHUTDOWN) {
-		if (!(flags & MSG_NOSIGNAL))
-			send_sig(SIGPIPE, current, 0);
 		err = -EPIPE;
-		goto out;
+		goto out_err;
 	}
 
 	if ((flags & MSG_TRYHARD) && sk->dst_cache)
@@ -1934,20 +2005,9 @@
 	mss = scp->segsize_rem;
 	fctype = scp->services_rem & NSP_FC_MASK;
 
-	if (sk->dst_cache && sk->dst_cache->neighbour) {
-		struct dn_neigh *dn = (struct dn_neigh *)sk->dst_cache->neighbour;
-		if (dn->blksize < (mss + 11))
-			mss = dn->blksize - 11;
-	}
-
-	/*
-	 * The only difference between SEQPACKET & STREAM sockets under DECnet
-	 * is that SEQPACKET sockets set the MSG_EOR flag for the last
-	 * session control message segment. 
-	 */
+	mss = dn_current_mss(sk, flags);
 
 	if (flags & MSG_OOB) {
-		mss = 16;
 		queue = &scp->other_xmit_queue;
 		if (size > mss) {
 			err = -EMSGSIZE;
@@ -2008,7 +2068,7 @@
 
 		cb = DN_SKB_CB(skb);
 
-		ptr = skb_put(skb, 9);
+		skb_reserve(skb, DN_MAX_NSP_DATA_HEADER);
 
 		if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
 			err = -EFAULT;
@@ -2016,45 +2076,26 @@
 		}
 
 		if (flags & MSG_OOB) {
-			cb->segnum = scp->numoth;
-			seq_add(&scp->numoth, 1);
-			msgflg = 0x30;
-			ack = (scp->numoth_rcv & 0x0FFF) | 0x8000;
-			scp->ackxmt_oth = scp->numoth_rcv;
+			cb->nsp_flags = 0x30;
 			if (fctype != NSP_FC_NONE)
 				scp->flowrem_oth--;
 		} else {
-			cb->segnum = scp->numdat;
-			seq_add(&scp->numdat, 1);
-			msgflg = 0x00;
-			if (sock->type == SOCK_STREAM)
-				msgflg = 0x60;
+			cb->nsp_flags = 0x00;
 			if (scp->seg_total == 0)
-				msgflg |= 0x20;
+				cb->nsp_flags |= 0x20;
 
 			scp->seg_total += len;
 		
 			if (((sent + len) == size) && (flags & MSG_EOR)) {
-				msgflg |= 0x40;
+				cb->nsp_flags |= 0x40;
 				scp->seg_total = 0;
 				if (fctype == NSP_FC_SCMC)
 					scp->flowrem_dat--;
 			}
-			ack = (scp->numdat_rcv & 0x0FFF) | 0x8000;
-			scp->ackxmt_dat = scp->numdat_rcv;
 			if (fctype == NSP_FC_SRC)
 				scp->flowrem_dat--;
 		}
 
-		*ptr++ = msgflg;
-		*(__u16 *)ptr = scp->addrrem;
-		ptr += 2;
-		*(__u16 *)ptr = scp->addrloc;
-		ptr += 2;
-		*(__u16 *)ptr = dn_htons(ack);
-		ptr += 2;
-		*(__u16 *)ptr = dn_htons(cb->segnum);
-
 		sent += len;
 		dn_nsp_queue_xmit(sk, skb, sk->allocation, flags & MSG_OOB);
 		skb = NULL;
@@ -2070,6 +2111,11 @@
 	release_sock(sk);
 
 	return sent ? sent : err;
+
+out_err:
+	err = dn_error(sk, flags, err);
+	release_sock(sk);
+	return err;
 }
 
 static int dn_device_event(struct notifier_block *this, unsigned long event,
@@ -2215,10 +2261,8 @@
 	.sendpage =	sock_no_sendpage,
 };
 
-#ifdef CONFIG_SYSCTL
 void dn_register_sysctl(void);
 void dn_unregister_sysctl(void);
-#endif
 
 
 MODULE_DESCRIPTION("The Linux DECnet Network Protocol");
@@ -2226,7 +2270,7 @@
 MODULE_LICENSE("GPL");
 
 
-static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.5.40s (C) 1995-2002 Linux DECnet Project Team\n";
+static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.5.67s (C) 1995-2003 Linux DECnet Project Team\n";
 
 static int __init decnet_init(void)
 {
@@ -2253,9 +2297,7 @@
 	dn_fib_init();
 #endif /* CONFIG_DECNET_ROUTER */
 
-#ifdef CONFIG_SYSCTL
 	dn_register_sysctl();
-#endif /* CONFIG_SYSCTL */
 
 	/*
 	 * Prevent DECnet module unloading until its fixed properly.
@@ -2273,9 +2315,7 @@
 	sock_unregister(AF_DECnet);
 	dev_remove_pack(&dn_dix_packet_type);
 
-#ifdef CONFIG_SYSCTL
 	dn_unregister_sysctl();
-#endif /* CONFIG_SYSCTL */
 
 	unregister_netdevice_notifier(&dn_dev_notifier);
 
diff -urN linux-2.5.67-bk9/net/decnet/dn_dev.c linux-2.5.67-bk10/net/decnet/dn_dev.c
--- linux-2.5.67-bk9/net/decnet/dn_dev.c	2003-04-07 10:31:01.000000000 -0700
+++ linux-2.5.67-bk10/net/decnet/dn_dev.c	2003-04-19 04:35:43.000000000 -0700
@@ -36,9 +36,11 @@
 #include <linux/skbuff.h>
 #include <linux/rtnetlink.h>
 #include <linux/sysctl.h>
+#include <linux/notifier.h>
 #include <asm/uaccess.h>
 #include <net/neighbour.h>
 #include <net/dst.h>
+#include <net/flow.h>
 #include <net/dn.h>
 #include <net/dn_dev.h>
 #include <net/dn_route.h>
@@ -61,6 +63,7 @@
 
 static rwlock_t dndev_lock = RW_LOCK_UNLOCKED;
 static struct net_device *decnet_default_device;
+static struct notifier_block *dnaddr_chain;
 
 static struct dn_dev *dn_dev_create(struct net_device *dev, int *err);
 static void dn_dev_delete(struct net_device *dev);
@@ -478,7 +481,7 @@
 	}
 
 	rtmsg_ifa(RTM_DELADDR, ifa1);
-
+	notifier_call_chain(&dnaddr_chain, NETDEV_DOWN, ifa1);
 	if (destroy) {
 		dn_dev_free_ifa(ifa1);
 
@@ -513,6 +516,7 @@
 	dn_db->ifa_list = ifa;
 
 	rtmsg_ifa(RTM_NEWADDR, ifa);
+	notifier_call_chain(&dnaddr_chain, NETDEV_UP, ifa);
 
 	return 0;
 }
@@ -609,7 +613,7 @@
 				dn_dev_del_ifa(dn_db, ifap, 0);
 			}
 
-			ifa->ifa_local = dn_saddr2dn(sdn);
+			ifa->ifa_local = ifa->ifa_address = dn_saddr2dn(sdn);
 
 			ret = dn_dev_set_ifa(dev, ifa);
 	}
@@ -686,7 +690,10 @@
 	if ((ifa = dn_dev_alloc_ifa()) == NULL)
 		return -ENOBUFS;
 
+	if (!rta[IFA_ADDRESS - 1])
+		rta[IFA_ADDRESS - 1] = rta[IFA_LOCAL - 1];
 	memcpy(&ifa->ifa_local, RTA_DATA(rta[IFA_LOCAL-1]), 2);
+	memcpy(&ifa->ifa_address, RTA_DATA(rta[IFA_ADDRESS-1]), 2);
 	ifa->ifa_flags = ifm->ifa_flags;
 	ifa->ifa_scope = ifm->ifa_scope;
 	ifa->ifa_dev = dn_db;
@@ -716,7 +723,10 @@
 	ifm->ifa_flags = ifa->ifa_flags | IFA_F_PERMANENT;
 	ifm->ifa_scope = ifa->ifa_scope;
 	ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
-	RTA_PUT(skb, IFA_LOCAL, 2, &ifa->ifa_local);
+	if (ifa->ifa_address)
+		RTA_PUT(skb, IFA_ADDRESS, 2, &ifa->ifa_address);
+	if (ifa->ifa_local)
+		RTA_PUT(skb, IFA_LOCAL, 2, &ifa->ifa_local);
 	if (ifa->ifa_label[0])
 		RTA_PUT(skb, IFA_LABEL, IFNAMSIZ, &ifa->ifa_label);
 	nlh->nlmsg_len = skb->tail - b;
@@ -758,10 +768,7 @@
 	s_idx = cb->args[0];
 	s_dn_idx = dn_idx = cb->args[1];
 	read_lock(&dev_base_lock);
-	for(dev = dev_base, idx = 0; dev; dev = dev->next) {
-		if ((dn_db = dev->dn_ptr) == NULL)
-			continue;
-		idx++;
+	for(dev = dev_base, idx = 0; dev; dev = dev->next, idx++) {
 		if (idx < s_idx)
 			continue;
 		if (idx > s_idx)
@@ -773,7 +780,10 @@
 			if (dn_idx < s_dn_idx)
 				continue;
 
-			if (dn_dev_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, RTM_NEWADDR) <= 0)
+			if (dn_dev_fill_ifaddr(skb, ifa,
+					       NETLINK_CB(cb->skb).pid,
+					       cb->nlh->nlmsg_seq,
+					       RTM_NEWADDR) <= 0)
 				goto done;
 		}
 	}
@@ -872,8 +882,6 @@
 }
 
 
-#ifdef CONFIG_DECNET_ROUTER
-
 #define DRDELAY (5 * HZ)
 
 static int dn_am_i_a_router(struct dn_neigh *dn, struct dn_dev *dn_db, struct dn_ifaddr *ifa)
@@ -981,12 +989,6 @@
 	else
 		dn_send_router_hello(dev, ifa);
 }
-#else
-static void dn_send_brd_hello(struct net_device *dev, struct dn_ifaddr *ifa)
-{
-	dn_send_endnode_hello(dev, ifa);
-}
-#endif
 
 #if 0
 static void dn_send_ptp_hello(struct net_device *dev, struct dn_ifaddr *ifa)
@@ -1175,7 +1177,7 @@
 	if ((ifa = dn_dev_alloc_ifa()) == NULL)
 		return;
 
-	ifa->ifa_local = addr;
+	ifa->ifa_local = ifa->ifa_address = addr;
 	ifa->ifa_flags = 0;
 	ifa->ifa_scope = RT_SCOPE_UNIVERSE;
 	strcpy(ifa->ifa_label, dev->name);
@@ -1274,6 +1276,15 @@
 	rtnl_unlock();
 }
 
+int register_dnaddr_notifier(struct notifier_block *nb)
+{
+	return notifier_chain_register(&dnaddr_chain, nb);
+}
+
+int unregister_dnaddr_notifier(struct notifier_block *nb)
+{
+	return notifier_chain_unregister(&dnaddr_chain, nb);
+}
 
 #ifdef CONFIG_DECNET_SIOCGIFCONF
 /*
@@ -1390,43 +1401,21 @@
 
 static struct rtnetlink_link dnet_rtnetlink_table[RTM_MAX-RTM_BASE+1] = 
 {
-	{ NULL,			NULL,			},
-	{ NULL,			NULL,			},
-	{ NULL,			NULL,			},
-	{ NULL,			NULL,			},
-
-	{ dn_dev_rtm_newaddr,	NULL,			},
-	{ dn_dev_rtm_deladdr,	NULL,			},
-	{ NULL,			dn_dev_dump_ifaddr,	},
-	{ NULL,			NULL,			},
+	 [4] = { .doit   = dn_dev_rtm_newaddr,	},
+	 [5] = { .doit   = dn_dev_rtm_deladdr,	},
+	 [6] = { .dumpit = dn_dev_dump_ifaddr,	},
 
 #ifdef CONFIG_DECNET_ROUTER
-	{ dn_fib_rtm_newroute,	NULL,			},
-	{ dn_fib_rtm_delroute,	NULL,			},
-	{ dn_cache_getroute,	dn_fib_dump,		},
-	{ NULL,			NULL,			},
+	 [8] = { .doit   = dn_fib_rtm_newroute,	},
+	 [9] = { .doit   = dn_fib_rtm_delroute,	},
+	[10] = { .doit   = dn_cache_getroute, .dumpit = dn_fib_dump, },
+	[16] = { .doit   = dn_fib_rtm_newrule, },
+	[17] = { .doit   = dn_fib_rtm_delrule, },
+	[18] = { .dumpit = dn_fib_dump_rules,  },
 #else
-	{ NULL,			NULL,			},
-	{ NULL,			NULL,			},
-	{ dn_cache_getroute,	dn_cache_dump,		},
-	{ NULL,			NULL,			},
+	[10] = { .doit   = dn_cache_getroute, .dumpit = dn_cache_dump, },
 #endif
-	{ NULL,			NULL,			},
-	{ NULL,			NULL,			},
-	{ NULL,			NULL,			},
-	{ NULL,			NULL,			},
 
-#ifdef CONFIG_DECNET_ROUTER
-	{ dn_fib_rtm_newrule,	NULL,			},
-	{ dn_fib_rtm_delrule,	NULL,			},
-	{ NULL,			dn_fib_dump_rules,	},
-	{ NULL,			NULL,			}
-#else
-	{ NULL,			NULL,			},
-	{ NULL,			NULL,			},
-	{ NULL,			NULL,			},
-	{ NULL,			NULL,			}
-#endif
 };
 
 #ifdef MODULE
diff -urN linux-2.5.67-bk9/net/decnet/dn_fib.c linux-2.5.67-bk10/net/decnet/dn_fib.c
--- linux-2.5.67-bk9/net/decnet/dn_fib.c	2003-04-07 10:33:03.000000000 -0700
+++ linux-2.5.67-bk10/net/decnet/dn_fib.c	2003-04-19 04:35:43.000000000 -0700
@@ -12,6 +12,9 @@
  *              Alexey Kuznetsov : SMP locking changes
  *              Steve Whitehouse : Rewrote it... Well to be more correct, I
  *                                 copied most of it from the ipv4 fib code.
+ *              Steve Whitehouse : Updated it in style and fixed a few bugs
+ *                                 which were fixed in the ipv4 code since
+ *                                 this code was copied from it.
  *
  */
 #include <linux/config.h>
@@ -31,12 +34,14 @@
 #include <asm/uaccess.h>
 #include <net/neighbour.h>
 #include <net/dst.h>
+#include <net/flow.h>
 #include <net/dn.h>
 #include <net/dn_route.h>
 #include <net/dn_fib.h>
 #include <net/dn_neigh.h>
 #include <net/dn_dev.h>
 
+#define RT_MIN_TABLE 1
 
 #define for_fib_info() { struct dn_fib_info *fi;\
 	for(fi = dn_fib_info_list; fi; fi = fi->fib_next)
@@ -52,7 +57,7 @@
 
 extern int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb);
 
-
+static spinlock_t dn_fib_multipath_lock = SPIN_LOCK_UNLOCKED;
 static struct dn_fib_info *dn_fib_info_list;
 static rwlock_t dn_fib_info_lock = RW_LOCK_UNLOCKED;
 int dn_fib_info_cnt;
@@ -62,18 +67,18 @@
 	int error;
 	u8 scope;
 } dn_fib_props[RTA_MAX+1] = {
-	{ 0, RT_SCOPE_NOWHERE },		/* RTN_UNSPEC */
-	{ 0, RT_SCOPE_UNIVERSE },		/* RTN_UNICAST */
-	{ 0, RT_SCOPE_HOST },			/* RTN_LOCAL */
-	{ -EINVAL, RT_SCOPE_NOWHERE },		/* RTN_BROADCAST */
-	{ -EINVAL, RT_SCOPE_NOWHERE },		/* RTN_ANYCAST */
-	{ -EINVAL, RT_SCOPE_NOWHERE },		/* RTN_MULTICAST */
-	{ -EINVAL, RT_SCOPE_UNIVERSE },		/* RTN_BLACKHOLE */
-	{ -EHOSTUNREACH, RT_SCOPE_UNIVERSE },	/* RTN_UNREACHABLE */
-	{ -EACCES, RT_SCOPE_UNIVERSE },		/* RTN_PROHIBIT */
-	{ -EAGAIN, RT_SCOPE_UNIVERSE },		/* RTN_THROW */
-	{ -EINVAL, RT_SCOPE_NOWHERE },		/* RTN_NAT */
-	{ -EINVAL, RT_SCOPE_NOWHERE }		/* RTN_XRESOLVE */
+	{ .error = 0, .scope = RT_SCOPE_NOWHERE },	  /* RTN_UNSPEC */
+	{ .error = 0, .scope = RT_SCOPE_UNIVERSE },	  /* RTN_UNICAST */
+	{ .error = 0, .scope = RT_SCOPE_HOST },		  /* RTN_LOCAL */
+	{ .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },  /* RTN_BROADCAST */
+	{ .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },  /* RTN_ANYCAST */
+	{ .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },  /* RTN_MULTICAST */
+	{ .error = -EINVAL, .scope = RT_SCOPE_UNIVERSE }, /* RTN_BLACKHOLE */
+	{ .error = -EHOSTUNREACH, .scope = RT_SCOPE_UNIVERSE },	/* RTN_UNREACHABLE */
+	{ .error = -EACCES, .scope = RT_SCOPE_UNIVERSE }, /* RTN_PROHIBIT */
+	{ .error = -EAGAIN, .scope = RT_SCOPE_UNIVERSE }, /* RTN_THROW */
+	{ .error = 0, .scope = RT_SCOPE_NOWHERE },  /* RTN_NAT */
+	{ .error = -EINVAL, .scope = RT_SCOPE_NOWHERE }	  /* RTN_XRESOLVE */
 };
 
 void dn_fib_free_info(struct dn_fib_info *fi)
@@ -108,7 +113,7 @@
 	write_unlock(&dn_fib_info_lock);
 }
 
-static __inline__ int dn_fib_nh_comp(const struct dn_fib_info *fi, const struct dn_fib_info *ofi)
+static inline int dn_fib_nh_comp(const struct dn_fib_info *fi, const struct dn_fib_info *ofi)
 {
 	const struct dn_fib_nh *onh = ofi->fib_nh;
 
@@ -124,7 +129,7 @@
 	return 0;
 }
 
-static __inline__ struct dn_fib_info *dn_fib_find_info(const struct dn_fib_info *nfi)
+static inline struct dn_fib_info *dn_fib_find_info(const struct dn_fib_info *nfi)
 {
 	for_fib_info() {
 		if (fi->fib_nhs != nfi->fib_nhs)
@@ -132,6 +137,7 @@
 		if (nfi->fib_protocol == fi->fib_protocol &&
 			nfi->fib_prefsrc == fi->fib_prefsrc &&
 			nfi->fib_priority == fi->fib_priority &&
+			memcmp(nfi->fib_metrics, fi->fib_metrics, sizeof(fi->fib_metrics)) == 0 &&
 			((nfi->fib_flags^fi->fib_flags)&~RTNH_F_DEAD) == 0 &&
 			(nfi->fib_nhs == 0 || dn_fib_nh_comp(fi, nfi) == 0))
 				return fi;
@@ -195,14 +201,18 @@
 	int err;
 
 	if (nh->nh_gw) {
-		struct dn_fib_key key;
+		struct flowi fl;
 		struct dn_fib_res res;
 
+		memset(&fl, 0, sizeof(fl));
+
 		if (nh->nh_flags&RTNH_F_ONLINK) {
 			struct net_device *dev;
 
 			if (r->rtm_scope >= RT_SCOPE_LINK)
 				return -EINVAL;
+			if (dnet_addr_type(nh->nh_gw) != RTN_UNICAST)
+				return -EINVAL;
 			if ((dev = __dev_get_by_index(nh->nh_oif)) == NULL)
 				return -ENODEV;
 			if (!(dev->flags&IFF_UP))
@@ -213,23 +223,33 @@
 			return 0;
 		}
 
-		memset(&key, 0, sizeof(key));
-		key.dst = nh->nh_gw;
-		key.oif = nh->nh_oif;
-		key.scope = r->rtm_scope + 1;
+		memset(&fl, 0, sizeof(fl));
+		fl.fld_dst = nh->nh_gw;
+		fl.oif = nh->nh_oif;
+		fl.fld_scope = r->rtm_scope + 1;
 
-		if (key.scope < RT_SCOPE_LINK)
-			key.scope = RT_SCOPE_LINK;
+		if (fl.fld_scope < RT_SCOPE_LINK)
+			fl.fld_scope = RT_SCOPE_LINK;
 
-		if ((err = dn_fib_lookup(&key, &res)) != 0)
+		if ((err = dn_fib_lookup(&fl, &res)) != 0)
 			return err;
 
+		err = -EINVAL;
+		if (res.type != RTN_UNICAST && res.type != RTN_LOCAL)
+			goto out;
 		nh->nh_scope = res.scope;
 		nh->nh_oif = DN_FIB_RES_OIF(res);
 		nh->nh_dev = DN_FIB_RES_DEV(res);
-		if (nh->nh_dev)
-			atomic_inc(&nh->nh_dev->refcnt);
+		if (nh->nh_dev == NULL)
+			goto out;
+		atomic_inc(&nh->nh_dev->refcnt);
+		err = -ENETDOWN;
+		if (!(nh->nh_dev->flags & IFF_UP))
+			goto out;
+		err = 0;
+out:
 		dn_fib_res_put(&res);
+		return err;
 	} else {
 		struct net_device *dev;
 
@@ -277,6 +297,20 @@
 	fi->fib_flags = r->rtm_flags;
 	if (rta->rta_priority)
 		fi->fib_priority = *rta->rta_priority;
+	if (rta->rta_mx) {
+		int attrlen = RTA_PAYLOAD(rta->rta_mx);
+		struct rtattr *attr = RTA_DATA(rta->rta_mx);
+
+		while(RTA_OK(attr, attrlen)) {
+			unsigned flavour = attr->rta_type;
+			if (flavour) {
+				if (flavour > RTAX_MAX)
+					goto err_inval;
+				fi->fib_metrics[flavour-1] = *(unsigned*)RTA_DATA(attr);
+			}
+			attr = RTA_NEXT(attr, attrlen);
+		}
+	}
 	if (rta->rta_prefsrc)
 		memcpy(&fi->fib_prefsrc, rta->rta_prefsrc, 2);
 
@@ -297,6 +331,13 @@
 		nh->nh_weight = 1;
 	}
 
+	if (r->rtm_type == RTN_NAT) {
+		if (rta->rta_gw == NULL || nhs != 1 || rta->rta_oif)
+			goto err_inval;
+		memcpy(&fi->fib_nh->nh_gw, rta->rta_gw, 2);
+		goto link_it;
+	}
+
 	if (dn_fib_props[r->rtm_type].error) {
 		if (rta->rta_gw || rta->rta_oif || rta->rta_mp)
 			goto err_inval;
@@ -324,14 +365,12 @@
 		} endfor_nexthops(fi)
 	}
 
-#if I_GET_AROUND_TO_FIXING_PREFSRC
 	if (fi->fib_prefsrc) {
 		if (r->rtm_type != RTN_LOCAL || rta->rta_dst == NULL ||
 		    memcmp(&fi->fib_prefsrc, rta->rta_dst, 2))
-			if (dn_addr_type(fi->fib_prefsrc) != RTN_LOCAL)
+			if (dnet_addr_type(fi->fib_prefsrc) != RTN_LOCAL)
 				goto err_inval;
 	}
-#endif
 
 link_it:
 	if ((ofi = dn_fib_find_info(fi)) != NULL) {
@@ -366,12 +405,53 @@
 	return NULL;
 }
 
+int dn_fib_semantic_match(int type, struct dn_fib_info *fi, const struct flowi *fl, struct dn_fib_res *res)
+{
+	int err = dn_fib_props[type].error;
+
+	if (err == 0) {
+		if (fi->fib_flags & RTNH_F_DEAD)
+			return 1;
+
+		res->fi = fi;
+
+		switch(type) {
+			case RTN_NAT:
+				DN_FIB_RES_RESET(*res);
+				atomic_inc(&fi->fib_clntref);
+				return 0;
+			case RTN_UNICAST:
+			case RTN_LOCAL:
+				for_nexthops(fi) {
+					if (nh->nh_flags & RTNH_F_DEAD)
+						continue;
+					if (!fl->oif || fl->oif == nh->nh_oif)
+						break;
+				}
+				if (nhsel < fi->fib_nhs) {
+					res->nh_sel = nhsel;
+					atomic_inc(&fi->fib_clntref);
+					return 0;
+				}
+				endfor_nexthops(fi);
+				res->fi = NULL;
+				return 1;
+			default:
+				if (net_ratelimit())
+					 printk("DECnet: impossible routing event : dn_fib_semantic_match type=%d\n", type);
+				res->fi = NULL;
+				return -EINVAL;
+		}
+	}
+	return err;
+}
 
-void dn_fib_select_multipath(const struct dn_fib_key *key, struct dn_fib_res *res)
+void dn_fib_select_multipath(const struct flowi *fl, struct dn_fib_res *res)
 {
 	struct dn_fib_info *fi = res->fi;
 	int w;
 
+	spin_lock_bh(&dn_fib_multipath_lock);
 	if (fi->fib_power <= 0) {
 		int power = 0;
 		change_nexthops(fi) {
@@ -381,6 +461,11 @@
 			}
 		} endfor_nexthops(fi);
 		fi->fib_power = power;
+		if (power < 0) {
+			spin_unlock_bh(&dn_fib_multipath_lock);
+			res->nh_sel = 0;
+			return;
+		}
 	}
 
 	w = jiffies % fi->fib_power;
@@ -391,16 +476,16 @@
 				nh->nh_power--;
 				fi->fib_power--;
 				res->nh_sel = nhsel;
+				spin_unlock_bh(&dn_fib_multipath_lock);
 				return;
 			}
 		}
 	} endfor_nexthops(fi);
-
-	printk(KERN_DEBUG "DECnet: BUG! dn_fib_select_multipath\n");
+	res->nh_sel = 0;
+	spin_unlock_bh(&dn_fib_multipath_lock);
 }
 
 
-
 /*
  * Punt to user via netlink for example, but for now
  * we just drop it.
@@ -475,9 +560,9 @@
 
 	s_t = cb->args[0];
 	if (s_t == 0)
-		s_t = cb->args[0] = DN_MIN_TABLE;
+		s_t = cb->args[0] = RT_MIN_TABLE;
 
-	for(t = s_t; t < DN_NUM_TABLES; t++) {
+	for(t = s_t; t <= RT_TABLE_MAX; t++) {
 		if (t < s_t)
 			continue;
 		if (t > s_t)
@@ -494,6 +579,125 @@
 	return skb->len;
 }
 
+static void fib_magic(int cmd, int type, __u16 dst, int dst_len, struct dn_ifaddr *ifa)
+{
+	struct dn_fib_table *tb;
+	struct {
+		struct nlmsghdr nlh;
+		struct rtmsg rtm;
+	} req;
+	struct dn_kern_rta rta;
+
+	memset(&req.rtm, 0, sizeof(req.rtm));
+	memset(&rta, 0, sizeof(rta));
+
+	if (type == RTN_UNICAST)
+		tb = dn_fib_get_table(RT_MIN_TABLE, 1);
+	else
+		tb = dn_fib_get_table(RT_TABLE_LOCAL, 1);
+
+	if (tb == NULL)
+		return;
+
+	req.nlh.nlmsg_len = sizeof(req);
+	req.nlh.nlmsg_type = cmd;
+	req.nlh.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_APPEND;
+	req.nlh.nlmsg_pid = 0;
+	req.nlh.nlmsg_seq = 0;
+
+	req.rtm.rtm_dst_len = dst_len;
+	req.rtm.rtm_table = tb->n;
+	req.rtm.rtm_protocol = RTPROT_KERNEL;
+	req.rtm.rtm_scope = (type != RTN_LOCAL ? RT_SCOPE_LINK : RT_SCOPE_HOST);
+	req.rtm.rtm_type = type;
+
+	rta.rta_dst = &dst;
+	rta.rta_prefsrc = &ifa->ifa_local;
+	rta.rta_oif = &ifa->ifa_dev->dev->ifindex;
+
+	if (cmd == RTM_NEWROUTE)
+		tb->insert(tb, &req.rtm, &rta, &req.nlh, NULL);
+	else
+		tb->delete(tb, &req.rtm, &rta, &req.nlh, NULL);
+}
+
+static void dn_fib_add_ifaddr(struct dn_ifaddr *ifa)
+{
+
+	fib_magic(RTM_NEWROUTE, RTN_LOCAL, ifa->ifa_local, 16, ifa);
+
+#if 0
+	if (!(dev->flags&IFF_UP))
+		return;
+	/* In the future, we will want to add default routes here */
+
+#endif
+}
+
+static void dn_fib_del_ifaddr(struct dn_ifaddr *ifa)
+{
+	int found_it = 0;
+	struct net_device *dev;
+	struct dn_dev *dn_db;
+	struct dn_ifaddr *ifa2;
+
+	ASSERT_RTNL();
+
+	/* Scan device list */
+	read_lock(&dev_base_lock);
+	for(dev = dev_base; dev; dev = dev->next) {
+		dn_db = dev->dn_ptr;
+		if (dn_db == NULL)
+			continue;
+		for(ifa2 = dn_db->ifa_list; ifa2; ifa2 = ifa2->ifa_next) {
+			if (ifa2->ifa_local == ifa->ifa_local) {
+				found_it = 1;
+				break;
+			}
+		}
+	}
+	read_unlock(&dev_base_lock);
+
+	if (found_it == 0) {
+		fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 16, ifa);
+
+		if (dnet_addr_type(ifa->ifa_local) != RTN_LOCAL) {
+			if (dn_fib_sync_down(ifa->ifa_local, NULL, 0))
+				dn_fib_flush();
+		}
+	}
+}
+
+static void dn_fib_disable_addr(struct net_device *dev, int force)
+{
+	if (dn_fib_sync_down(0, dev, force))
+		dn_fib_flush();
+	dn_rt_cache_flush(0);
+	neigh_ifdown(&dn_neigh_table, dev);
+}
+
+static int dn_fib_dnaddr_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+	struct dn_ifaddr *ifa = (struct dn_ifaddr *)ptr;
+
+	switch(event) {
+		case NETDEV_UP:
+			dn_fib_add_ifaddr(ifa);
+			dn_fib_sync_up(ifa->ifa_dev->dev);
+			dn_rt_cache_flush(-1);
+			break;
+		case NETDEV_DOWN:
+			dn_fib_del_ifaddr(ifa);
+			if (ifa->ifa_dev && ifa->ifa_dev->ifa_list == NULL) {
+				dn_fib_disable_addr(ifa->ifa_dev->dev, 1);
+			} else {
+				dn_rt_cache_flush(-1);
+			}
+			break;
+	}
+	return NOTIFY_DONE;
+}
+
 int dn_fib_sync_down(dn_address local, struct net_device *dev, int force)
 {
         int ret = 0;
@@ -520,9 +724,11 @@
                                         dead++;
                                 else if (nh->nh_dev == dev &&
                                                 nh->nh_scope != scope) {
+					spin_lock_bh(&dn_fib_multipath_lock);
                                         nh->nh_flags |= RTNH_F_DEAD;
                                         fi->fib_power -= nh->nh_power;
                                         nh->nh_power = 0;
+					spin_unlock_bh(&dn_fib_multipath_lock);
                                         dead++;
                                 }
                         } endfor_nexthops(fi)
@@ -556,11 +762,13 @@
                         if (nh->nh_dev != dev || dev->dn_ptr == NULL)
                                 continue;
                         alive++;
+			spin_lock_bh(&dn_fib_multipath_lock);
                         nh->nh_power = 0;
                         nh->nh_flags &= ~RTNH_F_DEAD;
+			spin_unlock_bh(&dn_fib_multipath_lock);
                 } endfor_nexthops(fi);
 
-                if (alive == fi->fib_nhs) {
+                if (alive > 0) {
                         fi->fib_flags &= ~RTNH_F_DEAD;
                         ret++;
                 }
@@ -574,7 +782,7 @@
         struct dn_fib_table *tb;
         int id;
 
-        for(id = DN_NUM_TABLES; id > 0; id--) {
+        for(id = RT_TABLE_MAX; id > 0; id--) {
                 if ((tb = dn_fib_get_table(id, 0)) == NULL)
                         continue;
                 flushed += tb->flush(tb);
@@ -584,21 +792,6 @@
                 dn_rt_cache_flush(-1);
 }
 
-int dn_fib_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
-
-	if (!capable(CAP_NET_ADMIN))
-		return -EPERM;
-
-	switch(cmd) {
-		case SIOCADDRT:
-		case SIOCDELRT:
-			return 0;
-	}
-
-	return -EINVAL;
-}
-
 #ifdef CONFIG_PROC_FS
 
 static int decnet_rt_get_info(char *buffer, char **start, off_t offset, int length)
@@ -620,7 +813,7 @@
         }
 
 
-        for(i = DN_MIN_TABLE; (i <= DN_NUM_TABLES) && (count > 0); i++) {
+        for(i = RT_MIN_TABLE; (i <= RT_TABLE_MAX) && (count > 0); i++) {
                 if ((tb = dn_fib_get_table(i, 0)) != NULL) {
                         int n = tb->get_info(tb, ptr, first, count);
                         count -= n;
@@ -638,12 +831,18 @@
 }
 #endif /* CONFIG_PROC_FS */
 
+static struct notifier_block dn_fib_dnaddr_notifier = {
+	.notifier_call = dn_fib_dnaddr_event,
+};
+
 void __exit dn_fib_cleanup(void)
 {
 	proc_net_remove("decnet_route");
 
 	dn_fib_table_cleanup();
 	dn_fib_rules_cleanup();
+
+	unregister_dnaddr_notifier(&dn_fib_dnaddr_notifier);
 }
 
 
@@ -656,6 +855,8 @@
 
 	dn_fib_table_init();
 	dn_fib_rules_init();
+
+	register_dnaddr_notifier(&dn_fib_dnaddr_notifier);
 }
 
 
diff -urN linux-2.5.67-bk9/net/decnet/dn_neigh.c linux-2.5.67-bk10/net/decnet/dn_neigh.c
--- linux-2.5.67-bk9/net/decnet/dn_neigh.c	2003-04-07 10:31:58.000000000 -0700
+++ linux-2.5.67-bk10/net/decnet/dn_neigh.c	2003-04-19 04:35:43.000000000 -0700
@@ -20,6 +20,7 @@
  *     Steve Whitehouse     : Fixed neighbour states (for now anyway).
  *     Steve Whitehouse     : Made error_report functions dummies. This
  *                            is not the right place to return skbs.
+ *     Steve Whitehouse     : Convert to seq_file
  *
  */
 
@@ -33,9 +34,11 @@
 #include <linux/string.h>
 #include <linux/netfilter_decnet.h>
 #include <linux/spinlock.h>
+#include <linux/seq_file.h>
 #include <asm/atomic.h>
 #include <net/neighbour.h>
 #include <net/dst.h>
+#include <net/flow.h>
 #include <net/dn.h>
 #include <net/dn_dev.h>
 #include <net/dn_neigh.h>
@@ -160,7 +163,20 @@
 		return -EINVAL;
 	}
 
-	dn->blksize = 230;
+	/*
+	 * Make an estimate of the remote block size by assuming that its
+	 * two less then the device mtu, which it true for ethernet (and
+	 * other things which support long format headers) since there is
+	 * an extra length field (of 16 bits) which isn't part of the
+	 * ethernet headers and which the DECnet specs won't admit is part
+	 * of the DECnet routing headers either.
+	 *
+	 * If we over estimate here its no big deal, the NSP negotiations
+	 * will prevent us from sending packets which are too large for the
+	 * remote node to handle. In any case this figure is normally updated
+	 * by a hello message in most cases.
+	 */
+	dn->blksize = dev->mtu - 2;
 
 	return 0;
 }
@@ -330,7 +346,7 @@
  * basically does a neigh_lookup(), but without comparing the device
  * field. This is required for the On-Ethernet cache
  */
-struct neighbour *dn_neigh_lookup(struct neigh_table *tbl, void *ptr)
+struct neighbour *dn_neigh_lookup(struct neigh_table *tbl, const void *ptr)
 {
 	struct neighbour *neigh;
 	u32 hash_val;
@@ -466,8 +482,6 @@
 	return 0;
 }
 
-
-#ifdef CONFIG_DECNET_ROUTER
 static char *dn_find_slot(char *base, int max, int priority)
 {
 	int i;
@@ -526,78 +540,200 @@
 
 	return t;
 }
-#endif /* CONFIG_DECNET_ROUTER */
-
 
 
 #ifdef CONFIG_PROC_FS
-static int dn_neigh_get_info(char *buffer, char **start, off_t offset, int length)
+
+struct dn_neigh_iter_state {
+	int bucket;
+};
+
+static struct neighbour *neigh_get_first(struct seq_file *seq)
 {
-        int len     = 0;
-        off_t pos   = 0;
-        off_t begin = 0;
-	struct neighbour *n;
-	int i;
-	char buf[DN_ASCBUF_LEN];
+	struct dn_neigh_iter_state *state = seq->private;
+	struct neighbour *n = NULL;
+
+	for(state->bucket = 0;
+	    state->bucket <= NEIGH_HASHMASK;
+	    ++state->bucket) {
+		n = dn_neigh_table.hash_buckets[state->bucket];
+		if (n)
+			break;
+	}
 
-	len += sprintf(buffer + len, "Addr    Flags State Use Blksize Dev\n");
+	return n;
+}
 
-	for(i=0;i <= NEIGH_HASHMASK; i++) {
-		read_lock_bh(&dn_neigh_table.lock);
-		n = dn_neigh_table.hash_buckets[i];
-		for(; n != NULL; n = n->next) {
-			struct dn_neigh *dn = (struct dn_neigh *)n;
-
-			read_lock(&n->lock);
-			len += sprintf(buffer+len, "%-7s %s%s%s   %02x    %02d  %07ld %-8s\n",
-					dn_addr2asc(dn_ntohs(dn->addr), buf),
-					(dn->flags&DN_NDFLAG_R1) ? "1" : "-",
-					(dn->flags&DN_NDFLAG_R2) ? "2" : "-",
-					(dn->flags&DN_NDFLAG_P3) ? "3" : "-",
-					dn->n.nud_state,
-					atomic_read(&dn->n.refcnt),
-					dn->blksize,
-					(dn->n.dev) ? dn->n.dev->name : "?");
-			read_unlock(&n->lock);
-
-			pos = begin + len;
-
-                	if (pos < offset) {
-                        	len = 0;
-                        	begin = pos;
-                	}
-
-                	if (pos > offset + length) {
-				read_unlock_bh(&dn_neigh_table.lock);
-                       		goto done;
-			}
-		}
+static struct neighbour *neigh_get_next(struct seq_file *seq,
+					struct neighbour *n)
+{
+	struct dn_neigh_iter_state *state = seq->private;
+
+	n = n->next;
+try_again:
+	if (n)
+		goto out;
+	if (++state->bucket > NEIGH_HASHMASK)
+		goto out;
+	n = dn_neigh_table.hash_buckets[state->bucket];
+	goto try_again;
+out:
+	return n;
+}
+
+static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos)
+{
+	struct neighbour *n = neigh_get_first(seq);
+
+	if (n)
+		while(*pos && (n = neigh_get_next(seq, n)))
+			--*pos;
+	return *pos ? NULL : n;
+}
+
+static void *dn_neigh_get_idx(struct seq_file *seq, loff_t pos)
+{
+	void *rc;
+	read_lock_bh(&dn_neigh_table.lock);
+	rc = neigh_get_idx(seq, &pos);
+	if (!rc) {
 		read_unlock_bh(&dn_neigh_table.lock);
 	}
+	return rc;
+}
 
-done:
+static void *dn_neigh_seq_start(struct seq_file *seq, loff_t *pos)
+{
+	return *pos ? dn_neigh_get_idx(seq, *pos - 1) : (void*)1;
+}
+
+static void *dn_neigh_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	void *rc;
 
-        *start = buffer + (offset - begin);
-        len   -= offset - begin;
 
-        if (len > length) len = length;
+	if (v == (void*)1) {
+		rc = dn_neigh_get_idx(seq, 0);
+		goto out;
+	}
 
-        return len;
+	rc = neigh_get_next(seq, v);
+	if (rc)
+		goto out;
+	read_unlock_bh(&dn_neigh_table.lock);
+out:
+	++*pos;
+	return rc;
+}
+
+static void dn_neigh_seq_stop(struct seq_file *seq, void *v)
+{
+	if (v && v != (void*)1)
+		read_unlock_bh(&dn_neigh_table.lock);
 }
 
+static inline void dn_neigh_format_entry(struct seq_file *seq,
+					 struct neighbour *n)
+{
+	struct dn_neigh *dn = (struct dn_neigh *)n;
+	char buf[DN_ASCBUF_LEN];
+
+	read_lock(&n->lock);
+	seq_printf(seq, "%-7s %s%s%s   %02x    %02d  %07ld %-8s\n",
+		   dn_addr2asc(dn_ntohs(dn->addr), buf),
+		   (dn->flags&DN_NDFLAG_R1) ? "1" : "-",
+		   (dn->flags&DN_NDFLAG_R2) ? "2" : "-",
+		   (dn->flags&DN_NDFLAG_P3) ? "3" : "-",
+		   dn->n.nud_state,
+		   atomic_read(&dn->n.refcnt),
+		   dn->blksize,
+		   (dn->n.dev) ? dn->n.dev->name : "?");
+	read_unlock(&n->lock);
+}
+
+static int dn_neigh_seq_show(struct seq_file *seq, void *v)
+{
+	if (v == (void*)1) {
+		seq_puts(seq, "Addr    Flags State Use Blksize Dev\n");
+	} else {
+		dn_neigh_format_entry(seq, v);
+	}
+
+	return 0;
+}
+
+static struct seq_operations dn_neigh_seq_ops = {
+	.start = dn_neigh_seq_start,
+	.next  = dn_neigh_seq_next,
+	.stop  = dn_neigh_seq_stop,
+	.show  = dn_neigh_seq_show,
+};
+
+static int dn_neigh_seq_open(struct inode *inode, struct file *file)
+{
+	struct seq_file *seq;
+	int rc = -ENOMEM;
+	struct dn_neigh_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
+
+	if (!s)
+		goto out;
+
+	rc = seq_open(file, &dn_neigh_seq_ops);
+	if (rc)
+		goto out_kfree;
+
+	seq          = file->private_data;
+	seq->private = s;
+	memset(s, 0, sizeof(*s));
+out:
+	return rc;
+out_kfree:
+	kfree(s);
+	goto out;
+}
+
+static int dn_seq_release(struct inode *inode, struct file *file)
+{
+	struct seq_file *seq  = (struct seq_file *)file->private_data;
+
+	kfree(seq->private);
+	seq->private = NULL;
+	return seq_release(inode, file);
+}
+
+static struct file_operations dn_neigh_seq_fops = {
+	.open		= dn_neigh_seq_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= dn_seq_release,
+};
+
+static int __init dn_neigh_proc_init(void)
+{
+	int rc = 0;
+	struct proc_dir_entry *p = create_proc_entry("decnet_neigh", S_IRUGO, proc_net);
+	if (p)
+		p->proc_fops = &dn_neigh_seq_fops;
+	else
+		rc = -ENOMEM;
+	return rc;
+}
+
+#else
+static int __init dn_neigh_proc_init(void)
+{
+	return 0;
+}
 #endif
 
 void __init dn_neigh_init(void)
 {
 	neigh_table_init(&dn_neigh_table);
 
-#ifdef CONFIG_PROC_FS
-	proc_net_create("decnet_neigh",0,dn_neigh_get_info);
-#endif /* CONFIG_PROC_FS */
+	dn_neigh_proc_init();
 }
 
 void __exit dn_neigh_cleanup(void)
 {
-	proc_net_remove("decnet_neigh");
 	neigh_table_clear(&dn_neigh_table);
 }
diff -urN linux-2.5.67-bk9/net/decnet/dn_nsp_in.c linux-2.5.67-bk10/net/decnet/dn_nsp_in.c
--- linux-2.5.67-bk9/net/decnet/dn_nsp_in.c	2003-04-07 10:31:02.000000000 -0700
+++ linux-2.5.67-bk10/net/decnet/dn_nsp_in.c	2003-04-19 04:35:43.000000000 -0700
@@ -434,7 +434,15 @@
 		sk->state_change(sk);
 	}
 
-	dn_nsp_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC, GFP_ATOMIC);
+	/* 
+	 * It appears that its possible for remote machines to send disc
+	 * init messages with no port identifier if we are in the CI and
+	 * possibly also the CD state. Obviously we shouldn't reply with
+	 * a message if we don't know what the end point is.
+	 */
+	if (scp->addrrem) {
+		dn_nsp_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC, GFP_ATOMIC);
+	}
 	scp->persist_fxn = dn_destroy_timer;
 	scp->persist = dn_nsp_persist(sk);
 
diff -urN linux-2.5.67-bk9/net/decnet/dn_nsp_out.c linux-2.5.67-bk10/net/decnet/dn_nsp_out.c
--- linux-2.5.67-bk9/net/decnet/dn_nsp_out.c	2003-04-07 10:32:54.000000000 -0700
+++ linux-2.5.67-bk10/net/decnet/dn_nsp_out.c	2003-04-19 04:35:43.000000000 -0700
@@ -21,6 +21,7 @@
  *         Paul Koning:  Connect Confirm message fix.
  *      Eduardo Serrat:  Fix to stop dn_nsp_do_disc() sending malformed packets.
  *    Steve Whitehouse:  dn_nsp_output() and friends needed a spring clean
+ *    Steve Whitehouse:  Moved dn_nsp_send() in here from route.h
  */
 
 /******************************************************************************
@@ -63,6 +64,7 @@
 #include <linux/if_packet.h>
 #include <net/neighbour.h>
 #include <net/dst.h>
+#include <net/flow.h>
 #include <net/dn.h>
 #include <net/dn_nsp.h>
 #include <net/dn_dev.h>
@@ -71,6 +73,41 @@
 
 static int nsp_backoff[NSP_MAXRXTSHIFT + 1] = { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 };
 
+static void dn_nsp_send(struct sk_buff *skb)
+{
+	struct sock *sk = skb->sk;
+	struct dn_scp *scp = DN_SK(sk);
+	struct dst_entry *dst;
+	struct flowi fl;
+
+	skb->h.raw = skb->data;
+	scp->stamp = jiffies;
+
+	dst = sk_dst_check(sk, 0);
+	if (dst) {
+try_again:
+		skb->dst = dst;
+		dst_output(skb);
+		return;
+	}
+
+	memset(&fl, 0, sizeof(fl));
+	fl.oif = sk->bound_dev_if;
+	fl.fld_src = dn_saddr2dn(&scp->addr);
+	fl.fld_dst = dn_saddr2dn(&scp->peer);
+	dn_sk_ports_copy(&fl, scp);
+	if (dn_route_output_sock(&sk->dst_cache, &fl, sk, 0) == 0) {
+		dst = sk_dst_get(sk);
+		sk->route_caps = dst->dev->features;
+		goto try_again;
+	}
+
+	sk->err = EHOSTUNREACH;
+	if (!test_bit(SOCK_DEAD, &sk->flags))
+		sk->state_change(sk);
+}
+
+
 /*
  * If sk == NULL, then we assume that we are supposed to be making
  * a routing layer skb. If sk != NULL, then we are supposed to be
@@ -356,12 +393,33 @@
 	return ptr;
 }
 
+static unsigned short *dn_nsp_mk_data_header(struct sock *sk, struct sk_buff *skb, int oth)
+{
+	struct dn_scp *scp = DN_SK(sk);
+	struct dn_skb_cb *cb = DN_SKB_CB(skb);
+	unsigned short *ptr = dn_mk_ack_header(sk, skb, cb->nsp_flags, 11, oth);
+
+	if (unlikely(oth)) {
+		cb->segnum = scp->numoth;
+		seq_add(&scp->numoth, 1);
+	} else {
+		cb->segnum = scp->numdat;
+		seq_add(&scp->numdat, 1);
+	}
+	*(ptr++) = dn_htons(cb->segnum);
+
+	return ptr;
+}
+
 void dn_nsp_queue_xmit(struct sock *sk, struct sk_buff *skb, int gfp, int oth)
 {
 	struct dn_scp *scp = DN_SK(sk);
 	struct dn_skb_cb *cb = DN_SKB_CB(skb);
 	unsigned long t = ((scp->nsp_srtt >> 2) + scp->nsp_rttvar) >> 1;
 
+	cb->xmit_count = 0;
+	dn_nsp_mk_data_header(sk, skb, oth);
+
 	/*
 	 * Slow start: If we have been idle for more than
 	 * one RTT, then reset window to min size.
@@ -369,10 +427,6 @@
 	if ((jiffies - scp->stamp) > t)
 		scp->snd_window = NSP_MIN_WINDOW;
 
-	/* printk(KERN_DEBUG "Window: %lu\n", scp->snd_window); */
-
-	cb->xmit_count = 0;
-
 	if (oth)
 		skb_queue_tail(&scp->other_xmit_queue, skb);
 	else
@@ -630,19 +684,15 @@
 {
 	struct dn_scp *scp = DN_SK(sk);
 	struct sk_buff *skb;
-	unsigned short *segnum;
 	unsigned char *ptr;
 	int gfp = GFP_ATOMIC;
 
-	if ((skb = dn_alloc_skb(sk, 13, gfp)) == NULL)
+	if ((skb = dn_alloc_skb(sk, DN_MAX_NSP_DATA_HEADER + 2, gfp)) == NULL)
 		return;
 
-	skb_reserve(skb, 13);
-	segnum = dn_mk_ack_header(sk, skb, 0x10, 13, 1);
-	*segnum = dn_htons(scp->numoth);
-        DN_SKB_CB(skb)->segnum = scp->numoth;
-	seq_add(&scp->numoth, 1);
-	ptr = (unsigned char *)(segnum + 1);
+	skb_reserve(skb, DN_MAX_NSP_DATA_HEADER);
+	ptr = skb_put(skb, 2);
+	DN_SKB_CB(skb)->nsp_flags = 0x10;
 	*ptr++ = lsflags;
 	*ptr = fcval;
 
diff -urN linux-2.5.67-bk9/net/decnet/dn_route.c linux-2.5.67-bk10/net/decnet/dn_route.c
--- linux-2.5.67-bk9/net/decnet/dn_route.c	2003-04-07 10:32:51.000000000 -0700
+++ linux-2.5.67-bk10/net/decnet/dn_route.c	2003-04-19 04:35:43.000000000 -0700
@@ -37,7 +37,8 @@
  *                                 backlog congestion level return codes.
  *		Steve Whitehouse : Fixed bug where routes were set up with
  *                                 no ref count on net devices.
- *                                 
+ *              Steve Whitehouse : RCU for the route cache
+ *              Steve Whitehouse : Preparations for the flow cache
  */
 
 /******************************************************************************
@@ -65,17 +66,19 @@
 #include <linux/netdevice.h>
 #include <linux/inet.h>
 #include <linux/route.h>
+#include <linux/in_route.h>
 #include <net/sock.h>
-#include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/proc_fs.h>
 #include <linux/init.h>
 #include <linux/rtnetlink.h>
 #include <linux/string.h>
 #include <linux/netfilter_decnet.h>
+#include <linux/rcupdate.h>
 #include <asm/errno.h>
 #include <net/neighbour.h>
 #include <net/dst.h>
+#include <net/flow.h>
 #include <net/dn.h>
 #include <net/dn_dev.h>
 #include <net/dn_nsp.h>
@@ -86,7 +89,7 @@
 struct dn_rt_hash_bucket
 {
 	struct dn_route *chain;
-	rwlock_t lock;
+	spinlock_t lock;
 } __attribute__((__aligned__(8)));
 
 extern struct neigh_table dn_neigh_table;
@@ -134,6 +137,18 @@
 	return dn_rt_hash_mask & (unsigned)tmp;
 }
 
+static inline void dnrt_free(struct dn_route *rt)
+{
+	call_rcu(&rt->u.dst.rcu_head, (void (*)(void *))dst_free, &rt->u.dst);
+}
+
+static inline void dnrt_drop(struct dn_route *rt)
+{
+	if (rt)
+		dst_release(&rt->u.dst);
+	call_rcu(&rt->u.dst.rcu_head, (void (*)(void *))dst_free, &rt->u.dst);
+}
+
 static void SMP_TIMER_NAME(dn_dst_check_expire)(unsigned long dummy)
 {
 	int i;
@@ -144,7 +159,7 @@
 	for(i = 0; i <= dn_rt_hash_mask; i++) {
 		rtp = &dn_rt_hash_table[i].chain;
 
-		write_lock(&dn_rt_hash_table[i].lock);
+		spin_lock(&dn_rt_hash_table[i].lock);
 		while((rt=*rtp) != NULL) {
 			if (atomic_read(&rt->u.dst.__refcnt) ||
 					(now - rt->u.dst.lastuse) < expire) {
@@ -153,9 +168,9 @@
 			}
 			*rtp = rt->u.rt_next;
 			rt->u.rt_next = NULL;
-			dst_free(&rt->u.dst);
+			dnrt_free(rt);
 		}
-		write_unlock(&dn_rt_hash_table[i].lock);
+		spin_unlock(&dn_rt_hash_table[i].lock);
 
 		if ((jiffies - now) > 0)
 			break;
@@ -175,7 +190,7 @@
 
 	for(i = 0; i <= dn_rt_hash_mask; i++) {
 
-		write_lock_bh(&dn_rt_hash_table[i].lock);
+		spin_lock_bh(&dn_rt_hash_table[i].lock);
 		rtp = &dn_rt_hash_table[i].chain;
 
 		while((rt=*rtp) != NULL) {
@@ -186,10 +201,10 @@
 			}
 			*rtp = rt->u.rt_next;
 			rt->u.rt_next = NULL;
-			dst_free(&rt->u.dst);
+			dnrt_drop(rt);
 			break;
 		}
-		write_unlock_bh(&dn_rt_hash_table[i].lock);
+		spin_unlock_bh(&dn_rt_hash_table[i].lock);
 	}
 
 	return 0;
@@ -216,19 +231,53 @@
 	return;
 }
 
-static void dn_insert_route(struct dn_route *rt, unsigned hash)
+static inline int compare_keys(struct flowi *fl1, struct flowi *fl2)
 {
+	return memcmp(&fl1->nl_u.dn_u, &fl2->nl_u.dn_u, sizeof(fl1->nl_u.dn_u)) == 0 &&
+		fl1->oif == fl2->oif &&
+		fl1->iif == fl2->iif;
+}
+
+static int dn_insert_route(struct dn_route *rt, unsigned hash, struct dn_route **rp)
+{
+	struct dn_route *rth, **rthp;
 	unsigned long now = jiffies;
 
-	write_lock_bh(&dn_rt_hash_table[hash].lock);
+	rthp = &dn_rt_hash_table[hash].chain;
+
+	spin_lock_bh(&dn_rt_hash_table[hash].lock);
+	while((rth = *rthp) != NULL) {
+		if (compare_keys(&rth->fl, &rt->fl)) {
+			/* Put it first */
+			*rthp = rth->u.rt_next;
+			smp_wmb();
+			rth->u.rt_next = dn_rt_hash_table[hash].chain;
+			smp_wmb();
+			dn_rt_hash_table[hash].chain = rth;
+
+			rth->u.dst.__use++;
+			dst_hold(&rth->u.dst);
+			rth->u.dst.lastuse = now;
+			spin_unlock_bh(&dn_rt_hash_table[hash].lock);
+
+			dnrt_drop(rt);
+			*rp = rth;
+			return 0;
+		}
+		rthp = &rth->u.rt_next;
+	}
+
+	smp_wmb();
 	rt->u.rt_next = dn_rt_hash_table[hash].chain;
+	smp_wmb();
 	dn_rt_hash_table[hash].chain = rt;
 	
 	dst_hold(&rt->u.dst);
 	rt->u.dst.__use++;
 	rt->u.dst.lastuse = now;
-
-	write_unlock_bh(&dn_rt_hash_table[hash].lock);
+	spin_unlock_bh(&dn_rt_hash_table[hash].lock);
+	*rp = rt;
+	return 0;
 }
 
 void SMP_TIMER_NAME(dn_run_flush)(unsigned long dummy)
@@ -237,7 +286,7 @@
 	struct dn_route *rt, *next;
 
 	for(i = 0; i < dn_rt_hash_mask; i++) {
-		write_lock_bh(&dn_rt_hash_table[i].lock);
+		spin_lock_bh(&dn_rt_hash_table[i].lock);
 
 		if ((rt = xchg(&dn_rt_hash_table[i].chain, NULL)) == NULL)
 			goto nothing_to_declare;
@@ -249,7 +298,7 @@
 		}
 
 nothing_to_declare:
-		write_unlock_bh(&dn_rt_hash_table[i].lock);
+		spin_unlock_bh(&dn_rt_hash_table[i].lock);
 	}
 }
 
@@ -628,51 +677,50 @@
 	return err;
 }
 
-#ifdef CONFIG_DECNET_ROUTER
 static int dn_forward(struct sk_buff *skb)
 {
 	struct dn_skb_cb *cb = DN_SKB_CB(skb);
 	struct dst_entry *dst = skb->dst;
-	struct neighbour *neigh;
+	struct dn_dev *dn_db = dst->dev->dn_ptr;
+	struct dn_route *rt;
+	struct neighbour *neigh = dst->neighbour;
+	int header_len;
 #ifdef CONFIG_NETFILTER
 	struct net_device *dev = skb->dev;
 #endif
-	int err = -EINVAL;
 
-	if ((neigh = dst->neighbour) == NULL)
-		goto error;
+	if (skb->pkt_type != PACKET_HOST)
+		goto drop;
+
+	/* Ensure that we have enough space for headers */
+	rt = (struct dn_route *)skb->dst;
+	header_len = dn_db->use_long ? 21 : 6;
+	if (skb_cow(skb, LL_RESERVED_SPACE(rt->u.dst.dev)+header_len))
+		goto drop;
 
 	/*
 	 * Hop count exceeded.
 	 */
-	err = NET_RX_DROP;
 	if (++cb->hops > 30)
 		goto drop;
 
-	skb->dev = dst->dev;
+	skb->dev = rt->u.dst.dev;
 
 	/*
 	 * If packet goes out same interface it came in on, then set
 	 * the Intra-Ethernet bit. This has no effect for short
 	 * packets, so we don't need to test for them here.
 	 */
-	if (cb->iif == dst->dev->ifindex)
+	cb->rt_flags &= ~DN_RT_F_IE;
+	if (rt->rt_flags | RTCF_DOREDIRECT)
 		cb->rt_flags |= DN_RT_F_IE;
-	else
-		cb->rt_flags &= ~DN_RT_F_IE;
 
 	return NF_HOOK(PF_DECnet, NF_DN_FORWARD, skb, dev, skb->dev, neigh->output);
 
-
-error:
-	if (net_ratelimit())
-		printk(KERN_DEBUG "dn_forward: This should not happen\n");
 drop:
 	kfree_skb(skb);
-
-	return err;
+	return NET_RX_DROP;
 }
-#endif
 
 /*
  * Drop packet. This is used for endnodes and for
@@ -703,182 +751,450 @@
 	return NET_RX_BAD;
 }
 
-static int dn_route_output_slow(struct dst_entry **pprt, dn_address dst, dn_address src, int flags)
+static int dn_rt_set_next_hop(struct dn_route *rt, struct dn_fib_res *res)
 {
+	struct dn_fib_info *fi = res->fi;
+	struct net_device *dev = rt->u.dst.dev;
+	struct neighbour *n;
+	unsigned mss;
+
+	if (fi) {
+		if (DN_FIB_RES_GW(*res) &&
+		    DN_FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
+			rt->rt_gateway = DN_FIB_RES_GW(*res);
+		memcpy(rt->u.dst.metrics, fi->fib_metrics,
+		       sizeof(rt->u.dst.metrics));
+	}
+	rt->rt_type = res->type;
+
+	if (dev != NULL && rt->u.dst.neighbour == NULL) {
+		n = __neigh_lookup_errno(&dn_neigh_table, &rt->rt_gateway, dev);
+		if (IS_ERR(n))
+			return PTR_ERR(n);
+		rt->u.dst.neighbour = n;
+	}
+
+	if (rt->u.dst.metrics[RTAX_MTU-1] == 0 || 
+            rt->u.dst.metrics[RTAX_MTU-1] > rt->u.dst.dev->mtu)
+		rt->u.dst.metrics[RTAX_MTU-1] = rt->u.dst.dev->mtu;
+	mss = dn_mss_from_pmtu(dev, dst_pmtu(&rt->u.dst));
+	if (rt->u.dst.metrics[RTAX_ADVMSS-1] == 0 ||
+	    rt->u.dst.metrics[RTAX_ADVMSS-1] > mss)
+		rt->u.dst.metrics[RTAX_ADVMSS-1] = mss;
+	return 0;
+}
+
+static inline int dn_match_addr(__u16 addr1, __u16 addr2)
+{
+	__u16 tmp = dn_ntohs(addr1) ^ dn_ntohs(addr2);
+	int match = 16;
+	while(tmp)
+		tmp >>= 1, match--;
+	return match;
+}
+
+static __u16 dnet_select_source(const struct net_device *dev, __u16 daddr, int scope)
+{
+	__u16 saddr = 0;
+	struct dn_dev *dn_db = dev->dn_ptr;
+	struct dn_ifaddr *ifa;
+	int best_match = 0;
+	int ret;
+
+	read_lock(&dev_base_lock);
+	for(ifa = dn_db->ifa_list; ifa; ifa = ifa->ifa_next) {
+		if (ifa->ifa_scope > scope)
+			continue;
+		if (!daddr) {
+			saddr = ifa->ifa_local;
+			break;
+		}
+		ret = dn_match_addr(daddr, ifa->ifa_local);
+		if (ret > best_match)
+			saddr = ifa->ifa_local;
+		if (best_match == 0)
+			saddr = ifa->ifa_local;
+	}
+	read_unlock(&dev_base_lock);
+
+	return saddr;
+}
+
+static inline __u16 __dn_fib_res_prefsrc(struct dn_fib_res *res)
+{
+	return dnet_select_source(DN_FIB_RES_DEV(*res), DN_FIB_RES_GW(*res), res->scope);
+}
+
+static inline __u16 dn_fib_rules_map_destination(__u16 daddr, struct dn_fib_res *res)
+{
+	__u16 mask = dnet_make_mask(res->prefixlen);
+	return (daddr&~mask)|res->fi->fib_nh->nh_gw;
+}
+
+static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *oldflp, int try_hard)
+{
+	struct flowi fl = { .nl_u = { .dn_u = 
+				      { .daddr = oldflp->fld_dst,
+					.saddr = oldflp->fld_src,
+					.scope = RT_SCOPE_UNIVERSE,
+#ifdef CONFIG_DECNET_ROUTE_FWMARK
+					.fwmark = oldflp->fld_fwmark
+#endif
+				     } },
+			    .iif = loopback_dev.ifindex,
+			    .oif = oldflp->oif };
 	struct dn_route *rt = NULL;
-	struct net_device *dev = NULL;
+	struct net_device *dev_out = NULL;
 	struct neighbour *neigh = NULL;
-	struct dn_dev *dn_db;
 	unsigned hash;
-
-#ifdef CONFIG_DECNET_ROUTER
-	struct dn_fib_key key;
-	struct dn_fib_res res;
+	unsigned flags = 0;
+	struct dn_fib_res res = { .fi = NULL, .type = RTN_UNICAST };
 	int err;
+	int free_res = 0;
+	__u16 gateway = 0;
 
-	key.src = src;
-	key.dst = dst;
-	key.iif = 0;
-	key.oif = 0;
-	key.fwmark = 0;
-	key.scope = RT_SCOPE_UNIVERSE;
-
-	if ((err = dn_fib_lookup(&key, &res)) == 0) {
-		switch(res.type) {
-			case RTN_UNICAST:
-				/*
-				 * This method of handling multipath
-				 * routes is a hack and will change.
-				 * It works for now though.
-				 */
-				if (res.fi->fib_nhs)
-					dn_fib_select_multipath(&key, &res);
-				neigh = __neigh_lookup(&dn_neigh_table, &DN_FIB_RES_GW(res), DN_FIB_RES_DEV(res), 1);
-				err = -ENOBUFS;
-				if (!neigh)
-					break;
-				err = 0;
-				break;
-			case RTN_UNREACHABLE:
-				err = -EHOSTUNREACH;
-				break;
-			default:
-				err = -EINVAL;
+	if (decnet_debug_level & 16)
+		printk(KERN_DEBUG
+		       "dn_route_output_slow: dst=%04x src=%04x mark=%d"
+		       " iif=%d oif=%d\n", oldflp->fld_dst, oldflp->fld_src,
+                       oldflp->fld_fwmark, loopback_dev.ifindex, oldflp->oif);
+
+	/* If we have an output interface, verify its a DECnet device */
+	if (oldflp->oif) {
+		dev_out = dev_get_by_index(oldflp->oif);
+		err = -ENODEV;
+		if (dev_out && dev_out->dn_ptr == NULL) {
+			dev_put(dev_out);
+			dev_out = NULL;
 		}
-		dn_fib_res_put(&res);
-		if (err < 0)
-			return err;
-		goto got_route;
+		if (dev_out == NULL)
+			goto out;
 	}
 
-	if (err != -ESRCH)
-		return err;
-#endif 
+	/* If we have a source address, verify that its a local address */
+	if (oldflp->fld_src) {
+		err = -EADDRNOTAVAIL;
+
+		if (dev_out) {
+			if (dn_dev_islocal(dev_out, oldflp->fld_src))
+				goto source_ok;
+			dev_put(dev_out);
+			goto out;
+		}
+		read_lock(&dev_base_lock);
+		for(dev_out = dev_base; dev_out; dev_out = dev_out->next) {
+			if (!dev_out->dn_ptr)
+				continue;
+			if (dn_dev_islocal(dev_out, oldflp->fld_src))
+				break;
+		}
+		read_unlock(&dev_base_lock);
+		if (dev_out == NULL)
+			goto out;
+		dev_hold(dev_out);
+source_ok:
+	}
 
-	/* Look in On-Ethernet cache first */
-	if (!(flags & MSG_TRYHARD)) {
-		if ((neigh = dn_neigh_lookup(&dn_neigh_table, &dst)) != NULL)
-			goto got_route;
+	/* No destination? Assume its local */
+	if (!fl.fld_dst) {
+		fl.fld_dst = fl.fld_src;
+#if 0
+		if (!fl.fld_dst)
+			/* grab an address from loopback? */
+#endif
+		err = -EADDRNOTAVAIL;
+		if (dev_out)
+			dev_put(dev_out);
+		if (!fl.fld_dst)
+			goto out;
+		dev_out = &loopback_dev;
+		dev_hold(dev_out);
+		fl.oif = loopback_dev.ifindex;
+		res.type = RTN_LOCAL;
+		goto make_route;
 	}
 
-	dev = dn_dev_get_default();
-	if (dev == NULL)
-		return -EINVAL;
+	if (decnet_debug_level & 16)
+		printk(KERN_DEBUG
+		       "dn_route_output_slow: initial checks complete."
+		       " dst=%o4x src=%04x oif=%d try_hard=%d\n", fl.fld_dst,
+		       fl.fld_src, fl.oif, try_hard);
 
-	dn_db = dev->dn_ptr;
+	/*
+	 * N.B. If the kernel is compiled without router support then
+	 * dn_fib_lookup() will evaluate to non-zero so this if () block
+	 * will always be executed.
+	 */
+	err = -ESRCH;
+	if (try_hard || (err = dn_fib_lookup(&fl, &res)) != 0) {
+		struct dn_dev *dn_db;
+		if (err != -ESRCH)
+			goto out;
+		/*
+	 	 * Here the fallback is basically the standard algorithm for 
+		 * routing in endnodes which is described in the DECnet routing
+		 * docs
+		 *
+		 * If we are not trying hard, look in neighbour cache.
+		 * The result is tested to ensure that if a specific output
+		 * device/source address was requested, then we honour that 
+		 * here
+		 */
+		if (!try_hard) {
+			neigh = dn_neigh_lookup(&dn_neigh_table, &fl.fld_dst);
+			if (neigh) {
+				if ((oldflp->oif && 
+				    (neigh->dev->ifindex != oldflp->oif)) ||
+				    (oldflp->fld_src &&
+				    (!dn_dev_islocal(neigh->dev,
+						      oldflp->fld_src)))) {
+					neigh_release(neigh);
+					neigh = NULL;
+				} else {
+					if (dev_out)
+						dev_put(dev_out);
+					if (dn_dev_islocal(neigh->dev, fl.fld_dst)) {
+						dev_out = &loopback_dev;
+						res.type = RTN_LOCAL;
+					} else {
+						dev_out = neigh->dev;
+					}
+					dev_hold(dev_out);
+					goto select_source;
+				}
+			}
+		}
 
-	/* Check to see if its one of our own local addresses */
-	if (dn_dev_islocal(dev, dst)) {
-		struct net_device *lo = &loopback_dev;
-		if (lo->dn_ptr) {
-			neigh = __neigh_lookup(&dn_neigh_table, &dst, lo, 1);
-			if (neigh)
-				goto got_route;
-		}
-		if (net_ratelimit())
-			printk("dn_route_output_slow: Dest is local interface address, but loopback device is not up\n");
-		dev_put(dev);
-		return -EINVAL;
+		/* Not there? Perhaps its a local address */
+		if (dev_out == NULL)
+			dev_out = dn_dev_get_default();
+		err = -ENODEV;
+		if (dev_out == NULL)
+			goto out;
+		dn_db = dev_out->dn_ptr;
+		/* Possible improvement - check all devices for local addr */
+		if (dn_dev_islocal(dev_out, fl.fld_dst)) {
+			dev_put(dev_out);
+			dev_out = &loopback_dev;
+			dev_hold(dev_out);
+			res.type = RTN_LOCAL;
+			goto select_source;
+		}
+		/* Not local either.... try sending it to the default router */
+		neigh = neigh_clone(dn_db->router);
+		BUG_ON(neigh && neigh->dev != dev_out);
+
+		/* Ok then, we assume its directly connected and move on */
+select_source:
+		if (neigh)
+			gateway = ((struct dn_neigh *)neigh)->addr;
+		if (gateway == 0)
+			gateway = fl.fld_dst;
+		if (fl.fld_src == 0) {
+			fl.fld_src = dnet_select_source(dev_out, gateway,
+							 res.type == RTN_LOCAL ?
+							 RT_SCOPE_HOST : 
+							 RT_SCOPE_LINK);
+			if (fl.fld_src == 0 && res.type != RTN_LOCAL)
+				goto e_addr;
+		}
+		fl.oif = dev_out->ifindex;
+		goto make_route;
 	}
+	free_res = 1;
 
-	/* Try default router */
-	if ((neigh = neigh_clone(dn_db->router)) != NULL)
-		goto got_route;
-
-	/* Send to default device (and hope for the best) if above fail */
-	if ((neigh = __neigh_lookup(&dn_neigh_table, &dst, dev, 1)) != NULL)
-		goto got_route;
-
-	dev_put(dev);
-	return -EINVAL;
-
-got_route:
-	if (dev)
-		dev_put(dev);
+	if (res.type == RTN_NAT)
+		goto e_inval;
 
-	if ((rt = dst_alloc(&dn_dst_ops)) == NULL) {
-		neigh_release(neigh);
-		return -EINVAL;
-	}
+	if (res.type == RTN_LOCAL) {
+		if (!fl.fld_src)
+			fl.fld_src = fl.fld_dst;
+		if (dev_out)
+			dev_put(dev_out);
+		dev_out = &loopback_dev;
+		dev_hold(dev_out);
+		fl.oif = dev_out->ifindex;
+		if (res.fi)
+			dn_fib_info_put(res.fi);
+		res.fi = NULL;
+		goto make_route;
+	}
+
+	if (res.fi->fib_nhs > 1 && fl.oif == 0)
+		dn_fib_select_multipath(&fl, &res);
+
+	/* 
+	 * We could add some logic to deal with default routes here and
+	 * get rid of some of the special casing above.
+	 */
 
-	dn_db = (struct dn_dev *)neigh->dev->dn_ptr;
+	if (!fl.fld_src)
+		fl.fld_src = DN_FIB_RES_PREFSRC(res);
 	
-	rt->key.saddr  = src;
-	rt->rt_saddr   = src;
-	rt->key.daddr  = dst;
-	rt->rt_daddr   = dst;
-	rt->key.oif    = neigh ? neigh->dev->ifindex : -1;
-	rt->key.iif    = 0;
-	rt->key.fwmark = 0;
+	if (dev_out)
+		dev_put(dev_out);
+	dev_out = DN_FIB_RES_DEV(res);
+	dev_hold(dev_out);
+	fl.oif = dev_out->ifindex;
+	gateway = DN_FIB_RES_GW(res);
+
+make_route:
+	if (dev_out->flags & IFF_LOOPBACK)
+		flags |= RTCF_LOCAL;
+
+	rt = dst_alloc(&dn_dst_ops);
+	if (rt == NULL)
+		goto e_nobufs;
+
+	atomic_set(&rt->u.dst.__refcnt, 1);
+	rt->u.dst.flags   = DST_HOST;
+
+	rt->fl.fld_src    = oldflp->fld_src;
+	rt->fl.fld_dst    = oldflp->fld_dst;
+	rt->fl.oif        = oldflp->oif;
+	rt->fl.iif        = 0;
+#ifdef CONFIG_DECNET_ROUTE_FWMARK
+	rt->fl.fld_fwmark = flp->fld_fwmark;
+#endif
+
+	rt->rt_saddr      = fl.fld_src;
+	rt->rt_daddr      = fl.fld_dst;
+	rt->rt_gateway    = gateway ? gateway : fl.fld_dst;
+
+	rt->rt_dst_map    = fl.fld_dst;
+	rt->rt_src_map    = fl.fld_src;
 
+	rt->u.dst.dev = dev_out;
+	dev_hold(dev_out);
 	rt->u.dst.neighbour = neigh;
-	rt->u.dst.dev = neigh ? neigh->dev : NULL;
-	if (rt->u.dst.dev)
-		dev_hold(rt->u.dst.dev);
-	rt->u.dst.lastuse = jiffies;
-	rt->u.dst.output = dn_output;
-	rt->u.dst.input  = dn_rt_bug;
+	neigh = NULL;
 
-	if (neigh->dev->flags & IFF_LOOPBACK)
-		rt->u.dst.input = dn_nsp_rx;
+	rt->u.dst.lastuse = jiffies;
+	rt->u.dst.output  = dn_output;
+	rt->u.dst.input   = dn_rt_bug;
+	rt->rt_flags      = flags;
+	if (flags & RTCF_LOCAL)
+		rt->u.dst.output = dn_nsp_rx;
+
+	if (dn_rt_set_next_hop(rt, &res))
+		goto e_neighbour;
+
+	hash = dn_hash(rt->fl.fld_src, rt->fl.fld_dst);
+	dn_insert_route(rt, hash, (struct dn_route **)pprt);
+	err = 0;
 
-	hash = dn_hash(rt->key.saddr, rt->key.daddr);
-	dn_insert_route(rt, hash);
-	*pprt = &rt->u.dst;
+done:
+	if (neigh)
+		neigh_release(neigh);
+	if (free_res)
+		dn_fib_res_put(&res);
+	if (dev_out)
+		dev_put(dev_out);
+out:
+	return err;
 
-	return 0;
+e_addr:
+        err = -EADDRNOTAVAIL;
+        goto done;
+e_inval:
+	err = -EINVAL;
+	goto done;
+e_nobufs:
+	err = -ENOBUFS;
+	goto done;
+e_neighbour:
+	dst_free(&rt->u.dst);
+	goto e_nobufs;
 }
 
-int dn_route_output(struct dst_entry **pprt, dn_address dst, dn_address src, int flags)
+
+/*
+ * N.B. The flags may be moved into the flowi at some future stage.
+ */
+static int __dn_route_output_key(struct dst_entry **pprt, const struct flowi *flp, int flags)
 {
-	unsigned hash = dn_hash(src, dst);
+	unsigned hash = dn_hash(flp->fld_src, flp->fld_dst);
 	struct dn_route *rt = NULL;
 
 	if (!(flags & MSG_TRYHARD)) {
-		read_lock_bh(&dn_rt_hash_table[hash].lock);
+		rcu_read_lock();
 		for(rt = dn_rt_hash_table[hash].chain; rt; rt = rt->u.rt_next) {
-			if ((dst == rt->key.daddr) &&
-					(src == rt->key.saddr) &&
-					(rt->key.iif == 0) &&
-					(rt->key.oif != 0)) {
+			read_barrier_depends();
+			if ((flp->fld_dst == rt->fl.fld_dst) &&
+			    (flp->fld_src == rt->fl.fld_src) &&
+#ifdef CONFIG_DECNET_ROUTE_FWMARK
+			    (flp->fld_fwmark == rt->fl.fld_fwmark) &&
+#endif
+			    (rt->fl.iif == 0) &&
+			    (rt->fl.oif == flp->oif)) {
 				rt->u.dst.lastuse = jiffies;
 				dst_hold(&rt->u.dst);
 				rt->u.dst.__use++;
-				read_unlock_bh(&dn_rt_hash_table[hash].lock);
+				rcu_read_unlock();
 				*pprt = &rt->u.dst;
 				return 0;
 			}
 		}
-		read_unlock_bh(&dn_rt_hash_table[hash].lock);
+		rcu_read_unlock();
+	}
+
+	return dn_route_output_slow(pprt, flp, flags);
+}
+
+static int dn_route_output_key(struct dst_entry **pprt, struct flowi *flp, int flags)
+{
+	int err;
+
+	err = __dn_route_output_key(pprt, flp, flags);
+	if (err == 0 && flp->proto) {
+		err = xfrm_lookup(pprt, flp, NULL, 0);
 	}
+	return err;
+}
+
+int dn_route_output_sock(struct dst_entry **pprt, struct flowi *fl, struct sock *sk, int flags)
+{
+	int err;
 
-	return dn_route_output_slow(pprt, dst, src, flags);
+	err = __dn_route_output_key(pprt, fl, flags & MSG_TRYHARD);
+	if (err == 0 && fl->proto) {
+		err = xfrm_lookup(pprt, fl, sk, !(flags & MSG_DONTWAIT));
+	}
+	return err;
 }
 
 static int dn_route_input_slow(struct sk_buff *skb)
 {
 	struct dn_route *rt = NULL;
 	struct dn_skb_cb *cb = DN_SKB_CB(skb);
-	struct net_device *dev = skb->dev;
+	struct net_device *in_dev = skb->dev;
+	struct net_device *out_dev = NULL;
 	struct dn_dev *dn_db;
 	struct neighbour *neigh = NULL;
-	int (*dnrt_input)(struct sk_buff *skb);
-	int (*dnrt_output)(struct sk_buff *skb);
-	u32 fwmark = 0;
 	unsigned hash;
-	dn_address saddr = cb->src;
-	dn_address daddr = cb->dst;
-#ifdef CONFIG_DECNET_ROUTER
-	struct dn_fib_key key;
-	struct dn_fib_res res;
-	int err;
+	int flags = 0;
+	__u16 gateway = 0;
+	struct flowi fl = { .nl_u = { .dn_u = 
+				     { .daddr = cb->dst,
+				       .saddr = cb->src,
+				       .scope = RT_SCOPE_UNIVERSE,
+#ifdef CONFIG_DECNET_ROUTE_FWMARK
+				       .fwmark = skb->fwmark
 #endif
+				    } },
+			    .iif = skb->dev->ifindex };
+	struct dn_fib_res res = { .fi = NULL, .type = RTN_UNREACHABLE };
+	int err = -EINVAL;
+	int free_res = 0;
 
-	if (dev == NULL)
-		return -EINVAL;
+	dev_hold(in_dev);
 
-	if ((dn_db = dev->dn_ptr) == NULL)
-		return -EINVAL;
+	if ((dn_db = in_dev->dn_ptr) == NULL)
+		goto out;
+
+	/* Zero source addresses are not allowed */
+	if (fl.fld_src == 0)
+		goto out;
 
 	/*
 	 * In this case we've just received a packet from a source
@@ -887,122 +1203,183 @@
 	 * other nasties. Loopback packets already have the dst attached
 	 * so this only affects packets which have originated elsewhere.
 	 */
-	if (dn_dev_islocal(dev, cb->src))
-		return -ENOTUNIQ;
-
-	/*
-	 * Default is to create a drop everything entry
-	 */
-	dnrt_input  = dn_blackhole;
-	dnrt_output = dn_rt_bug;
-
-	/*
-	 * Is the destination us ?
-	 */
-	if (!dn_dev_islocal(dev, cb->dst))
-		goto non_local_input;
-
-	/*
-	 * Local input... find source of skb
-	 */
-	dnrt_input  = dn_nsp_rx;
-	dnrt_output = dn_output;
-	saddr = cb->dst;
-	daddr = cb->src;
-
-	if ((neigh = neigh_lookup(&dn_neigh_table, &cb->src, dev)) != NULL)
-		goto add_entry;
-
-	if (dn_db->router && ((neigh = neigh_clone(dn_db->router)) != NULL))
-		goto add_entry;
-
-	neigh = neigh_create(&dn_neigh_table, &cb->src, dev);
-	if (!IS_ERR(neigh)) {
-		if (dev->type == ARPHRD_ETHER)
-			memcpy(neigh->ha, skb->mac.ethernet->h_source, ETH_ALEN);
-		goto add_entry;
-	}
-
-	return PTR_ERR(neigh);
+	err  = -ENOTUNIQ;
+	if (dn_dev_islocal(in_dev, cb->src))
+		goto out;
 
-non_local_input:
+	err = dn_fib_lookup(&fl, &res);
+	if (err) {
+		if (err != -ESRCH)
+			goto out;
+		/*
+		 * Is the destination us ?
+		 */
+		if (!dn_dev_islocal(in_dev, cb->dst))
+			goto e_inval;
 
-#ifdef CONFIG_DECNET_ROUTER
-	/*
-	 * Destination is another node... find next hop in
-	 * routing table here.
-	 */
+		res.type = RTN_LOCAL;
+		flags |= RTCF_DIRECTSRC;
+	} else {
+		__u16 src_map = fl.fld_src;
+		free_res = 1;
 
-	key.src = cb->src;
-	key.dst = cb->dst;
-	key.iif = dev->ifindex;
-	key.oif = 0;
-	key.scope = RT_SCOPE_UNIVERSE;
+		out_dev = DN_FIB_RES_DEV(res);
+		if (out_dev == NULL) {
+			if (net_ratelimit())
+				printk(KERN_CRIT "Bug in dn_route_input_slow() "
+						 "No output device\n");
+			goto e_inval;
+		}
+		dev_hold(out_dev);
 
-#ifdef CONFIG_DECNET_ROUTE_FWMARK
-	key.fwmark = skb->nfmark;
-#else
-	key.fwmark = 0;
-#endif
+		if (res.r)
+			src_map = dn_fib_rules_policy(fl.fld_src, &res, &flags);
 
-	if ((err = dn_fib_lookup(&key, &res)) == 0) {
-		switch(res.type) {
-			case RTN_UNICAST:
-				if (res.fi->fib_nhs)
-					dn_fib_select_multipath(&key, &res);
-				neigh = __neigh_lookup(&dn_neigh_table, &DN_FIB_RES_GW(res), DN_FIB_RES_DEV(res), 1);
-				err = -ENOBUFS;
-				if (!neigh)
-					break;
-				err = 0;
-				dnrt_input = dn_forward;
-				fwmark = key.fwmark;
-				break;
-			case RTN_UNREACHABLE:
-				dnrt_input = dn_blackhole;
-				fwmark = key.fwmark;
-				break;
-			default:
-				err = -EINVAL;
+		gateway = DN_FIB_RES_GW(res);
+		if (res.type == RTN_NAT) {
+			fl.fld_dst = dn_fib_rules_map_destination(fl.fld_dst, &res);
+			dn_fib_res_put(&res);
+			free_res = 0;
+			if (dn_fib_lookup(&fl, &res))
+				goto e_inval;
+			free_res = 1;
+			if (res.type != RTN_UNICAST)
+				goto e_inval;
+			flags |= RTCF_DNAT;
+			gateway = fl.fld_dst;
 		}
-		dn_fib_res_put(&res);
-		if (err < 0)
-			return err;
-		goto add_entry;
+		fl.fld_src = src_map;
 	}
 
-	return err;
-
-#endif /* CONFIG_DECNET_ROUTER */
-
-add_entry:
+	switch(res.type) {
+	case RTN_UNICAST:
+		/*
+		 * Forwarding check here, we only check for forwarding
+		 * being turned off, if you want to only forward intra
+		 * area, its up to you to set the routing tables up
+		 * correctly.
+		 */
+		if (dn_db->parms.forwarding == 0)
+			goto e_inval;
+
+		if (res.fi->fib_nhs > 1 && fl.oif == 0)
+			dn_fib_select_multipath(&fl, &res);
+
+		/* 
+		 * Check for out_dev == in_dev. We use the RTCF_DOREDIRECT
+		 * flag as a hint to set the intra-ethernet bit when
+		 * forwarding. If we've got NAT in operation, we don't do
+		 * this optimisation.
+		 */
+		if (out_dev == in_dev && !(flags & RTCF_NAT))
+			flags |= RTCF_DOREDIRECT;
+
+	case RTN_BLACKHOLE:
+	case RTN_UNREACHABLE:
+		break;
+	case RTN_LOCAL:
+		flags |= RTCF_LOCAL;
+		fl.fld_src = cb->dst;
+		fl.fld_dst = cb->src;
+
+		/* Routing tables gave us a gateway */
+		if (gateway)
+			goto make_route;
+
+		/* Packet was intra-ethernet, so we know its on-link */
+		if (cb->rt_flags | DN_RT_F_IE) {
+			gateway = cb->src;
+			flags |= RTCF_DIRECTSRC;
+			goto make_route;
+		}
 
-	if ((rt = dst_alloc(&dn_dst_ops)) == NULL) {
-                neigh_release(neigh);
-                return -EINVAL;
-        }
+		/* Use the default router if there is one */
+		neigh = neigh_clone(dn_db->router);
+		if (neigh) {
+			gateway = ((struct dn_neigh *)neigh)->addr;
+			goto make_route;
+		}
 
-	rt->key.saddr  = cb->src;
-	rt->rt_saddr   = saddr;
-	rt->key.daddr  = cb->dst;
-	rt->rt_daddr   = daddr;
-	rt->key.oif    = 0;
-	rt->key.iif    = dev->ifindex;
-	rt->key.fwmark = fwmark;
+		/* Close eyes and pray */
+		gateway = cb->src;
+		flags |= RTCF_DIRECTSRC;
+		goto make_route;
+	default:
+		goto e_inval;
+	}
+
+make_route:
+	rt = dst_alloc(&dn_dst_ops);
+	if (rt == NULL)
+		goto e_nobufs;
+
+	rt->rt_saddr      = fl.fld_src;
+	rt->rt_daddr      = fl.fld_dst;
+	rt->rt_gateway    = fl.fld_dst;
+	if (gateway)
+		rt->rt_gateway = gateway;
+	rt->rt_dst_map    = fl.fld_dst;
+	rt->rt_src_map    = fl.fld_src;
+
+	rt->fl.fld_src    = cb->src;
+	rt->fl.fld_dst    = cb->dst;
+	rt->fl.oif        = 0;
+	rt->fl.iif        = in_dev->ifindex;
+	rt->fl.fld_fwmark = fl.fld_fwmark;
 
+	rt->u.dst.flags = DST_HOST;
 	rt->u.dst.neighbour = neigh;
-	rt->u.dst.dev = neigh ? neigh->dev : NULL;
+	rt->u.dst.dev = out_dev;
+	rt->u.dst.lastuse = jiffies;
+	rt->u.dst.output = dn_rt_bug;
+	switch(res.type) {
+		case RTN_UNICAST:
+			rt->u.dst.input = dn_forward;
+			break;
+		case RTN_LOCAL:
+			rt->u.dst.output = dn_output;
+			rt->u.dst.input = dn_nsp_rx;
+			rt->u.dst.dev = in_dev;
+			flags |= RTCF_LOCAL;
+			break;
+		default:
+		case RTN_UNREACHABLE:
+		case RTN_BLACKHOLE:
+			rt->u.dst.input = dn_blackhole;
+	}
+	rt->rt_flags = flags;
 	if (rt->u.dst.dev)
 		dev_hold(rt->u.dst.dev);
-	rt->u.dst.lastuse = jiffies;
-	rt->u.dst.output = dnrt_output;
-	rt->u.dst.input = dnrt_input;
 
-	hash = dn_hash(rt->key.saddr, rt->key.daddr);
-	dn_insert_route(rt, hash);
-	skb->dst = (struct dst_entry *)rt;
+	if (dn_rt_set_next_hop(rt, &res))
+		goto e_neighbour;
 
-	return 0;
+	hash = dn_hash(rt->fl.fld_src, rt->fl.fld_dst);
+	dn_insert_route(rt, hash, (struct dn_route **)&skb->dst);
+	err = 0;
+
+done:
+	if (neigh)
+		neigh_release(neigh);
+	if (free_res)
+		dn_fib_res_put(&res);
+	dev_put(in_dev);
+	if (out_dev)
+		dev_put(out_dev);
+out:
+	return err;
+
+e_inval:
+	err = -EINVAL;
+	goto done;
+
+e_nobufs:
+	err = -ENOBUFS;
+	goto done;
+
+e_neighbour:
+	dst_free(&rt->u.dst);
+	goto done;
 }
 
 int dn_route_input(struct sk_buff *skb)
@@ -1014,24 +1391,25 @@
 	if (skb->dst)
 		return 0;
 
-	read_lock(&dn_rt_hash_table[hash].lock);
+	rcu_read_lock();
 	for(rt = dn_rt_hash_table[hash].chain; rt != NULL; rt = rt->u.rt_next) {
-		if ((rt->key.saddr == cb->src) &&
-				(rt->key.daddr == cb->dst) &&
-				(rt->key.oif == 0) &&
+		read_barrier_depends();
+		if ((rt->fl.fld_src == cb->src) &&
+	 	    (rt->fl.fld_dst == cb->dst) &&
+		    (rt->fl.oif == 0) &&
 #ifdef CONFIG_DECNET_ROUTE_FWMARK
-				(rt->key.fwmark == skb->nfmark) &&
+		    (rt->fl.fld_fwmark == skb->nfmark) &&
 #endif
-				(rt->key.iif == cb->iif)) {
+		    (rt->fl.iif == cb->iif)) {
 			rt->u.dst.lastuse = jiffies;
 			dst_hold(&rt->u.dst);
 			rt->u.dst.__use++;
-			read_unlock(&dn_rt_hash_table[hash].lock);
+			rcu_read_unlock();
 			skb->dst = (struct dst_entry *)rt;
 			return 0;
 		}
 	}
-	read_unlock(&dn_rt_hash_table[hash].lock);
+	rcu_read_unlock();
 
 	return dn_route_input_slow(skb);
 }
@@ -1042,29 +1420,51 @@
 	struct rtmsg *r;
 	struct nlmsghdr *nlh;
 	unsigned char *b = skb->tail;
+	struct rta_cacheinfo ci;
 
 	nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*r));
 	r = NLMSG_DATA(nlh);
-	nlh->nlmsg_flags = nowait ? NLM_F_MULTI : 0;
+	nlh->nlmsg_flags = (nowait && pid) ? NLM_F_MULTI : 0;
 	r->rtm_family = AF_DECnet;
 	r->rtm_dst_len = 16;
-	r->rtm_src_len = 16;
+	r->rtm_src_len = 0;
 	r->rtm_tos = 0;
-	r->rtm_table = 0;
-	r->rtm_type = 0;
-	r->rtm_flags = 0;
+	r->rtm_table = RT_TABLE_MAIN;
+	r->rtm_type = rt->rt_type;
+	r->rtm_flags = (rt->rt_flags & ~0xFFFF) | RTM_F_CLONED;
 	r->rtm_scope = RT_SCOPE_UNIVERSE;
 	r->rtm_protocol = RTPROT_UNSPEC;
+	if (rt->rt_flags & RTCF_NOTIFY)
+		r->rtm_flags |= RTM_F_NOTIFY;
 	RTA_PUT(skb, RTA_DST, 2, &rt->rt_daddr);
-	RTA_PUT(skb, RTA_SRC, 2, &rt->rt_saddr);
+	if (rt->fl.fld_src) {
+		r->rtm_src_len = 16;
+		RTA_PUT(skb, RTA_SRC, 2, &rt->fl.fld_src);
+	}
 	if (rt->u.dst.dev)
 		RTA_PUT(skb, RTA_OIF, sizeof(int), &rt->u.dst.dev->ifindex);
-	if (dst_metric(&rt->u.dst, RTAX_WINDOW))
-		RTA_PUT(skb, RTAX_WINDOW, sizeof(unsigned),
-			&rt->u.dst.metrics[RTAX_WINDOW - 1]);
-	if (dst_metric(&rt->u.dst, RTAX_RTT))
-		RTA_PUT(skb, RTAX_RTT, sizeof(unsigned),
-			&rt->u.dst.metrics[RTAX_RTT]);
+	/*
+	 * Note to self - change this if input routes reverse direction when
+	 * they deal only with inputs and not with replies like they do
+	 * currently.
+	 */
+	RTA_PUT(skb, RTA_PREFSRC, 2, &rt->rt_saddr);
+	if (rt->rt_daddr != rt->rt_gateway)
+		RTA_PUT(skb, RTA_GATEWAY, 2, &rt->rt_gateway);
+	if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0)
+		goto rtattr_failure;
+	ci.rta_lastuse = jiffies - rt->u.dst.lastuse;
+	ci.rta_used     = rt->u.dst.__use;
+	ci.rta_clntref  = atomic_read(&rt->u.dst.__refcnt);
+	if (rt->u.dst.expires)
+		ci.rta_expires = rt->u.dst.expires - jiffies;
+	else
+		ci.rta_expires = 0;
+	ci.rta_error    = rt->u.dst.error;
+	ci.rta_id       = ci.rta_ts = ci.rta_tsage = 0;
+	RTA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci);
+	if (rt->fl.iif)
+		RTA_PUT(skb, RTA_IIF, sizeof(int), &rt->fl.iif);
 
 	nlh->nlmsg_len = skb->tail - b;
 	return skb->len;
@@ -1081,13 +1481,14 @@
 int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void *arg)
 {
 	struct rtattr **rta = arg;
+	struct rtmsg *rtm = NLMSG_DATA(nlh);
 	struct dn_route *rt = NULL;
 	struct dn_skb_cb *cb;
-	dn_address dst = 0;
-	dn_address src = 0;
-	int iif = 0;
 	int err;
 	struct sk_buff *skb;
+	struct flowi fl;
+
+	memset(&fl, 0, sizeof(fl));
 
 	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
 	if (skb == NULL)
@@ -1096,15 +1497,15 @@
 	cb = DN_SKB_CB(skb);
 
 	if (rta[RTA_SRC-1])
-		memcpy(&src, RTA_DATA(rta[RTA_SRC-1]), 2);
+		memcpy(&fl.fld_src, RTA_DATA(rta[RTA_SRC-1]), 2);
 	if (rta[RTA_DST-1])
-		memcpy(&dst, RTA_DATA(rta[RTA_DST-1]), 2);
+		memcpy(&fl.fld_dst, RTA_DATA(rta[RTA_DST-1]), 2);
 	if (rta[RTA_IIF-1])
-		memcpy(&iif, RTA_DATA(rta[RTA_IIF-1]), sizeof(int));
+		memcpy(&fl.iif, RTA_DATA(rta[RTA_IIF-1]), sizeof(int));
 
-	if (iif) {
+	if (fl.iif) {
 		struct net_device *dev;
-		if ((dev = dev_get_by_index(iif)) == NULL) {
+		if ((dev = dev_get_by_index(fl.iif)) == NULL) {
 			kfree_skb(skb);
 			return -ENODEV;
 		}
@@ -1115,25 +1516,31 @@
 		}
 		skb->protocol = __constant_htons(ETH_P_DNA_RT);
 		skb->dev = dev;
-		cb->src = src;
-		cb->dst = dst;
+		cb->src = fl.fld_src;
+		cb->dst = fl.fld_dst;
 		local_bh_disable();
 		err = dn_route_input(skb);
 		local_bh_enable();
 		memset(cb, 0, sizeof(struct dn_skb_cb));
 		rt = (struct dn_route *)skb->dst;
+		if (!err && -rt->u.dst.error)
+			err = rt->u.dst.error;
 	} else {
-		err = dn_route_output((struct dst_entry **)&rt, dst, src, 0);
+		int oif = 0;
+		if (rta[RTA_OIF - 1])
+			memcpy(&oif, RTA_DATA(rta[RTA_OIF - 1]), sizeof(int));
+		fl.oif = oif;
+		err = dn_route_output_key((struct dst_entry **)&rt, &fl, 0);
 	}
 
-	if (!err && rt->u.dst.error)
-		err = rt->u.dst.error;
 	if (skb->dev)
 		dev_put(skb->dev);
 	skb->dev = NULL;
 	if (err)
 		goto out_free;
 	skb->dst = &rt->u.dst;
+	if (rtm->rtm_flags & RTM_F_NOTIFY)
+		rt->rt_flags |= RTCF_NOTIFY;
 
 	NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid;
 
@@ -1177,20 +1584,21 @@
 			continue;
 		if (h > s_h)
 			s_idx = 0;
-		read_lock_bh(&dn_rt_hash_table[h].lock);
+		rcu_read_lock();
 		for(rt = dn_rt_hash_table[h].chain, idx = 0; rt; rt = rt->u.rt_next, idx++) {
+			read_barrier_depends();
 			if (idx < s_idx)
 				continue;
 			skb->dst = dst_clone(&rt->u.dst);
 			if (dn_rt_fill_info(skb, NETLINK_CB(cb->skb).pid,
 					cb->nlh->nlmsg_seq, RTM_NEWROUTE, 1) <= 0) {
 				dst_release(xchg(&skb->dst, NULL));
-				read_unlock_bh(&dn_rt_hash_table[h].lock);
+				rcu_read_unlock();
 				goto done;
 			}
 			dst_release(xchg(&skb->dst, NULL));
 		}
-		read_unlock_bh(&dn_rt_hash_table[h].lock);
+		rcu_read_unlock();
 	}
 
 done:
@@ -1211,9 +1619,10 @@
 	char buf1[DN_ASCBUF_LEN], buf2[DN_ASCBUF_LEN];
 
 	for(i = 0; i <= dn_rt_hash_mask; i++) {
-		read_lock_bh(&dn_rt_hash_table[i].lock);
+		rcu_read_lock();
 		rt = dn_rt_hash_table[i].chain;
 		for(; rt != NULL; rt = rt->u.rt_next) {
+			read_barrier_depends();
 			len += sprintf(buffer + len, "%-8s %-7s %-7s %04d %04d %04d\n",
 					rt->u.dst.dev ? rt->u.dst.dev->name : "*",
 					dn_addr2asc(dn_ntohs(rt->rt_daddr), buf1),
@@ -1234,7 +1643,7 @@
               		if (pos > offset + length)
                 	        break;
 		}
-		read_unlock_bh(&dn_rt_hash_table[i].lock);
+		rcu_read_unlock();
 		if (pos > offset + length)
 			break;
 	}
@@ -1298,7 +1707,7 @@
 
 	dn_rt_hash_mask--;
         for(i = 0; i <= dn_rt_hash_mask; i++) {
-                dn_rt_hash_table[i].lock = RW_LOCK_UNLOCKED;
+                dn_rt_hash_table[i].lock = SPIN_LOCK_UNLOCKED;
                 dn_rt_hash_table[i].chain = NULL;
         }
 
diff -urN linux-2.5.67-bk9/net/decnet/dn_rules.c linux-2.5.67-bk10/net/decnet/dn_rules.c
--- linux-2.5.67-bk9/net/decnet/dn_rules.c	2003-04-07 10:32:18.000000000 -0700
+++ linux-2.5.67-bk10/net/decnet/dn_rules.c	2003-04-19 04:35:43.000000000 -0700
@@ -26,10 +26,12 @@
 #include <linux/netdevice.h>
 #include <linux/timer.h>
 #include <linux/spinlock.h>
+#include <linux/in_route.h>
 #include <asm/atomic.h>
 #include <asm/uaccess.h>
 #include <net/neighbour.h>
 #include <net/dst.h>
+#include <net/flow.h>
 #include <net/dn.h>
 #include <net/dn_fib.h>
 #include <net/dn_neigh.h>
@@ -48,6 +50,7 @@
 	dn_address		r_srcmask;
 	dn_address		r_dst;
 	dn_address		r_dstmask;
+	dn_address		r_srcmap;
 	u8			r_flags;
 #ifdef CONFIG_DECNET_ROUTE_FWMARK
 	u32			r_fwmark;
@@ -60,7 +63,7 @@
 static struct dn_fib_rule default_rule = {
 	.r_clntref =		ATOMIC_INIT(2),
 	.r_preference =		0x7fff,
-	.r_table =		DN_DEFAULT_TABLE,
+	.r_table =		RT_TABLE_MAIN,
 	.r_action =		RTN_UNICAST
 };
 
@@ -150,6 +153,8 @@
 		memcpy(&new_r->r_src, RTA_DATA(rta[RTA_SRC-1]), 2);
 	if (rta[RTA_DST-1])
 		memcpy(&new_r->r_dst, RTA_DATA(rta[RTA_DST-1]), 2);
+	if (rta[RTA_GATEWAY-1])
+		memcpy(&new_r->r_srcmap, RTA_DATA(rta[RTA_GATEWAY-1]), 2);
 	new_r->r_src_len = rtm->rtm_src_len;
 	new_r->r_dst_len = rtm->rtm_dst_len;
 	new_r->r_srcmask = dnet_make_mask(rtm->rtm_src_len);
@@ -198,12 +203,12 @@
 }
 
 
-int dn_fib_lookup(struct dn_fib_key *key, struct dn_fib_res *res)
+int dn_fib_lookup(const struct flowi *flp, struct dn_fib_res *res)
 {
 	struct dn_fib_rule *r, *policy;
 	struct dn_fib_table *tb;
-	dn_address saddr = key->src;
-	dn_address daddr = key->dst;
+	dn_address saddr = flp->fld_src;
+	dn_address daddr = flp->fld_dst;
 	int err;
 
 	read_lock(&dn_fib_rules_lock);
@@ -211,13 +216,14 @@
 		if (((saddr^r->r_src) & r->r_srcmask) ||
 		    ((daddr^r->r_dst) & r->r_dstmask) ||
 #ifdef CONFIG_DECNET_ROUTE_FWMARK
-		    (r->r_fwmark && r->r_fwmark != key->fwmark) ||
+		    (r->r_fwmark && r->r_fwmark != flp->fld_fwmark) ||
 #endif
-		    (r->r_ifindex && r->r_ifindex != key->iif))
+		    (r->r_ifindex && r->r_ifindex != flp->iif))
 			continue;
 
 		switch(r->r_action) {
 			case RTN_UNICAST:
+			case RTN_NAT:
 				policy = r;
 				break;
 			case RTN_UNREACHABLE:
@@ -234,7 +240,7 @@
 
 		if ((tb = dn_fib_get_table(r->r_table, 0)) == NULL)
 			continue;
-		err = tb->lookup(tb, key, res);
+		err = tb->lookup(tb, flp, res);
 		if (err == 0) {
 			res->r = policy;
 			if (policy)
@@ -252,6 +258,42 @@
 	return -ESRCH;
 }
 
+unsigned dnet_addr_type(__u16 addr)
+{
+	struct flowi fl = { .nl_u = { .dn_u = { .daddr = addr } } };
+	struct dn_fib_res res;
+	unsigned ret = RTN_UNICAST;
+	struct dn_fib_table *tb = dn_fib_tables[RT_TABLE_LOCAL];
+
+	res.r = NULL;
+
+	if (tb) {
+		if (!tb->lookup(tb, &fl, &res)) {
+			ret = res.type;
+			dn_fib_res_put(&res);
+		}
+	}
+	return ret;
+}
+
+__u16 dn_fib_rules_policy(__u16 saddr, struct dn_fib_res *res, unsigned *flags)
+{
+	struct dn_fib_rule *r = res->r;
+
+	if (r->r_action == RTN_NAT) {
+		int addrtype = dnet_addr_type(r->r_srcmap);
+
+		if (addrtype == RTN_NAT) {
+			saddr = (saddr&~r->r_srcmask)|r->r_srcmap;
+			*flags |= RTCF_SNAT;
+		} else if (addrtype == RTN_LOCAL || r->r_srcmap == 0) {
+			saddr = r->r_srcmap;
+			*flags |= RTCF_MASQ;
+		}
+	}
+	return saddr;
+}
+
 static void dn_fib_rules_detach(struct net_device *dev)
 {
 	struct dn_fib_rule *r;
@@ -330,6 +372,8 @@
 		RTA_PUT(skb, RTA_IIF, IFNAMSIZ, &r->r_ifname);
 	if (r->r_preference)
 		RTA_PUT(skb, RTA_PRIORITY, 4, &r->r_preference);
+	if (r->r_srcmap)
+		RTA_PUT(skb, RTA_GATEWAY, 2, &r->r_srcmap);
 	nlh->nlmsg_len = skb->tail - b;
 	return skb->len;
 
diff -urN linux-2.5.67-bk9/net/decnet/dn_table.c linux-2.5.67-bk10/net/decnet/dn_table.c
--- linux-2.5.67-bk9/net/decnet/dn_table.c	2003-04-07 10:30:58.000000000 -0700
+++ linux-2.5.67-bk10/net/decnet/dn_table.c	2003-04-19 04:35:43.000000000 -0700
@@ -30,6 +30,7 @@
 #include <linux/route.h> /* RTF_xxx */
 #include <net/neighbour.h>
 #include <net/dst.h>
+#include <net/flow.h>
 #include <net/dn.h>
 #include <net/dn_route.h>
 #include <net/dn_fib.h>
@@ -45,7 +46,7 @@
 	u32			dz_hashmask;
 #define DZ_HASHMASK(dz)	((dz)->dz_hashmask)
 	int			dz_order;
-	u32			dz_mask;
+	u16			dz_mask;
 #define DZ_MASK(dz)	((dz)->dz_mask)
 };
 
@@ -73,53 +74,53 @@
 #define DN_FIB_SCAN_KEY(f, fp, key) \
 for( ; ((f) = *(fp)) != NULL && dn_key_eq((f)->fn_key, (key)); (fp) = &(f)->fn_next)
 
+#define RT_TABLE_MIN 1
 
 static rwlock_t dn_fib_tables_lock = RW_LOCK_UNLOCKED;
-static struct dn_fib_table *dn_fib_tables[DN_NUM_TABLES + 1];
+struct dn_fib_table *dn_fib_tables[RT_TABLE_MAX + 1];
 
 static kmem_cache_t *dn_hash_kmem;
 static int dn_fib_hash_zombies;
 
-static __inline__ dn_fib_idx_t dn_hash(dn_fib_key_t key, struct dn_zone *dz)
+static inline dn_fib_idx_t dn_hash(dn_fib_key_t key, struct dn_zone *dz)
 {
-	u32 h = ntohs(key.datum)>>(16 - dz->dz_order);
+	u16 h = ntohs(key.datum)>>(16 - dz->dz_order);
 	h ^= (h >> 10);
 	h ^= (h >> 6);
-	h ^= (h >> 3);
 	h &= DZ_HASHMASK(dz);
 	return *(dn_fib_idx_t *)&h;
 }
 
-static __inline__ dn_fib_key_t dz_key(u16 dst, struct dn_zone *dz)
+static inline dn_fib_key_t dz_key(u16 dst, struct dn_zone *dz)
 {
 	dn_fib_key_t k;
 	k.datum = dst & DZ_MASK(dz);
 	return k;
 }
 
-static __inline__ struct dn_fib_node **dn_chain_p(dn_fib_key_t key, struct dn_zone *dz)
+static inline struct dn_fib_node **dn_chain_p(dn_fib_key_t key, struct dn_zone *dz)
 {
 	return &dz->dz_hash[dn_hash(key, dz).datum];
 }
 
-static __inline__ struct dn_fib_node *dz_chain(dn_fib_key_t key, struct dn_zone *dz)
+static inline struct dn_fib_node *dz_chain(dn_fib_key_t key, struct dn_zone *dz)
 {
 	return dz->dz_hash[dn_hash(key, dz).datum];
 }
 
-static __inline__ int dn_key_eq(dn_fib_key_t a, dn_fib_key_t b)
+static inline int dn_key_eq(dn_fib_key_t a, dn_fib_key_t b)
 {
 	return a.datum == b.datum;
 }
 
-static __inline__ int dn_key_leq(dn_fib_key_t a, dn_fib_key_t b)
+static inline int dn_key_leq(dn_fib_key_t a, dn_fib_key_t b)
 {
 	return a.datum <= b.datum;
 }
 
-static __inline__ void dn_rebuild_zone(struct dn_zone *dz,
-					struct dn_fib_node **old_ht,
-					int old_divisor)
+static inline void dn_rebuild_zone(struct dn_zone *dz,
+				   struct dn_fib_node **old_ht,
+				   int old_divisor)
 {
 	int i;
 	struct dn_fib_node *f, **fp, *next;
@@ -290,6 +291,8 @@
         rtm->rtm_protocol = fi->fib_protocol;
         if (fi->fib_priority)
                 RTA_PUT(skb, RTA_PRIORITY, 4, &fi->fib_priority);
+	if (rtnetlink_put_metrics(skb, fi->fib_metrics) < 0)
+		goto rtattr_failure;
         if (fi->fib_nhs == 1) {
                 if (fi->fib_nh->nh_gw)
                         RTA_PUT(skb, RTA_GATEWAY, 2, &fi->fib_nh->nh_gw);
@@ -654,7 +657,7 @@
         return -ESRCH;
 }
 
-static __inline__ int dn_flush_list(struct dn_fib_node **fp, int z, struct dn_hash *table)
+static inline int dn_flush_list(struct dn_fib_node **fp, int z, struct dn_hash *table)
 {
 	int found = 0;
 	struct dn_fib_node *f;
@@ -696,8 +699,7 @@
 	return found;
 }
 
-static int dn_fib_table_lookup(struct dn_fib_table *tb, const struct dn_fib_key *
-key, struct dn_fib_res *res)
+static int dn_fib_table_lookup(struct dn_fib_table *tb, const struct flowi *flp, struct dn_fib_res *res)
 {
         int err;
 	struct dn_zone *dz;
@@ -706,25 +708,29 @@
 	read_lock(&dn_fib_tables_lock);
 	for(dz = t->dh_zone_list; dz; dz = dz->dz_next) {
 		struct dn_fib_node *f;
-		dn_fib_key_t k = dz_key(key->dst, dz);
+		dn_fib_key_t k = dz_key(flp->fld_dst, dz);
 
 		for(f = dz_chain(k, dz); f; f = f->fn_next) {
-			if (!dn_key_leq(k, f->fn_key))
-				break;
-			else
-				continue;
+			if (!dn_key_eq(k, f->fn_key)) {
+				if (dn_key_leq(k, f->fn_key))
+					break;
+				else
+					continue;
+			}
 
 			f->fn_state |= DN_S_ACCESSED;
 
 			if (f->fn_state&DN_S_ZOMBIE)
 				continue;
-			if (f->fn_scope < key->scope)
+
+			if (f->fn_scope < flp->fld_scope)
 				continue;
 
-			err = dn_fib_semantic_match(f->fn_type, DN_FIB_INFO(f), key, res);
+			err = dn_fib_semantic_match(f->fn_type, DN_FIB_INFO(f), flp, res);
+
 			if (err == 0) {
 				res->type = f->fn_type;
-				res->scope = f->fn_scope;
+				res->scope = f->fn_scope; 
 				res->prefixlen = dz->dz_order;
 				goto out;
 			}
@@ -763,7 +769,7 @@
 
 	if (fi) {
 		len = sprintf(buffer, "%s\t%04x\t%04x\t%04x\t%d\t%u\t%d\t%04x\t%d\t%u\t%u",
-				fi->fib_dev ? fi->fib_dev->name : "*", prefix,
+				fi->dn_fib_dev ? fi->dn_fib_dev->name : "*", prefix,
 				fi->fib_nh->nh_gw, flags, 0, 0, fi->fib_priority,
 				mask, 0, 0, 0);
 	} else {
@@ -823,10 +829,10 @@
 {
         struct dn_fib_table *t;
 
-        if (n < DN_MIN_TABLE)
+        if (n < RT_TABLE_MIN)
                 return NULL;
 
-        if (n > DN_NUM_TABLES)
+        if (n > RT_TABLE_MAX)
                 return NULL;
 
         if (dn_fib_tables[n]) 
@@ -839,7 +845,7 @@
                 printk(KERN_DEBUG "DECnet: BUG! Attempt to create routing table from interrupt\n"); 
                 return NULL;
         }
-        if ((t = kmalloc(sizeof(struct dn_fib_table), GFP_KERNEL)) == NULL)
+        if ((t = kmalloc(sizeof(struct dn_fib_table) + sizeof(struct dn_hash), GFP_KERNEL)) == NULL)
                 return NULL;
 
         memset(t, 0, sizeof(struct dn_fib_table));
@@ -853,6 +859,7 @@
 	t->get_info = dn_fib_table_get_info;
 #endif
         t->dump = dn_fib_table_dump;
+	memset(t->data, 0, sizeof(struct dn_hash));
         dn_fib_tables[n] = t;
 
         return t;
@@ -876,7 +883,7 @@
 {
         int id;
 
-        for(id = DN_MIN_TABLE; id <= DN_NUM_TABLES; id++)
+        for(id = RT_TABLE_MIN; id <= RT_TABLE_MAX; id++)
                 if (dn_fib_tables[id] == NULL)
                         return dn_fib_get_table(id, 1);
         return NULL;
@@ -894,7 +901,7 @@
 {
 	int i;
 
-	for (i = 0; i < DN_NUM_TABLES + 1; ++i)
+	for (i = RT_TABLE_MIN; i <= RT_TABLE_MAX; ++i)
 		dn_fib_del_tree(i);
 
 	return;
diff -urN linux-2.5.67-bk9/net/decnet/dn_timer.c linux-2.5.67-bk10/net/decnet/dn_timer.c
--- linux-2.5.67-bk9/net/decnet/dn_timer.c	2003-04-07 10:31:46.000000000 -0700
+++ linux-2.5.67-bk10/net/decnet/dn_timer.c	2003-04-19 04:35:43.000000000 -0700
@@ -23,6 +23,7 @@
 #include <linux/spinlock.h>
 #include <net/sock.h>
 #include <asm/atomic.h>
+#include <net/flow.h>
 #include <net/dn.h>
 
 /*
diff -urN linux-2.5.67-bk9/net/decnet/sysctl_net_decnet.c linux-2.5.67-bk10/net/decnet/sysctl_net_decnet.c
--- linux-2.5.67-bk9/net/decnet/sysctl_net_decnet.c	2003-04-07 10:30:57.000000000 -0700
+++ linux-2.5.67-bk10/net/decnet/sysctl_net_decnet.c	2003-04-19 04:35:43.000000000 -0700
@@ -20,6 +20,7 @@
 #include <linux/string.h>
 #include <net/neighbour.h>
 #include <net/dst.h>
+#include <net/flow.h>
 
 #include <asm/uaccess.h>
 
diff -urN linux-2.5.67-bk9/net/ipv4/xfrm4_policy.c linux-2.5.67-bk10/net/ipv4/xfrm4_policy.c
--- linux-2.5.67-bk9/net/ipv4/xfrm4_policy.c	2003-04-19 04:35:32.000000000 -0700
+++ linux-2.5.67-bk10/net/ipv4/xfrm4_policy.c	2003-04-19 04:35:43.000000000 -0700
@@ -180,8 +180,8 @@
 			if (pskb_may_pull(skb, xprth + 4 - skb->data)) {
 				u16 *ports = (u16 *)xprth;
 
-				fl->uli_u.ports.sport = ports[0];
-				fl->uli_u.ports.dport = ports[1];
+				fl->fl_ip_sport = ports[0];
+				fl->fl_ip_dport = ports[1];
 			}
 			break;
 
@@ -189,7 +189,7 @@
 			if (pskb_may_pull(skb, xprth + 4 - skb->data)) {
 				u32 *ehdr = (u32 *)xprth;
 
-				fl->uli_u.spi = ehdr[0];
+				fl->fl_ipsec_spi = ehdr[0];
 			}
 			break;
 
@@ -197,7 +197,7 @@
 			if (pskb_may_pull(skb, xprth + 8 - skb->data)) {
 				u32 *ah_hdr = (u32*)xprth;
 
-				fl->uli_u.spi = ah_hdr[1];
+				fl->fl_ipsec_spi = ah_hdr[1];
 			}
 			break;
 
@@ -205,11 +205,11 @@
 			if (pskb_may_pull(skb, xprth + 4 - skb->data)) {
 				u16 *ipcomp_hdr = (u16 *)xprth;
 
-				fl->uli_u.spi = ntohl(ntohs(ipcomp_hdr[1]));
+				fl->fl_ipsec_spi = ntohl(ntohs(ipcomp_hdr[1]));
 			}
 			break;
 		default:
-			fl->uli_u.spi = 0;
+			fl->fl_ipsec_spi = 0;
 			break;
 		};
 	} else {
diff -urN linux-2.5.67-bk9/net/ipv4/xfrm4_state.c linux-2.5.67-bk10/net/ipv4/xfrm4_state.c
--- linux-2.5.67-bk9/net/ipv4/xfrm4_state.c	2003-04-07 10:30:38.000000000 -0700
+++ linux-2.5.67-bk10/net/ipv4/xfrm4_state.c	2003-04-19 04:35:43.000000000 -0700
@@ -20,9 +20,9 @@
 {
 	x->sel.daddr.a4 = fl->fl4_dst;
 	x->sel.saddr.a4 = fl->fl4_src;
-	x->sel.dport = fl->uli_u.ports.dport;
+	x->sel.dport = fl->fl_ip_dport;
 	x->sel.dport_mask = ~0;
-	x->sel.sport = fl->uli_u.ports.sport;
+	x->sel.sport = fl->fl_ip_sport;
 	x->sel.sport_mask = ~0;
 	x->sel.prefixlen_d = 32;
 	x->sel.prefixlen_s = 32;
diff -urN linux-2.5.67-bk9/net/ipv6/datagram.c linux-2.5.67-bk10/net/ipv6/datagram.c
--- linux-2.5.67-bk9/net/ipv6/datagram.c	2003-04-07 10:30:41.000000000 -0700
+++ linux-2.5.67-bk10/net/ipv6/datagram.c	2003-04-19 04:35:43.000000000 -0700
@@ -91,7 +91,7 @@
 	serr->ee.ee_info = info;
 	serr->ee.ee_data = 0;
 	serr->addr_offset = (u8*)&iph->daddr - skb->nh.raw;
-	serr->port = fl->uli_u.ports.dport;
+	serr->port = fl->fl_ip_dport;
 
 	skb->h.raw = skb->tail;
 	__skb_pull(skb, skb->tail - skb->data);
diff -urN linux-2.5.67-bk9/net/ipv6/icmp.c linux-2.5.67-bk10/net/ipv6/icmp.c
--- linux-2.5.67-bk9/net/ipv6/icmp.c	2003-04-19 04:35:32.000000000 -0700
+++ linux-2.5.67-bk10/net/ipv6/icmp.c	2003-04-19 04:35:43.000000000 -0700
@@ -313,12 +313,12 @@
 	}
 
 	fl.proto = IPPROTO_ICMPV6;
-	fl.nl_u.ip6_u.daddr = &hdr->saddr;
-	fl.nl_u.ip6_u.saddr = saddr;
+	fl.fl6_dst = &hdr->saddr;
+	fl.fl6_src = saddr;
 	fl.oif = iif;
 	fl.fl6_flowlabel = 0;
-	fl.uli_u.icmpt.type = type;
-	fl.uli_u.icmpt.code = code;
+	fl.fl_icmp_type = type;
+	fl.fl_icmp_code = code;
 
 	icmpv6_xmit_lock();
 
@@ -387,12 +387,12 @@
 	msg.daddr =  &skb->nh.ipv6h->saddr;
 
 	fl.proto = IPPROTO_ICMPV6;
-	fl.nl_u.ip6_u.daddr = msg.daddr;
-	fl.nl_u.ip6_u.saddr = saddr;
+	fl.fl6_dst = msg.daddr;
+	fl.fl6_src = saddr;
 	fl.oif = skb->dev->ifindex;
 	fl.fl6_flowlabel = 0;
-	fl.uli_u.icmpt.type = ICMPV6_ECHO_REPLY;
-	fl.uli_u.icmpt.code = 0;
+	fl.fl_icmp_type = ICMPV6_ECHO_REPLY;
+	fl.fl_icmp_code = 0;
 
 	icmpv6_xmit_lock();
 
diff -urN linux-2.5.67-bk9/net/ipv6/ip6_output.c linux-2.5.67-bk10/net/ipv6/ip6_output.c
--- linux-2.5.67-bk9/net/ipv6/ip6_output.c	2003-04-19 04:35:32.000000000 -0700
+++ linux-2.5.67-bk10/net/ipv6/ip6_output.c	2003-04-19 04:35:43.000000000 -0700
@@ -147,8 +147,8 @@
 	fl.fl6_src = &iph->saddr;
 	fl.oif = skb->sk ? skb->sk->bound_dev_if : 0;
 	fl.fl6_flowlabel = 0;
-	fl.uli_u.ports.dport = 0;
-	fl.uli_u.ports.sport = 0;
+	fl.fl_ip_dport = 0;
+	fl.fl_ip_sport = 0;
 
 	dst = ip6_route_output(skb->sk, &fl);
 
@@ -188,7 +188,7 @@
 	     struct ipv6_txoptions *opt)
 {
 	struct ipv6_pinfo *np = sk ? inet6_sk(sk) : NULL;
-	struct in6_addr *first_hop = fl->nl_u.ip6_u.daddr;
+	struct in6_addr *first_hop = fl->fl6_dst;
 	struct dst_entry *dst = skb->dst;
 	struct ipv6hdr *hdr;
 	u8  proto = fl->proto;
@@ -243,7 +243,7 @@
 	hdr->nexthdr = proto;
 	hdr->hop_limit = hlimit;
 
-	ipv6_addr_copy(&hdr->saddr, fl->nl_u.ip6_u.saddr);
+	ipv6_addr_copy(&hdr->saddr, fl->fl6_src);
 	ipv6_addr_copy(&hdr->daddr, first_hop);
 
 	mtu = dst_pmtu(dst);
@@ -308,8 +308,8 @@
 	hdr->hop_limit = hlimit;
 	hdr->nexthdr = fl->proto;
 
-	ipv6_addr_copy(&hdr->saddr, fl->nl_u.ip6_u.saddr);
-	ipv6_addr_copy(&hdr->daddr, fl->nl_u.ip6_u.daddr);
+	ipv6_addr_copy(&hdr->saddr, fl->fl6_src);
+	ipv6_addr_copy(&hdr->daddr, fl->fl6_dst);
 	return hdr;
 }
 
@@ -526,7 +526,7 @@
 		fl->fl6_dst = rt0->addr;
 	}
 
-	if (!fl->oif && ipv6_addr_is_multicast(fl->nl_u.ip6_u.daddr))
+	if (!fl->oif && ipv6_addr_is_multicast(fl->fl6_dst))
 		fl->oif = np->mcast_oif;
 
 	dst = __sk_dst_check(sk, np->dst_cookie);
@@ -703,7 +703,7 @@
 	 *	cleanup
 	 */
 out:
-	ip6_dst_store(sk, dst, fl->nl_u.ip6_u.daddr == &np->daddr ? &np->daddr : NULL);
+	ip6_dst_store(sk, dst, fl->fl6_dst == &np->daddr ? &np->daddr : NULL);
 	if (err > 0)
 		err = np->recverr ? net_xmit_errno(err) : 0;
 	return err;
diff -urN linux-2.5.67-bk9/net/ipv6/ndisc.c linux-2.5.67-bk10/net/ipv6/ndisc.c
--- linux-2.5.67-bk9/net/ipv6/ndisc.c	2003-04-19 04:35:32.000000000 -0700
+++ linux-2.5.67-bk10/net/ipv6/ndisc.c	2003-04-19 04:35:43.000000000 -0700
@@ -405,8 +405,8 @@
 	fl->fl6_src		= saddr;
 	fl->fl6_dst	 	= daddr;
 	fl->proto	 	= IPPROTO_ICMPV6;
-	fl->uli_u.icmpt.type	= type;
-	fl->uli_u.icmpt.code	= 0;
+	fl->fl_icmp_type	= type;
+	fl->fl_icmp_code	= 0;
 }
 
 static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
diff -urN linux-2.5.67-bk9/net/ipv6/raw.c linux-2.5.67-bk10/net/ipv6/raw.c
--- linux-2.5.67-bk9/net/ipv6/raw.c	2003-04-19 04:35:32.000000000 -0700
+++ linux-2.5.67-bk10/net/ipv6/raw.c	2003-04-19 04:35:43.000000000 -0700
@@ -622,8 +622,8 @@
 	fl.fl6_dst = daddr;
 	if (fl.fl6_src == NULL && !ipv6_addr_any(&np->saddr))
 		fl.fl6_src = &np->saddr;
-	fl.uli_u.icmpt.type = 0;
-	fl.uli_u.icmpt.code = 0;
+	fl.fl_icmp_type = 0;
+	fl.fl_icmp_code = 0;
 	
 	if (raw_opt->checksum) {
 		struct rawv6_fakehdr hdr;
diff -urN linux-2.5.67-bk9/net/ipv6/route.c linux-2.5.67-bk10/net/ipv6/route.c
--- linux-2.5.67-bk9/net/ipv6/route.c	2003-04-19 04:35:32.000000000 -0700
+++ linux-2.5.67-bk10/net/ipv6/route.c	2003-04-19 04:35:43.000000000 -0700
@@ -449,13 +449,12 @@
 	int strict;
 	int attempts = 3;
 
-	strict = ipv6_addr_type(fl->nl_u.ip6_u.daddr) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL);
+	strict = ipv6_addr_type(fl->fl6_dst) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL);
 
 relookup:
 	read_lock_bh(&rt6_lock);
 
-	fn = fib6_lookup(&ip6_routing_table, fl->nl_u.ip6_u.daddr,
-			 fl->nl_u.ip6_u.saddr);
+	fn = fib6_lookup(&ip6_routing_table, fl->fl6_dst, fl->fl6_src);
 
 restart:
 	rt = fn->leaf;
@@ -477,9 +476,8 @@
 	if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) {
 		read_unlock_bh(&rt6_lock);
 
-		rt = rt6_cow(rt, fl->nl_u.ip6_u.daddr,
-			     fl->nl_u.ip6_u.saddr);
-			
+		rt = rt6_cow(rt, fl->fl6_dst, fl->fl6_src);
+
 		if (rt->u.dst.error != -EEXIST || --attempts <= 0)
 			goto out2;
 
@@ -1585,15 +1583,11 @@
 	skb->mac.raw = skb->data;
 	skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr));
 
-	fl.proto = 0;
-	fl.nl_u.ip6_u.daddr = NULL;
-	fl.nl_u.ip6_u.saddr = NULL;
-	fl.uli_u.icmpt.type = 0;
-	fl.uli_u.icmpt.code = 0;
+	memset(&fl, 0, sizeof(fl));
 	if (rta[RTA_SRC-1])
-		fl.nl_u.ip6_u.saddr = (struct in6_addr*)RTA_DATA(rta[RTA_SRC-1]);
+		fl.fl6_src = (struct in6_addr*)RTA_DATA(rta[RTA_SRC-1]);
 	if (rta[RTA_DST-1])
-		fl.nl_u.ip6_u.daddr = (struct in6_addr*)RTA_DATA(rta[RTA_DST-1]);
+		fl.fl6_dst = (struct in6_addr*)RTA_DATA(rta[RTA_DST-1]);
 
 	if (rta[RTA_IIF-1])
 		memcpy(&iif, RTA_DATA(rta[RTA_IIF-1]), sizeof(int));
@@ -1617,8 +1611,7 @@
 
 	NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid;
 	err = rt6_fill_node(skb, rt, 
-			    fl.nl_u.ip6_u.daddr,
-			    fl.nl_u.ip6_u.saddr,
+			    fl.fl6_dst, fl.fl6_src,
 			    iif,
 			    RTM_NEWROUTE, NETLINK_CB(in_skb).pid,
 			    nlh->nlmsg_seq, nlh);
diff -urN linux-2.5.67-bk9/net/ipv6/tcp_ipv6.c linux-2.5.67-bk10/net/ipv6/tcp_ipv6.c
--- linux-2.5.67-bk9/net/ipv6/tcp_ipv6.c	2003-04-19 04:35:32.000000000 -0700
+++ linux-2.5.67-bk10/net/ipv6/tcp_ipv6.c	2003-04-19 04:35:43.000000000 -0700
@@ -670,12 +670,12 @@
 	fl.fl6_dst = &np->daddr;
 	fl.fl6_src = saddr;
 	fl.oif = sk->bound_dev_if;
-	fl.uli_u.ports.dport = usin->sin6_port;
-	fl.uli_u.ports.sport = inet->sport;
+	fl.fl_ip_dport = usin->sin6_port;
+	fl.fl_ip_sport = inet->sport;
 
 	if (np->opt && np->opt->srcrt) {
 		struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
-		fl.nl_u.ip6_u.daddr = rt0->addr;
+		fl.fl6_dst = rt0->addr;
 	}
 
 	if (!fl.fl6_src)
@@ -796,11 +796,11 @@
 			   for now.
 			 */
 			fl.proto = IPPROTO_TCP;
-			fl.nl_u.ip6_u.daddr = &np->daddr;
-			fl.nl_u.ip6_u.saddr = &np->saddr;
+			fl.fl6_dst = &np->daddr;
+			fl.fl6_src = &np->saddr;
 			fl.oif = sk->bound_dev_if;
-			fl.uli_u.ports.dport = inet->dport;
-			fl.uli_u.ports.sport = inet->sport;
+			fl.fl_ip_dport = inet->dport;
+			fl.fl_ip_sport = inet->sport;
 
 			dst = ip6_route_output(sk, &fl);
 		} else
@@ -881,12 +881,12 @@
 	int err = -1;
 
 	fl.proto = IPPROTO_TCP;
-	fl.nl_u.ip6_u.daddr = &req->af.v6_req.rmt_addr;
-	fl.nl_u.ip6_u.saddr = &req->af.v6_req.loc_addr;
+	fl.fl6_dst = &req->af.v6_req.rmt_addr;
+	fl.fl6_src = &req->af.v6_req.loc_addr;
 	fl.fl6_flowlabel = 0;
 	fl.oif = req->af.v6_req.iif;
-	fl.uli_u.ports.dport = req->rmt_port;
-	fl.uli_u.ports.sport = inet_sk(sk)->sport;
+	fl.fl_ip_dport = req->rmt_port;
+	fl.fl_ip_sport = inet_sk(sk)->sport;
 
 	if (dst == NULL) {
 		opt = np->opt;
@@ -901,7 +901,7 @@
 
 		if (opt && opt->srcrt) {
 			struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
-			fl.nl_u.ip6_u.daddr = rt0->addr;
+			fl.fl6_dst = rt0->addr;
 		}
 
 		dst = ip6_route_output(sk, &fl);
@@ -917,7 +917,7 @@
 					 &req->af.v6_req.loc_addr, &req->af.v6_req.rmt_addr,
 					 csum_partial((char *)th, skb->len, skb->csum));
 
-		fl.nl_u.ip6_u.daddr = &req->af.v6_req.rmt_addr;
+		fl.fl6_dst = &req->af.v6_req.rmt_addr;
 		err = ip6_xmit(sk, skb, &fl, opt);
 		if (err == NET_XMIT_CN)
 			err = 0;
@@ -1019,19 +1019,18 @@
 
 	buff->csum = csum_partial((char *)t1, sizeof(*t1), 0);
 
-	fl.nl_u.ip6_u.daddr = &skb->nh.ipv6h->saddr;
-	fl.nl_u.ip6_u.saddr = &skb->nh.ipv6h->daddr;
+	fl.fl6_dst = &skb->nh.ipv6h->saddr;
+	fl.fl6_src = &skb->nh.ipv6h->daddr;
 	fl.fl6_flowlabel = 0;
 
-	t1->check = csum_ipv6_magic(fl.nl_u.ip6_u.saddr,
-				    fl.nl_u.ip6_u.daddr, 
+	t1->check = csum_ipv6_magic(fl.fl6_src, fl.fl6_dst, 
 				    sizeof(*t1), IPPROTO_TCP,
 				    buff->csum);
 
 	fl.proto = IPPROTO_TCP;
 	fl.oif = tcp_v6_iif(skb);
-	fl.uli_u.ports.dport = t1->dest;
-	fl.uli_u.ports.sport = t1->source;
+	fl.fl_ip_dport = t1->dest;
+	fl.fl_ip_sport = t1->source;
 
 	/* sk = NULL, but it is safe for now. RST socket required. */
 	buff->dst = ip6_route_output(NULL, &fl);
@@ -1084,19 +1083,18 @@
 
 	buff->csum = csum_partial((char *)t1, tot_len, 0);
 
-	fl.nl_u.ip6_u.daddr = &skb->nh.ipv6h->saddr;
-	fl.nl_u.ip6_u.saddr = &skb->nh.ipv6h->daddr;
+	fl.fl6_dst = &skb->nh.ipv6h->saddr;
+	fl.fl6_src = &skb->nh.ipv6h->daddr;
 	fl.fl6_flowlabel = 0;
 
-	t1->check = csum_ipv6_magic(fl.nl_u.ip6_u.saddr,
-				    fl.nl_u.ip6_u.daddr, 
+	t1->check = csum_ipv6_magic(fl.fl6_src, fl.fl6_dst, 
 				    tot_len, IPPROTO_TCP,
 				    buff->csum);
 
 	fl.proto = IPPROTO_TCP;
 	fl.oif = tcp_v6_iif(skb);
-	fl.uli_u.ports.dport = t1->dest;
-	fl.uli_u.ports.sport = t1->source;
+	fl.fl_ip_dport = t1->dest;
+	fl.fl_ip_sport = t1->source;
 
 	buff->dst = ip6_route_output(NULL, &fl);
 
@@ -1335,16 +1333,16 @@
 
 	if (dst == NULL) {
 		fl.proto = IPPROTO_TCP;
-		fl.nl_u.ip6_u.daddr = &req->af.v6_req.rmt_addr;
+		fl.fl6_dst = &req->af.v6_req.rmt_addr;
 		if (opt && opt->srcrt) {
 			struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
-			fl.nl_u.ip6_u.daddr = rt0->addr;
+			fl.fl6_dst = rt0->addr;
 		}
-		fl.nl_u.ip6_u.saddr = &req->af.v6_req.loc_addr;
+		fl.fl6_src = &req->af.v6_req.loc_addr;
 		fl.fl6_flowlabel = 0;
 		fl.oif = sk->bound_dev_if;
-		fl.uli_u.ports.dport = req->rmt_port;
-		fl.uli_u.ports.sport = inet_sk(sk)->sport;
+		fl.fl_ip_dport = req->rmt_port;
+		fl.fl_ip_sport = inet_sk(sk)->sport;
 
 		dst = ip6_route_output(sk, &fl);
 	}
@@ -1732,16 +1730,16 @@
 		struct flowi fl;
 
 		fl.proto = IPPROTO_TCP;
-		fl.nl_u.ip6_u.daddr = &np->daddr;
-		fl.nl_u.ip6_u.saddr = &np->saddr;
+		fl.fl6_dst = &np->daddr;
+		fl.fl6_src = &np->saddr;
 		fl.fl6_flowlabel = np->flow_label;
 		fl.oif = sk->bound_dev_if;
-		fl.uli_u.ports.dport = inet->dport;
-		fl.uli_u.ports.sport = inet->sport;
+		fl.fl_ip_dport = inet->dport;
+		fl.fl_ip_sport = inet->sport;
 
 		if (np->opt && np->opt->srcrt) {
 			struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
-			fl.nl_u.ip6_u.daddr = rt0->addr;
+			fl.fl6_dst = rt0->addr;
 		}
 
 		dst = ip6_route_output(sk, &fl);
@@ -1774,12 +1772,12 @@
 	fl.fl6_flowlabel = np->flow_label;
 	IP6_ECN_flow_xmit(sk, fl.fl6_flowlabel);
 	fl.oif = sk->bound_dev_if;
-	fl.uli_u.ports.sport = inet->sport;
-	fl.uli_u.ports.dport = inet->dport;
+	fl.fl_ip_sport = inet->sport;
+	fl.fl_ip_dport = inet->dport;
 
 	if (np->opt && np->opt->srcrt) {
 		struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
-		fl.nl_u.ip6_u.daddr = rt0->addr;
+		fl.fl6_dst = rt0->addr;
 	}
 
 	dst = __sk_dst_check(sk, np->dst_cookie);
@@ -1799,7 +1797,7 @@
 	skb->dst = dst_clone(dst);
 
 	/* Restore final destination back after routing done */
-	fl.nl_u.ip6_u.daddr = &np->daddr;
+	fl.fl6_dst = &np->daddr;
 
 	return ip6_xmit(sk, skb, &fl, np->opt);
 }
diff -urN linux-2.5.67-bk9/net/ipv6/udp.c linux-2.5.67-bk10/net/ipv6/udp.c
--- linux-2.5.67-bk9/net/ipv6/udp.c	2003-04-19 04:35:32.000000000 -0700
+++ linux-2.5.67-bk10/net/ipv6/udp.c	2003-04-19 04:35:43.000000000 -0700
@@ -352,8 +352,8 @@
 	fl.fl6_dst = &np->daddr;
 	fl.fl6_src = &saddr;
 	fl.oif = sk->bound_dev_if;
-	fl.uli_u.ports.dport = inet->dport;
-	fl.uli_u.ports.sport = inet->sport;
+	fl.fl_ip_dport = inet->dport;
+	fl.fl_ip_sport = inet->sport;
 
 	if (!fl.oif && (addr_type&IPV6_ADDR_MULTICAST))
 		fl.oif = np->mcast_oif;
@@ -936,8 +936,8 @@
 	fl.fl6_dst = daddr;
 	if (fl.fl6_src == NULL && !ipv6_addr_any(&np->saddr))
 		fl.fl6_src = &np->saddr;
-	fl.uli_u.ports.dport = udh.uh.dest;
-	fl.uli_u.ports.sport = udh.uh.source;
+	fl.fl_ip_dport = udh.uh.dest;
+	fl.fl_ip_sport = udh.uh.source;
 
 	err = ip6_build_xmit(sk, udpv6_getfrag, &udh, &fl, len, opt, hlimit,
 			     msg->msg_flags);
diff -urN linux-2.5.67-bk9/net/ipv6/xfrm6_policy.c linux-2.5.67-bk10/net/ipv6/xfrm6_policy.c
--- linux-2.5.67-bk9/net/ipv6/xfrm6_policy.c	2003-04-19 04:35:32.000000000 -0700
+++ linux-2.5.67-bk10/net/ipv6/xfrm6_policy.c	2003-04-19 04:35:43.000000000 -0700
@@ -195,8 +195,8 @@
 			if (pskb_may_pull(skb, skb->nh.raw + offset + 4 - skb->data)) {
 				u16 *ports = (u16 *)exthdr;
 
-				fl->uli_u.ports.sport = ports[0];
-				fl->uli_u.ports.dport = ports[1];
+				fl->fl_ip_sport = ports[0];
+				fl->fl_ip_dport = ports[1];
 			}
 			return;
 
@@ -205,7 +205,7 @@
 		case IPPROTO_ESP:
 		case IPPROTO_COMP:
 		default:
-			fl->uli_u.spi = 0;
+			fl->fl_ipsec_spi = 0;
 			return;
 		};
 	}
diff -urN linux-2.5.67-bk9/net/ipv6/xfrm6_state.c linux-2.5.67-bk10/net/ipv6/xfrm6_state.c
--- linux-2.5.67-bk9/net/ipv6/xfrm6_state.c	2003-04-07 10:31:05.000000000 -0700
+++ linux-2.5.67-bk10/net/ipv6/xfrm6_state.c	2003-04-19 04:35:43.000000000 -0700
@@ -27,9 +27,9 @@
 	 * to current session. */
 	memcpy(&x->sel.daddr, fl->fl6_dst, sizeof(struct in6_addr));
 	memcpy(&x->sel.saddr, fl->fl6_src, sizeof(struct in6_addr));
-	x->sel.dport = fl->uli_u.ports.dport;
+	x->sel.dport = fl->fl_ip_dport;
 	x->sel.dport_mask = ~0;
-	x->sel.sport = fl->uli_u.ports.sport;
+	x->sel.sport = fl->fl_ip_sport;
 	x->sel.sport_mask = ~0;
 	x->sel.prefixlen_d = 128;
 	x->sel.prefixlen_s = 128;
diff -urN linux-2.5.67-bk9/net/netsyms.c linux-2.5.67-bk10/net/netsyms.c
--- linux-2.5.67-bk9/net/netsyms.c	2003-04-19 04:35:32.000000000 -0700
+++ linux-2.5.67-bk10/net/netsyms.c	2003-04-19 04:35:43.000000000 -0700
@@ -228,7 +228,7 @@
 #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
 EXPORT_SYMBOL(dev_change_flags);
 #endif
-EXPORT_SYMBOL(vlan_ioctl_hook);
+EXPORT_SYMBOL(vlan_ioctl_set);
 
 EXPORT_SYMBOL(scm_detach_fds);
 
diff -urN linux-2.5.67-bk9/net/sctp/ipv6.c linux-2.5.67-bk10/net/sctp/ipv6.c
--- linux-2.5.67-bk9/net/sctp/ipv6.c	2003-04-19 04:35:32.000000000 -0700
+++ linux-2.5.67-bk10/net/sctp/ipv6.c	2003-04-19 04:35:43.000000000 -0700
@@ -165,8 +165,8 @@
 		fl.oif = transport->saddr.v6.sin6_scope_id;
 	else
 		fl.oif = sk->bound_dev_if;
-	fl.uli_u.ports.sport = inet_sk(sk)->sport;
-	fl.uli_u.ports.dport = transport->ipaddr.v6.sin6_port;
+	fl.fl_ip_sport = inet_sk(sk)->sport;
+	fl.fl_ip_dport = transport->ipaddr.v6.sin6_port;
 
 	if (np->opt && np->opt->srcrt) {
 		struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
diff -urN linux-2.5.67-bk9/net/socket.c linux-2.5.67-bk10/net/socket.c
--- linux-2.5.67-bk9/net/socket.c	2003-04-19 04:35:32.000000000 -0700
+++ linux-2.5.67-bk10/net/socket.c	2003-04-19 04:35:43.000000000 -0700
@@ -714,6 +714,11 @@
 }
 
 
+/*
+ * Atomic setting of ioctl hooks to avoid race
+ * with module unload.
+ */
+
 static DECLARE_MUTEX(br_ioctl_mutex);
 static int (*br_ioctl_hook)(unsigned long arg) = NULL;
 
@@ -724,8 +729,15 @@
 	up(&br_ioctl_mutex);
 }
 
+static DECLARE_MUTEX(vlan_ioctl_mutex);
+static int (*vlan_ioctl_hook)(unsigned long arg);
 
-int (*vlan_ioctl_hook)(unsigned long arg);
+void vlan_ioctl_set(int (*hook)(unsigned long))
+{
+	down(&vlan_ioctl_mutex);
+	vlan_ioctl_hook = hook;
+	up(&vlan_ioctl_mutex);
+}
 
 #ifdef CONFIG_DLCI
 extern int dlci_ioctl(unsigned int, void *);
@@ -789,8 +801,10 @@
 			if (!vlan_ioctl_hook)
 				request_module("8021q");
 #endif
+			down(&vlan_ioctl_mutex);
 			if (vlan_ioctl_hook)
 				err = vlan_ioctl_hook(arg);
+			up(&vlan_ioctl_mutex);
 			break;
 		case SIOCGIFDIVERT:
 		case SIOCSIFDIVERT:
diff -urN linux-2.5.67-bk9/scripts/kconfig/gconf.c linux-2.5.67-bk10/scripts/kconfig/gconf.c
--- linux-2.5.67-bk9/scripts/kconfig/gconf.c	2003-04-07 10:32:51.000000000 -0700
+++ linux-2.5.67-bk10/scripts/kconfig/gconf.c	2003-04-19 04:35:43.000000000 -0700
@@ -64,7 +64,7 @@
 enum {
 	COL_OPTION, COL_NAME, COL_NO, COL_MOD, COL_YES, COL_VALUE,
 	COL_MENU, COL_COLOR, COL_EDIT, COL_PIXBUF,
-	COL_PIXVIS, COL_BTNVIS, COL_BTNACT, COL_BTNINC,
+	COL_PIXVIS, COL_BTNVIS, COL_BTNACT, COL_BTNINC, COL_BTNRAD,
 	COL_NUMBER
 };
 
@@ -295,7 +295,8 @@
 					  G_TYPE_POINTER, GDK_TYPE_COLOR,
 					  G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
 					  G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
-					  G_TYPE_BOOLEAN, G_TYPE_BOOLEAN);
+					  G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
+					  G_TYPE_BOOLEAN);
 	model2 = GTK_TREE_MODEL(tree2);
 
 	for (parents[0] = NULL, i = 1; i < 256; i++)
@@ -308,7 +309,8 @@
 				   G_TYPE_POINTER, GDK_TYPE_COLOR,
 				   G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
 				   G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
-				   G_TYPE_BOOLEAN, G_TYPE_BOOLEAN);
+				   G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
+				   G_TYPE_BOOLEAN);
 	model1 = GTK_TREE_MODEL(tree1);
 }
 
@@ -370,7 +372,8 @@
 					    renderer,
 					    "active", COL_BTNACT,
 					    "inconsistent", COL_BTNINC,
-					    "visible", COL_BTNVIS, NULL);
+					    "visible", COL_BTNVIS, 
+					    "radio", COL_BTNRAD, NULL);
 	/*g_signal_connect(G_OBJECT(renderer), "toggled",
 	   G_CALLBACK(renderer_toggled), NULL); */
 	renderer = gtk_cell_renderer_text_new();
@@ -1219,6 +1222,8 @@
 		struct symbol *def_sym = sym_get_choice_value(sym);
 		struct menu *def_menu = NULL;
 
+		row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
+
 		for (child = menu->list; child; child = child->next) {
 			if (menu_is_visible(child)
 			    && child->sym == def_sym)
@@ -1229,6 +1234,8 @@
 			row[COL_VALUE] =
 			    g_strdup(menu_get_prompt(def_menu));
 	}
+	if(sym->flags & SYMBOL_CHOICEVAL)
+		row[COL_BTNRAD] = GINT_TO_POINTER(TRUE);
 
 	stype = sym_get_type(sym);
 	switch (stype) {
@@ -1307,6 +1314,7 @@
 			   COL_BTNVIS, GPOINTER_TO_INT(row[COL_BTNVIS]),
 			   COL_BTNACT, GPOINTER_TO_INT(row[COL_BTNACT]),
 			   COL_BTNINC, GPOINTER_TO_INT(row[COL_BTNINC]),
+			   COL_BTNRAD, GPOINTER_TO_INT(row[COL_BTNRAD]),
 			   -1);
 
 	g_object_unref(pix);
