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

diff -urN linux-2.5.69-bk1/MAINTAINERS linux-2.5.69-bk2/MAINTAINERS
--- linux-2.5.69-bk1/MAINTAINERS	2003-05-04 16:53:32.000000000 -0700
+++ linux-2.5.69-bk2/MAINTAINERS	2003-05-07 04:41:16.000000000 -0700
@@ -801,20 +801,13 @@
 M:	drivers@neukum.org
 S:	Maintained
 
-I2C DRIVERS
-P:	Simon Vogl
-M:	simon@tk.uni-linz.ac.at
-P:	Frodo Looijaard
-M:	frodol@dds.nl
-L:	linux-i2c@pelican.tk.uni-linz.ac.at
-W:	http://www.tk.uni-linz.ac.at/~simon/private/i2c
-S:	Maintained
-
-SENSORS DRIVERS
+I2C AND SENSORS DRIVERS
 P:      Frodo Looijaard
 M:      frodol@dds.nl
 P:      Philip Edelbrock
 M:      phil@netroedge.com
+P:	Greg Kroah-Hartman
+M:	greg@kroah.com
 L:      sensors@stimpy.netroedge.com
 W:      http://www.lm-sensors.nu/
 S:      Maintained
diff -urN linux-2.5.69-bk1/Makefile linux-2.5.69-bk2/Makefile
--- linux-2.5.69-bk1/Makefile	2003-05-07 04:41:12.000000000 -0700
+++ linux-2.5.69-bk2/Makefile	2003-05-07 04:41:16.000000000 -0700
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 5
 SUBLEVEL = 69
-EXTRAVERSION = -bk1
+EXTRAVERSION = -bk2
 
 # *DOCUMENTATION*
 # To see a list of typical targets execute "make help"
diff -urN linux-2.5.69-bk1/arch/sparc64/kernel/power.c linux-2.5.69-bk2/arch/sparc64/kernel/power.c
--- linux-2.5.69-bk1/arch/sparc64/kernel/power.c	2003-05-04 16:53:41.000000000 -0700
+++ linux-2.5.69-bk2/arch/sparc64/kernel/power.c	2003-05-07 04:41:16.000000000 -0700
@@ -84,6 +84,16 @@
 	return 0;
 }
 
+static int __init has_button_interrupt(struct linux_ebus_device *edev)
+{
+	if (edev->irqs[0] == PCI_IRQ_NONE)
+		return 0;
+	if (!prom_node_has_property(edev->prom_node, "button"))
+		return 0;
+
+	return 1;
+}
+
 void __init power_init(void)
 {
 	struct linux_ebus *ebus;
@@ -106,7 +116,7 @@
 	power_reg = (unsigned long)ioremap(edev->resource[0].start, 0x4);
 	printk("power: Control reg at %016lx ... ", power_reg);
 	poweroff_method = machine_halt;  /* able to use the standard halt */
-	if (edev->irqs[0] != PCI_IRQ_NONE) {
+	if (has_button_interrupt(edev)) {
 		if (kernel_thread(powerd, 0, CLONE_FS) < 0) {
 			printk("Failed to start power daemon.\n");
 			return;
diff -urN linux-2.5.69-bk1/drivers/acpi/acpi_ksyms.c linux-2.5.69-bk2/drivers/acpi/acpi_ksyms.c
--- linux-2.5.69-bk1/drivers/acpi/acpi_ksyms.c	2003-05-04 16:53:09.000000000 -0700
+++ linux-2.5.69-bk2/drivers/acpi/acpi_ksyms.c	2003-05-07 04:41:16.000000000 -0700
@@ -80,6 +80,7 @@
 EXPORT_SYMBOL(acpi_get_possible_resources);
 EXPORT_SYMBOL(acpi_walk_resources);
 EXPORT_SYMBOL(acpi_set_current_resources);
+EXPORT_SYMBOL(acpi_resource_to_address64);
 EXPORT_SYMBOL(acpi_enable_event);
 EXPORT_SYMBOL(acpi_disable_event);
 EXPORT_SYMBOL(acpi_clear_event);
diff -urN linux-2.5.69-bk1/drivers/atm/ambassador.c linux-2.5.69-bk2/drivers/atm/ambassador.c
--- linux-2.5.69-bk1/drivers/atm/ambassador.c	2003-05-04 16:53:02.000000000 -0700
+++ linux-2.5.69-bk2/drivers/atm/ambassador.c	2003-05-07 04:41:16.000000000 -0700
@@ -290,12 +290,11 @@
 /********** microcode **********/
 
 #ifdef AMB_NEW_MICROCODE
-#define UCODE(x) UCODE1(atmsar12.,x)
+#define UCODE(x) UCODE2(atmsar12.x)
 #else
-#define UCODE(x) UCODE1(atmsar11.,x)
+#define UCODE(x) UCODE2(atmsar11.x)
 #endif
 #define UCODE2(x) #x
-#define UCODE1(x,y) UCODE2(x ## y)
 
 static u32 __initdata ucode_start = 
 #include UCODE(start)
diff -urN linux-2.5.69-bk1/drivers/atm/iphase.c linux-2.5.69-bk2/drivers/atm/iphase.c
--- linux-2.5.69-bk1/drivers/atm/iphase.c	2003-05-04 16:53:42.000000000 -0700
+++ linux-2.5.69-bk2/drivers/atm/iphase.c	2003-05-07 04:41:16.000000000 -0700
@@ -2792,11 +2792,15 @@
              break;
           case MEMDUMP_FFL:
           {  
-             ia_regs_t       regs_local;
-             ffredn_t        *ffL = &regs_local.ffredn;
-             rfredn_t        *rfL = &regs_local.rfredn;
+             ia_regs_t       *regs_local;
+             ffredn_t        *ffL;
+             rfredn_t        *rfL;
                      
 	     if (!capable(CAP_NET_ADMIN)) return -EPERM;
+	     regs_local = kmalloc(sizeof(*regs_local), GFP_KERNEL);
+	     if (!regs_local) return -ENOMEM;
+	     ffL = &regs_local->ffredn;
+	     rfL = &regs_local->rfredn;
              /* Copy real rfred registers into the local copy */
  	     for (i=0; i<(sizeof (rfredn_t))/4; i++)
                 ((u_int *)rfL)[i] = ((u_int *)iadev->reass_reg)[i] & 0xffff;
@@ -2804,8 +2808,11 @@
 	     for (i=0; i<(sizeof (ffredn_t))/4; i++)
                 ((u_int *)ffL)[i] = ((u_int *)iadev->seg_reg)[i] & 0xffff;
 
-             if (copy_to_user(ia_cmds.buf, &regs_local,sizeof(ia_regs_t)))
+             if (copy_to_user(ia_cmds.buf, regs_local,sizeof(ia_regs_t))) {
+                kfree(regs_local);
                 return -EFAULT;
+             }
+             kfree(regs_local);
              printk("Board %d registers dumped\n", board);
              ia_cmds.status = 0;                  
 	 }	
diff -urN linux-2.5.69-bk1/drivers/bluetooth/hci_usb.c linux-2.5.69-bk2/drivers/bluetooth/hci_usb.c
--- linux-2.5.69-bk1/drivers/bluetooth/hci_usb.c	2003-05-04 16:53:41.000000000 -0700
+++ linux-2.5.69-bk2/drivers/bluetooth/hci_usb.c	2003-05-07 04:41:16.000000000 -0700
@@ -64,8 +64,8 @@
 #endif
 
 #ifndef CONFIG_BT_USB_ZERO_PACKET
-#undef  USB_ZERO_PACKET
-#define USB_ZERO_PACKET 0
+#undef  URB_ZERO_PACKET
+#define URB_ZERO_PACKET 0
 #endif
 
 static struct usb_driver hci_usb_driver; 
@@ -458,7 +458,7 @@
 	pipe = usb_sndbulkpipe(husb->udev, husb->bulk_out_ep->desc.bEndpointAddress);
 	usb_fill_bulk_urb(urb, husb->udev, pipe, skb->data, skb->len, 
 			hci_usb_tx_complete, husb);
-	urb->transfer_flags = USB_ZERO_PACKET;
+	urb->transfer_flags = URB_ZERO_PACKET;
 
 	BT_DBG("%s skb %p len %d", husb->hdev.name, skb, skb->len);
 
diff -urN linux-2.5.69-bk1/drivers/char/n_hdlc.c linux-2.5.69-bk2/drivers/char/n_hdlc.c
--- linux-2.5.69-bk1/drivers/char/n_hdlc.c	2003-05-04 16:53:08.000000000 -0700
+++ linux-2.5.69-bk2/drivers/char/n_hdlc.c	2003-05-07 04:41:16.000000000 -0700
@@ -9,7 +9,7 @@
  *	Al Longyear <longyear@netcom.com>, Paul Mackerras <Paul.Mackerras@cs.anu.edu.au>
  *
  * Original release 01/11/99
- * $Id: n_hdlc.c,v 4.6 2003/04/21 19:14:07 paulkf Exp $
+ * $Id: n_hdlc.c,v 4.8 2003/05/06 21:18:51 paulkf Exp $
  *
  * This code is released under the GNU General Public License (GPL)
  *
@@ -78,7 +78,7 @@
  */
 
 #define HDLC_MAGIC 0x239e
-#define HDLC_VERSION "$Revision: 4.6 $"
+#define HDLC_VERSION "$Revision: 4.8 $"
 
 #include <linux/version.h>
 #include <linux/config.h>
@@ -215,6 +215,21 @@
 /* Define this string only once for all macro invocations */
 static char szVersion[] = HDLC_VERSION;
 
+static struct tty_ldisc n_hdlc_ldisc = {
+	.owner		= THIS_MODULE,
+	.magic		= TTY_LDISC_MAGIC,
+	.name		= "hdlc",
+	.open		= n_hdlc_tty_open,
+	.close		= n_hdlc_tty_close,
+	.read		= n_hdlc_tty_read,
+	.write		= n_hdlc_tty_write,
+	.ioctl		= n_hdlc_tty_ioctl,
+	.poll		= n_hdlc_tty_poll,
+	.receive_buf	= n_hdlc_tty_receive,
+	.receive_room	= n_hdlc_tty_room,
+	.write_wakeup	= n_hdlc_tty_wakeup,
+};
+
 /* n_hdlc_release()
  *
  *	release an n_hdlc per device line discipline info structure
@@ -968,25 +983,6 @@
 
 static int __init n_hdlc_init(void)
 {
-	static struct tty_ldisc	n_hdlc_ldisc = {
-		TTY_LDISC_MAGIC,    /* magic */
-		"hdlc",             /* name */
-		0,                  /* num */
-		0,                  /* flags */
-		n_hdlc_tty_open,    /* open */
-		n_hdlc_tty_close,   /* close */
-		0,                  /* flush_buffer */
-		0,                  /* chars_in_buffer */
-		n_hdlc_tty_read,    /* read */
-		n_hdlc_tty_write,   /* write */
-		n_hdlc_tty_ioctl,   /* ioctl */
-		0,                  /* set_termios */
-		n_hdlc_tty_poll,    /* poll */
-		n_hdlc_tty_receive, /* receive_buf */
-		n_hdlc_tty_room,    /* receive_room */
-		n_hdlc_tty_wakeup,  /* write_wakeup */
-		THIS_MODULE         /* owner */
-	};
 	int    status;
 
 	/* range check maxframe arg */
diff -urN linux-2.5.69-bk1/drivers/char/synclink.c linux-2.5.69-bk2/drivers/char/synclink.c
--- linux-2.5.69-bk1/drivers/char/synclink.c	2003-05-04 16:53:12.000000000 -0700
+++ linux-2.5.69-bk2/drivers/char/synclink.c	2003-05-07 04:41:16.000000000 -0700
@@ -1,7 +1,7 @@
 /*
  * linux/drivers/char/synclink.c
  *
- * $Id: synclink.c,v 4.6 2003/04/21 17:46:54 paulkf Exp $
+ * $Id: synclink.c,v 4.9 2003/05/06 21:18:51 paulkf Exp $
  *
  * Device driver for Microgate SyncLink ISA and PCI
  * high speed multiprotocol serial adapters.
@@ -193,6 +193,7 @@
 	int			flags;
 	int			count;		/* count of opens */
 	int			line;
+	int                     hw_version;
 	unsigned short		close_delay;
 	unsigned short		closing_wait;	/* time to wait before closing */
 	
@@ -917,7 +918,7 @@
 MODULE_PARM(txholdbufs,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i");
 
 static char *driver_name = "SyncLink serial driver";
-static char *driver_version = "$Revision: 4.6 $";
+static char *driver_version = "$Revision: 4.9 $";
 
 static int synclink_init_one (struct pci_dev *dev,
 				     const struct pci_device_id *ent);
@@ -925,6 +926,7 @@
 
 static struct pci_device_id synclink_pci_tbl[] __devinitdata = {
 	{ PCI_VENDOR_ID_MICROGATE, PCI_DEVICE_ID_MICROGATE_USC, PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_MICROGATE, 0x0210, PCI_ANY_ID, PCI_ANY_ID, },
 	{ 0, }, /* terminate list */
 };
 MODULE_DEVICE_TABLE(pci, synclink_pci_tbl);
@@ -4216,9 +4218,7 @@
 				info->get_tx_holding_index=0;
 
 			/* restart transmit timer */
-			del_timer(&info->tx_timer);
-			info->tx_timer.expires = jiffies + jiffies_from_ms(5000);
-			add_timer(&info->tx_timer);
+			mod_timer(&info->tx_timer, jiffies + jiffies_from_ms(5000));
 
 			ret = 1;
 		}
@@ -4436,12 +4436,12 @@
 		info->max_frame_size = 65535;
 	
 	if ( info->bus_type == MGSL_BUS_TYPE_PCI ) {
-		printk( "SyncLink device %s added:PCI bus IO=%04X IRQ=%d Mem=%08X LCR=%08X MaxFrameSize=%u\n",
-			info->device_name, info->io_base, info->irq_level,
+		printk( "SyncLink PCI v%d %s: IO=%04X IRQ=%d Mem=%08X,%08X MaxFrameSize=%u\n",
+			info->hw_version + 1, info->device_name, info->io_base, info->irq_level,
 			info->phys_memory_base, info->phys_lcr_base,
 		     	info->max_frame_size );
 	} else {
-		printk( "SyncLink device %s added:ISA bus IO=%04X IRQ=%d DMA=%d MaxFrameSize=%u\n",
+		printk( "SyncLink ISA %s: IO=%04X IRQ=%d DMA=%d MaxFrameSize=%u\n",
 			info->device_name, info->io_base, info->irq_level, info->dma_level,
 		     	info->max_frame_size );
 	}
@@ -5296,10 +5296,11 @@
 	info->mbre_bit = BIT8;
 	outw( BIT8, info->io_base );			/* set Master Bus Enable (DCAR) */
 
-	/* Enable DMAEN (Port 7, Bit 14) */
-	/* This connects the DMA request signal to the ISA bus */
-	/* on the ISA adapter. This has no effect for the PCI adapter */
-	usc_OutReg( info, PCR, (u16)((usc_InReg(info, PCR) | BIT15) & ~BIT14) );
+	if (info->bus_type == MGSL_BUS_TYPE_ISA) {
+		/* Enable DMAEN (Port 7, Bit 14) */
+		/* This connects the DMA request signal to the ISA bus */
+		usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT15) & ~BIT14));
+	}
 
 	/* DMA Control Register (DCR)
 	 *
@@ -6276,10 +6277,11 @@
 
 	usc_EnableMasterIrqBit( info );
 
-	/* Enable INTEN (Port 6, Bit12) */
-	/* This connects the IRQ request signal to the ISA bus */
-	/* on the ISA adapter. This has no effect for the PCI adapter */
-	usc_OutReg( info, PCR, (u16)((usc_InReg(info, PCR) | BIT13) & ~BIT12) );
+	if (info->bus_type == MGSL_BUS_TYPE_ISA) {
+		/* Enable INTEN (Port 6, Bit12) */
+		/* This connects the IRQ request signal to the ISA bus */
+		usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT13) & ~BIT12));
+	}
 
 }	/* end of usc_set_async_mode() */
 
@@ -6370,10 +6372,11 @@
 	usc_loopback_frame( info );
 	usc_set_sdlc_mode( info );
 
-	/* Enable INTEN (Port 6, Bit12) */
-	/* This connects the IRQ request signal to the ISA bus */
-	/* on the ISA adapter. This has no effect for the PCI adapter */
-	usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT13) & ~BIT12));
+	if (info->bus_type == MGSL_BUS_TYPE_ISA) {
+		/* Enable INTEN (Port 6, Bit12) */
+		/* This connects the IRQ request signal to the ISA bus */
+		usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT13) & ~BIT12));
+	}
 
 	usc_enable_aux_clock(info, info->params.clock_speed);
 
@@ -8115,17 +8118,20 @@
 	info->bus_type = MGSL_BUS_TYPE_PCI;
 	info->io_addr_size = 8;
 	info->irq_flags = SA_SHIRQ;
-		
-	/* Store the PCI9050 misc control register value because a flaw
-	 * in the PCI9050 prevents LCR registers from being read if 
-	 * BIOS assigns an LCR base address with bit 7 set.
-	 *  
-	 * Only the misc control register is accessed for which only 
-	 * write access is needed, so set an initial value and change 
-	 * bits to the device instance data as we write the value
-	 * to the actual misc control register.
-	 */
-	info->misc_ctrl_value = 0x087e4546;
+
+	if (dev->device == 0x0210) {
+		/* Version 1 PCI9030 based universal PCI adapter */
+		info->misc_ctrl_value = 0x007c4080;
+		info->hw_version = 1;
+	} else {
+		/* Version 0 PCI9050 based 5V PCI adapter
+		 * A PCI9050 bug prevents reading LCR registers if 
+		 * LCR base address bit 7 is set. Maintain shadow
+		 * value so we can write to LCR misc control reg.
+		 */
+		info->misc_ctrl_value = 0x087e4546;
+		info->hw_version = 0;
+	}
 				
 	mgsl_add_device(info);
 
diff -urN linux-2.5.69-bk1/drivers/hotplug/Kconfig linux-2.5.69-bk2/drivers/hotplug/Kconfig
--- linux-2.5.69-bk1/drivers/hotplug/Kconfig	2003-05-04 16:53:13.000000000 -0700
+++ linux-2.5.69-bk2/drivers/hotplug/Kconfig	2003-05-07 04:41:16.000000000 -0700
@@ -61,7 +61,7 @@
 
 config HOTPLUG_PCI_ACPI
 	tristate "ACPI PCI Hotplug driver"
-	depends on ACPI && HOTPLUG_PCI
+	depends on ACPI_BUS && HOTPLUG_PCI
 	help
 	  Say Y here if you have a system that supports PCI Hotplug using
 	  ACPI.
diff -urN linux-2.5.69-bk1/drivers/hotplug/acpiphp_glue.c linux-2.5.69-bk2/drivers/hotplug/acpiphp_glue.c
--- linux-2.5.69-bk1/drivers/hotplug/acpiphp_glue.c	2003-05-04 16:53:09.000000000 -0700
+++ linux-2.5.69-bk2/drivers/hotplug/acpiphp_glue.c	2003-05-07 04:41:16.000000000 -0700
@@ -806,6 +806,7 @@
 	struct list_head *l;
 	struct acpiphp_func *func;
 	int retval = 0;
+	int num;
 
 	if (slot->flags & SLOT_ENABLED)
 		goto err_exit;
@@ -825,7 +826,10 @@
 		goto err_exit;
 
 	/* returned `dev' is the *first function* only! */
-	dev = pci_scan_slot(slot->bridge->pci_bus, PCI_DEVFN(slot->device, 0));
+	num = pci_scan_slot(slot->bridge->pci_bus, PCI_DEVFN(slot->device, 0));
+	if (num)
+		pci_bus_add_devices(slot->bridge->pci_bus);
+	dev = pci_find_slot(slot->bridge->bus, PCI_DEVFN(slot->device, 0));
 
 	if (!dev) {
 		err("No new device found\n");
diff -urN linux-2.5.69-bk1/drivers/hotplug/cpqphp.h linux-2.5.69-bk2/drivers/hotplug/cpqphp.h
--- linux-2.5.69-bk1/drivers/hotplug/cpqphp.h	2003-05-04 16:53:37.000000000 -0700
+++ linux-2.5.69-bk2/drivers/hotplug/cpqphp.h	2003-05-07 04:41:16.000000000 -0700
@@ -31,7 +31,7 @@
 #include "pci_hotplug.h"
 #include <linux/interrupt.h>
 #include <asm/io.h>		/* for read? and write? functions */
-
+#include <linux/delay.h>	/* for delays */
 
 #if !defined(CONFIG_HOTPLUG_PCI_COMPAQ_MODULE)
 	#define MY_NAME	"cpqphp.o"
@@ -146,6 +146,10 @@
 	u8	reserved11;		/* 0x2b */
 	u8	slot_SERR;		/* 0x2c */
 	u8	slot_power;		/* 0x2d */
+	u8	reserved12;		/* 0x2e */
+	u8	reserved13;		/* 0x2f */
+	u8	next_curr_freq;		/* 0x30 */
+	u8	reset_freq_mode;	/* 0x31 */
 } __attribute__ ((packed));
 
 /* offsets to the controller registers based on the above structure layout */
@@ -173,6 +177,8 @@
 	CTRL_RESERVED11 =	offsetof(struct ctrl_reg, reserved11),
 	SLOT_SERR =		offsetof(struct ctrl_reg, slot_SERR),
 	SLOT_POWER =		offsetof(struct ctrl_reg, slot_power),
+	NEXT_CURR_FREQ =	offsetof(struct ctrl_reg, next_curr_freq),
+	RESET_FREQ_MODE =	offsetof(struct ctrl_reg, reset_freq_mode),
 };
 
 struct hrt {
@@ -294,12 +300,11 @@
 	struct pci_resource *bus_head;
 	struct pci_dev *pci_dev;
 	struct pci_bus *pci_bus;
-	struct proc_dir_entry* proc_entry;
-	struct proc_dir_entry* proc_entry2;
 	struct event_info event_queue[10];
 	struct slot *slot;
 	u8 next_event;
 	u8 interrupt;
+	u8 cfgspc_irq;
 	u8 bus;				/* bus number for the pci hotplug controller */
 	u8 rev;
 	u8 slot_device_offset;
@@ -316,8 +321,6 @@
 	u8 pcix_speed_capability;	/* PCI-X */
 	u8 pcix_support;		/* PCI-X */
 	u16 vendor_id;
-	char proc_name[20];
-	char proc_name2[20];
 	struct work_struct int_task_event;
 	wait_queue_head_t queue;	/* sleep & wake process */
 };
@@ -344,6 +347,7 @@
 #define PCI_SUB_HPC_ID2			0xA2F8
 #define PCI_SUB_HPC_ID3			0xA2F9
 #define PCI_SUB_HPC_ID_INTC		0xA2FA
+#define PCI_SUB_HPC_ID4			0xA2FD
 
 #define INT_BUTTON_IGNORE		0
 #define INT_PRESENCE_ON			1
@@ -436,7 +440,7 @@
 extern void	cpqhp_destroy_resource_list	(struct resource_lists * resources);
 extern int	cpqhp_configure_device		(struct controller* ctrl, struct pci_func* func);
 extern int	cpqhp_unconfigure_device	(struct pci_func* func);
-
+extern struct slot *cpqhp_find_slot		(struct controller *ctrl, u8 device);
 
 /* Global variables */
 extern int cpqhp_debug;
@@ -564,6 +568,7 @@
 	u32 led_control;
 	
 	led_control = readl(ctrl->hpc_reg + LED_CONTROL);
+	led_control &= ~(0x0101L << slot);
 	led_control |= (0x0001L << slot);
 	writel(led_control, ctrl->hpc_reg + LED_CONTROL);
 }
@@ -605,14 +610,63 @@
 }
 
 
+/*
+ * get_controller_speed - find the current frequency/mode of controller.
+ *
+ * @ctrl: controller to get frequency/mode for.
+ *
+ * Returns controller speed.
+ *
+ */
 static inline u8 get_controller_speed (struct controller *ctrl)
 {
-	u16 misc;
-	
-	misc = readw(ctrl->hpc_reg + MISC);
-	return (misc & 0x0800) ? PCI_SPEED_66MHz : PCI_SPEED_33MHz;
+	u8 curr_freq;
+ 	u16 misc;
+ 	
+	if (ctrl->pcix_support) {
+		curr_freq = readb(ctrl->hpc_reg + NEXT_CURR_FREQ);
+		if ((curr_freq & 0xB0) == 0xB0) 
+			return PCI_SPEED_133MHz_PCIX;
+		if ((curr_freq & 0xA0) == 0xA0)
+			return PCI_SPEED_100MHz_PCIX;
+		if ((curr_freq & 0x90) == 0x90)
+			return PCI_SPEED_66MHz_PCIX;
+		if (curr_freq & 0x10)
+			return PCI_SPEED_66MHz;
+
+		return PCI_SPEED_33MHz;
+	}
+
+ 	misc = readw(ctrl->hpc_reg + MISC);
+ 	return (misc & 0x0800) ? PCI_SPEED_66MHz : PCI_SPEED_33MHz;
 }
+ 
+
+/*
+ * get_adapter_speed - find the max supported frequency/mode of adapter.
+ *
+ * @ctrl: hotplug controller.
+ * @hp_slot: hotplug slot where adapter is installed.
+ *
+ * Returns adapter speed.
+ *
+ */
+static inline u8 get_adapter_speed (struct controller *ctrl, u8 hp_slot)
+{
+	u32 temp_dword = readl(ctrl->hpc_reg + NON_INT_INPUT);
+	dbg("slot: %d, PCIXCAP: %8x\n", hp_slot, temp_dword);
+	if (ctrl->pcix_support) {
+		if (temp_dword & (0x10000 << hp_slot))
+			return PCI_SPEED_133MHz_PCIX;
+		if (temp_dword & (0x100 << hp_slot))
+			return PCI_SPEED_66MHz_PCIX;
+	}
 
+	if (temp_dword & (0x01 << hp_slot))
+		return PCI_SPEED_66MHz;
+
+	return PCI_SPEED_33MHz;
+}
 
 static inline void enable_slot_power (struct controller *ctrl, u8 slot)
 {
@@ -721,5 +775,138 @@
 	return retval;
 }
 
+
+/**
+ * set_controller_speed - set the frequency and/or mode of a specific
+ * controller segment.
+ *
+ * @ctrl: controller to change frequency/mode for.
+ * @adapter_speed: the speed of the adapter we want to match.
+ * @hp_slot: the slot number where the adapter is installed.
+ *
+ * Returns 0 if we successfully change frequency and/or mode to match the
+ * adapter speed.
+ * 
+ */
+static inline u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_slot)
+{
+	struct slot *slot;
+	u8 reg;
+	u8 slot_power = readb(ctrl->hpc_reg + SLOT_POWER);
+	u16 reg16;
+	u32 leds = readl(ctrl->hpc_reg + LED_CONTROL);
+	
+	if (ctrl->speed == adapter_speed)
+		return 0;
+	
+	/* We don't allow freq/mode changes if we find another adapter running
+	 * in another slot on this controller */
+	for(slot = ctrl->slot; slot; slot = slot->next) {
+		if (slot->device == (hp_slot + ctrl->slot_device_offset)) 
+			continue;
+		if (!slot->hotplug_slot && !slot->hotplug_slot->info) 
+			continue;
+		if (slot->hotplug_slot->info->adapter_status == 0) 
+			continue;
+		/* If another adapter is running on the same segment but at a
+		 * lower speed/mode, we allow the new adapter to function at
+		 * this rate if supported */
+		if (ctrl->speed < adapter_speed) 
+			return 0;
+
+		return 1;
+	}
+	
+	/* If the controller doesn't support freq/mode changes and the
+	 * controller is running at a higher mode, we bail */
+	if ((ctrl->speed > adapter_speed) && (!ctrl->pcix_speed_capability))
+		return 1;
+	
+	/* But we allow the adapter to run at a lower rate if possible */
+	if ((ctrl->speed < adapter_speed) && (!ctrl->pcix_speed_capability))
+		return 0;
+
+	/* We try to set the max speed supported by both the adapter and
+	 * controller */
+	if (ctrl->speed_capability < adapter_speed) {
+		if (ctrl->speed == ctrl->speed_capability)
+			return 0;
+		adapter_speed = ctrl->speed_capability;
+	}
+
+	writel(0x0L, ctrl->hpc_reg + LED_CONTROL);
+	writeb(0x00, ctrl->hpc_reg + SLOT_ENABLE);
+	
+	set_SOGO(ctrl); 
+	wait_for_ctrl_irq(ctrl);
+	
+	if (adapter_speed != PCI_SPEED_133MHz_PCIX)
+		reg = 0xF5;
+	else
+		reg = 0xF4;	
+	pci_write_config_byte(ctrl->pci_dev, 0x41, reg);
+	
+	reg16 = readw(ctrl->hpc_reg + NEXT_CURR_FREQ);
+	reg16 &= ~0x000F;
+	switch(adapter_speed) {
+		case(PCI_SPEED_133MHz_PCIX): 
+			reg = 0x75;
+			reg16 |= 0xB; 
+			break;
+		case(PCI_SPEED_100MHz_PCIX):
+			reg = 0x74;
+			reg16 |= 0xA;
+			break;
+		case(PCI_SPEED_66MHz_PCIX):
+			reg = 0x73;
+			reg16 |= 0x9;
+			break;
+		case(PCI_SPEED_66MHz):
+			reg = 0x73;
+			reg16 |= 0x1;
+			break;
+		default: /* 33MHz PCI 2.2 */
+			reg = 0x71;
+			break;
+			
+	}
+	reg16 |= 0xB << 12;
+	writew(reg16, ctrl->hpc_reg + NEXT_CURR_FREQ);
+	
+	mdelay(5); 
+	
+	/* Reenable interrupts */
+	writel(0, ctrl->hpc_reg + INT_MASK);
+
+	pci_write_config_byte(ctrl->pci_dev, 0x41, reg); 
+	
+	/* Restart state machine */
+	reg = ~0xF;
+	pci_read_config_byte(ctrl->pci_dev, 0x43, &reg);
+	pci_write_config_byte(ctrl->pci_dev, 0x43, reg);
+	
+	/* Only if mode change...*/
+	if (((ctrl->speed == PCI_SPEED_66MHz) && (adapter_speed == PCI_SPEED_66MHz_PCIX)) ||
+		((ctrl->speed == PCI_SPEED_66MHz_PCIX) && (adapter_speed == PCI_SPEED_66MHz))) 
+			set_SOGO(ctrl);
+	
+	wait_for_ctrl_irq(ctrl);
+	mdelay(1100);
+	
+	/* Restore LED/Slot state */
+	writel(leds, ctrl->hpc_reg + LED_CONTROL);
+	writeb(slot_power, ctrl->hpc_reg + SLOT_ENABLE);
+	
+	set_SOGO(ctrl);
+	wait_for_ctrl_irq(ctrl);
+
+	ctrl->speed = adapter_speed;
+	slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+
+	info("Successfully changed frequency/mode for adapter in slot %d\n", 
+			slot->number);
+	return 0;
+}
+
 #endif
 
diff -urN linux-2.5.69-bk1/drivers/hotplug/cpqphp_core.c linux-2.5.69-bk2/drivers/hotplug/cpqphp_core.c
--- linux-2.5.69-bk1/drivers/hotplug/cpqphp_core.c	2003-05-04 16:52:48.000000000 -0700
+++ linux-2.5.69-bk2/drivers/hotplug/cpqphp_core.c	2003-05-07 04:41:16.000000000 -0700
@@ -24,6 +24,9 @@
  *
  * Send feedback to <greg@kroah.com>
  *
+ * Jan 12, 2003 -	Added 66/100/133MHz PCI-X support,
+ * 			Torben Mathiasen <torben.mathiasen@hp.com>
+ *
  */
 
 #include <linux/config.h>
@@ -57,7 +60,7 @@
 static u8 power_mode;
 static int debug;
 
-#define DRIVER_VERSION	"0.9.6"
+#define DRIVER_VERSION	"0.9.7"
 #define DRIVER_AUTHOR	"Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>"
 #define DRIVER_DESC	"Compaq Hot Plug PCI Controller Driver"
 
@@ -835,6 +838,7 @@
 	u8 hp_slot = 0;
 	u8 device;
 	u8 rev;
+	u8 bus_cap;
 	u16 temp_word;
 	u16 vendor_id;
 	u16 subsystem_vid;
@@ -896,6 +900,39 @@
 
 		switch (subsystem_vid) {
 			case PCI_VENDOR_ID_COMPAQ:
+				if (rev >= 0x13) { /* CIOBX */
+					ctrl->push_flag = 1;
+					ctrl->slot_switch_type = 1;		// Switch is present
+					ctrl->push_button = 1;			// Pushbutton is present
+					ctrl->pci_config_space = 1;		// Index/data access to working registers 0 = not supported, 1 = supported
+					ctrl->defeature_PHP = 1;		// PHP is supported
+					ctrl->pcix_support = 1;			// PCI-X supported
+					ctrl->pcix_speed_capability = 1;
+					pci_read_config_byte(pdev, 0x41, &bus_cap);
+					if (bus_cap & 0x80) {
+						dbg("bus max supports 133MHz PCI-X\n");
+						ctrl->speed_capability = PCI_SPEED_133MHz_PCIX;
+						break;
+					}
+					if (bus_cap & 0x40) {
+						dbg("bus max supports 100MHz PCI-X\n");
+						ctrl->speed_capability = PCI_SPEED_100MHz_PCIX;
+						break;
+					}
+					if (bus_cap & 20) {
+						dbg("bus max supports 66MHz PCI-X\n");
+						ctrl->speed_capability = PCI_SPEED_66MHz_PCIX;
+						break;
+					}
+					if (bus_cap & 10) {
+						dbg("bus max supports 66MHz PCI\n");
+						ctrl->speed_capability = PCI_SPEED_66MHz;
+						break;
+					}
+
+					break;
+				}
+
 				switch (subsystem_deviceid) {
 					case PCI_SUB_HPC_ID:
 						/* Original 6500/7000 implementation */
@@ -939,8 +976,18 @@
 						ctrl->pcix_support = 0;			// PCI-X not supported
 						ctrl->pcix_speed_capability = 0;	// N/A since PCI-X not supported
 						break;
+					case PCI_SUB_HPC_ID4:
+						/* First PCI-X implementation, 100MHz */
+						ctrl->push_flag = 1;
+						ctrl->slot_switch_type = 1;		// Switch is present
+						ctrl->speed_capability = PCI_SPEED_100MHz_PCIX;
+						ctrl->push_button = 1;			// Pushbutton is present
+						ctrl->pci_config_space = 1;		// Index/data access to working registers 0 = not supported, 1 = supported
+						ctrl->defeature_PHP = 1;		// PHP is supported
+						ctrl->pcix_support = 1;			// PCI-X supported
+						ctrl->pcix_speed_capability = 0;	
+						break;
 					default:
-						// TODO: Add SSIDs for CPQ systems that support PCI-X
 						err(msg_HPC_not_supported);
 						rc = -ENODEV;
 						goto err_free_ctrl;
@@ -1029,7 +1076,7 @@
 	info("Initializing the PCI hot plug controller residing on PCI bus %d\n", pdev->bus->number);
 
 	dbg ("Hotplug controller capabilities:\n");
-	dbg ("    speed_capability       %s\n", ctrl->speed_capability == PCI_SPEED_33MHz ? "33MHz" : "66Mhz");
+	dbg ("    speed_capability       %d\n", ctrl->speed_capability);
 	dbg ("    slot_switch_type       %s\n", ctrl->slot_switch_type == 0 ? "no switch" : "switch present");
 	dbg ("    defeature_PHP          %s\n", ctrl->defeature_PHP == 0 ? "PHP not supported" : "PHP supported");
 	dbg ("    alternate_base_address %s\n", ctrl->alternate_base_address == 0 ? "not supported" : "supported");
@@ -1082,7 +1129,6 @@
 	}
 
 	// Check for 66Mhz operation
-	// TODO: Add PCI-X support
 	ctrl->speed = get_controller_speed(ctrl);
 
 
@@ -1119,6 +1165,9 @@
 	// The next line is required for cpqhp_find_available_resources
 	ctrl->interrupt = pdev->irq;
 
+	ctrl->cfgspc_irq = 0;
+	pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &ctrl->cfgspc_irq);
+
 	rc = cpqhp_find_available_resources(ctrl, cpqhp_rom_start);
 	ctrl->add_support = !rc;
 	if (rc) {
diff -urN linux-2.5.69-bk1/drivers/hotplug/cpqphp_ctrl.c linux-2.5.69-bk2/drivers/hotplug/cpqphp_ctrl.c
--- linux-2.5.69-bk1/drivers/hotplug/cpqphp_ctrl.c	2003-05-04 16:53:10.000000000 -0700
+++ linux-2.5.69-bk2/drivers/hotplug/cpqphp_ctrl.c	2003-05-07 04:41:16.000000000 -0700
@@ -136,9 +136,9 @@
 
 
 /*
- * find_slot
+ * cpqhp_find_slot
  */
-static inline struct slot *find_slot (struct controller * ctrl, u8 device)
+struct slot *cpqhp_find_slot (struct controller * ctrl, u8 device)
 {
 	struct slot *slot;
 
@@ -187,7 +187,7 @@
 
 			rc++;
 
-			p_slot = find_slot(ctrl, hp_slot + (readb(ctrl->hpc_reg + SLOT_MASK) >> 4));
+			p_slot = cpqhp_find_slot(ctrl, hp_slot + (readb(ctrl->hpc_reg + SLOT_MASK) >> 4));
 			if (!p_slot)
 				return 0;
 
@@ -920,6 +920,7 @@
 {
 	struct controller *ctrl = data;
 	u8 schedule_flag = 0;
+	u8 reset;
 	u16 misc;
 	u32 Diff;
 	u32 temp_dword;
@@ -971,6 +972,15 @@
 		schedule_flag += handle_power_fault((u8)((Diff & 0xFF00L) >> 8), ctrl);
 	}
 
+	reset = readb(ctrl->hpc_reg + RESET_FREQ_MODE);
+	if (reset & 0x40) {
+		/* Bus reset has completed */
+		reset &= 0xCF;
+		writeb(reset, ctrl->hpc_reg + RESET_FREQ_MODE);
+		reset = readb(ctrl->hpc_reg + RESET_FREQ_MODE);
+		wake_up_interruptible(&ctrl->queue);
+	}
+
 	if (schedule_flag) {
 		up(&event_semaphore);
 		dbg("Signal event_semaphore\n");
@@ -1172,6 +1182,7 @@
 {
 	u8 hp_slot;
 	u8 temp_byte;
+	u8 adapter_speed;
 	u32 index;
 	u32 rc = 0;
 	u32 src = 8;
@@ -1189,46 +1200,46 @@
 		//*********************************
 		rc = CARD_FUNCTIONING;
 	} else {
-		if (ctrl->speed == PCI_SPEED_66MHz) {
-			// Wait for exclusive access to hardware
-			down(&ctrl->crit_sect);
-
-			// turn on board without attaching to the bus
-			enable_slot_power (ctrl, hp_slot);
+		// Wait for exclusive access to hardware
+		down(&ctrl->crit_sect);
 
-			set_SOGO(ctrl);
+		// turn on board without attaching to the bus
+		enable_slot_power (ctrl, hp_slot);
 
-			// Wait for SOBS to be unset
-			wait_for_ctrl_irq (ctrl);
+		set_SOGO(ctrl);
 
-			// Change bits in slot power register to force another shift out
-			// NOTE: this is to work around the timer bug
-			temp_byte = readb(ctrl->hpc_reg + SLOT_POWER);
-			writeb(0x00, ctrl->hpc_reg + SLOT_POWER);
-			writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER);
+		// Wait for SOBS to be unset
+		wait_for_ctrl_irq (ctrl);
 
-			set_SOGO(ctrl);
+		// Change bits in slot power register to force another shift out
+		// NOTE: this is to work around the timer bug
+		temp_byte = readb(ctrl->hpc_reg + SLOT_POWER);
+		writeb(0x00, ctrl->hpc_reg + SLOT_POWER);
+		writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER);
 
-			// Wait for SOBS to be unset
-			wait_for_ctrl_irq (ctrl);
+		set_SOGO(ctrl);
 
-			if (!(readl(ctrl->hpc_reg + NON_INT_INPUT) & (0x01 << hp_slot))) {
+		// Wait for SOBS to be unset
+		wait_for_ctrl_irq (ctrl);
+		
+		adapter_speed = get_adapter_speed(ctrl, hp_slot);
+		if (ctrl->speed != adapter_speed)
+			if (set_controller_speed(ctrl, adapter_speed, hp_slot))
 				rc = WRONG_BUS_FREQUENCY;
-			}
-			// turn off board without attaching to the bus
-			disable_slot_power (ctrl, hp_slot);
 
-			set_SOGO(ctrl);
+		// turn off board without attaching to the bus
+		disable_slot_power (ctrl, hp_slot);
 
-			// Wait for SOBS to be unset
-			wait_for_ctrl_irq (ctrl);
+		set_SOGO(ctrl);
 
-			// Done with exclusive hardware access
-			up(&ctrl->crit_sect);
+		// Wait for SOBS to be unset
+		wait_for_ctrl_irq (ctrl);
 
-			if (rc)
-				return(rc);
-		}
+		// Done with exclusive hardware access
+		up(&ctrl->crit_sect);
+
+		if (rc)
+			return(rc);
 
 		// Wait for exclusive access to hardware
 		down(&ctrl->crit_sect);
@@ -1376,6 +1387,7 @@
 {
 	u8 hp_slot;
 	u8 temp_byte;
+	u8 adapter_speed;
 	int index;
 	u32 temp_register = 0xFFFFFFFF;
 	u32 rc = 0;
@@ -1387,47 +1399,48 @@
 	dbg("%s: func->device, slot_offset, hp_slot = %d, %d ,%d\n",
 	    __FUNCTION__, func->device, ctrl->slot_device_offset, hp_slot);
 
-	if (ctrl->speed == PCI_SPEED_66MHz) {
-		// Wait for exclusive access to hardware
-		down(&ctrl->crit_sect);
-
-		// turn on board without attaching to the bus
-		enable_slot_power (ctrl, hp_slot);
+	// Wait for exclusive access to hardware
+	down(&ctrl->crit_sect);
 
-		set_SOGO(ctrl);
+	// turn on board without attaching to the bus
+	enable_slot_power (ctrl, hp_slot);
 
-		// Wait for SOBS to be unset
-		wait_for_ctrl_irq (ctrl);
+	set_SOGO(ctrl);
 
-		// Change bits in slot power register to force another shift out
-		// NOTE: this is to work around the timer bug
-		temp_byte = readb(ctrl->hpc_reg + SLOT_POWER);
-		writeb(0x00, ctrl->hpc_reg + SLOT_POWER);
-		writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER);
+	// Wait for SOBS to be unset
+	wait_for_ctrl_irq (ctrl);
 
-		set_SOGO(ctrl);
+	// Change bits in slot power register to force another shift out
+	// NOTE: this is to work around the timer bug
+	temp_byte = readb(ctrl->hpc_reg + SLOT_POWER);
+	writeb(0x00, ctrl->hpc_reg + SLOT_POWER);
+	writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER);
 
-		// Wait for SOBS to be unset
-		wait_for_ctrl_irq (ctrl);
+	set_SOGO(ctrl);
 
-		if (!(readl(ctrl->hpc_reg + NON_INT_INPUT) & (0x01 << hp_slot))) {
+	// Wait for SOBS to be unset
+	wait_for_ctrl_irq (ctrl);
+	
+	adapter_speed = get_adapter_speed(ctrl, hp_slot);
+	if (ctrl->speed != adapter_speed)
+		if (set_controller_speed(ctrl, adapter_speed, hp_slot))
 			rc = WRONG_BUS_FREQUENCY;
-		}
-		// turn off board without attaching to the bus
-		disable_slot_power (ctrl, hp_slot);
+	
+	// turn off board without attaching to the bus
+	disable_slot_power (ctrl, hp_slot);
 
-		set_SOGO(ctrl);
+	set_SOGO(ctrl);
 
-		// Wait for SOBS to be unset
-		wait_for_ctrl_irq (ctrl);
+	// Wait for SOBS to be unset
+	wait_for_ctrl_irq (ctrl);
 
-		// Done with exclusive hardware access
-		up(&ctrl->crit_sect);
+	// Done with exclusive hardware access
+	up(&ctrl->crit_sect);
 
-		if (rc)
-			return(rc);
-	}
-	p_slot = find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+	if (rc)
+		return(rc);
+	
+	p_slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
 
 	// turn on board and blink green LED
 
@@ -1800,7 +1813,7 @@
 				if (!func)
 					return;
 
-				p_slot = find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+				p_slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
 				if (!p_slot)
 					return;
 
@@ -1860,11 +1873,12 @@
 					}
 					// Wait for exclusive access to hardware
 					down(&ctrl->crit_sect);
-
+					
 					dbg("blink green LED and turn off amber\n");
+					
 					amber_LED_off (ctrl, hp_slot);
 					green_LED_blink (ctrl, hp_slot);
-
+					
 					set_SOGO(ctrl);
 
 					// Wait for SOBS to be unset
@@ -1992,7 +2006,7 @@
 
 	device = func->device;
 	hp_slot = device - ctrl->slot_device_offset;
-	p_slot = find_slot(ctrl, device);
+	p_slot = cpqhp_find_slot(ctrl, device);
 	if (p_slot) {
 		physical_slot = p_slot->number;
 	}
@@ -2091,7 +2105,7 @@
 
 	device = func->device; 
 	func = cpqhp_slot_find(ctrl->bus, device, index++);
-	p_slot = find_slot(ctrl, device);
+	p_slot = cpqhp_find_slot(ctrl, device);
 	if (p_slot) {
 		physical_slot = p_slot->number;
 	}
diff -urN linux-2.5.69-bk1/drivers/hotplug/cpqphp_pci.c linux-2.5.69-bk2/drivers/hotplug/cpqphp_pci.c
--- linux-2.5.69-bk1/drivers/hotplug/cpqphp_pci.c	2003-05-04 16:53:41.000000000 -0700
+++ linux-2.5.69-bk2/drivers/hotplug/cpqphp_pci.c	2003-05-07 04:41:16.000000000 -0700
@@ -85,18 +85,20 @@
 {
 	unsigned char bus;
 	struct pci_bus *child;
-	int rc = 0;
+	int num;
 
 	if (func->pci_dev == NULL)
-		func->pci_dev = pci_find_slot(func->bus, (func->device << 3) | (func->function & 0x7));
+		func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function));
 
-	//Still NULL ? Well then scan for it !
+	/* No pci device, we need to create it then */
 	if (func->pci_dev == NULL) {
 		dbg("INFO: pci_dev still null\n");
 
-		//this will generate pci_dev structures for all functions, but we will only call this case when lookup fails
-		func->pci_dev = pci_scan_slot(ctrl->pci_dev->bus,
-				 (func->device << 3) + (func->function & 0x7));
+		num = pci_scan_slot(ctrl->pci_dev->bus, PCI_DEVFN(func->device, func->function));
+		if (num)
+			pci_bus_add_devices(ctrl->pci_dev->bus);
+
+		func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function));
 		if (func->pci_dev == NULL) {
 			dbg("ERROR: pci_dev still null\n");
 			return 0;
@@ -107,10 +109,9 @@
 		pci_read_config_byte(func->pci_dev, PCI_SECONDARY_BUS, &bus);
 		child = (struct pci_bus*) pci_add_new_bus(func->pci_dev->bus, (func->pci_dev), bus);
 		pci_do_scan_bus(child);
-
 	}
 
-	return rc;
+	return 0;
 }
 
 
@@ -1209,11 +1210,11 @@
 	temp = 0;
 
 	if (!cpqhp_nic_irq) {
-		cpqhp_nic_irq = ctrl->interrupt;
+		cpqhp_nic_irq = ctrl->cfgspc_irq;
 	}
 
 	if (!cpqhp_disk_irq) {
-		cpqhp_disk_irq = ctrl->interrupt;
+		cpqhp_disk_irq = ctrl->cfgspc_irq;
 	}
 
 	dbg("cpqhp_disk_irq, cpqhp_nic_irq= %d, %d\n", cpqhp_disk_irq, cpqhp_nic_irq);
diff -urN linux-2.5.69-bk1/drivers/hotplug/ibmphp_core.c linux-2.5.69-bk2/drivers/hotplug/ibmphp_core.c
--- linux-2.5.69-bk1/drivers/hotplug/ibmphp_core.c	2003-05-04 16:53:57.000000000 -0700
+++ linux-2.5.69-bk2/drivers/hotplug/ibmphp_core.c	2003-05-07 04:41:16.000000000 -0700
@@ -846,22 +846,24 @@
 {
 	unsigned char bus;
 	struct pci_bus *child;
-	int rc = 0;
+	int num;
 	int flag = 0;	/* this is to make sure we don't double scan the bus, for bridged devices primarily */
 
 	if (!(bus_structure_fixup (func->busno)))
 		flag = 1;
 	if (func->dev == NULL)
-		func->dev = pci_find_slot (func->busno, (func->device << 3) | (func->function & 0x7));
+		func->dev = pci_find_slot (func->busno, PCI_DEVFN(func->device, func->function));
 
 	if (func->dev == NULL) {
 		struct pci_bus *bus = ibmphp_find_bus (func->busno);
 		if (!bus)
 			return 0;
 
-		func->dev = pci_scan_slot(bus,
-				 (func->device << 3) + (func->function & 0x7));
+		num = pci_scan_slot(bus, PCI_DEVFN(func->device, func->function));
+		if (num)
+			pci_bus_add_devices(bus);
 
+		func->dev = pci_find_slot(func->busno, PCI_DEVFN(func->device, func->function));
 		if (func->dev == NULL) {
 			err ("ERROR... : pci_dev still NULL \n");
 			return 0;
@@ -873,7 +875,7 @@
 		pci_do_scan_bus (child);
 	}
 
-	return rc;
+	return 0;
 }
 
 /*******************************************************
@@ -1415,7 +1417,7 @@
 
 	/* lock ourselves into memory with a module 
 	 * count of -1 so that no one can unload us. */
-	MOD_DEC_USE_COUNT;
+	module_put(THIS_MODULE);
 
 exit:
 	return rc;
diff -urN linux-2.5.69-bk1/drivers/i2c/busses/i2c-ali15x3.c linux-2.5.69-bk2/drivers/i2c/busses/i2c-ali15x3.c
--- linux-2.5.69-bk1/drivers/i2c/busses/i2c-ali15x3.c	2003-05-04 16:53:29.000000000 -0700
+++ linux-2.5.69-bk2/drivers/i2c/busses/i2c-ali15x3.c	2003-05-07 04:41:16.000000000 -0700
@@ -475,6 +475,7 @@
 static struct i2c_adapter ali15x3_adapter = {
 	.owner		= THIS_MODULE,
 	.id		= I2C_ALGO_SMBUS | I2C_HW_SMBUS_ALI15X3,
+	.class          = I2C_ADAP_CLASS_SMBUS,
 	.algo		= &smbus_algorithm,
 	.dev		= {
 		.name	= "unset",
diff -urN linux-2.5.69-bk1/drivers/i2c/busses/i2c-amd756.c linux-2.5.69-bk2/drivers/i2c/busses/i2c-amd756.c
--- linux-2.5.69-bk1/drivers/i2c/busses/i2c-amd756.c	2003-05-04 16:53:40.000000000 -0700
+++ linux-2.5.69-bk2/drivers/i2c/busses/i2c-amd756.c	2003-05-07 04:41:16.000000000 -0700
@@ -313,6 +313,7 @@
 static struct i2c_adapter amd756_adapter = {
 	.owner		= THIS_MODULE,
 	.id		= I2C_ALGO_SMBUS | I2C_HW_SMBUS_AMD756,
+	.class          = I2C_ADAP_CLASS_SMBUS,
 	.algo		= &smbus_algorithm,
 	.dev		= {
 		.name	= "unset",
diff -urN linux-2.5.69-bk1/drivers/i2c/busses/i2c-amd8111.c linux-2.5.69-bk2/drivers/i2c/busses/i2c-amd8111.c
--- linux-2.5.69-bk1/drivers/i2c/busses/i2c-amd8111.c	2003-05-04 16:53:37.000000000 -0700
+++ linux-2.5.69-bk2/drivers/i2c/busses/i2c-amd8111.c	2003-05-07 04:41:16.000000000 -0700
@@ -360,6 +360,7 @@
 	snprintf(smbus->adapter.dev.name, DEVICE_NAME_SIZE,
 		"SMBus2 AMD8111 adapter at %04x", smbus->base);
 	smbus->adapter.id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_AMD8111;
+	smbus->adapter.class = I2C_ADAP_CLASS_SMBUS;
 	smbus->adapter.algo = &smbus_algorithm;
 	smbus->adapter.algo_data = smbus;
 
diff -urN linux-2.5.69-bk1/drivers/i2c/busses/i2c-i801.c linux-2.5.69-bk2/drivers/i2c/busses/i2c-i801.c
--- linux-2.5.69-bk1/drivers/i2c/busses/i2c-i801.c	2003-05-04 16:53:14.000000000 -0700
+++ linux-2.5.69-bk2/drivers/i2c/busses/i2c-i801.c	2003-05-07 04:41:16.000000000 -0700
@@ -547,6 +547,7 @@
 static struct i2c_adapter i801_adapter = {
 	.owner		= THIS_MODULE,
 	.id		= I2C_ALGO_SMBUS | I2C_HW_SMBUS_I801,
+	.class		= I2C_ADAP_CLASS_SMBUS,
 	.algo		= &smbus_algorithm,
 	.dev		= {
 		.name	= "unset",
diff -urN linux-2.5.69-bk1/drivers/i2c/busses/i2c-isa.c linux-2.5.69-bk2/drivers/i2c/busses/i2c-isa.c
--- linux-2.5.69-bk1/drivers/i2c/busses/i2c-isa.c	2003-05-04 16:53:31.000000000 -0700
+++ linux-2.5.69-bk2/drivers/i2c/busses/i2c-isa.c	2003-05-07 04:41:16.000000000 -0700
@@ -40,6 +40,7 @@
 static struct i2c_adapter isa_adapter = {
 	.owner		= THIS_MODULE,
 	.id		= I2C_ALGO_ISA | I2C_HW_ISA,
+	.class          = I2C_ADAP_CLASS_SMBUS,
 	.algo		= &isa_algorithm,
 	.dev		= {
 		.name	= "ISA main adapter",
diff -urN linux-2.5.69-bk1/drivers/i2c/busses/i2c-piix4.c linux-2.5.69-bk2/drivers/i2c/busses/i2c-piix4.c
--- linux-2.5.69-bk1/drivers/i2c/busses/i2c-piix4.c	2003-05-04 16:53:09.000000000 -0700
+++ linux-2.5.69-bk2/drivers/i2c/busses/i2c-piix4.c	2003-05-07 04:41:16.000000000 -0700
@@ -395,6 +395,7 @@
 static struct i2c_adapter piix4_adapter = {
 	.owner		= THIS_MODULE,
 	.id		= I2C_ALGO_SMBUS | I2C_HW_SMBUS_PIIX4,
+	.class		= I2C_ADAP_CLASS_SMBUS,
 	.algo		= &smbus_algorithm,
 	.dev		= {
 		.name	= "unset",
diff -urN linux-2.5.69-bk1/drivers/i2c/busses/i2c-viapro.c linux-2.5.69-bk2/drivers/i2c/busses/i2c-viapro.c
--- linux-2.5.69-bk1/drivers/i2c/busses/i2c-viapro.c	2003-05-04 16:53:36.000000000 -0700
+++ linux-2.5.69-bk2/drivers/i2c/busses/i2c-viapro.c	2003-05-07 04:41:16.000000000 -0700
@@ -295,6 +295,7 @@
 static struct i2c_adapter vt596_adapter = {
 	.owner		= THIS_MODULE,
 	.id		= I2C_ALGO_SMBUS | I2C_HW_SMBUS_VIA2,
+	.class		= I2C_ADAP_CLASS_SMBUS,
 	.algo		= &smbus_algorithm,
 	.dev		= {
 		.name	= "unset",
diff -urN linux-2.5.69-bk1/drivers/i2c/chips/adm1021.c linux-2.5.69-bk2/drivers/i2c/chips/adm1021.c
--- linux-2.5.69-bk1/drivers/i2c/chips/adm1021.c	2003-05-04 16:52:49.000000000 -0700
+++ linux-2.5.69-bk2/drivers/i2c/chips/adm1021.c	2003-05-07 04:41:16.000000000 -0700
@@ -203,6 +203,8 @@
 
 static int adm1021_attach_adapter(struct i2c_adapter *adapter)
 {
+	if (!(adapter->class & I2C_ADAP_CLASS_SMBUS))
+		return 0;
 	return i2c_detect(adapter, &addr_data, adm1021_detect);
 }
 
diff -urN linux-2.5.69-bk1/drivers/i2c/chips/it87.c linux-2.5.69-bk2/drivers/i2c/chips/it87.c
--- linux-2.5.69-bk1/drivers/i2c/chips/it87.c	2003-05-04 16:53:36.000000000 -0700
+++ linux-2.5.69-bk2/drivers/i2c/chips/it87.c	2003-05-07 04:41:16.000000000 -0700
@@ -3,7 +3,7 @@
              monitoring.
 
     Supports: IT8705F  Super I/O chip w/LPC interface
-              IT8712F  Super I/O chup w/LPC interface & SMbus
+              IT8712F  Super I/O chip w/LPC interface & SMbus
               Sis950   A clone of the IT8705F
 
     Copyright (c) 2001 Chris Gauthron <chrisg@0-in.com> 
@@ -238,6 +238,7 @@
 	u8 temp[3];		/* Register value */
 	u8 temp_high[3];	/* Register value */
 	u8 temp_low[3];		/* Register value */
+	u8 sensor;		/* Register value */
 	u8 fan_div[3];		/* Register encoding, shifted right */
 	u8 vid;			/* Register encoding, combined */
 	u32 alarms;		/* Register encoding, combined */
@@ -252,7 +253,7 @@
 static int it87_write_value(struct i2c_client *client, u8 register,
 			u8 value);
 static void it87_update_client(struct i2c_client *client);
-static void it87_init_client(struct i2c_client *client);
+static void it87_init_client(struct i2c_client *client, struct it87_data *data);
 
 
 static struct i2c_driver it87_driver = {
@@ -350,6 +351,10 @@
 show_in_offset(2);
 show_in_offset(3);
 show_in_offset(4);
+show_in_offset(5);
+show_in_offset(6);
+show_in_offset(7);
+show_in_offset(8);
 
 /* 3 temperatures */
 static ssize_t show_temp(struct device *dev, char *buf, int nr)
@@ -430,7 +435,52 @@
 show_temp_offset(2);
 show_temp_offset(3);
 
-/* 2 Fans */
+/* more like overshoot temperature */
+static ssize_t show_sensor(struct device *dev, char *buf, int nr)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct it87_data *data = i2c_get_clientdata(client);
+	it87_update_client(client);
+	if (data->sensor & (1 << nr))
+	    return sprintf(buf, "1\n");
+	if (data->sensor & (8 << nr))
+	    return sprintf(buf, "2\n");
+	return sprintf(buf, "0\n");
+}
+static ssize_t set_sensor(struct device *dev, const char *buf, 
+		size_t count, int nr)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct it87_data *data = i2c_get_clientdata(client);
+	int val = simple_strtol(buf, NULL, 10);
+
+	data->sensor &= ~(1 << nr);
+	data->sensor &= ~(8 << nr);
+	if (val == 1)
+	    data->sensor |= 1 << nr;
+	else if (val == 2)
+	    data->sensor |= 8 << nr;
+	it87_write_value(client, IT87_REG_TEMP_ENABLE, data->sensor);
+	return count;
+}
+#define show_sensor_offset(offset)					\
+static ssize_t show_sensor_##offset (struct device *dev, char *buf)	\
+{									\
+	return show_sensor(dev, buf, 0x##offset - 1);			\
+}									\
+static ssize_t set_sensor_##offset (struct device *dev, 		\
+		const char *buf, size_t count) 				\
+{									\
+	return set_sensor(dev, buf, count, 0x##offset - 1);		\
+}									\
+static DEVICE_ATTR(sensor##offset, S_IRUGO | S_IWUSR,	 		\
+		show_sensor_##offset, set_sensor_##offset)
+
+show_sensor_offset(1);
+show_sensor_offset(2);
+show_sensor_offset(3);
+
+/* 3 Fans */
 static ssize_t show_fan(struct device *dev, char *buf, int nr)
 {
 	struct i2c_client *client = to_i2c_client(dev);
@@ -508,6 +558,7 @@
 
 show_fan_offset(1);
 show_fan_offset(2);
+show_fan_offset(3);
 
 /* Alarm */
 static ssize_t show_alarm(struct device *dev, char *buf)
@@ -525,6 +576,8 @@
      * when a new adapter is inserted (and it87_driver is still present) */
 static int it87_attach_adapter(struct i2c_adapter *adapter)
 {
+	if (!(adapter->class & I2C_ADAP_CLASS_SMBUS))
+		return 0;
 	return i2c_detect(adapter, &addr_data, it87_detect);
 }
 
@@ -574,6 +627,7 @@
 			}
 		}
 	}
+	memset (new_client, 0x00, sizeof(struct i2c_client) + sizeof(struct it87_data));
 
 	/* OK. For now, we presume we have a valid client. We now create the
 	   client structure, even though we cannot fill it completely yet.
@@ -585,6 +639,8 @@
 		err = -ENOMEM;
 		goto ERROR1;
 	}
+	memset(new_client, 0x00, sizeof(struct i2c_client) +
+				 sizeof(struct it87_data));
 
 	data = (struct it87_data *) (new_client + 1);
 	if (is_isa)
@@ -652,16 +708,28 @@
 	device_create_file(&new_client->dev, &dev_attr_in_input2);
 	device_create_file(&new_client->dev, &dev_attr_in_input3);
 	device_create_file(&new_client->dev, &dev_attr_in_input4);
+	device_create_file(&new_client->dev, &dev_attr_in_input5);
+	device_create_file(&new_client->dev, &dev_attr_in_input6);
+	device_create_file(&new_client->dev, &dev_attr_in_input7);
+	device_create_file(&new_client->dev, &dev_attr_in_input8);
 	device_create_file(&new_client->dev, &dev_attr_in_min0);
 	device_create_file(&new_client->dev, &dev_attr_in_min1);
 	device_create_file(&new_client->dev, &dev_attr_in_min2);
 	device_create_file(&new_client->dev, &dev_attr_in_min3);
 	device_create_file(&new_client->dev, &dev_attr_in_min4);
+	device_create_file(&new_client->dev, &dev_attr_in_min5);
+	device_create_file(&new_client->dev, &dev_attr_in_min6);
+	device_create_file(&new_client->dev, &dev_attr_in_min7);
+	device_create_file(&new_client->dev, &dev_attr_in_min8);
 	device_create_file(&new_client->dev, &dev_attr_in_max0);
 	device_create_file(&new_client->dev, &dev_attr_in_max1);
 	device_create_file(&new_client->dev, &dev_attr_in_max2);
 	device_create_file(&new_client->dev, &dev_attr_in_max3);
 	device_create_file(&new_client->dev, &dev_attr_in_max4);
+	device_create_file(&new_client->dev, &dev_attr_in_max5);
+	device_create_file(&new_client->dev, &dev_attr_in_max6);
+	device_create_file(&new_client->dev, &dev_attr_in_max7);
+	device_create_file(&new_client->dev, &dev_attr_in_max8);
 	device_create_file(&new_client->dev, &dev_attr_temp_input1);
 	device_create_file(&new_client->dev, &dev_attr_temp_input2);
 	device_create_file(&new_client->dev, &dev_attr_temp_input3);
@@ -671,16 +739,22 @@
 	device_create_file(&new_client->dev, &dev_attr_temp_min1);
 	device_create_file(&new_client->dev, &dev_attr_temp_min2);
 	device_create_file(&new_client->dev, &dev_attr_temp_min3);
+	device_create_file(&new_client->dev, &dev_attr_sensor1);
+	device_create_file(&new_client->dev, &dev_attr_sensor2);
+	device_create_file(&new_client->dev, &dev_attr_sensor3);
 	device_create_file(&new_client->dev, &dev_attr_fan_input1);
 	device_create_file(&new_client->dev, &dev_attr_fan_input2);
+	device_create_file(&new_client->dev, &dev_attr_fan_input3);
 	device_create_file(&new_client->dev, &dev_attr_fan_min1);
 	device_create_file(&new_client->dev, &dev_attr_fan_min2);
+	device_create_file(&new_client->dev, &dev_attr_fan_min3);
 	device_create_file(&new_client->dev, &dev_attr_fan_div1);
 	device_create_file(&new_client->dev, &dev_attr_fan_div2);
+	device_create_file(&new_client->dev, &dev_attr_fan_div3);
 	device_create_file(&new_client->dev, &dev_attr_alarm);
 
 	/* Initialize the IT87 chip */
-	it87_init_client(new_client);
+	it87_init_client(new_client, data);
 	return 0;
 
 ERROR1:
@@ -753,7 +827,7 @@
 }
 
 /* Called when we have found a new IT87. It should set limits, etc. */
-static void it87_init_client(struct i2c_client *client)
+static void it87_init_client(struct i2c_client *client, struct it87_data *data)
 {
 	/* Reset all except Watchdog values and last conversion values
 	   This sets fan-divs to 2, among others */
@@ -814,9 +888,9 @@
 	it87_write_value(client, IT87_REG_VIN_ENABLE, 0xff);
 
 	/* Enable Temp1-Temp3 */
-	it87_write_value(client, IT87_REG_TEMP_ENABLE,
-			(it87_read_value(client, IT87_REG_TEMP_ENABLE) & 0xc0)
-			| (temp_type & 0x3f));
+	data->sensor = (it87_read_value(client, IT87_REG_TEMP_ENABLE) & 0xc0);
+	data->sensor |= temp_type & 0x3f;
+	it87_write_value(client, IT87_REG_TEMP_ENABLE, data->sensor);
 
 	/* Enable fans */
 	it87_write_value(client, IT87_REG_FAN_CTRL,
diff -urN linux-2.5.69-bk1/drivers/i2c/chips/lm75.c linux-2.5.69-bk2/drivers/i2c/chips/lm75.c
--- linux-2.5.69-bk1/drivers/i2c/chips/lm75.c	2003-05-04 16:52:48.000000000 -0700
+++ linux-2.5.69-bk2/drivers/i2c/chips/lm75.c	2003-05-07 04:41:16.000000000 -0700
@@ -121,6 +121,8 @@
 
 static int lm75_attach_adapter(struct i2c_adapter *adapter)
 {
+	if (!(adapter->class & I2C_ADAP_CLASS_SMBUS))
+		return 0;
 	return i2c_detect(adapter, &addr_data, lm75_detect);
 }
 
diff -urN linux-2.5.69-bk1/drivers/i2c/chips/via686a.c linux-2.5.69-bk2/drivers/i2c/chips/via686a.c
--- linux-2.5.69-bk1/drivers/i2c/chips/via686a.c	2003-05-04 16:53:02.000000000 -0700
+++ linux-2.5.69-bk2/drivers/i2c/chips/via686a.c	2003-05-07 04:41:16.000000000 -0700
@@ -661,6 +661,8 @@
 /* This is called when the module is loaded */
 static int via686a_attach_adapter(struct i2c_adapter *adapter)
 {
+	if (!(adapter->class & I2C_ADAP_CLASS_SMBUS))
+		return 0;
 	return i2c_detect(adapter, &addr_data, via686a_detect);
 }
 
diff -urN linux-2.5.69-bk1/drivers/i2c/chips/w83781d.c linux-2.5.69-bk2/drivers/i2c/chips/w83781d.c
--- linux-2.5.69-bk1/drivers/i2c/chips/w83781d.c	2003-05-04 16:52:48.000000000 -0700
+++ linux-2.5.69-bk2/drivers/i2c/chips/w83781d.c	2003-05-07 04:41:16.000000000 -0700
@@ -1026,6 +1026,8 @@
 static int
 w83781d_attach_adapter(struct i2c_adapter *adapter)
 {
+	if (!(adapter->class & I2C_ADAP_CLASS_SMBUS))
+		return 0;
 	return i2c_detect(adapter, &addr_data, w83781d_detect);
 }
 
diff -urN linux-2.5.69-bk1/drivers/i2c/i2c-core.c linux-2.5.69-bk2/drivers/i2c/i2c-core.c
--- linux-2.5.69-bk1/drivers/i2c/i2c-core.c	2003-05-04 16:53:02.000000000 -0700
+++ linux-2.5.69-bk2/drivers/i2c/i2c-core.c	2003-05-07 04:41:16.000000000 -0700
@@ -38,8 +38,8 @@
 #define DEB(x) if (i2c_debug>=1) x;
 #define DEB2(x) if (i2c_debug>=2) x;
 
-static struct i2c_adapter *adapters[I2C_ADAP_MAX];
-static struct i2c_driver *drivers[I2C_DRIVER_MAX];
+static LIST_HEAD(adapters);
+static LIST_HEAD(drivers);
 static DECLARE_MUTEX(core_lists);
 
 /**** debug level */
@@ -75,23 +75,17 @@
  */
 int i2c_add_adapter(struct i2c_adapter *adap)
 {
-	int res = 0, i, j;
+	static int nr = 0;
+	struct list_head   *item;
+	struct i2c_driver  *driver;
 
 	down(&core_lists);
-	for (i = 0; i < I2C_ADAP_MAX; i++)
-		if (NULL == adapters[i])
-			break;
-	if (I2C_ADAP_MAX == i) {
-		dev_warn(&adap->dev,
-			"register_adapter - enlarge I2C_ADAP_MAX.\n");
-		res = -ENOMEM;
-		goto out_unlock;
-	}
 
-	adapters[i] = adap;
-
-	init_MUTEX(&adap->bus);
-	init_MUTEX(&adap->list);
+	adap->nr = nr++;
+	init_MUTEX(&adap->bus_lock);
+	init_MUTEX(&adap->clist_lock);
+	list_add_tail(&adap->list,&adapters);
+	INIT_LIST_HEAD(&adap->clients);
 
 	/* Add the adapter to the driver core.
 	 * If the parent pointer is not set up,
@@ -99,77 +93,65 @@
 	 */
 	if (adap->dev.parent == NULL)
 		adap->dev.parent = &legacy_bus;
-	sprintf(adap->dev.bus_id, "i2c-%d", i);
+	sprintf(adap->dev.bus_id, "i2c-%d", adap->nr);
 	adap->dev.driver = &i2c_generic_driver;
 	device_register(&adap->dev);
 
 	/* inform drivers of new adapters */
-	for (j=0;j<I2C_DRIVER_MAX;j++)
-		if (drivers[j]!=NULL && 
-		    (drivers[j]->flags&(I2C_DF_NOTIFY|I2C_DF_DUMMY)))
+	list_for_each(item,&drivers) {
+		driver = list_entry(item, struct i2c_driver, list);
+		if (driver->flags & I2C_DF_NOTIFY)
 			/* We ignore the return code; if it fails, too bad */
-			drivers[j]->attach_adapter(adap);
+			driver->attach_adapter(adap);
+	}
 	up(&core_lists);
-	
-	DEB(dev_dbg(&adap->dev, "registered as adapter %d.\n", i));
 
- out_unlock:
-	up(&core_lists);
-	return res;;
+	DEB(dev_dbg(&adap->dev, "registered as adapter #%d\n", adap->nr));
+	return 0;
 }
 
 
 int i2c_del_adapter(struct i2c_adapter *adap)
 {
-	int res = 0, i, j;
+	struct list_head  *item;
+	struct i2c_driver *driver;
+	struct i2c_client *client;
+	int res = 0;
 
 	down(&core_lists);
-	for (i = 0; i < I2C_ADAP_MAX; i++)
-		if (adap == adapters[i])
-			break;
-	if (I2C_ADAP_MAX == i) {
-		dev_warn(&adap->dev, "unregister_adapter adap not found.\n");
-		res = -ENODEV;
-		goto out_unlock;
-	}
 
-	/* DUMMY drivers do not register their clients, so we have to
-	 * use a trick here: we call driver->attach_adapter to
-	 * *detach* it! Of course, each dummy driver should know about
-	 * this or hell will break loose...
-	 */
-	for (j = 0; j < I2C_DRIVER_MAX; j++) 
-		if (drivers[j] && (drivers[j]->flags & I2C_DF_DUMMY))
-			if ((res = drivers[j]->attach_adapter(adap))) {
+	list_for_each(item,&drivers) {
+		driver = list_entry(item, struct i2c_driver, list);
+		if (driver->detach_adapter)
+			if ((res = driver->detach_adapter(adap))) {
 				dev_warn(&adap->dev, "can't detach adapter"
-				       "while detaching driver %s: driver not "
-				       "detached!", drivers[j]->name);
+					 "while detaching driver %s: driver not "
+					 "detached!", driver->name);
 				goto out_unlock;
 			}
+	}
 
 	/* detach any active clients. This must be done first, because
 	 * it can fail; in which case we give upp. */
-	for (j=0;j<I2C_CLIENT_MAX;j++) {
-		struct i2c_client *client = adap->clients[j];
-		if (client!=NULL) {
-		    /* detaching devices is unconditional of the set notify
-		     * flag, as _all_ clients that reside on the adapter
-		     * must be deleted, as this would cause invalid states.
-		     */
-			if ((res=client->driver->detach_client(client))) {
-				dev_err(&adap->dev, "adapter not "
-					"unregistered, because client at "
-					"address %02x can't be detached. ",
-					client->addr);
-				goto out_unlock;
-			}
+	list_for_each(item,&adap->clients) {
+		client = list_entry(item, struct i2c_client, list);
+
+		/* detaching devices is unconditional of the set notify
+		 * flag, as _all_ clients that reside on the adapter
+		 * must be deleted, as this would cause invalid states.
+		 */
+		if ((res=client->driver->detach_client(client))) {
+			dev_err(&adap->dev, "adapter not "
+				"unregistered, because client at "
+				"address %02x can't be detached. ",
+				client->addr);
+			goto out_unlock;
 		}
 	}
 
 	/* clean up the sysfs representation */
 	device_unregister(&adap->dev);
-
-	adapters[i] = NULL;
+	list_del(&adap->list);
 
 	DEB(dev_dbg(&adap->dev, "adapter unregistered\n"));
 
@@ -187,24 +169,11 @@
 
 int i2c_add_driver(struct i2c_driver *driver)
 {
-	int res = 0, i;
+	struct list_head   *item;
+	struct i2c_adapter *adapter;
+	int res = 0;
 
 	down(&core_lists);
-	for (i = 0; i < I2C_DRIVER_MAX; i++)
-		if (NULL == drivers[i])
-			break;
-	if (I2C_DRIVER_MAX == i) {
-		printk(KERN_WARNING 
-		       " i2c-core.o: register_driver(%s) "
-		       "- enlarge I2C_DRIVER_MAX.\n",
-			driver->name);
-		res = -ENOMEM;
-		goto out_unlock;
-	}
-
-	drivers[i] = driver;
-	
-	DEB(printk(KERN_DEBUG "i2c-core.o: driver %s registered.\n",driver->name));
 
 	/* add the driver to the list of i2c drivers in the driver core */
 	driver->driver.name = driver->name;
@@ -216,13 +185,14 @@
 	if (res)
 		goto out_unlock;
 	
-	/* now look for instances of driver on our adapters
-	 */
-	if (driver->flags& (I2C_DF_NOTIFY|I2C_DF_DUMMY)) {
-		for (i=0;i<I2C_ADAP_MAX;i++) {
-			if (adapters[i]!=NULL)
-				/* Ignore errors */
-				driver->attach_adapter(adapters[i]);
+	list_add_tail(&driver->list,&drivers);
+	DEB(printk(KERN_DEBUG "i2c-core.o: driver %s registered.\n",driver->name));
+
+	/* now look for instances of driver on our adapters */
+	if (driver->flags & I2C_DF_NOTIFY) {
+		list_for_each(item,&adapters) {
+			adapter = list_entry(item, struct i2c_adapter, list);
+			driver->attach_adapter(adapter);
 		}
 	}
 
@@ -233,44 +203,29 @@
 
 int i2c_del_driver(struct i2c_driver *driver)
 {
-	int res = 0, i, j, k;
+	struct list_head   *item1;
+	struct list_head   *item2;
+	struct i2c_client  *client;
+	struct i2c_adapter *adap;
+	
+	int res = 0;
 
 	down(&core_lists);
-	for (i = 0; i < I2C_DRIVER_MAX; i++)
-		if (driver == drivers[i])
-			break;
-	if (I2C_DRIVER_MAX == i) {
-		printk(KERN_WARNING " i2c-core.o: unregister_driver: "
-				    "[%s] not found\n",
-			driver->name);
-		res = -ENODEV;
-		goto out_unlock;
-	}
-
-	driver_unregister(&driver->driver);
 
 	/* Have a look at each adapter, if clients of this driver are still
 	 * attached. If so, detach them to be able to kill the driver 
 	 * afterwards.
 	 */
 	DEB2(printk(KERN_DEBUG "i2c-core.o: unregister_driver - looking for clients.\n"));
-
 	/* removing clients does not depend on the notify flag, else 
 	 * invalid operation might (will!) result, when using stale client
 	 * pointers.
 	 */
-	for (k=0;k<I2C_ADAP_MAX;k++) {
-		struct i2c_adapter *adap = adapters[k];
-		if (adap == NULL) /* skip empty entries. */
-			continue;
+	list_for_each(item1,&adapters) {
+		adap = list_entry(item1, struct i2c_adapter, list);
 		DEB2(dev_dbg(&adap->dev, "examining adapter\n"));
-		if (driver->flags & I2C_DF_DUMMY) {
-		/* DUMMY drivers do not register their clients, so we have to
-		 * use a trick here: we call driver->attach_adapter to
-		 * *detach* it! Of course, each dummy driver should know about
-		 * this or hell will break loose...  
-		 */
-			if ((res = driver->attach_adapter(adap))) {
+		if (driver->detach_adapter) {
+			if ((res = driver->detach_adapter(adap))) {
 				dev_warn(&adap->dev, "while unregistering "
 				       "dummy driver %s, adapter could "
 				       "not be detached properly; driver "
@@ -278,31 +233,31 @@
 				goto out_unlock;
 			}
 		} else {
-			for (j=0;j<I2C_CLIENT_MAX;j++) { 
-				struct i2c_client *client = adap->clients[j];
-				if (client != NULL && 
-				    client->driver == driver) {
-					DEB2(printk(KERN_DEBUG "i2c-core.o: "
-						    "detaching client %s:\n",
-					            client->dev.name));
-					if ((res = driver->detach_client(client))) {
-						dev_err(&adap->dev, "while "
-						       "unregistering driver "
-						       "`%s', the client at "
-						       "address %02x of "
-						       "adapter could not "
-						       "be detached; driver "
-						       "not unloaded!",
-						       driver->name,
-						       client->addr);
-						goto out_unlock;
-					}
+			list_for_each(item2,&adap->clients) {
+				client = list_entry(item2, struct i2c_client, list);
+				if (client->driver != driver)
+					continue;
+				DEB2(printk(KERN_DEBUG "i2c-core.o: "
+					    "detaching client %s:\n",
+					    client->dev.name));
+				if ((res = driver->detach_client(client))) {
+					dev_err(&adap->dev, "while "
+						"unregistering driver "
+						"`%s', the client at "
+						"address %02x of "
+						"adapter could not "
+						"be detached; driver "
+						"not unloaded!",
+						driver->name,
+						client->addr);
+					goto out_unlock;
 				}
 			}
 		}
 	}
-	drivers[i] = NULL;
-	
+
+	driver_unregister(&driver->driver);
+	list_del(&driver->list);
 	DEB(printk(KERN_DEBUG "i2c-core.o: driver unregistered: %s\n",driver->name));
 
  out_unlock:
@@ -310,14 +265,16 @@
 	return 0;
 }
 
-static int __i2c_check_addr(struct i2c_adapter *adapter, int addr)
+static int __i2c_check_addr(struct i2c_adapter *adapter, unsigned int addr)
 {
-	int i;
+	struct list_head   *item;
+	struct i2c_client  *client;
 
-	for (i = 0; i < I2C_CLIENT_MAX ; i++)
-		if (adapter->clients[i] && (adapter->clients[i]->addr == addr))
+	list_for_each(item,&adapter->clients) {
+		client = list_entry(item, struct i2c_client, list);
+		if (client->addr == addr)
 			return -EBUSY;
-
+	}
 	return 0;
 }
 
@@ -325,9 +282,9 @@
 {
 	int rval;
 
-	down(&adapter->list);
+	down(&adapter->clist_lock);
 	rval = __i2c_check_addr(adapter, addr);
-	up(&adapter->list);
+	up(&adapter->clist_lock);
 
 	return rval;
 }
@@ -335,28 +292,14 @@
 int i2c_attach_client(struct i2c_client *client)
 {
 	struct i2c_adapter *adapter = client->adapter;
-	int i;
-
-	down(&adapter->list);
-	if (__i2c_check_addr(client->adapter, client->addr))
-		goto out_unlock_list;
 
-	for (i = 0; i < I2C_CLIENT_MAX; i++) {
-		if (!adapter->clients[i])
-			goto free_slot;
+	down(&adapter->clist_lock);
+	if (__i2c_check_addr(client->adapter, client->addr)) {
+		up(&adapter->clist_lock);
+		return -EBUSY;
 	}
-
-	printk(KERN_WARNING 
-	       " i2c-core.o: attach_client(%s) - enlarge I2C_CLIENT_MAX.\n",
-	       client->dev.name);
-
- out_unlock_list:
-	up(&adapter->list);
-	return -EBUSY;
-
- free_slot:
-	adapter->clients[i] = client;
-	up(&adapter->list);
+	list_add_tail(&client->list,&adapter->clients);
+	up(&adapter->clist_lock);
 	
 	if (adapter->client_register)  {
 		if (adapter->client_register(client))  {
@@ -366,8 +309,8 @@
 		}
 	}
 
-	DEB(dev_dbg(&adapter->dev, "client [%s] registered to adapter "
-			"(pos. %d).\n", client->dev.name, i));
+	DEB(dev_dbg(&adapter->dev, "client [%s] registered to adapter\n",
+			client->dev.name));
 
 	if (client->flags & I2C_CLIENT_ALLOW_USE)
 		client->usage_count = 0;
@@ -388,7 +331,7 @@
 int i2c_detach_client(struct i2c_client *client)
 {
 	struct i2c_adapter *adapter = client->adapter;
-	int res = 0, i;
+	int res = 0;
 	
 	if ((client->flags & I2C_CLIENT_ALLOW_USE) && (client->usage_count > 0))
 		return -EBUSY;
@@ -403,22 +346,11 @@
 		}
 	}
 
-	down(&adapter->list);
-	for (i = 0; i < I2C_CLIENT_MAX; i++) {
-		if (client == adapter->clients[i]) {
-			adapter->clients[i] = NULL;
-			goto out_unlock;
-		}
-	}
-
-	printk(KERN_WARNING
-	       " i2c-core.o: unregister_client [%s] not found\n",
-	       client->dev.name);
-	res = -ENODEV;
-
- out_unlock:
+	down(&adapter->clist_lock);
+	list_del(&client->list);
 	device_unregister(&client->dev);
-	up(&adapter->list);
+	up(&adapter->clist_lock);
+
  out:
 	return res;
 }
@@ -479,6 +411,27 @@
 	return 0;
 }
 
+void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg)
+{
+	struct list_head  *item;
+	struct i2c_client *client;
+
+	down(&adap->clist_lock);
+	list_for_each(item,&adap->clients) {
+		client = list_entry(item, struct i2c_client, list);
+		if (!try_module_get(client->driver->owner))
+			continue;
+		if (NULL != client->driver->command) {
+			up(&adap->clist_lock);
+			client->driver->command(client,cmd,arg);
+			down(&adap->clist_lock);
+		}
+		module_put(client->driver->owner);
+       }
+       up(&adap->clist_lock);
+}
+
+
 /* match always succeeds, as we want the probe() to tell if we really accept this match */
 static int i2c_device_match(struct device *dev, struct device_driver *drv)
 {
@@ -516,9 +469,9 @@
 	if (adap->algo->master_xfer) {
  	 	DEB2(dev_dbg(&adap->dev, "master_xfer: with %d msgs.\n", num));
 
-		down(&adap->bus);
+		down(&adap->bus_lock);
 		ret = adap->algo->master_xfer(adap,msgs,num);
-		up(&adap->bus);
+		up(&adap->bus_lock);
 
 		return ret;
 	} else {
@@ -542,9 +495,9 @@
 		DEB2(dev_dbg(&client->adapter->dev, "master_send: writing %d bytes.\n",
 				count));
 	
-		down(&adap->bus);
+		down(&adap->bus_lock);
 		ret = adap->algo->master_xfer(adap,&msg,1);
-		up(&adap->bus);
+		up(&adap->bus_lock);
 
 		/* if everything went ok (i.e. 1 msg transmitted), return #bytes
 		 * transmitted, else error code.
@@ -572,9 +525,9 @@
 		DEB2(dev_dbg(&client->adapter->dev, "master_recv: reading %d bytes.\n",
 				count));
 	
-		down(&adap->bus);
+		down(&adap->bus_lock);
 		ret = adap->algo->master_xfer(adap,&msg,1);
-		up(&adap->bus);
+		up(&adap->bus_lock);
 	
 		DEB2(printk(KERN_DEBUG "i2c-core.o: master_recv: return:%d (count:%d, addr:0x%02x)\n",
 			ret, count, client->addr));
@@ -743,11 +696,30 @@
  */
 int i2c_adapter_id(struct i2c_adapter *adap)
 {
-	int i;
-	for (i = 0; i < I2C_ADAP_MAX; i++)
-		if (adap == adapters[i])
-			return i;
-	return -1;
+	return adap->nr;
+}
+
+struct i2c_adapter* i2c_get_adapter(int id)
+{
+	struct list_head   *item;
+	struct i2c_adapter *adapter;
+	
+	down(&core_lists);
+	list_for_each(item,&adapters) {
+		adapter = list_entry(item, struct i2c_adapter, list);
+		if (id == adapter->nr &&
+		    try_module_get(adapter->owner)) {
+			up(&core_lists);
+			return adapter;
+		}
+	}
+	up(&core_lists);
+	return NULL;
+}
+
+void i2c_put_adapter(struct i2c_adapter *adap)
+{
+	module_put(adap->owner);
 }
 
 /* The SMBus parts */
@@ -1189,10 +1161,10 @@
 	}
 
 	if (adapter->algo->smbus_xfer) {
-		down(&adapter->bus);
+		down(&adapter->bus_lock);
 		res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write,
 		                                command,size,data);
-		up(&adapter->bus);
+		up(&adapter->bus_lock);
 	} else
 		res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write,
 	                                      command,size,data);
@@ -1232,6 +1204,7 @@
 EXPORT_SYMBOL(i2c_detach_client);
 EXPORT_SYMBOL(i2c_use_client);
 EXPORT_SYMBOL(i2c_release_client);
+EXPORT_SYMBOL(i2c_clients_command);
 EXPORT_SYMBOL(i2c_check_addr);
 
 EXPORT_SYMBOL(i2c_master_send);
@@ -1239,6 +1212,8 @@
 EXPORT_SYMBOL(i2c_control);
 EXPORT_SYMBOL(i2c_transfer);
 EXPORT_SYMBOL(i2c_adapter_id);
+EXPORT_SYMBOL(i2c_get_adapter);
+EXPORT_SYMBOL(i2c_put_adapter);
 EXPORT_SYMBOL(i2c_probe);
 
 EXPORT_SYMBOL(i2c_smbus_xfer);
diff -urN linux-2.5.69-bk1/drivers/i2c/i2c-dev.c linux-2.5.69-bk2/drivers/i2c/i2c-dev.c
--- linux-2.5.69-bk1/drivers/i2c/i2c-dev.c	2003-05-04 16:53:36.000000000 -0700
+++ linux-2.5.69-bk2/drivers/i2c/i2c-dev.c	2003-05-07 04:41:16.000000000 -0700
@@ -58,6 +58,7 @@
 static int i2cdev_release (struct inode *inode, struct file *file);
 
 static int i2cdev_attach_adapter(struct i2c_adapter *adap);
+static int i2cdev_detach_adapter(struct i2c_adapter *adap);
 static int i2cdev_detach_client(struct i2c_client *client);
 static int i2cdev_command(struct i2c_client *client, unsigned int cmd,
                            void *arg);
@@ -72,15 +73,13 @@
 	.release	= i2cdev_release,
 };
 
-#define I2CDEV_ADAPS_MAX I2C_ADAP_MAX
-static struct i2c_adapter *i2cdev_adaps[I2CDEV_ADAPS_MAX];
-
 static struct i2c_driver i2cdev_driver = {
 	.owner		= THIS_MODULE,
 	.name		= "dev driver",
 	.id		= I2C_DRIVERID_I2CDEV,
-	.flags		= I2C_DF_DUMMY,
+	.flags		= I2C_DF_NOTIFY,
 	.attach_adapter	= i2cdev_attach_adapter,
+	.detach_adapter	= i2cdev_detach_adapter,
 	.detach_client	= i2cdev_detach_client,
 	.command	= i2cdev_command,
 };
@@ -340,35 +339,31 @@
 {
 	unsigned int minor = minor(inode->i_rdev);
 	struct i2c_client *client;
+	struct i2c_adapter *adap;
 
-	if ((minor >= I2CDEV_ADAPS_MAX) || !(i2cdev_adaps[minor]))
+	adap = i2c_get_adapter(minor);
+	if (NULL == adap)
 		return -ENODEV;
 
 	client = kmalloc(sizeof(*client), GFP_KERNEL);
-	if (!client)
+	if (!client) {
+		i2c_put_adapter(adap);
 		return -ENOMEM;
+	}
 	memcpy(client, &i2cdev_client_template, sizeof(*client));
 
 	/* registered with adapter, passed as client to user */
-	client->adapter = i2cdev_adaps[minor];
+	client->adapter = adap;
 	file->private_data = client;
 
-	/* use adapter module, i2c-dev handled with fops */
-	if (!try_module_get(client->adapter->owner))
-		goto out_kfree;
-
 	return 0;
-
-out_kfree:
-	kfree(client);
-	return -ENODEV;
 }
 
 static int i2cdev_release(struct inode *inode, struct file *file)
 {
 	struct i2c_client *client = file->private_data;
 
-	module_put(client->adapter->owner);
+	i2c_put_adapter(client->adapter);
 	kfree(client);
 	file->private_data = NULL;
 
@@ -377,33 +372,28 @@
 
 int i2cdev_attach_adapter(struct i2c_adapter *adap)
 {
-	int i;
 	char name[12];
+	int i;
 
-	if ((i = i2c_adapter_id(adap)) < 0) {
-		dev_dbg(&adap->dev, "Unknown adapter ?!?\n");
-		return -ENODEV;
-	}
-	if (i >= I2CDEV_ADAPS_MAX) {
-		dev_dbg(&adap->dev, "Adapter number too large?!? (%d)\n",i);
-		return -ENODEV;
-	}
-
+	i = i2c_adapter_id(adap);
 	sprintf (name, "i2c/%d", i);
-	if (! i2cdev_adaps[i]) {
-		i2cdev_adaps[i] = adap;
-		devfs_register (NULL, name,
+
+	devfs_register (NULL, name,
 			DEVFS_FL_DEFAULT, I2C_MAJOR, i,
 			S_IFCHR | S_IRUSR | S_IWUSR,
 			&i2cdev_fops, NULL);
-		dev_dbg(&adap->dev, "Registered as minor %d\n", i);
-	} else {
-		/* This is actually a detach_adapter call! */
-		devfs_remove("i2c/%d", i);
-		i2cdev_adaps[i] = NULL;
-		dev_dbg(&adap->dev, "Adapter unregistered\n");
-	}
+	dev_dbg(&adap->dev, "Registered as minor %d\n", i);
+	return 0;
+}
+
+int i2cdev_detach_adapter(struct i2c_adapter *adap)
+{
+	int i;
+
+	i = i2c_adapter_id(adap);
 
+	devfs_remove("i2c/%d", i);
+	dev_dbg(&adap->dev, "Adapter unregistered\n");
 	return 0;
 }
 
diff -urN linux-2.5.69-bk1/drivers/i2c/i2c-keywest.c linux-2.5.69-bk2/drivers/i2c/i2c-keywest.c
--- linux-2.5.69-bk1/drivers/i2c/i2c-keywest.c	2003-05-04 16:53:35.000000000 -0700
+++ linux-2.5.69-bk2/drivers/i2c/i2c-keywest.c	2003-05-07 04:41:16.000000000 -0700
@@ -212,7 +212,7 @@
 #ifndef POLLED_MODE
 
 /* Interrupt handler */
-static void
+static irqreturn_t
 keywest_irq(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct keywest_iface *iface = (struct keywest_iface *)dev_id;
@@ -225,6 +225,7 @@
 		add_timer(&iface->timeout_timer);
 	}
 	spin_unlock(&iface->lock);
+	return IRQ_HANDLED;
 }
 
 static void
diff -urN linux-2.5.69-bk1/drivers/media/video/bt832.c linux-2.5.69-bk2/drivers/media/video/bt832.c
--- linux-2.5.69-bk1/drivers/media/video/bt832.c	2003-05-04 16:53:36.000000000 -0700
+++ linux-2.5.69-bk2/drivers/media/video/bt832.c	2003-05-07 04:41:16.000000000 -0700
@@ -198,25 +198,9 @@
 
 static int bt832_probe(struct i2c_adapter *adap)
 {
-	int rc;
-
-	printk("bt832_probe\n");
-
-	switch (adap->id) {
-	case I2C_ALGO_BIT | I2C_HW_B_BT848:
-	case I2C_ALGO_BIT | I2C_HW_B_RIVA:
-	case I2C_ALGO_SAA7134:
-		printk("bt832: probing %s i2c adapter [id=0x%x]\n",
-		       adap->name,adap->id);
-		rc = i2c_probe(adap, &addr_data, bt832_attach);
-		break;
-	default:
-		printk("bt832: ignoring %s i2c adapter [id=0x%x]\n",
-		       adap->name,adap->id);
-		rc = 0;
-		/* nothing */
-	}
-	return rc;
+	if (adap->class & I2C_ADAP_CLASS_TV_ANALOG)
+		return i2c_probe(adap, &addr_data, bt832_attach);
+	return 0;
 }
 
 static int bt832_detach(struct i2c_client *client)
diff -urN linux-2.5.69-bk1/drivers/media/video/bttv-if.c linux-2.5.69-bk2/drivers/media/video/bttv-if.c
--- linux-2.5.69-bk1/drivers/media/video/bttv-if.c	2003-05-04 16:53:02.000000000 -0700
+++ linux-2.5.69-bk2/drivers/media/video/bttv-if.c	2003-05-07 04:41:16.000000000 -0700
@@ -7,7 +7,7 @@
 
     Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
                            & Marcus Metzler (mocm@thp.uni-koeln.de)
-    (c) 1999,2000 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+    (c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -195,51 +195,21 @@
 static int attach_inform(struct i2c_client *client)
 {
         struct bttv *btv = i2c_get_adapdata(client->adapter);
-	int i;
 
-	for (i = 0; i < I2C_CLIENTS_MAX; i++) {
-		if (btv->i2c_clients[i] == NULL) {
-			btv->i2c_clients[i] = client;
-			break;
-		}
-	}
-	if (btv->tuner_type != -1)
+	if (btv->tuner_type != UNSET)
 		bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type);
-        if (bttv_verbose)
-		printk("bttv%d: i2c attach [client=%s,%s]\n",btv->nr,
-		       client->dev.name, (i < I2C_CLIENTS_MAX) ?  "ok" : "failed");
-        return 0;
-}
-
-static int detach_inform(struct i2c_client *client)
-{
-        struct bttv *btv = i2c_get_adapdata(client->adapter);
-	int i;
 
-	for (i = 0; i < I2C_CLIENTS_MAX; i++) {
-		if (btv->i2c_clients[i] == client) {
-			btv->i2c_clients[i] = NULL;
-			break;
-		}
-	}
-        if (bttv_verbose)
-		printk("bttv%d: i2c detach [client=%s,%s]\n",btv->nr,
-		       client->dev.name, (i < I2C_CLIENTS_MAX) ?  "ok" : "failed");
+        if (bttv_debug)
+		printk("bttv%d: i2c attach [client=%s]\n",
+		       btv->nr, i2c_clientname(client));
         return 0;
 }
 
 void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg)
 {
-	int i;
-	
-	for (i = 0; i < I2C_CLIENTS_MAX; i++) {
-		if (NULL == btv->i2c_clients[i])
-			continue;
-		if (NULL == btv->i2c_clients[i]->driver->command)
-			continue;
-		btv->i2c_clients[i]->driver->command(
-			btv->i2c_clients[i],cmd,arg);
-	}
+	if (0 != btv->i2c_rc)
+		return;
+	i2c_clients_command(&btv->i2c_adap, cmd, arg);
 }
 
 void bttv_i2c_call(unsigned int card, unsigned int cmd, void *arg)
@@ -260,20 +230,16 @@
 };
 
 static struct i2c_adapter bttv_i2c_adap_template = {
-	.owner          = THIS_MODULE,
+	.owner             = THIS_MODULE,
+	I2C_DEVNAME("bt848"),
 	.id                = I2C_HW_B_BT848,
+	.class             = I2C_ADAP_CLASS_TV_ANALOG,
 	.client_register   = attach_inform,
-	.client_unregister = detach_inform,
-	.dev		= {
-		.name	= "bt848",
-	},
 };
 
 static struct i2c_client bttv_i2c_client_template = {
-        .id	= -1,
-        .dev	= {
-		.name = "bttv internal",
-	},
+	I2C_DEVNAME("bttv internal"),
+        .id       = -1,
 };
 
 
@@ -347,8 +313,8 @@
 	memcpy(&btv->i2c_client, &bttv_i2c_client_template,
 	       sizeof(struct i2c_client));
 
-	sprintf(btv->i2c_adap.dev.name+strlen(btv->i2c_adap.dev.name),
-		" #%d", btv->nr);
+	sprintf(btv->i2c_adap.dev.name, "bt848 #%d", btv->nr);
+
         btv->i2c_algo.data = btv;
         i2c_set_adapdata(&btv->i2c_adap, btv);
         btv->i2c_adap.algo_data = &btv->i2c_algo;
diff -urN linux-2.5.69-bk1/drivers/media/video/bttv.h linux-2.5.69-bk2/drivers/media/video/bttv.h
--- linux-2.5.69-bk1/drivers/media/video/bttv.h	2003-05-04 16:53:02.000000000 -0700
+++ linux-2.5.69-bk2/drivers/media/video/bttv.h	2003-05-07 04:41:16.000000000 -0700
@@ -243,7 +243,6 @@
 
 
 /* i2c */
-#define I2C_CLIENTS_MAX 16
 extern void bttv_bit_setscl(void *data, int state);
 extern void bttv_bit_setsda(void *data, int state);
 extern void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg);
diff -urN linux-2.5.69-bk1/drivers/media/video/bttvp.h linux-2.5.69-bk2/drivers/media/video/bttvp.h
--- linux-2.5.69-bk1/drivers/media/video/bttvp.h	2003-05-04 16:53:12.000000000 -0700
+++ linux-2.5.69-bk2/drivers/media/video/bttvp.h	2003-05-07 04:41:16.000000000 -0700
@@ -62,6 +62,8 @@
 #define RAW_LINES            640
 #define RAW_BPL             1024
 
+#define UNSET (-1U)
+
 /* ---------------------------------------------------------- */
 
 struct bttv_tvnorm 
@@ -276,7 +278,6 @@
 	struct i2c_algo_bit_data   i2c_algo;
 	struct i2c_client          i2c_client;
 	int                        i2c_state, i2c_rc;
-	struct i2c_client         *i2c_clients[I2C_CLIENTS_MAX];
 
 	/* video4linux (1) */
 	struct video_device video_dev;
diff -urN linux-2.5.69-bk1/drivers/media/video/dpc7146.c linux-2.5.69-bk2/drivers/media/video/dpc7146.c
--- linux-2.5.69-bk1/drivers/media/video/dpc7146.c	2003-05-04 16:53:13.000000000 -0700
+++ linux-2.5.69-bk2/drivers/media/video/dpc7146.c	2003-05-07 04:41:16.000000000 -0700
@@ -96,7 +96,8 @@
 static int dpc_probe(struct saa7146_dev* dev)
 {
 	struct dpc* dpc = 0;	
-	int i = 0;
+	struct i2c_client *client;
+	struct list_head *item;
 
 	dpc = (struct dpc*)kmalloc(sizeof(struct dpc), GFP_KERNEL);
 	if( NULL == dpc ) {
@@ -117,12 +118,10 @@
 	}
 
 	/* loop through all i2c-devices on the bus and look who is there */
-	for(i = 0; i < I2C_CLIENT_MAX; i++) {
-		if( NULL == dpc->i2c_adapter.clients[i] ) {
-			continue;
-		}
-		if( I2C_SAA7111A == dpc->i2c_adapter.clients[i]->addr ) 
-			dpc->saa7111a = dpc->i2c_adapter.clients[i];
+	list_for_each(item,&dpc->i2c_adapter.clients) {
+		client = list_entry(item, struct i2c_client, list);
+		if( I2C_SAA7111A == client->addr ) 
+			dpc->saa7111a = client;
 	}
 
 	/* check if all devices are present */
diff -urN linux-2.5.69-bk1/drivers/media/video/msp3400.c linux-2.5.69-bk2/drivers/media/video/msp3400.c
--- linux-2.5.69-bk1/drivers/media/video/msp3400.c	2003-05-04 16:53:32.000000000 -0700
+++ linux-2.5.69-bk2/drivers/media/video/msp3400.c	2003-05-07 04:41:16.000000000 -0700
@@ -1372,7 +1372,7 @@
 
 static int msp_probe(struct i2c_adapter *adap)
 {
-	if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
+	if (adap->class & I2C_ADAP_CLASS_TV_ANALOG)
 		return i2c_probe(adap, &addr_data, msp_attach);
 	return 0;
 }
diff -urN linux-2.5.69-bk1/drivers/media/video/mxb.c linux-2.5.69-bk2/drivers/media/video/mxb.c
--- linux-2.5.69-bk1/drivers/media/video/mxb.c	2003-05-04 16:53:01.000000000 -0700
+++ linux-2.5.69-bk2/drivers/media/video/mxb.c	2003-05-07 04:41:16.000000000 -0700
@@ -208,7 +208,8 @@
 static int mxb_probe(struct saa7146_dev* dev)
 {
 	struct mxb* mxb = 0;
-	int i = 0;	
+	struct i2c_client *client;
+	struct list_head *item;
 
 	request_module("tuner");
 	request_module("tea6420");
@@ -235,22 +236,20 @@
 	}
 
 	/* loop through all i2c-devices on the bus and look who is there */
-	for(i = 0; i < I2C_CLIENT_MAX; i++) {
-		if( NULL == mxb->i2c_adapter.clients[i] ) {
-			continue;
-		}
-		if( I2C_TEA6420_1 == mxb->i2c_adapter.clients[i]->addr )
-			mxb->tea6420_1 = mxb->i2c_adapter.clients[i];
-		if( I2C_TEA6420_2 == mxb->i2c_adapter.clients[i]->addr ) 
-			mxb->tea6420_2 = mxb->i2c_adapter.clients[i];
-		if( I2C_TEA6415C_2 == mxb->i2c_adapter.clients[i]->addr ) 
-			mxb->tea6415c = mxb->i2c_adapter.clients[i];
-		if( I2C_TDA9840 == mxb->i2c_adapter.clients[i]->addr ) 
-			mxb->tda9840 = mxb->i2c_adapter.clients[i];
-		if( I2C_SAA7111A == mxb->i2c_adapter.clients[i]->addr ) 
-			mxb->saa7111a = mxb->i2c_adapter.clients[i];
-		if( 0x60 == mxb->i2c_adapter.clients[i]->addr ) 
-			mxb->tuner = mxb->i2c_adapter.clients[i];
+	list_for_each(item,&mxb->i2c_adapter.clients) {
+		client = list_entry(item, struct i2c_client, list);
+		if( I2C_TEA6420_1 == client->addr )
+			mxb->tea6420_1 = client;
+		if( I2C_TEA6420_2 == client->addr ) 
+			mxb->tea6420_2 = client;
+		if( I2C_TEA6415C_2 == client->addr ) 
+			mxb->tea6415c = client;
+		if( I2C_TDA9840 == client->addr ) 
+			mxb->tda9840 = client;
+		if( I2C_SAA7111A == client->addr ) 
+			mxb->saa7111a = client;
+		if( 0x60 == client->addr ) 
+			mxb->tuner = client;
 	}
 
 	/* check if all devices are present */
diff -urN linux-2.5.69-bk1/drivers/media/video/saa5249.c linux-2.5.69-bk2/drivers/media/video/saa5249.c
--- linux-2.5.69-bk1/drivers/media/video/saa5249.c	2003-05-04 16:53:36.000000000 -0700
+++ linux-2.5.69-bk2/drivers/media/video/saa5249.c	2003-05-07 04:41:16.000000000 -0700
@@ -224,12 +224,8 @@
  
 static int saa5249_probe(struct i2c_adapter *adap)
 {
-	/* Only attach these chips to the BT848 bus for now */
-	
-	if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
-	{
+	if (adap->class & I2C_ADAP_CLASS_TV_ANALOG)
 		return i2c_probe(adap, &addr_data, saa5249_attach);
-	}
 	return 0;
 }
 
diff -urN linux-2.5.69-bk1/drivers/media/video/saa7134/saa7134-i2c.c linux-2.5.69-bk2/drivers/media/video/saa7134/saa7134-i2c.c
--- linux-2.5.69-bk1/drivers/media/video/saa7134/saa7134-i2c.c	2003-05-04 16:53:02.000000000 -0700
+++ linux-2.5.69-bk2/drivers/media/video/saa7134/saa7134-i2c.c	2003-05-07 04:41:16.000000000 -0700
@@ -334,19 +334,16 @@
 
 static struct i2c_adapter saa7134_adap_template = {
 	.owner         = THIS_MODULE,
+	I2C_DEVNAME("saa7134"),
 	.id            = I2C_ALGO_SAA7134,
+	.class         = I2C_ADAP_CLASS_TV_ANALOG,
 	.algo          = &saa7134_algo,
 	.client_register = attach_inform,
-	.dev		= {
-		.name	= "saa7134",
-	},
 };
 
 static struct i2c_client saa7134_client_template = {
-        .id   = -1,
-	.dev	= {
-		.name	= "saa7134 internal",
-	},
+	I2C_DEVNAME("saa7134 internal"),
+        .id        = -1,
 };
 
 /* ----------------------------------------------------------- */
@@ -399,22 +396,13 @@
 void saa7134_i2c_call_clients(struct saa7134_dev *dev,
 			      unsigned int cmd, void *arg)
 {
-	int i;
-
-	for (i = 0; i < I2C_CLIENT_MAX; i++) {
-		if (NULL == dev->i2c_adap.clients[i])
-			continue;
-		if (NULL == dev->i2c_adap.clients[i]->driver->command)
-			continue;
-		dev->i2c_adap.clients[i]->driver->command
-			(dev->i2c_adap.clients[i],cmd,arg);
-	}
+	i2c_clients_command(&dev->i2c_adap, cmd, arg);
 }
 
 int saa7134_i2c_register(struct saa7134_dev *dev)
 {
 	dev->i2c_adap = saa7134_adap_template;
-	strncpy(dev->i2c_adap.dev.name, dev->name, DEVICE_NAME_SIZE);
+	strcpy(dev->i2c_adap.dev.name,dev->name);
 	dev->i2c_adap.algo_data = dev;
 	i2c_add_adapter(&dev->i2c_adap);
 	
diff -urN linux-2.5.69-bk1/drivers/media/video/tda7432.c linux-2.5.69-bk2/drivers/media/video/tda7432.c
--- linux-2.5.69-bk1/drivers/media/video/tda7432.c	2003-05-04 16:53:35.000000000 -0700
+++ linux-2.5.69-bk2/drivers/media/video/tda7432.c	2003-05-07 04:41:16.000000000 -0700
@@ -340,7 +340,7 @@
 
 static int tda7432_probe(struct i2c_adapter *adap)
 {
-	if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
+	if (adap->class & I2C_ADAP_CLASS_TV_ANALOG)
 		return i2c_probe(adap, &addr_data, tda7432_attach);
 	return 0;
 }
diff -urN linux-2.5.69-bk1/drivers/media/video/tda9875.c linux-2.5.69-bk2/drivers/media/video/tda9875.c
--- linux-2.5.69-bk1/drivers/media/video/tda9875.c	2003-05-04 16:53:13.000000000 -0700
+++ linux-2.5.69-bk2/drivers/media/video/tda9875.c	2003-05-07 04:41:16.000000000 -0700
@@ -273,7 +273,7 @@
 
 static int tda9875_probe(struct i2c_adapter *adap)
 {
-	if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
+	if (adap->class & I2C_ADAP_CLASS_TV_ANALOG)
 		return i2c_probe(adap, &addr_data, tda9875_attach);
 	return 0;
 }
diff -urN linux-2.5.69-bk1/drivers/media/video/tda9887.c linux-2.5.69-bk2/drivers/media/video/tda9887.c
--- linux-2.5.69-bk1/drivers/media/video/tda9887.c	2003-05-04 16:52:48.000000000 -0700
+++ linux-2.5.69-bk2/drivers/media/video/tda9887.c	2003-05-07 04:41:16.000000000 -0700
@@ -368,23 +368,9 @@
 
 static int tda9887_probe(struct i2c_adapter *adap)
 {
-	int rc;
-
-	switch (adap->id) {
-	case I2C_ALGO_BIT | I2C_HW_B_BT848:
-	case I2C_ALGO_BIT | I2C_HW_B_RIVA:
-	case I2C_ALGO_SAA7134:
-		printk("tda9887: probing %s i2c adapter [id=0x%x]\n",
-		       adap->dev.name,adap->id);
-		rc = i2c_probe(adap, &addr_data, tda9887_attach);
-		break;
-	default:
-		printk("tda9887: ignoring %s i2c adapter [id=0x%x]\n",
-		       adap->dev.name,adap->id);
-		rc = 0;
-		/* nothing */
-	}
-	return rc;
+	if (adap->class & I2C_ADAP_CLASS_TV_ANALOG)
+		return i2c_probe(adap, &addr_data, tda9887_attach);
+	return 0;
 }
 
 static int tda9887_detach(struct i2c_client *client)
diff -urN linux-2.5.69-bk1/drivers/media/video/tuner.c linux-2.5.69-bk2/drivers/media/video/tuner.c
--- linux-2.5.69-bk1/drivers/media/video/tuner.c	2003-05-04 16:53:40.000000000 -0700
+++ linux-2.5.69-bk2/drivers/media/video/tuner.c	2003-05-07 04:41:16.000000000 -0700
@@ -817,29 +817,15 @@
 
 static int tuner_probe(struct i2c_adapter *adap)
 {
-	int rc;
-
 	if (0 != addr) {
 		normal_i2c_range[0] = addr;
 		normal_i2c_range[1] = addr;
 	}
 	this_adap = 0;
-	switch (adap->id) {
-	case I2C_ALGO_BIT | I2C_HW_B_BT848:
-	case I2C_ALGO_BIT | I2C_HW_B_RIVA:
-	case I2C_ALGO_SAA7134:
-	case I2C_ALGO_SAA7146:
-		printk("tuner: probing %s i2c adapter [id=0x%x]\n",
-		       adap->dev.name,adap->id);
-		rc = i2c_probe(adap, &addr_data, tuner_attach);
-		break;
-	default:
-		printk("tuner: ignoring %s i2c adapter [id=0x%x]\n",
-		       adap->dev.name,adap->id);
-		rc = 0;
-		/* nothing */
-	}
-	return rc;
+
+	if (adap->class & I2C_ADAP_CLASS_TV_ANALOG)
+		return i2c_probe(adap, &addr_data, tuner_attach);
+	return 0;
 }
 
 static int tuner_detach(struct i2c_client *client)
diff -urN linux-2.5.69-bk1/drivers/media/video/tvaudio.c linux-2.5.69-bk2/drivers/media/video/tvaudio.c
--- linux-2.5.69-bk1/drivers/media/video/tvaudio.c	2003-05-04 16:53:09.000000000 -0700
+++ linux-2.5.69-bk2/drivers/media/video/tvaudio.c	2003-05-07 04:41:16.000000000 -0700
@@ -1408,14 +1408,9 @@
 
 static int chip_probe(struct i2c_adapter *adap)
 {
-	switch (adap->id) {
-	case I2C_ALGO_BIT | I2C_HW_B_BT848:
-	case I2C_ALGO_BIT | I2C_HW_B_RIVA:
+	if (adap->class & I2C_ADAP_CLASS_TV_ANALOG)
 		return i2c_probe(adap, &addr_data, chip_attach);
-	default:
-		/* ignore this i2c bus */
-		return 0;
-	}
+	return 0;
 }
 
 static int chip_detach(struct i2c_client *client)
diff -urN linux-2.5.69-bk1/drivers/media/video/tvmixer.c linux-2.5.69-bk2/drivers/media/video/tvmixer.c
--- linux-2.5.69-bk1/drivers/media/video/tvmixer.c	2003-05-04 16:53:41.000000000 -0700
+++ linux-2.5.69-bk2/drivers/media/video/tvmixer.c	2003-05-07 04:41:16.000000000 -0700
@@ -217,8 +217,9 @@
 	.owner           = THIS_MODULE,
 	.name            = "tv card mixer driver",
         .id              = I2C_DRIVERID_TVMIXER,
-	.flags           = I2C_DF_DUMMY,
+	.flags           = I2C_DF_NOTIFY,
         .attach_adapter  = tvmixer_adapters,
+        .detach_adapter  = tvmixer_adapters,
         .detach_client   = tvmixer_clients,
 };
 
@@ -234,14 +235,15 @@
 
 static int tvmixer_adapters(struct i2c_adapter *adap)
 {
-	int i;
+	struct list_head  *item;
+	struct i2c_client *client;
 
 	if (debug)
 		printk("tvmixer: adapter %s\n",adap->dev.name);
-	for (i=0; i<I2C_CLIENT_MAX; i++) {
-		if (!adap->clients[i])
-			continue;
-		tvmixer_clients(adap->clients[i]);
+
+	list_for_each(item,&adap->clients) {
+		client = list_entry(item, struct i2c_client, list);
+		tvmixer_clients(client);
 	}
 	return 0;
 }
@@ -252,19 +254,15 @@
 	int i,minor;
 
 	/* TV card ??? */
-	switch (client->adapter->id) {
-	case I2C_ALGO_BIT | I2C_HW_B_BT848:
-	case I2C_ALGO_BIT | I2C_HW_B_RIVA:
-		/* ok, have a look ... */
-		break;
-	default:
+	if (!(client->adapter->class & I2C_ADAP_CLASS_TV_ANALOG)) {
 		/* ignore that one */
 		if (debug)
 			printk("tvmixer: %s is not a tv card\n",
 			       client->adapter->dev.name);
 		return -1;
 	}
-	printk("tvmixer: debug: %s\n",client->dev.name);
+	if (debug)
+		printk("tvmixer: debug: %s\n",client->dev.name);
 
 	/* unregister ?? */
 	for (i = 0; i < DEV_MAX; i++) {
diff -urN linux-2.5.69-bk1/drivers/net/ppp_deflate.c linux-2.5.69-bk2/drivers/net/ppp_deflate.c
--- linux-2.5.69-bk1/drivers/net/ppp_deflate.c	2003-05-04 16:53:41.000000000 -0700
+++ linux-2.5.69-bk2/drivers/net/ppp_deflate.c	2003-05-07 04:41:16.000000000 -0700
@@ -88,7 +88,6 @@
 		if (state->strm.workspace)
 			vfree(state->strm.workspace);
 		kfree(state);
-		MOD_DEC_USE_COUNT;
 	}
 }
 
@@ -118,7 +117,6 @@
 	if (state == NULL)
 		return NULL;
 
-	MOD_INC_USE_COUNT;
 	memset (state, 0, sizeof (struct ppp_deflate_state));
 	state->strm.next_in   = NULL;
 	state->w_size         = w_size;
@@ -274,7 +272,6 @@
 		if (state->strm.workspace)
 			kfree(state->strm.workspace);
 		kfree(state);
-		MOD_DEC_USE_COUNT;
 	}
 }
 
@@ -303,7 +300,6 @@
 	if (state == NULL)
 		return NULL;
 
-	MOD_INC_USE_COUNT;
 	memset (state, 0, sizeof (struct ppp_deflate_state));
 	state->w_size         = w_size;
 	state->strm.next_out  = NULL;
diff -urN linux-2.5.69-bk1/fs/binfmt_elf.c linux-2.5.69-bk2/fs/binfmt_elf.c
--- linux-2.5.69-bk1/fs/binfmt_elf.c	2003-05-04 16:53:14.000000000 -0700
+++ linux-2.5.69-bk2/fs/binfmt_elf.c	2003-05-07 04:41:16.000000000 -0700
@@ -1105,7 +1105,7 @@
 
 	i = p->state ? ffz(~p->state) + 1 : 0;
 	psinfo->pr_state = i;
-	psinfo->pr_sname = (i < 0 || i > 5) ? '.' : "RSDZTD"[i];
+	psinfo->pr_sname = (i < 0 || i > 5) ? '.' : "RSDTZW"[i];
 	psinfo->pr_zomb = psinfo->pr_sname == 'Z';
 	psinfo->pr_nice = task_nice(p);
 	psinfo->pr_flag = p->flags;
diff -urN linux-2.5.69-bk1/fs/seq_file.c linux-2.5.69-bk2/fs/seq_file.c
--- linux-2.5.69-bk1/fs/seq_file.c	2003-05-04 16:53:35.000000000 -0700
+++ linux-2.5.69-bk2/fs/seq_file.c	2003-05-07 04:41:16.000000000 -0700
@@ -338,3 +338,13 @@
 	kfree(op);
 	return res;
 }
+
+int seq_release_private(struct inode *inode, struct file *file)
+{
+	struct seq_file *seq = file->private_data;
+
+	kfree(seq->private);
+	seq->private = NULL;
+	return seq_release(inode, file);
+}
+
diff -urN linux-2.5.69-bk1/include/linux/i2c.h linux-2.5.69-bk2/include/linux/i2c.h
--- linux-2.5.69-bk1/include/linux/i2c.h	2003-05-04 16:53:03.000000000 -0700
+++ linux-2.5.69-bk2/include/linux/i2c.h	2003-05-07 04:41:16.000000000 -0700
@@ -39,12 +39,6 @@
 
 /* --- General options ------------------------------------------------	*/
 
-#define I2C_ALGO_MAX	4		/* control memory consumption	*/
-#define I2C_ADAP_MAX	16
-#define I2C_DRIVER_MAX	16
-#define I2C_CLIENT_MAX	32
-#define I2C_DUMMY_MAX 4
-
 struct i2c_msg;
 struct i2c_algorithm;
 struct i2c_adapter;
@@ -131,6 +125,7 @@
 	 * i2c_attach_client.
 	 */
 	int (*attach_adapter)(struct i2c_adapter *);
+	int (*detach_adapter)(struct i2c_adapter *);
 
 	/* tells the driver that a client is about to be deleted & gives it 
 	 * the chance to remove its private data. Also, if the client struct
@@ -145,6 +140,7 @@
 	int (*command)(struct i2c_client *client,unsigned int cmd, void *arg);
 
 	struct device_driver driver;
+	struct list_head list;
 };
 #define to_i2c_driver(d) container_of(d, struct i2c_driver, driver)
 
@@ -169,6 +165,7 @@
 	int usage_count;		/* How many accesses currently  */
 					/* to the client		*/
 	struct device dev;		/* the device structure		*/
+	struct list_head list;
 };
 #define to_i2c_client(d) container_of(d, struct i2c_client, dev)
 
@@ -228,6 +225,7 @@
 	struct module *owner;
 	unsigned int id;/* == is algo->id | hwdep.struct->id, 		*/
 			/* for registered values see below		*/
+	unsigned int class;
 	struct i2c_algorithm *algo;/* the algorithm to access the bus	*/
 	void *algo_data;
 
@@ -236,12 +234,10 @@
 	int (*client_unregister)(struct i2c_client *);
 
 	/* data fields that are valid for all devices	*/
-	struct semaphore bus;
-	struct semaphore list;  
+	struct semaphore bus_lock;
+	struct semaphore clist_lock;
 	unsigned int flags;/* flags specifying div. data		*/
 
-	struct i2c_client *clients[I2C_CLIENT_MAX];
-
 	int timeout;
 	int retries;
 	struct device dev;	/* the adapter device */
@@ -250,6 +246,10 @@
 	/* No need to set this when you initialize the adapter          */
 	int inode;
 #endif /* def CONFIG_PROC_FS */
+
+	int nr;
+	struct list_head clients;
+	struct list_head list;
 };
 #define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)
 
@@ -265,7 +265,11 @@
 
 /*flags for the driver struct: */
 #define I2C_DF_NOTIFY	0x01		/* notify on bus (de/a)ttaches 	*/
-#define I2C_DF_DUMMY	0x02		/* do not connect any clients */
+#if 0
+/* this flag is gone -- there is a (optional) driver->detach_adapter
+ * callback now which can be used instead */
+# define I2C_DF_DUMMY	0x02
+#endif
 
 /*flags for the client struct: */
 #define I2C_CLIENT_ALLOW_USE		0x01	/* Client allows access */
@@ -275,6 +279,12 @@
 #define I2C_CLIENT_TEN	0x10			/* we have a ten bit chip address	*/
 						/* Must equal I2C_M_TEN below */
 
+/* i2c adapter classes (bitmask) */
+#define I2C_ADAP_CLASS_SMBUS      (1<<0)        /* lm_sensors, ... */
+#define I2C_ADAP_CLASS_TV_ANALOG  (1<<1)        /* bttv + friends */
+#define I2C_ADAP_CLASS_TV_DIGINAL (1<<2)        /* dbv cards */
+#define I2C_ADAP_CLASS_DDC        (1<<3)        /* i2c-matroxfb ? */
+
 /* i2c_client_address_data is the struct for holding default client
  * addresses for a driver and for the parameters supplied on the
  * command line
@@ -331,6 +341,11 @@
 extern int i2c_use_client(struct i2c_client *);
 extern int i2c_release_client(struct i2c_client *);
 
+/* call the i2c_client->command() of all attached clients with
+ * the given arguments */
+extern void i2c_clients_command(struct i2c_adapter *adap,
+				unsigned int cmd, void *arg);
+
 /* returns -EBUSY if address has been taken, 0 if not. Note that the only
    other place at which this is called is within i2c_attach_client; so
    you can cheat by simply not registering. Not recommended, of course! */
@@ -352,7 +367,8 @@
  * or -1 if the adapter was not registered. 
  */
 extern int i2c_adapter_id(struct i2c_adapter *adap);
-
+extern struct i2c_adapter* i2c_get_adapter(int id);
+extern void i2c_put_adapter(struct i2c_adapter *adap);
 
 
 /* Return the functionality mask */
diff -urN linux-2.5.69-bk1/include/linux/ipx.h linux-2.5.69-bk2/include/linux/ipx.h
--- linux-2.5.69-bk1/include/linux/ipx.h	2003-05-04 16:53:41.000000000 -0700
+++ linux-2.5.69-bk2/include/linux/ipx.h	2003-05-07 04:41:16.000000000 -0700
@@ -5,8 +5,7 @@
 #define IPX_NODE_LEN	6
 #define IPX_MTU		576
 
-struct sockaddr_ipx
-{
+struct sockaddr_ipx {
 	sa_family_t	sipx_family;
 	__u16		sipx_port;
 	__u32		sipx_network;
@@ -16,9 +15,8 @@
 };
 
 /*
- *	So we can fit the extra info for SIOCSIFADDR into the address nicely
+ * So we can fit the extra info for SIOCSIFADDR into the address nicely
  */
- 
 #define sipx_special	sipx_port
 #define sipx_action	sipx_zero
 #define IPX_DLTITF	0
@@ -56,14 +54,13 @@
  * OLD Route Definition for backward compatibility.
  */
 
-struct ipx_route_def
-{
-	__u32         ipx_network;
-	__u32         ipx_router_network;
+struct ipx_route_def {
+	__u32		ipx_network;
+	__u32		ipx_router_network;
 #define IPX_ROUTE_NO_ROUTER	0
-	unsigned char ipx_router_node[IPX_NODE_LEN];
-	unsigned char ipx_device[16];
-	unsigned short ipx_flags;
+	unsigned char	ipx_router_node[IPX_NODE_LEN];
+	unsigned char	ipx_device[16];
+	unsigned short	ipx_flags;
 #define IPX_RT_SNAP		8
 #define IPX_RT_8022		4
 #define IPX_RT_BLUEBOOK		2
@@ -71,7 +68,7 @@
 };
 
 #define SIOCAIPXITFCRT		(SIOCPROTOPRIVATE)
-#define SIOCAIPXPRISLT		(SIOCPROTOPRIVATE+1)
-#define SIOCIPXCFGDATA		(SIOCPROTOPRIVATE+2)
-#define SIOCIPXNCPCONN		(SIOCPROTOPRIVATE+3)
-#endif /* def _IPX_H_ */
+#define SIOCAIPXPRISLT		(SIOCPROTOPRIVATE + 1)
+#define SIOCIPXCFGDATA		(SIOCPROTOPRIVATE + 2)
+#define SIOCIPXNCPCONN		(SIOCPROTOPRIVATE + 3)
+#endif /* _IPX_H_ */
diff -urN linux-2.5.69-bk1/include/linux/list.h linux-2.5.69-bk2/include/linux/list.h
--- linux-2.5.69-bk1/include/linux/list.h	2003-05-04 16:53:31.000000000 -0700
+++ linux-2.5.69-bk2/include/linux/list.h	2003-05-07 04:41:16.000000000 -0700
@@ -297,6 +297,19 @@
 		     prefetch(pos->member.next))
 
 /**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos:	the type * to use as a loop counter.
+ * @n:		another type * to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member)			\
+	for (pos = list_entry((head)->next, typeof(*pos), member),	\
+		n = list_entry(pos->member.next, typeof(*pos), member);	\
+	     &pos->member != (head); 					\
+	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
  * list_for_each_rcu	-	iterate over an rcu-protected list
  * @pos:	the &struct list_head to use as a loop counter.
  * @head:	the head for your list.
diff -urN linux-2.5.69-bk1/include/linux/netfilter_ipv4/ip_nat_core.h linux-2.5.69-bk2/include/linux/netfilter_ipv4/ip_nat_core.h
--- linux-2.5.69-bk1/include/linux/netfilter_ipv4/ip_nat_core.h	2003-05-04 16:52:48.000000000 -0700
+++ linux-2.5.69-bk2/include/linux/netfilter_ipv4/ip_nat_core.h	2003-05-07 04:41:16.000000000 -0700
@@ -16,10 +16,10 @@
 
 extern struct list_head protos;
 
-extern unsigned int icmp_reply_translation(struct sk_buff *skb,
-					   struct ip_conntrack *conntrack,
-					   unsigned int hooknum,
-					   int dir);
+extern int icmp_reply_translation(struct sk_buff **pskb,
+				  struct ip_conntrack *conntrack,
+				  unsigned int hooknum,
+				  int dir);
 
 extern void replace_in_hashes(struct ip_conntrack *conntrack,
 			      struct ip_nat_info *info);
@@ -30,4 +30,10 @@
 extern struct ip_nat_protocol ip_nat_protocol_tcp;
 extern struct ip_nat_protocol ip_nat_protocol_udp;
 extern struct ip_nat_protocol ip_nat_protocol_icmp;
+
+/* Call this before modifying an existing IP packet: ensures it is
+   modifiable and linear to the point you care about (writable_len).
+   Returns true or false. */
+extern int skb_ip_make_writable(struct sk_buff **pskb,
+				unsigned int writable_len);
 #endif /* _IP_NAT_CORE_H */
diff -urN linux-2.5.69-bk1/include/linux/netfilter_ipv4/ip_nat_helper.h linux-2.5.69-bk2/include/linux/netfilter_ipv4/ip_nat_helper.h
--- linux-2.5.69-bk1/include/linux/netfilter_ipv4/ip_nat_helper.h	2003-05-04 16:53:08.000000000 -0700
+++ linux-2.5.69-bk2/include/linux/netfilter_ipv4/ip_nat_helper.h	2003-05-07 04:41:16.000000000 -0700
@@ -43,22 +43,23 @@
 
 extern int ip_nat_helper_register(struct ip_nat_helper *me);
 extern void ip_nat_helper_unregister(struct ip_nat_helper *me);
+
+/* These return true or false. */
 extern int ip_nat_mangle_tcp_packet(struct sk_buff **skb,
 				struct ip_conntrack *ct,
 				enum ip_conntrack_info ctinfo,
 				unsigned int match_offset,
 				unsigned int match_len,
-				char *rep_buffer,
+				const char *rep_buffer,
 				unsigned int rep_len);
 extern int ip_nat_mangle_udp_packet(struct sk_buff **skb,
 				struct ip_conntrack *ct,
 				enum ip_conntrack_info ctinfo,
 				unsigned int match_offset,
 				unsigned int match_len,
-				char *rep_buffer,
+				const char *rep_buffer,
 				unsigned int rep_len);
-extern int ip_nat_seq_adjust(struct sk_buff *skb,
-				struct ip_conntrack *ct,
-				enum ip_conntrack_info ctinfo);
-extern void ip_nat_delete_sack(struct sk_buff *skb);
+extern int ip_nat_seq_adjust(struct sk_buff **pskb, 
+			     struct ip_conntrack *ct, 
+			     enum ip_conntrack_info ctinfo);
 #endif
diff -urN linux-2.5.69-bk1/include/linux/netfilter_ipv4/ip_nat_protocol.h linux-2.5.69-bk2/include/linux/netfilter_ipv4/ip_nat_protocol.h
--- linux-2.5.69-bk1/include/linux/netfilter_ipv4/ip_nat_protocol.h	2003-05-04 16:53:31.000000000 -0700
+++ linux-2.5.69-bk2/include/linux/netfilter_ipv4/ip_nat_protocol.h	2003-05-07 04:41:16.000000000 -0700
@@ -18,10 +18,11 @@
 	unsigned int protonum;
 
 	/* Do a packet translation according to the ip_nat_proto_manip
-	 * and manip type. */
-	void (*manip_pkt)(struct iphdr *iph, size_t len,
-			  const struct ip_conntrack_manip *manip,
-			  enum ip_nat_manip_type maniptype);
+	 * and manip type.  Return true if succeeded. */
+	int (*manip_pkt)(struct sk_buff **pskb,
+			 unsigned int hdroff,
+			 const struct ip_conntrack_manip *manip,
+			 enum ip_nat_manip_type maniptype);
 
 	/* Is the manipable part of the tuple between min and max incl? */
 	int (*in_range)(const struct ip_conntrack_tuple *tuple,
diff -urN linux-2.5.69-bk1/include/linux/pfkeyv2.h linux-2.5.69-bk2/include/linux/pfkeyv2.h
--- linux-2.5.69-bk1/include/linux/pfkeyv2.h	2003-05-04 16:53:40.000000000 -0700
+++ linux-2.5.69-bk2/include/linux/pfkeyv2.h	2003-05-07 04:41:16.000000000 -0700
@@ -275,8 +275,8 @@
 
 /* Encryption algorithms */
 #define SADB_EALG_NONE			0
-#define SADB_EALG_DESCBC		1
-#define SADB_EALG_3DESCBC		2
+#define SADB_EALG_DESCBC		2
+#define SADB_EALG_3DESCBC		3
 #define SADB_X_EALG_CASTCBC		6
 #define SADB_X_EALG_BLOWFISHCBC		7
 #define SADB_EALG_NULL			11
diff -urN linux-2.5.69-bk1/include/linux/proc_fs.h linux-2.5.69-bk2/include/linux/proc_fs.h
--- linux-2.5.69-bk1/include/linux/proc_fs.h	2003-05-04 16:52:48.000000000 -0700
+++ linux-2.5.69-bk2/include/linux/proc_fs.h	2003-05-07 04:41:16.000000000 -0700
@@ -163,6 +163,15 @@
 	return create_proc_info_entry(name,mode,proc_net,get_info);
 }
 
+static inline struct proc_dir_entry *proc_net_fops_create(const char *name,
+	mode_t mode, struct file_operations *fops)
+{
+	struct proc_dir_entry *res = create_proc_entry(name, mode, proc_net);
+	if (res)
+		res->proc_fops = fops;
+	return res;
+}
+
 static inline void proc_net_remove(const char *name)
 {
 	remove_proc_entry(name,proc_net);
@@ -171,7 +180,7 @@
 #else
 
 #define proc_root_driver NULL
-
+#define proc_net_fops_create(name,mode,fops) do {} while(0)
 static inline struct proc_dir_entry *proc_net_create(const char *name, mode_t mode, 
 	get_info_t *get_info) {return NULL;}
 static inline void proc_net_remove(const char *name) {}
diff -urN linux-2.5.69-bk1/include/linux/seq_file.h linux-2.5.69-bk2/include/linux/seq_file.h
--- linux-2.5.69-bk1/include/linux/seq_file.h	2003-05-04 16:53:57.000000000 -0700
+++ linux-2.5.69-bk2/include/linux/seq_file.h	2003-05-07 04:41:16.000000000 -0700
@@ -60,5 +60,6 @@
 
 int single_open(struct file *, int (*)(struct seq_file *, void *), void *);
 int single_release(struct inode *, struct file *);
+int seq_release_private(struct inode *, struct file *);
 #endif
 #endif
diff -urN linux-2.5.69-bk1/include/net/dn_dev.h linux-2.5.69-bk2/include/net/dn_dev.h
--- linux-2.5.69-bk1/include/net/dn_dev.h	2003-05-04 16:52:48.000000000 -0700
+++ linux-2.5.69-bk2/include/net/dn_dev.h	2003-05-07 04:41:16.000000000 -0700
@@ -71,7 +71,6 @@
 #define DN_DEV_MPOINT 4
 	int state;                /* Initial state                      */
 	int forwarding;	          /* 0=EndNode, 1=L1Router, 2=L2Router  */
-	unsigned short blksize;   /* Block Size                         */
 	unsigned long t2;         /* Default value of t2                */
 	unsigned long t3;         /* Default value of t3                */
 	int priority;             /* Priority to be a router            */
diff -urN linux-2.5.69-bk1/include/net/dn_fib.h linux-2.5.69-bk2/include/net/dn_fib.h
--- linux-2.5.69-bk1/include/net/dn_fib.h	2003-05-04 16:53:28.000000000 -0700
+++ linux-2.5.69-bk2/include/net/dn_fib.h	2003-05-07 04:41:16.000000000 -0700
@@ -101,10 +101,6 @@
 	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
-	int (*get_info)(struct dn_fib_table *table, char *buf,
-			int first, int count);
-#endif /* CONFIG_PROC_FS */
 	int (*dump)(struct dn_fib_table *t, struct sk_buff *skb, struct netlink_callback *cb);
 
 	unsigned char data[0];
@@ -184,6 +180,9 @@
 
 #else /* Endnode */
 
+#define dn_fib_init() (0)
+#define dn_fib_cleanup() (0)
+
 #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)
diff -urN linux-2.5.69-bk1/include/net/dn_route.h linux-2.5.69-bk2/include/net/dn_route.h
--- linux-2.5.69-bk1/include/net/dn_route.h	2003-05-04 16:52:59.000000000 -0700
+++ linux-2.5.69-bk2/include/net/dn_route.h	2003-05-07 04:41:16.000000000 -0700
@@ -74,7 +74,7 @@
 	__u16 rt_saddr;
 	__u16 rt_daddr;
 	__u16 rt_gateway;
-	__u16 __padding;
+	__u16 rt_local_src;	/* Source used for forwarding packets */
 	__u16 rt_src_map;
 	__u16 rt_dst_map;
 
diff -urN linux-2.5.69-bk1/include/net/ipx.h linux-2.5.69-bk2/include/net/ipx.h
--- linux-2.5.69-bk1/include/net/ipx.h	2003-05-04 16:53:01.000000000 -0700
+++ linux-2.5.69-bk2/include/net/ipx.h	2003-05-07 04:41:16.000000000 -0700
@@ -12,6 +12,7 @@
 #include <linux/netdevice.h>
 #include <net/datalink.h>
 #include <linux/ipx.h>
+#include <linux/list.h>
 
 struct ipx_address {
 	__u32   net;
@@ -25,11 +26,11 @@
 #define IPX_MAX_PPROP_HOPS 8
 
 struct ipxhdr {
-	__u16           ipx_checksum __attribute__ ((packed));
+	__u16			ipx_checksum __attribute__ ((packed));
 #define IPX_NO_CHECKSUM	0xFFFF
-	__u16           ipx_pktsize __attribute__ ((packed));
-	__u8            ipx_tctrl;
-	__u8            ipx_type;
+	__u16			ipx_pktsize __attribute__ ((packed));
+	__u8			ipx_tctrl;
+	__u8			ipx_type;
 #define IPX_TYPE_UNKNOWN	0x00
 #define IPX_TYPE_RIP		0x01	/* may also be 0 */
 #define IPX_TYPE_SAP		0x04	/* may also be 0 */
@@ -47,42 +48,42 @@
 
 struct ipx_interface {
 	/* IPX address */
-	__u32           if_netnum;
-	unsigned char	if_node[IPX_NODE_LEN];
-	atomic_t        refcnt;
+	__u32			if_netnum;
+	unsigned char		if_node[IPX_NODE_LEN];
+	atomic_t		refcnt;
 
 	/* physical device info */
 	struct net_device	*if_dev;
 	struct datalink_proto	*if_dlink;
-	unsigned short	if_dlink_type;
+	unsigned short		if_dlink_type;
 
 	/* socket support */
-	unsigned short	if_sknum;
-	struct sock	*if_sklist;
-	spinlock_t      if_sklist_lock;
+	unsigned short		if_sknum;
+	struct sock		*if_sklist;
+	spinlock_t		if_sklist_lock;
 
 	/* administrative overhead */
-	int		if_ipx_offset;
-	unsigned char	if_internal;
-	unsigned char	if_primary;
+	int			if_ipx_offset;
+	unsigned char		if_internal;
+	unsigned char		if_primary;
 	
-	struct ipx_interface	*if_next;
+	struct list_head	node; /* node in ipx_interfaces list */
 };
 
 struct ipx_route {
-	__u32         ir_net;
+	__u32			ir_net;
 	struct ipx_interface	*ir_intrfc;
-	unsigned char ir_routed;
-	unsigned char ir_router_node[IPX_NODE_LEN];
-	struct ipx_route	*ir_next;
-	atomic_t      refcnt;
+	unsigned char		ir_routed;
+	unsigned char		ir_router_node[IPX_NODE_LEN];
+	struct list_head	node; /* node in ipx_routes list */
+	atomic_t		refcnt;
 };
 
 #ifdef __KERNEL__
 struct ipx_cb {
-	u8 ipx_tctrl;
-	u32 ipx_dest_net;
-	u32 ipx_source_net;
+	u8	ipx_tctrl;
+	u32	ipx_dest_net;
+	u32	ipx_source_net;
 	struct {
 		u32 netnum;
 		int index;
@@ -92,14 +93,16 @@
 struct ipx_opt {
 	struct ipx_address	dest_addr;
 	struct ipx_interface	*intrfc;
-	unsigned short	port;
+	unsigned short		port;
 #ifdef CONFIG_IPX_INTERN
-	unsigned char	node[IPX_NODE_LEN];
+	unsigned char		node[IPX_NODE_LEN];
 #endif
-	unsigned short	type;
-	/* To handle special ncp connection-handling sockets for mars_nwe,
- 	 * the connection number must be stored in the socket. */
-	unsigned short	ipx_ncp_conn;
+	unsigned short		type;
+	/*
+	 * To handle special ncp connection-handling sockets for mars_nwe,
+ 	 * the connection number must be stored in the socket.
+	 */
+	unsigned short		ipx_ncp_conn;
 };
 
 #define ipx_sk(__sk) ((struct ipx_opt *)(__sk)->protinfo)
@@ -108,10 +111,11 @@
 #define IPX_MIN_EPHEMERAL_SOCKET	0x4000
 #define IPX_MAX_EPHEMERAL_SOCKET	0x7fff
 
-extern struct ipx_route *ipx_routes;
+extern struct list_head ipx_routes;
 extern rwlock_t ipx_routes_lock;
 
-extern struct ipx_interface *ipx_interfaces;
+extern struct list_head ipx_interfaces;
+extern struct ipx_interface *ipx_interfaces_head(void);
 extern spinlock_t ipx_interfaces_lock;
 
 extern struct ipx_interface *ipx_primary_net;
@@ -121,4 +125,4 @@
 
 extern const char *ipx_frame_name(unsigned short);
 extern const char *ipx_device_name(struct ipx_interface *intrfc);
-#endif /* def _NET_INET_IPX_H_ */
+#endif /* _NET_INET_IPX_H_ */
diff -urN linux-2.5.69-bk1/kernel/ksyms.c linux-2.5.69-bk2/kernel/ksyms.c
--- linux-2.5.69-bk1/kernel/ksyms.c	2003-05-04 16:52:49.000000000 -0700
+++ linux-2.5.69-bk2/kernel/ksyms.c	2003-05-07 04:41:16.000000000 -0700
@@ -540,6 +540,7 @@
 EXPORT_SYMBOL(seq_lseek);
 EXPORT_SYMBOL(single_open);
 EXPORT_SYMBOL(single_release);
+EXPORT_SYMBOL(seq_release_private);
 
 /* Program loader interfaces */
 #ifdef CONFIG_MMU
diff -urN linux-2.5.69-bk1/net/atm/mpc.c linux-2.5.69-bk2/net/atm/mpc.c
--- linux-2.5.69-bk1/net/atm/mpc.c	2003-05-04 16:53:37.000000000 -0700
+++ linux-2.5.69-bk2/net/atm/mpc.c	2003-05-07 04:41:16.000000000 -0700
@@ -324,7 +324,9 @@
 	return;
 }
 
-static const char * __attribute__ ((unused)) mpoa_device_type_string(char type)
+static const char *mpoa_device_type_string(char type) __attribute__ ((unused));
+
+static const char *mpoa_device_type_string(char type)
 {
 	switch(type) {
 	case NON_MPOA:
@@ -429,7 +431,7 @@
 		if (tlvs == NULL) return;
 	}
 	if (end_of_tlvs - tlvs != 0)
-		printk("mpoa: (%s) lane2_assoc_ind: ignoring %d bytes of trailing TLV carbage\n",
+		printk("mpoa: (%s) lane2_assoc_ind: ignoring %Zd bytes of trailing TLV carbage\n",
 		       dev->name, end_of_tlvs - tlvs);
 	return;
 }
diff -urN linux-2.5.69-bk1/net/atm/svc.c linux-2.5.69-bk2/net/atm/svc.c
--- linux-2.5.69-bk1/net/atm/svc.c	2003-05-04 16:53:33.000000000 -0700
+++ linux-2.5.69-bk2/net/atm/svc.c	2003-05-07 04:41:16.000000000 -0700
@@ -64,8 +64,8 @@
 
 	DPRINTK("svc_disconnect %p\n",vcc);
 	if (test_bit(ATM_VF_REGIS,&vcc->flags)) {
-		sigd_enq(vcc,as_close,NULL,NULL,NULL);
 		add_wait_queue(&vcc->sleep,&wait);
+		sigd_enq(vcc,as_close,NULL,NULL,NULL);
 		while (!test_bit(ATM_VF_RELEASED,&vcc->flags) && sigd) {
 			set_current_state(TASK_UNINTERRUPTIBLE);
 			schedule();
@@ -124,8 +124,8 @@
 	if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) return -EBADFD;
 	vcc->local = *addr;
 	vcc->reply = WAITING;
-	sigd_enq(vcc,as_bind,NULL,NULL,&vcc->local);
 	add_wait_queue(&vcc->sleep,&wait);
+	sigd_enq(vcc,as_bind,NULL,NULL,&vcc->local);
 	while (vcc->reply == WAITING && sigd) {
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule();
@@ -169,12 +169,13 @@
 		    !vcc->qos.rxtp.traffic_class) return -EINVAL;
 		vcc->remote = *addr;
 		vcc->reply = WAITING;
+		add_wait_queue(&vcc->sleep,&wait);
 		sigd_enq(vcc,as_connect,NULL,NULL,&vcc->remote);
 		if (flags & O_NONBLOCK) {
+			remove_wait_queue(&vcc->sleep,&wait);
 			sock->state = SS_CONNECTING;
 			return -EINPROGRESS;
 		}
-		add_wait_queue(&vcc->sleep,&wait);
 		error = 0;
 		while (vcc->reply == WAITING && sigd) {
 			set_current_state(TASK_INTERRUPTIBLE);
@@ -243,8 +244,8 @@
 	/* let server handle listen on unbound sockets */
 	if (test_bit(ATM_VF_SESSION,&vcc->flags)) return -EINVAL;
 	vcc->reply = WAITING;
-	sigd_enq(vcc,as_listen,NULL,NULL,&vcc->local);
 	add_wait_queue(&vcc->sleep,&wait);
+	sigd_enq(vcc,as_listen,NULL,NULL,&vcc->local);
 	while (vcc->reply == WAITING && sigd) {
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule();
@@ -313,8 +314,8 @@
 		}
 		/* wait should be short, so we ignore the non-blocking flag */
 		new_vcc->reply = WAITING;
-		sigd_enq(new_vcc,as_accept,old_vcc,NULL,NULL);
 		add_wait_queue(&new_vcc->sleep,&wait);
+		sigd_enq(new_vcc,as_accept,old_vcc,NULL,NULL);
 		while (new_vcc->reply == WAITING && sigd) {
 			set_current_state(TASK_UNINTERRUPTIBLE);
 			schedule();
@@ -347,8 +348,8 @@
 	DECLARE_WAITQUEUE(wait,current);
 
 	vcc->reply = WAITING;
-	sigd_enq2(vcc,as_modify,NULL,NULL,&vcc->local,qos,0);
 	add_wait_queue(&vcc->sleep,&wait);
+	sigd_enq2(vcc,as_modify,NULL,NULL,&vcc->local,qos,0);
 	while (vcc->reply == WAITING && !test_bit(ATM_VF_RELEASED,&vcc->flags)
 	    && sigd) {
 		set_current_state(TASK_UNINTERRUPTIBLE);
diff -urN linux-2.5.69-bk1/net/core/neighbour.c linux-2.5.69-bk2/net/core/neighbour.c
--- linux-2.5.69-bk1/net/core/neighbour.c	2003-05-04 16:53:00.000000000 -0700
+++ linux-2.5.69-bk2/net/core/neighbour.c	2003-05-07 04:41:16.000000000 -0700
@@ -440,8 +440,8 @@
 
 	if (!neigh->dead) {
 		printk(KERN_WARNING
-		       "Destroying alive neighbour %p from %08lx\n", neigh,
-		       *(((unsigned long *)&neigh) - 1));
+		       "Destroying alive neighbour %p\n", neigh);
+		dump_stack();
 		return;
 	}
 
diff -urN linux-2.5.69-bk1/net/decnet/Kconfig linux-2.5.69-bk2/net/decnet/Kconfig
--- linux-2.5.69-bk1/net/decnet/Kconfig	2003-05-04 16:53:56.000000000 -0700
+++ linux-2.5.69-bk2/net/decnet/Kconfig	2003-05-07 04:41:16.000000000 -0700
@@ -17,11 +17,11 @@
 	depends on DECNET && EXPERIMENTAL
 	---help---
 	  Add support for turning your DECnet Endnode into a level 1 or 2
-	  router.  This is an unfinished option for developers only.  If you
+	  router.  This is an experimental, but functional option.  If you
 	  do say Y here, then make sure that you also say Y to "Kernel/User
 	  network link driver", "Routing messages" and "Network packet
 	  filtering".  The first two are required to allow configuration via
-	  rtnetlink (currently you need Alexey Kuznetsov's iproute2 package
+	  rtnetlink (you will need Alexey Kuznetsov's iproute2 package
 	  from <ftp://ftp.inr.ac.ru/>). The "Network packet filtering" option
 	  will be required for the forthcoming routing daemon to work.
 
@@ -35,3 +35,5 @@
 	  packets with different FWMARK ("firewalling mark") values
 	  (see ipchains(8), "-m" argument).
 
+source "net/decnet/netfilter/Kconfig"
+
diff -urN linux-2.5.69-bk1/net/decnet/Makefile linux-2.5.69-bk2/net/decnet/Makefile
--- linux-2.5.69-bk1/net/decnet/Makefile	2003-05-04 16:53:08.000000000 -0700
+++ linux-2.5.69-bk2/net/decnet/Makefile	2003-05-07 04:41:17.000000000 -0700
@@ -1,7 +1,10 @@
 
 obj-$(CONFIG_DECNET) += decnet.o
 
-decnet-y := af_decnet.o dn_nsp_in.o dn_nsp_out.o dn_route.o dn_dev.o dn_neigh.o dn_timer.o
+decnet-y := af_decnet.o dn_nsp_in.o dn_nsp_out.o \
+	    dn_route.o dn_dev.o dn_neigh.o dn_timer.o
 decnet-$(CONFIG_DECNET_ROUTER) += dn_fib.o dn_rules.o dn_table.o
-decnet-$(CONFIG_DECNET_FW) += dn_fw.o
 decnet-y += sysctl_net_decnet.o
+
+obj-$(CONFIG_NETFILTER) += netfilter/
+
diff -urN linux-2.5.69-bk1/net/decnet/TODO linux-2.5.69-bk2/net/decnet/TODO
--- linux-2.5.69-bk1/net/decnet/TODO	2003-05-04 16:53:35.000000000 -0700
+++ linux-2.5.69-bk2/net/decnet/TODO	2003-05-07 04:41:17.000000000 -0700
@@ -23,15 +23,9 @@
 
  o check MSG_CTRUNC is set where it should be.
 
- o Start to hack together user level software and add more DECnet support
-   in ifconfig for example. 
-
  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 Add the routing message grabbing netfilter module [written, tested,
-   awaiting 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
@@ -45,5 +39,3 @@
 
  o AIO for DECnet
 
- o Eliminate dn_db->parms.blksize
-
diff -urN linux-2.5.69-bk1/net/decnet/af_decnet.c linux-2.5.69-bk2/net/decnet/af_decnet.c
--- linux-2.5.69-bk1/net/decnet/af_decnet.c	2003-05-04 16:53:31.000000000 -0700
+++ linux-2.5.69-bk2/net/decnet/af_decnet.c	2003-05-07 04:41:17.000000000 -0700
@@ -116,6 +116,7 @@
 #include <linux/inet.h>
 #include <linux/route.h>
 #include <linux/netfilter.h>
+#include <linux/seq_file.h>
 #include <net/sock.h>
 #include <net/tcp.h>
 #include <net/flow.h>
@@ -676,45 +677,6 @@
 }
 
 
-static char *dn_state2asc(unsigned char state)
-{
-	switch(state) {
-		case DN_O:
-			return "OPEN";
-		case DN_CR:
-			return "  CR";
-		case DN_DR:
-			return "  DR";
-		case DN_DRC:
-			return " DRC";
-		case DN_CC:
-			return "  CC";
-		case DN_CI:
-			return "  CI";
-		case DN_NR:
-			return "  NR";
-		case DN_NC:
-			return "  NC";
-		case DN_CD:
-			return "  CD";
-		case DN_RJ:
-			return "  RJ";
-		case DN_RUN:
-			return " RUN";
-		case DN_DI:
-			return "  DI";
-		case DN_DIC:
-			return " DIC";
-		case DN_DN:
-			return "  DN";
-		case DN_CL:
-			return "  CL";
-		case DN_CN:
-			return "  CN";
-	}
-
-	return "????";
-}
 
 static int dn_create(struct socket *sock, int protocol)
 {
@@ -1001,6 +963,7 @@
 	fl.fld_dst = dn_saddr2dn(&scp->peer);
 	fl.fld_src = dn_saddr2dn(&scp->addr);
 	dn_sk_ports_copy(&fl, scp);
+	fl.proto = DNPROTO_NSP;
 	if (dn_route_output_sock(&sk->dst_cache, &fl, sk, flags) < 0)
 		goto out;
 	sk->route_caps = sk->dst_cache->dev->features;
@@ -1964,7 +1927,7 @@
 	unsigned char fctype;
 	long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
 
-	if (flags & ~(MSG_TRYHARD|MSG_OOB|MSG_DONTWAIT|MSG_EOR|MSG_NOSIGNAL))
+	if (flags & ~(MSG_TRYHARD|MSG_OOB|MSG_DONTWAIT|MSG_EOR|MSG_NOSIGNAL|MSG_MORE))
 		return -EOPNOTSUPP;
 
 	if (addr_len && (addr_len != sizeof(struct sockaddr_dn)))
@@ -2143,6 +2106,95 @@
 	.data =		(void*)1,
 };
 
+#ifdef CONFIG_PROC_FS
+struct dn_iter_state {
+	int bucket;
+};
+
+static struct sock *dn_socket_get_first(struct seq_file *seq)
+{
+	struct dn_iter_state *state = seq->private;
+	struct sock *n = NULL;
+
+	for(state->bucket = 0;
+	    state->bucket < DN_SK_HASH_SIZE;
+	    ++state->bucket) {
+		n = dn_sk_hash[state->bucket];
+		if (n)
+			break;
+	}
+
+	return n;
+}
+
+static struct sock *dn_socket_get_next(struct seq_file *seq,
+				       struct sock *n)
+{
+	struct dn_iter_state *state = seq->private;
+
+	n = n->next;
+try_again:
+	if (n)
+		goto out;
+	if (++state->bucket >= DN_SK_HASH_SIZE)
+		goto out;
+	n = dn_sk_hash[state->bucket];
+	goto try_again;
+out:
+	return n;
+}
+
+static struct sock *socket_get_idx(struct seq_file *seq, loff_t *pos)
+{
+	struct sock *sk = dn_socket_get_first(seq);
+
+	if (sk) {
+		while(*pos && (sk = dn_socket_get_next(seq, sk)))
+			--*pos;
+	}
+	return *pos ? NULL : sk;
+}
+
+static void *dn_socket_get_idx(struct seq_file *seq, loff_t pos)
+{
+	void *rc;
+	read_lock_bh(&dn_hash_lock);
+	rc = socket_get_idx(seq, &pos);
+	if (!rc) {
+		read_unlock_bh(&dn_hash_lock);
+	}
+	return rc;
+}
+
+static void *dn_socket_seq_start(struct seq_file *seq, loff_t *pos)
+{
+	return *pos ? dn_socket_get_idx(seq, *pos - 1) : (void*)1;
+}
+
+static void *dn_socket_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	void *rc;
+
+	if (v == (void*)1) {
+		rc = dn_socket_get_idx(seq, 0);
+		goto out;
+	}
+
+	rc = dn_socket_get_next(seq, v);
+	if (rc)
+		goto out;
+	read_unlock_bh(&dn_hash_lock);
+out:
+	++*pos;
+	return rc;
+}
+
+static void dn_socket_seq_stop(struct seq_file *seq, void *v)
+{
+	if (v && v != (void*)1)
+		read_unlock_bh(&dn_hash_lock);
+}
+
 #define IS_NOT_PRINTABLE(x) ((x) < 32 || (x) > 126)
 
 static void dn_printable_object(struct sockaddr_dn *dn, unsigned char *buf)
@@ -2163,70 +2215,127 @@
     	}
 }
 
-static int dn_get_info(char *buffer, char **start, off_t offset, int length)
+static char *dn_state2asc(unsigned char state)
 {
-	struct sock *sk;
-	struct dn_scp *scp;
-	int len = 0;
-	off_t pos = 0;
-	off_t begin = 0;
+	switch(state) {
+		case DN_O:
+			return "OPEN";
+		case DN_CR:
+			return "  CR";
+		case DN_DR:
+			return "  DR";
+		case DN_DRC:
+			return " DRC";
+		case DN_CC:
+			return "  CC";
+		case DN_CI:
+			return "  CI";
+		case DN_NR:
+			return "  NR";
+		case DN_NC:
+			return "  NC";
+		case DN_CD:
+			return "  CD";
+		case DN_RJ:
+			return "  RJ";
+		case DN_RUN:
+			return " RUN";
+		case DN_DI:
+			return "  DI";
+		case DN_DIC:
+			return " DIC";
+		case DN_DN:
+			return "  DN";
+		case DN_CL:
+			return "  CL";
+		case DN_CN:
+			return "  CN";
+	}
+
+	return "????";
+}
+
+static inline void dn_socket_format_entry(struct seq_file *seq, struct sock *sk)
+{
+	struct dn_scp *scp = DN_SK(sk);
 	char buf1[DN_ASCBUF_LEN];
 	char buf2[DN_ASCBUF_LEN];
 	char local_object[DN_MAXOBJL+3];
 	char remote_object[DN_MAXOBJL+3];
-	int i;
 
-	len += sprintf(buffer + len, "Local                                              Remote\n");
+	dn_printable_object(&scp->addr, local_object);
+	dn_printable_object(&scp->peer, remote_object);
 
-	read_lock(&dn_hash_lock);
-	for(i = 0; i < DN_SK_HASH_SIZE; i++) {
-		for(sk = dn_sk_hash[i]; sk != NULL; sk = sk->next) {
-			scp = DN_SK(sk);
-
-			dn_printable_object(&scp->addr, local_object);
-			dn_printable_object(&scp->peer, remote_object);
-
-			len += sprintf(buffer + len,
-					"%6s/%04X %04d:%04d %04d:%04d %01d %-16s %6s/%04X %04d:%04d %04d:%04d %01d %-16s %4s %s\n",
-					dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->addr)), buf1),
-					scp->addrloc,
-					scp->numdat,
-					scp->numoth,
-					scp->ackxmt_dat,
-					scp->ackxmt_oth,
-					scp->flowloc_sw,
-					local_object,
-					dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->peer)), buf2),
-					scp->addrrem,
-					scp->numdat_rcv,
-					scp->numoth_rcv,
-					scp->ackrcv_dat,
-					scp->ackrcv_oth,
-					scp->flowrem_sw,
-					remote_object,
-					dn_state2asc(scp->state),
-					((scp->accept_mode == ACC_IMMED) ? "IMMED" : "DEFER"));
-
-			pos = begin + len;
-			if (pos < offset) {
-				len = 0;
-				begin = pos;
-			}
-			if (pos > (offset + length))
-				break;
-		}
+	seq_printf(seq,
+		   "%6s/%04X %04d:%04d %04d:%04d %01d %-16s "
+		   "%6s/%04X %04d:%04d %04d:%04d %01d %-16s %4s %s\n",
+		   dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->addr)), buf1),
+		   scp->addrloc,
+		   scp->numdat,
+		   scp->numoth,
+		   scp->ackxmt_dat,
+		   scp->ackxmt_oth,
+		   scp->flowloc_sw,
+		   local_object,
+		   dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->peer)), buf2),
+		   scp->addrrem,
+		   scp->numdat_rcv,
+		   scp->numoth_rcv,
+		   scp->ackrcv_dat,
+		   scp->ackrcv_oth,
+		   scp->flowrem_sw,
+		   remote_object,
+		   dn_state2asc(scp->state),
+		   ((scp->accept_mode == ACC_IMMED) ? "IMMED" : "DEFER"));
+}
+
+static int dn_socket_seq_show(struct seq_file *seq, void *v)
+{
+	if (v == (void*)1) {
+		seq_puts(seq, "Local                                              Remote\n");
+	} else {
+		dn_socket_format_entry(seq, v);
 	}
-	read_unlock(&dn_hash_lock);
+	return 0;
+}
 
-	*start = buffer + (offset - begin);
-	len -= (offset - begin);
+static struct seq_operations dn_socket_seq_ops = {
+	.start	= dn_socket_seq_start,
+	.next	= dn_socket_seq_next,
+	.stop	= dn_socket_seq_stop,
+	.show	= dn_socket_seq_show,
+};
 
-	if (len > length)
-		len = length;
+static int dn_socket_seq_open(struct inode *inode, struct file *file)
+{
+	struct seq_file *seq;
+	int rc = -ENOMEM;
+	struct dn_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
 
-	return len;
+	if (!s)
+		goto out;
+
+	rc = seq_open(file, &dn_socket_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 struct file_operations dn_socket_seq_fops = {
+	.open		= dn_socket_seq_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release_private,
+};
+#endif
 
 static struct net_proto_family	dn_family_ops = {
 	.family =	AF_DECnet,
@@ -2258,13 +2367,11 @@
 void dn_register_sysctl(void);
 void dn_unregister_sysctl(void);
 
-
 MODULE_DESCRIPTION("The Linux DECnet Network Protocol");
 MODULE_AUTHOR("Linux DECnet Project Team");
 MODULE_LICENSE("GPL");
 
-
-static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.5.67s (C) 1995-2003 Linux DECnet Project Team\n";
+static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.5.68s (C) 1995-2003 Linux DECnet Project Team\n";
 
 static int __init decnet_init(void)
 {
@@ -2281,15 +2388,12 @@
 	dev_add_pack(&dn_dix_packet_type);
 	register_netdevice_notifier(&dn_dev_notifier);
 
-	proc_net_create("decnet", 0, dn_get_info);
+	proc_net_fops_create("decnet", S_IRUGO, &dn_socket_seq_fops);
 
 	dn_neigh_init();
 	dn_dev_init();
 	dn_route_init();
-
-#ifdef CONFIG_DECNET_ROUTER
 	dn_fib_init();
-#endif /* CONFIG_DECNET_ROUTER */
 
 	dn_register_sysctl();
 
@@ -2316,10 +2420,7 @@
 	dn_route_cleanup();
 	dn_dev_cleanup();
 	dn_neigh_cleanup();
-
-#ifdef CONFIG_DECNET_ROUTER
 	dn_fib_cleanup();
-#endif /* CONFIG_DECNET_ROUTER */
 
 	proc_net_remove("decnet");
 
diff -urN linux-2.5.69-bk1/net/decnet/dn_dev.c linux-2.5.69-bk2/net/decnet/dn_dev.c
--- linux-2.5.69-bk1/net/decnet/dn_dev.c	2003-05-04 16:53:09.000000000 -0700
+++ linux-2.5.69-bk2/net/decnet/dn_dev.c	2003-05-07 04:41:17.000000000 -0700
@@ -20,6 +20,8 @@
  *          Steve Whitehouse : /proc/sys/net/decnet/conf/<sys>/forwarding
  *          Steve Whitehouse : Removed timer1 - it's a user space issue now
  *         Patrick Caulfield : Fixed router hello message format
+ *          Steve Whitehouse : Got rid of constant sizes for blksize for
+ *                             devices. All mtu based now.
  */
 
 #include <linux/config.h>
@@ -28,6 +30,7 @@
 #include <linux/net.h>
 #include <linux/netdevice.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <linux/timer.h>
 #include <linux/string.h>
 #include <linux/if_arp.h>
@@ -72,16 +75,13 @@
 static int dn_eth_up(struct net_device *);
 static void dn_eth_down(struct net_device *);
 static void dn_send_brd_hello(struct net_device *dev, struct dn_ifaddr *ifa);
-#if 0
 static void dn_send_ptp_hello(struct net_device *dev, struct dn_ifaddr *ifa);
-#endif
 
 static struct dn_dev_parms dn_dev_list[] =  {
 {
 	.type =		ARPHRD_ETHER, /* Ethernet */
 	.mode =		DN_DEV_BCAST,
 	.state =	DN_DEV_S_RU,
-	.blksize =	1498,
 	.t2 =		1,
 	.t3 =		10,
 	.name =		"ethernet",
@@ -94,7 +94,6 @@
 	.type =		ARPHRD_IPGRE, /* DECnet tunneled over GRE in IP */
 	.mode =		DN_DEV_BCAST,
 	.state =	DN_DEV_S_RU,
-	.blksize =	1400,
 	.t2 =		1,
 	.t3 =		10,
 	.name =		"ipgre",
@@ -106,7 +105,6 @@
 	.type =		ARPHRD_X25, /* Bog standard X.25 */
 	.mode =		DN_DEV_UCAST,
 	.state =	DN_DEV_S_DS,
-	.blksize =	230,
 	.t2 =		1,
 	.t3 =		120,
 	.name =		"x25",
@@ -119,7 +117,6 @@
 	.type =		ARPHRD_PPP, /* DECnet over PPP */
 	.mode =		DN_DEV_BCAST,
 	.state =	DN_DEV_S_RU,
-	.blksize =	230,
 	.t2 =		1,
 	.t3 =		10,
 	.name =		"ppp",
@@ -127,24 +124,20 @@
 	.timer3 =	dn_send_brd_hello,
 },
 #endif
-#if 0
 {
 	.type =		ARPHRD_DDCMP, /* DECnet over DDCMP */
 	.mode =		DN_DEV_UCAST,
 	.state =	DN_DEV_S_DS,
-	.blksize =	230,
 	.t2 =		1,
 	.t3 =		120,
 	.name =		"ddcmp",
 	.ctl_name =	NET_DECNET_CONF_DDCMP,
 	.timer3 =	dn_send_ptp_hello,
 },
-#endif
 {
 	.type =		ARPHRD_LOOPBACK, /* Loopback interface - always last */
 	.mode =		DN_DEV_BCAST,
 	.state =	DN_DEV_S_RU,
-	.blksize =	1498,
 	.t2 =		1,
 	.t3 =		10,
 	.name =		"loopback",
@@ -254,6 +247,21 @@
 	}, {0}}
 };
 
+static inline __u16 mtu2blksize(struct net_device *dev)
+{
+	u32 blksize = dev->mtu;
+	if (blksize > 0xffff)
+		blksize = 0xffff;
+
+	if (dev->type == ARPHRD_ETHER ||
+	    dev->type == ARPHRD_PPP ||
+	    dev->type == ARPHRD_IPGRE ||
+	    dev->type == ARPHRD_LOOPBACK)
+		blksize -= 2;
+
+	return (__u16)blksize;
+}
+
 static void dn_dev_sysctl_register(struct net_device *dev, struct dn_dev_parms *parms)
 {
 	struct dn_dev_sysctl_table *t;
@@ -858,7 +866,7 @@
         memcpy(msg->tiver, dn_eco_version, 3);
 	dn_dn2eth(msg->id, ifa->ifa_local);
         msg->iinfo   = DN_RT_INFO_ENDN;
-        msg->blksize = dn_htons(dn_db->parms.blksize);
+        msg->blksize = dn_htons(mtu2blksize(dev));
         msg->area    = 0x00;
         memset(msg->seed, 0, 8);
         memcpy(msg->neighbor, dn_hiord, ETH_ALEN);
@@ -920,10 +928,10 @@
 	unsigned short *pktlen;
 	char *src;
 
-	if (dn_db->parms.blksize < (26 + 7))
+	if (mtu2blksize(dev) < (26 + 7))
 		return;
 
-	n = dn_db->parms.blksize - 26;
+	n = mtu2blksize(dev) - 26;
 	n /= 7;
 
 	if (n > 32)
@@ -946,7 +954,7 @@
 	ptr += ETH_ALEN;
 	*ptr++ = dn_db->parms.forwarding == 1 ? 
 			DN_RT_INFO_L1RT : DN_RT_INFO_L2RT;
-	*((unsigned short *)ptr) = dn_htons(dn_db->parms.blksize);
+	*((unsigned short *)ptr) = dn_htons(mtu2blksize(dev));
 	ptr += 2;
 	*ptr++ = dn_db->parms.priority; /* Priority */ 
 	*ptr++ = 0; /* Area: Reserved */
@@ -990,16 +998,13 @@
 		dn_send_router_hello(dev, ifa);
 }
 
-#if 0
 static void dn_send_ptp_hello(struct net_device *dev, struct dn_ifaddr *ifa)
 {
 	int tdlen = 16;
 	int size = dev->hard_header_len + 2 + 4 + tdlen;
 	struct sk_buff *skb = dn_alloc_skb(NULL, size, GFP_ATOMIC);
-	struct dn_dev *dn_db = dev->dn_ptr;
 	int i;
 	unsigned char *ptr;
-	struct dn_neigh *dn = (struct dn_neigh *)dn_db->router;
 	char src[ETH_ALEN];
 
 	if (skb == NULL)
@@ -1020,7 +1025,6 @@
 	dn_dn2eth(src, ifa->ifa_local);
 	dn_rt_finish_output(skb, dn_rt_all_rt_mcast, src);
 }
-#endif
 
 static int dn_eth_up(struct net_device *dev)
 {
@@ -1332,6 +1336,63 @@
 
 
 #ifdef CONFIG_PROC_FS
+static inline struct net_device *dn_dev_get_next(struct seq_file *seq, struct net_device *dev)
+{
+	do {
+		dev = dev->next;
+	} while(dev && !dev->dn_ptr);
+
+	return dev;
+}
+
+static struct net_device *dn_dev_get_idx(struct seq_file *seq, loff_t pos)
+{
+	struct net_device *dev;
+
+	dev = dev_base;
+	if (dev && !dev->dn_ptr)
+		dev = dn_dev_get_next(seq, dev);
+	if (pos) {
+		while(dev && (dev = dn_dev_get_next(seq, dev)))
+			--pos;
+	}
+	return dev;
+}
+
+static void *dn_dev_seq_start(struct seq_file *seq, loff_t *pos)
+{
+	if (*pos) {
+		struct net_device *dev;
+		read_lock(&dev_base_lock);
+		dev = dn_dev_get_idx(seq, *pos - 1);
+		if (dev == NULL)
+			read_unlock(&dev_base_lock);
+		return dev;
+	}
+	return (void*)1;
+}
+
+static void *dn_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	struct net_device *dev = v;
+	loff_t one = 1;
+
+	if (v == (void*)1) {
+		dev = dn_dev_seq_start(seq, &one);
+	} else {
+		dev = dn_dev_get_next(seq, dev);
+		if (dev == NULL)
+			read_unlock(&dev_base_lock);
+	}
+	++*pos;
+	return dev;
+}
+
+static void dn_dev_seq_stop(struct seq_file *seq, void *v)
+{
+	if (v && v != (void*)1)
+		read_unlock(&dev_base_lock);
+}
 
 static char *dn_type2asc(char type)
 {
@@ -1347,56 +1408,50 @@
 	return "?";
 }
 
-static int decnet_dev_get_info(char *buffer, char **start, off_t offset, int length)
+static int dn_dev_seq_show(struct seq_file *seq, void *v)
 {
-        struct dn_dev *dn_db;
-	struct net_device *dev;
-        int len = 0;
-        off_t pos = 0;
-        off_t begin = 0;
-	char peer_buf[DN_ASCBUF_LEN];
-	char router_buf[DN_ASCBUF_LEN];
-
+	if (v == (void*)1)
+        	seq_puts(seq, "Name     Flags T1   Timer1 T3   Timer3 BlkSize Pri State DevType    Router Peer\n");
+	else {
+		struct net_device *dev = v;
+		char peer_buf[DN_ASCBUF_LEN];
+		char router_buf[DN_ASCBUF_LEN];
+		struct dn_dev *dn_db = dev->dn_ptr;
 
-        len += sprintf(buffer, "Name     Flags T1   Timer1 T3   Timer3 BlkSize Pri State DevType    Router Peer\n");
-
-	read_lock(&dev_base_lock);
-        for (dev = dev_base; dev; dev = dev->next) {
-		if ((dn_db = (struct dn_dev *)dev->dn_ptr) == NULL)
-			continue;
-
-                len += sprintf(buffer + len, "%-8s %1s     %04u %04u   %04lu %04lu   %04hu    %03d %02x    %-10s %-7s %-7s\n",
+                seq_printf(seq, "%-8s %1s     %04u %04u   %04lu %04lu"
+				"   %04hu    %03d %02x    %-10s %-7s %-7s\n",
                              	dev->name ? dev->name : "???",
                              	dn_type2asc(dn_db->parms.mode),
                              	0, 0,
 				dn_db->t3, dn_db->parms.t3,
-				dn_db->parms.blksize,
+				mtu2blksize(dev),
 				dn_db->parms.priority,
 				dn_db->parms.state, dn_db->parms.name,
 				dn_db->router ? dn_addr2asc(dn_ntohs(*(dn_address *)dn_db->router->primary_key), router_buf) : "",
 				dn_db->peer ? dn_addr2asc(dn_ntohs(*(dn_address *)dn_db->peer->primary_key), peer_buf) : "");
+	}
+	return 0;
+}
 
+static struct seq_operations dn_dev_seq_ops = {
+	.start	= dn_dev_seq_start,
+	.next	= dn_dev_seq_next,
+	.stop	= dn_dev_seq_stop,
+	.show	= dn_dev_seq_show,
+};
 
-                pos = begin + len;
-
-                if (pos < offset) {
-                        len   = 0;
-                        begin = pos;
-                }
-                if (pos > offset + length)
-                        break;
-        }
-
-	read_unlock(&dev_base_lock);
-
-        *start = buffer + (offset - begin);
-        len   -= (offset - begin);
-
-        if (len > length) len = length;
-
-        return(len);
+static int dn_dev_seq_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &dn_dev_seq_ops);
 }
 
+static struct file_operations dn_dev_seq_fops = {
+	.open	 = dn_dev_seq_open,
+	.read	 = seq_read,
+	.llseek	 = seq_lseek,
+	.release = seq_release,
+};
+
 #endif /* CONFIG_PROC_FS */
 
 static struct rtnetlink_link dnet_rtnetlink_table[RTM_MAX-RTM_BASE+1] = 
@@ -1448,9 +1503,7 @@
 
 	rtnetlink_links[PF_DECnet] = dnet_rtnetlink_table;
 
-#ifdef CONFIG_PROC_FS
-	proc_net_create("decnet_dev", 0, decnet_dev_get_info);
-#endif /* CONFIG_PROC_FS */
+	proc_net_fops_create("decnet_dev", S_IRUGO, &dn_dev_seq_fops);
 
 #ifdef CONFIG_SYSCTL
 	{
diff -urN linux-2.5.69-bk1/net/decnet/dn_fib.c linux-2.5.69-bk2/net/decnet/dn_fib.c
--- linux-2.5.69-bk1/net/decnet/dn_fib.c	2003-05-04 16:53:57.000000000 -0700
+++ linux-2.5.69-bk2/net/decnet/dn_fib.c	2003-05-07 04:41:17.000000000 -0700
@@ -67,18 +67,18 @@
 	int error;
 	u8 scope;
 } dn_fib_props[RTA_MAX+1] = {
-	{ .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 */
+	[RTN_UNSPEC] =      { .error = 0,       .scope = RT_SCOPE_NOWHERE },
+	[RTN_UNICAST] =     { .error = 0,       .scope = RT_SCOPE_UNIVERSE },
+	[RTN_LOCAL] =       { .error = 0,       .scope = RT_SCOPE_HOST },
+	[RTN_BROADCAST] =   { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },
+	[RTN_ANYCAST] =     { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },
+	[RTN_MULTICAST] =   { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },
+	[RTN_BLACKHOLE] =   { .error = -EINVAL, .scope = RT_SCOPE_UNIVERSE },
+	[RTN_UNREACHABLE] = { .error = -EHOSTUNREACH, .scope = RT_SCOPE_UNIVERSE },
+	[RTN_PROHIBIT] =    { .error = -EACCES, .scope = RT_SCOPE_UNIVERSE },
+	[RTN_THROW] =       { .error = -EAGAIN, .scope = RT_SCOPE_UNIVERSE },
+	[RTN_NAT] =         { .error = 0,       .scope = RT_SCOPE_NOWHERE },
+	[RTN_XRESOLVE] =    { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },
 };
 
 void dn_fib_free_info(struct dn_fib_info *fi)
@@ -792,53 +792,12 @@
                 dn_rt_cache_flush(-1);
 }
 
-#ifdef CONFIG_PROC_FS
-
-static int decnet_rt_get_info(char *buffer, char **start, off_t offset, int length)
-{
-        int first = offset / 128;
-        char *ptr = buffer;
-        int count = (length + 127) / 128;
-        int len;
-        int i;
-        struct dn_fib_table *tb;
-
-        *start = buffer + (offset % 128);
-
-        if (--first < 0) {
-                sprintf(buffer, "%-127s\n", "Iface\tDest\tGW  \tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU\tWindow\tIRTT");
-                --count;
-                ptr += 128;
-                first = 0;
-        }
-
-
-        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;
-                        ptr += n * 128;
-                }
-        }
-
-        len = ptr - *start;
-        if (len >= length)
-                return length;
-        if (len >= 0)
-                return len;
-
-        return 0;
-}
-#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();
 
@@ -849,10 +808,6 @@
 void __init dn_fib_init(void)
 {
 
-#ifdef CONFIG_PROC_FS
-	proc_net_create("decnet_route", 0, decnet_rt_get_info);
-#endif
-
 	dn_fib_table_init();
 	dn_fib_rules_init();
 
diff -urN linux-2.5.69-bk1/net/decnet/dn_neigh.c linux-2.5.69-bk2/net/decnet/dn_neigh.c
--- linux-2.5.69-bk1/net/decnet/dn_neigh.c	2003-05-04 16:53:35.000000000 -0700
+++ linux-2.5.69-bk2/net/decnet/dn_neigh.c	2003-05-07 04:41:17.000000000 -0700
@@ -202,7 +202,7 @@
 	struct net_device *dev = neigh->dev;
 	char mac_addr[ETH_ALEN];
 
-	dn_dn2eth(mac_addr, rt->rt_saddr);
+	dn_dn2eth(mac_addr, rt->rt_local_src);
 	if (!dev->hard_header || dev->hard_header(skb, dev, ntohs(skb->protocol), neigh->ha, mac_addr, skb->len) >= 0)
 		return neigh->ops->queue_xmit(skb);
 
@@ -692,48 +692,23 @@
 	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,
+	.release	= seq_release_private,
 };
 
-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);
-
-	dn_neigh_proc_init();
+	proc_net_fops_create("decnet_neigh", S_IRUGO, &dn_neigh_seq_fops);
 }
 
 void __exit dn_neigh_cleanup(void)
 {
+	proc_net_remove("decnet_neigh");
 	neigh_table_clear(&dn_neigh_table);
 }
diff -urN linux-2.5.69-bk1/net/decnet/dn_nsp_in.c linux-2.5.69-bk2/net/decnet/dn_nsp_in.c
--- linux-2.5.69-bk1/net/decnet/dn_nsp_in.c	2003-05-04 16:53:09.000000000 -0700
+++ linux-2.5.69-bk2/net/decnet/dn_nsp_in.c	2003-05-07 04:41:17.000000000 -0700
@@ -28,6 +28,7 @@
  *    Steve Whitehouse:  Added backlog congestion level return codes.
  *   Patrick Caulfield:
  *    Steve Whitehouse:  Added flow control support (outbound)
+ *    Steve Whitehouse:  Prepare for nonlinear skbs
  */
 
 /******************************************************************************
@@ -240,7 +241,7 @@
 	cb->info     = msg->info;
 	cb->segsize  = dn_ntohs(msg->segsize);
 
-	if (skb->len < sizeof(*msg))
+	if (!pskb_may_pull(skb, sizeof(*msg)))
 		goto err_out;
 
 	skb_pull(skb, sizeof(*msg));
@@ -721,34 +722,19 @@
 	unsigned char *ptr = (unsigned char *)skb->data;
 	unsigned short reason = NSP_REASON_NL;
 
+	if (!pskb_may_pull(skb, 2))
+		goto free_out;
+
 	skb->h.raw    = skb->data;
 	cb->nsp_flags = *ptr++;
 
 	if (decnet_debug_level & 2)
 		printk(KERN_DEBUG "dn_nsp_rx: Message type 0x%02x\n", (int)cb->nsp_flags);
 
-	if (skb->len < 2) 
-		goto free_out;
-
 	if (cb->nsp_flags & 0x83) 
 		goto free_out;
 
 	/*
-	 * Returned packets...
-	 * Swap src & dst and look up in the normal way.
-	 */
-	if (cb->rt_flags & DN_RT_F_RTS) {
-		unsigned short tmp = cb->dst_port;
-		cb->dst_port = cb->src_port;
-		cb->src_port = tmp;
-		tmp = cb->dst;
-		cb->dst = cb->src;
-		cb->src = tmp;
-		sk = dn_find_by_skb(skb);
-		goto got_it;
-	}
-
-	/*
 	 * Filter out conninits and useless packet types
 	 */
 	if ((cb->nsp_flags & 0x0c) == 0x08) {
@@ -759,12 +745,14 @@
 				goto free_out;
 			case 0x10:
 			case 0x60:
+				if (unlikely(cb->rt_flags & DN_RT_F_RTS))
+					goto free_out;
 				sk = dn_find_listener(skb, &reason);
 				goto got_it;
 		}
 	}
 
-	if (skb->len < 3)
+	if (!pskb_may_pull(skb, 3))
 		goto free_out;
 
 	/*
@@ -777,13 +765,26 @@
 	/*
 	 * If not a connack, grab the source address too.
 	 */
-	if (skb->len >= 5) {
+	if (pskb_may_pull(skb, 5)) {
 		cb->src_port = *(unsigned short *)ptr;
 		ptr += 2;
 		skb_pull(skb, 5);
 	}
 
 	/*
+	 * Returned packets...
+	 * Swap src & dst and look up in the normal way.
+	 */
+	if (unlikely(cb->rt_flags & DN_RT_F_RTS)) {
+		unsigned short tmp = cb->dst_port;
+		cb->dst_port = cb->src_port;
+		cb->src_port = tmp;
+		tmp = cb->dst;
+		cb->dst = cb->src;
+		cb->src = tmp;
+	}
+
+	/*
 	 * Find the socket to which this skb is destined.
 	 */
 	sk = dn_find_by_skb(skb);
@@ -795,6 +796,15 @@
 		/* Reset backoff */
 		scp->nsp_rxtshift = 0;
 
+		/*
+		 * We linearize everything except data segments here.
+		 */
+		if (cb->nsp_flags & ~0x60) {
+			if (unlikely(skb_is_nonlinear(skb)) &&
+			    skb_linearize(skb, GFP_ATOMIC) != 0)
+				goto free_out;
+		}
+
 		bh_lock_sock(sk);
 		ret = NET_RX_SUCCESS;
 		if (decnet_debug_level & 8)
@@ -835,7 +845,10 @@
 	struct dn_skb_cb *cb = DN_SKB_CB(skb);
 
 	if (cb->rt_flags & DN_RT_F_RTS) {
-		dn_returned_conn_init(sk, skb);
+		if (cb->nsp_flags == 0x18 || cb->nsp_flags == 0x68)
+			dn_returned_conn_init(sk, skb);
+		else
+			kfree_skb(skb);
 		return NET_RX_SUCCESS;
 	}
 
diff -urN linux-2.5.69-bk1/net/decnet/dn_nsp_out.c linux-2.5.69-bk2/net/decnet/dn_nsp_out.c
--- linux-2.5.69-bk1/net/decnet/dn_nsp_out.c	2003-05-04 16:53:55.000000000 -0700
+++ linux-2.5.69-bk2/net/decnet/dn_nsp_out.c	2003-05-07 04:41:17.000000000 -0700
@@ -96,6 +96,7 @@
 	fl.fld_src = dn_saddr2dn(&scp->addr);
 	fl.fld_dst = dn_saddr2dn(&scp->peer);
 	dn_sk_ports_copy(&fl, scp);
+	fl.proto = DNPROTO_NSP;
 	if (dn_route_output_sock(&sk->dst_cache, &fl, sk, 0) == 0) {
 		dst = sk_dst_get(sk);
 		sk->route_caps = dst->dev->features;
@@ -349,8 +350,7 @@
 {
 	unsigned char *ptr = skb_push(skb, len);
 
-	if (len < 5)
-		BUG();
+	BUG_ON(len < 5);
 
 	*ptr++ = msgflag;
 	*((unsigned short *)ptr) = scp->addrrem;
@@ -367,8 +367,7 @@
 	unsigned short ackcrs = scp->numoth_rcv & 0x0FFF;
 	unsigned short *ptr;
 
-	if (hlen < 9)
-		BUG();
+	BUG_ON(hlen < 9);
 
 	scp->ackxmt_dat = acknum;
 	scp->ackxmt_oth = ackcrs;
@@ -485,8 +484,8 @@
 		 * We don't expect to see acknowledgements for packets we
 		 * haven't sent yet.
 		 */
-		if (xmit_count == 0)
-			BUG();
+		WARN_ON(xmit_count == 0);
+
 		/*
 		 * If the packet has only been sent once, we can use it
 		 * to calculate the RTT and also open the window a little
diff -urN linux-2.5.69-bk1/net/decnet/dn_route.c linux-2.5.69-bk2/net/decnet/dn_route.c
--- linux-2.5.69-bk1/net/decnet/dn_route.c	2003-05-04 16:53:42.000000000 -0700
+++ linux-2.5.69-bk2/net/decnet/dn_route.c	2003-05-07 04:41:17.000000000 -0700
@@ -39,6 +39,7 @@
  *                                 no ref count on net devices.
  *              Steve Whitehouse : RCU for the route cache
  *              Steve Whitehouse : Preparations for the flow cache
+ *              Steve Whitehouse : Prepare for nonlinear skbs
  */
 
 /******************************************************************************
@@ -70,6 +71,7 @@
 #include <net/sock.h>
 #include <linux/mm.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <linux/init.h>
 #include <linux/rtnetlink.h>
 #include <linux/string.h>
@@ -97,14 +99,17 @@
 
 static unsigned char dn_hiord_addr[6] = {0xAA,0x00,0x04,0x00,0x00,0x00};
 
-int dn_rt_min_delay = 2*HZ;
-int dn_rt_max_delay = 10*HZ;
-static unsigned long dn_rt_deadline = 0;
+int dn_rt_min_delay = 2 * HZ;
+int dn_rt_max_delay = 10 * HZ;
+int dn_rt_mtu_expires = 10 * 60 * HZ;
+
+static unsigned long dn_rt_deadline;
 
 static int dn_dst_gc(void);
 static struct dst_entry *dn_dst_check(struct dst_entry *, __u32);
 static struct dst_entry *dn_dst_negative_advice(struct dst_entry *);
 static void dn_dst_link_failure(struct sk_buff *);
+static void dn_dst_update_pmtu(struct dst_entry *dst, u32 mtu);
 static int dn_route_input(struct sk_buff *);
 static void dn_run_flush(unsigned long dummy);
 
@@ -124,6 +129,7 @@
 	.check =		dn_dst_check,
 	.negative_advice =	dn_dst_negative_advice,
 	.link_failure =		dn_dst_link_failure,
+	.update_pmtu =		dn_dst_update_pmtu,
 	.entry_size =		sizeof(struct dn_route),
 	.entries =		ATOMIC_INIT(0),
 };
@@ -210,16 +216,49 @@
 	return 0;
 }
 
+/*
+ * The decnet standards don't impose a particular minimum mtu, what they
+ * do insist on is that the routing layer accepts a datagram of at least
+ * 230 bytes long. Here we have to subtract the routing header length from
+ * 230 to get the minimum acceptable mtu. If there is no neighbour, then we
+ * assume the worst and use a long header size.
+ *
+ * We update both the mtu and the advertised mss (i.e. the segment size we
+ * advertise to the other end).
+ */
+static void dn_dst_update_pmtu(struct dst_entry *dst, u32 mtu)
+{
+	u32 min_mtu = 230;
+	struct dn_dev *dn = dst->neighbour ?
+			    (struct dn_dev *)dst->neighbour->dev->dn_ptr : NULL;
+
+	if (dn && dn->use_long == 0)
+		min_mtu -= 6;
+	else
+		min_mtu -= 21;
+
+	if (dst->metrics[RTAX_MTU-1] > mtu && mtu >= min_mtu) {
+		if (!(dst_metric_locked(dst, RTAX_MTU))) {
+			dst->metrics[RTAX_MTU-1] = mtu;
+			dst_set_expires(dst, dn_rt_mtu_expires);
+		}
+		if (!(dst_metric_locked(dst, RTAX_ADVMSS))) {
+			u32 mss = mtu - DN_MAX_NSP_DATA_HEADER;
+			if (dst->metrics[RTAX_ADVMSS-1] > mss)
+				dst->metrics[RTAX_ADVMSS-1] = mss;
+		}
+	}
+}
+
+/* 
+ * When a route has been marked obsolete. (e.g. routing cache flush)
+ */
 static struct dst_entry *dn_dst_check(struct dst_entry *dst, __u32 cookie)
 {
 	dst_release(dst);
 	return NULL;
 }
 
-/*
- * This is called through sendmsg() when you specify MSG_TRYHARD
- * and there is already a route in cache.
- */
 static struct dst_entry *dn_dst_negative_advice(struct dst_entry *dst)
 {
 	dst_release(dst);
@@ -467,7 +506,7 @@
 	struct dn_skb_cb *cb = DN_SKB_CB(skb);
 	unsigned char *ptr = skb->data;
 
-	if (skb->len < 21) /* 20 for long header, 1 for shortest nsp */
+	if (!pskb_may_pull(skb, 21)) /* 20 for long header, 1 for shortest nsp */
 		goto drop_it;
 
 	skb_pull(skb, 20);
@@ -505,7 +544,7 @@
 	struct dn_skb_cb *cb = DN_SKB_CB(skb);
 	unsigned char *ptr = skb->data;
 
-	if (skb->len < 6) /* 5 for short header + 1 for shortest nsp */
+	if (!pskb_may_pull(skb, 6)) /* 5 for short header + 1 for shortest nsp */
 		goto drop_it;
 
 	skb_pull(skb, 5);
@@ -555,6 +594,9 @@
 	if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
 		goto out;
 
+	if (!pskb_may_pull(skb, 3))
+		goto dump_it;
+
 	skb_pull(skb, 2);
 
 	if (len > skb->len)
@@ -573,6 +615,8 @@
 	 */
 	if (flags & DN_RT_F_PF) {
 		padlen = flags & ~DN_RT_F_PF;
+		if (!pskb_may_pull(skb, padlen + 1))
+			goto dump_it;
 		skb_pull(skb, padlen);
 		flags = *skb->data;
 	}
@@ -594,6 +638,10 @@
 			padlen);
 
         if (flags & DN_RT_PKT_CNTL) {
+		if (unlikely(skb_is_nonlinear(skb)) &&
+		    skb_linearize(skb, GFP_ATOMIC) != 0)
+			goto dump_it;
+
                 switch(flags & DN_RT_CNTL_MSK) {
         	        case DN_RT_PKT_INIT:
 				dn_dev_init_pkt(skb);
@@ -712,7 +760,7 @@
 	 * packets, so we don't need to test for them here.
 	 */
 	cb->rt_flags &= ~DN_RT_F_IE;
-	if (rt->rt_flags | RTCF_DOREDIRECT)
+	if (rt->rt_flags & RTCF_DOREDIRECT)
 		cb->rt_flags |= DN_RT_F_IE;
 
 	return NF_HOOK(PF_DECnet, NF_DN_FORWARD, skb, dev, skb->dev, neigh->output);
@@ -788,8 +836,10 @@
 {
 	__u16 tmp = dn_ntohs(addr1) ^ dn_ntohs(addr2);
 	int match = 16;
-	while(tmp)
-		tmp >>= 1, match--;
+	while(tmp) {
+		tmp >>= 1;
+		match--;
+	}
 	return match;
 }
 
@@ -899,17 +949,19 @@
 	/* 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);
+		if (!fl.fld_dst) {
+			fl.fld_dst =
+			fl.fld_src = dnet_select_source(dev_out, 0,
+						       RT_SCOPE_HOST);
+			if (!fl.fld_dst)
+				goto out;
+		}
 		fl.oif = loopback_dev.ifindex;
 		res.type = RTN_LOCAL;
 		goto make_route;
@@ -1061,6 +1113,7 @@
 	rt->rt_saddr      = fl.fld_src;
 	rt->rt_daddr      = fl.fld_dst;
 	rt->rt_gateway    = gateway ? gateway : fl.fld_dst;
+	rt->rt_local_src  = fl.fld_src;
 
 	rt->rt_dst_map    = fl.fld_dst;
 	rt->rt_src_map    = fl.fld_src;
@@ -1075,14 +1128,14 @@
 	rt->u.dst.input   = dn_rt_bug;
 	rt->rt_flags      = flags;
 	if (flags & RTCF_LOCAL)
-		rt->u.dst.output = dn_nsp_rx;
+		rt->u.dst.input = dn_nsp_rx;
 
-	if (dn_rt_set_next_hop(rt, &res))
+	err = dn_rt_set_next_hop(rt, &res);
+	if (err)
 		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;
 
 done:
 	if (neigh)
@@ -1175,6 +1228,7 @@
 	unsigned hash;
 	int flags = 0;
 	__u16 gateway = 0;
+	__u16 local_src = 0;
 	struct flowi fl = { .nl_u = { .dn_u = 
 				     { .daddr = cb->dst,
 				       .saddr = cb->src,
@@ -1275,6 +1329,8 @@
 		if (out_dev == in_dev && !(flags & RTCF_NAT))
 			flags |= RTCF_DOREDIRECT;
 
+		local_src = DN_FIB_RES_PREFSRC(res);
+
 	case RTN_BLACKHOLE:
 	case RTN_UNREACHABLE:
 		break;
@@ -1319,6 +1375,8 @@
 	rt->rt_gateway    = fl.fld_dst;
 	if (gateway)
 		rt->rt_gateway = gateway;
+	rt->rt_local_src  = local_src ? local_src : rt->rt_saddr;
+
 	rt->rt_dst_map    = fl.fld_dst;
 	rt->rt_src_map    = fl.fld_src;
 
@@ -1352,12 +1410,12 @@
 	if (rt->u.dst.dev)
 		dev_hold(rt->u.dst.dev);
 
-	if (dn_rt_set_next_hop(rt, &res))
+	err = dn_rt_set_next_hop(rt, &res);
+	if (err)
 		goto e_neighbour;
 
 	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)
@@ -1449,7 +1507,7 @@
 	 * they deal only with inputs and not with replies like they do
 	 * currently.
 	 */
-	RTA_PUT(skb, RTA_PREFSRC, 2, &rt->rt_saddr);
+	RTA_PUT(skb, RTA_PREFSRC, 2, &rt->rt_local_src);
 	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)
@@ -1490,6 +1548,7 @@
 	struct flowi fl;
 
 	memset(&fl, 0, sizeof(fl));
+	fl.proto = DNPROTO_NSP;
 
 	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
 	if (skb == NULL)
@@ -1609,54 +1668,114 @@
 }
 
 #ifdef CONFIG_PROC_FS
+struct dn_rt_cache_iter_state {
+	int bucket;
+};
 
-static int decnet_cache_get_info(char *buffer, char **start, off_t offset, int length)
+static struct dn_route *dn_rt_cache_get_first(struct seq_file *seq)
 {
-        int len = 0;
-        off_t pos = 0;
-        off_t begin = 0;
-	struct dn_route *rt;
-	int i;
-	char buf1[DN_ASCBUF_LEN], buf2[DN_ASCBUF_LEN];
+	struct dn_route *rt = NULL;
+	struct dn_rt_cache_iter_state *s = seq->private;
 
-	for(i = 0; i <= dn_rt_hash_mask; i++) {
+	for(s->bucket = dn_rt_hash_mask; s->bucket >= 0; --s->bucket) {
 		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),
-					dn_addr2asc(dn_ntohs(rt->rt_saddr), buf2),
-					atomic_read(&rt->u.dst.__refcnt),
-					rt->u.dst.__use,
-					(int) dst_metric(&rt->u.dst, RTAX_RTT)
-					);
-
+		rt = dn_rt_hash_table[s->bucket].chain;
+		if (rt)
+			break;
+		rcu_read_unlock();
+	}
+	return rt;
+}
 
+static struct dn_route *dn_rt_cache_get_next(struct seq_file *seq, struct dn_route *rt)
+{
+	struct dn_rt_cache_iter_state *s = seq->private;
 
-	                pos = begin + len;
-	
-        	        if (pos < offset) {
-                	        len   = 0;
-                        	begin = pos;
-                	}
-              		if (pos > offset + length)
-                	        break;
-		}
+	smp_read_barrier_depends();
+	rt = rt->u.rt_next;
+	while(!rt) {
 		rcu_read_unlock();
-		if (pos > offset + length)
+		if (--s->bucket < 0)
 			break;
+		rcu_read_lock();
+		rt = dn_rt_hash_table[s->bucket].chain;
 	}
+	return rt;
+}
+
+static void *dn_rt_cache_seq_start(struct seq_file *seq, loff_t *pos)
+{
+	struct dn_route *rt = dn_rt_cache_get_first(seq);
+
+	if (rt) {
+		while(*pos && (rt = dn_rt_cache_get_next(seq, rt)))
+			--*pos;
+	}
+	return *pos ? NULL : rt;
+}
+
+static void *dn_rt_cache_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	struct dn_route *rt = dn_rt_cache_get_next(seq, v);
+	++*pos;
+	return rt;
+}
 
-        *start = buffer + (offset - begin);
-        len   -= (offset - begin);
+static void dn_rt_cache_seq_stop(struct seq_file *seq, void *v)
+{
+	rcu_read_unlock();
+}
 
-        if (len > length) len = length;
+static int dn_rt_cache_seq_show(struct seq_file *seq, void *v)
+{
+	struct dn_route *rt = v;
+	char buf1[DN_ASCBUF_LEN], buf2[DN_ASCBUF_LEN];
 
-        return(len);
+	seq_printf(seq, "%-8s %-7s %-7s %04d %04d %04d\n",
+			rt->u.dst.dev ? rt->u.dst.dev->name : "*",
+			dn_addr2asc(dn_ntohs(rt->rt_daddr), buf1),
+			dn_addr2asc(dn_ntohs(rt->rt_saddr), buf2),
+			atomic_read(&rt->u.dst.__refcnt),
+			rt->u.dst.__use,
+			(int) dst_metric(&rt->u.dst, RTAX_RTT));
+	return 0;
 } 
 
+static struct seq_operations dn_rt_cache_seq_ops = {
+	.start	= dn_rt_cache_seq_start,
+	.next	= dn_rt_cache_seq_next,
+	.stop	= dn_rt_cache_seq_stop,
+	.show	= dn_rt_cache_seq_show,
+};
+
+static int dn_rt_cache_seq_open(struct inode *inode, struct file *file)
+{
+	struct seq_file *seq;
+	int rc = -ENOMEM;
+	struct dn_rt_cache_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
+
+	if (!s)
+		goto out;
+	rc = seq_open(file, &dn_rt_cache_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 struct file_operations dn_rt_cache_seq_fops = {
+	.open	 = dn_rt_cache_seq_open,
+	.read	 = seq_read,
+	.llseek	 = seq_lseek,
+	.release = seq_release_private,
+};
+
 #endif /* CONFIG_PROC_FS */
 
 void __init dn_route_init(void)
@@ -1714,9 +1833,7 @@
 
         dn_dst_ops.gc_thresh = (dn_rt_hash_mask + 1);
 
-#ifdef CONFIG_PROC_FS
-	proc_net_create("decnet_cache",0,decnet_cache_get_info);
-#endif /* CONFIG_PROC_FS */
+	proc_net_fops_create("decnet_cache", S_IRUGO, &dn_rt_cache_seq_fops);
 }
 
 void __exit dn_route_cleanup(void)
diff -urN linux-2.5.69-bk1/net/decnet/dn_table.c linux-2.5.69-bk2/net/decnet/dn_table.c
--- linux-2.5.69-bk1/net/decnet/dn_table.c	2003-05-04 16:53:08.000000000 -0700
+++ linux-2.5.69-bk2/net/decnet/dn_table.c	2003-05-07 04:41:17.000000000 -0700
@@ -744,86 +744,6 @@
         return err;
 }
 
-#ifdef CONFIG_PROC_FS
-
-static unsigned dn_fib_flag_trans(int type, int dead, u16 mask, struct dn_fib_info *fi)
-{
-	static unsigned type2flags[RTN_MAX+1] = {
-		0, 0, 0, 0, 0, 0, 0, RTF_REJECT, RTF_REJECT, 0, 0, 0
-	};
-	unsigned flags = type2flags[type];
-
-	if (fi && fi->fib_nh->nh_gw)
-		flags |= RTF_GATEWAY;
-	if (mask == 0xFFFF)
-		flags |= RTF_HOST;
-	if (dead)
-		flags |= RTF_UP;
-	return flags;
-}
-
-static void dn_fib_node_get_info(int type, int dead, struct dn_fib_info *fi, u16 prefix, u16 mask, char *buffer)
-{
-	int len;
-	unsigned flags = dn_fib_flag_trans(type, dead, mask, fi);
-
-	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->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 {
-		len = sprintf(buffer, "*\t%04x\t%04x\t%04x\t%d\t%u\t%d\t%04x\t%d\t%u\t%u",
-					prefix, 0,
-					flags, 0, 0, 0,
-					mask, 0, 0, 0);
-	}
-	memset(buffer+len, ' ', 127-len);
-	buffer[127] = '\n';
-}
-
-static int dn_fib_table_get_info(struct dn_fib_table *tb, char *buffer, int first, int count)
-{
-	struct dn_hash *table = (struct dn_hash *)tb->data;
-	struct dn_zone *dz;
-	int pos = 0;
-	int n = 0;
-
-	read_lock(&dn_fib_tables_lock);
-	for(dz = table->dh_zone_list; dz; dz = dz->dz_next) {
-		int i;
-		struct dn_fib_node *f;
-		int maxslot = dz->dz_divisor;
-		struct dn_fib_node **fp = dz->dz_hash;
-
-		if (dz->dz_nent == 0)
-			continue;
-
-		if (pos + dz->dz_nent < first) {
-			pos += dz->dz_nent;
-			continue;
-		}
-
-		for(i = 0; i < maxslot; i++, fp++) {
-			for(f = *fp; f ; f = f->fn_next) {
-				if (++pos <= first)
-					continue;
-				dn_fib_node_get_info(f->fn_type,
-						f->fn_state & DN_S_ZOMBIE,
-						DN_FIB_INFO(f),
-						dz_prefix(f->fn_key, dz),
-						DZ_MASK(dz), buffer);
-				buffer += 128;
-				if (++n >= count)
-					goto out;
-			}
-		}
-	}
-out:
-	read_unlock(&dn_fib_tables_lock);
-	return n;
-}
-#endif /* CONFIG_PROC_FS */
 
 struct dn_fib_table *dn_fib_get_table(int n, int create)
 {
@@ -855,9 +775,6 @@
         t->delete = dn_fib_table_delete;
         t->lookup = dn_fib_table_lookup;
         t->flush  = dn_fib_table_flush;
-#ifdef CONFIG_PROC_FS
-	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;
diff -urN linux-2.5.69-bk1/net/decnet/netfilter/Kconfig linux-2.5.69-bk2/net/decnet/netfilter/Kconfig
--- linux-2.5.69-bk1/net/decnet/netfilter/Kconfig	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.5.69-bk2/net/decnet/netfilter/Kconfig	2003-05-07 04:41:17.000000000 -0700
@@ -0,0 +1,15 @@
+#
+# DECnet netfilter configuration
+#
+
+menu "DECnet: Netfilter Configuration"
+	depends on DECNET && NETFILTER && EXPERIMENTAL
+
+config DECNET_NF_GRABULATOR
+	tristate "Routing message grabulator (for userland routing daemon)"
+	help
+	  Enable this module if you want to use the userland DECnet routing
+	  daemon. You will also need to enable routing support for DECnet
+	  unless you just want to monitor routing messages from other nodes.
+
+endmenu
diff -urN linux-2.5.69-bk1/net/decnet/netfilter/Makefile linux-2.5.69-bk2/net/decnet/netfilter/Makefile
--- linux-2.5.69-bk1/net/decnet/netfilter/Makefile	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.5.69-bk2/net/decnet/netfilter/Makefile	2003-05-07 04:41:17.000000000 -0700
@@ -0,0 +1,6 @@
+#
+# Makefile for DECnet netfilter modules
+#
+
+obj-$(CONFIG_DECNET_NF_GRABULATOR) += dn_rtmsg.o
+
diff -urN linux-2.5.69-bk1/net/decnet/netfilter/dn_rtmsg.c linux-2.5.69-bk2/net/decnet/netfilter/dn_rtmsg.c
--- linux-2.5.69-bk1/net/decnet/netfilter/dn_rtmsg.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.5.69-bk2/net/decnet/netfilter/dn_rtmsg.c	2003-05-07 04:41:17.000000000 -0700
@@ -0,0 +1,167 @@
+/*
+ * DECnet       An implementation of the DECnet protocol suite for the LINUX
+ *              operating system.  DECnet is implemented using the  BSD Socket
+ *              interface as the means of communication with the user level.
+ *
+ *              DECnet Routing Message Grabulator
+ *
+ *              (C) 2000 ChyGwyn Limited  -  http://www.chygwyn.com/
+ *              This code may be copied under the GPL v.2 or at your option
+ *              any later version.
+ *
+ * Author:      Steven Whitehouse <steve@chygwyn.com>
+ *
+ */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/netfilter.h>
+#include <linux/spinlock.h>
+#include <linux/netlink.h>
+
+#include <net/sock.h>
+#include <net/flow.h>
+#include <net/dn.h>
+#include <net/dn_route.h>
+
+#include <linux/netfilter_decnet.h>
+
+static struct sock *dnrmg = NULL;
+
+
+static struct sk_buff *dnrmg_build_message(struct sk_buff *rt_skb, int *errp)
+{
+	struct sk_buff *skb = NULL;
+	size_t size;
+	unsigned char *old_tail;
+	struct nlmsghdr *nlh;
+	unsigned char *ptr;
+	struct nf_dn_rtmsg *rtm;
+
+	size = NLMSG_SPACE(rt_skb->len);
+	size += NLMSG_ALIGN(sizeof(struct nf_dn_rtmsg));
+	skb = alloc_skb(size, GFP_ATOMIC);
+	if (!skb)
+		goto nlmsg_failure;
+	old_tail = skb->tail;
+	nlh = NLMSG_PUT(skb, 0, 0, 0, size - sizeof(*nlh));
+	rtm = (struct nf_dn_rtmsg *)NLMSG_DATA(nlh);
+	rtm->nfdn_ifindex = rt_skb->dev->ifindex;
+	ptr = NFDN_RTMSG(rtm);
+	memcpy(ptr, rt_skb->data, rt_skb->len);
+	nlh->nlmsg_len = skb->tail - old_tail;
+	return skb;
+
+nlmsg_failure:
+	if (skb)
+		kfree(skb);
+	*errp = -ENOMEM;
+	if (net_ratelimit())
+		printk(KERN_ERR "dn_rtmsg: error creating netlink message\n");
+	return NULL;
+}
+
+static void dnrmg_send_peer(struct sk_buff *skb)
+{
+	struct sk_buff *skb2;
+	int status = 0;
+	int group = 0;
+	unsigned char flags = *skb->data;
+
+	switch(flags & DN_RT_CNTL_MSK) {
+		case DN_RT_PKT_L1RT:
+			group = DNRMG_L1_GROUP;
+			break;
+		case DN_RT_PKT_L2RT:
+			group = DNRMG_L2_GROUP;
+			break;
+		default:
+			return;
+	}
+
+	skb2 = dnrmg_build_message(skb, &status);
+	if (skb2 == NULL)
+		return;
+	NETLINK_CB(skb2).dst_groups = group;
+	netlink_broadcast(dnrmg, skb2, 0, group, GFP_ATOMIC);
+}
+
+
+static unsigned int dnrmg_hook(unsigned int hook,
+			struct sk_buff **pskb,
+			const struct net_device *in,
+			const struct net_device *out,
+			int (*okfn)(struct sk_buff *))
+{
+	dnrmg_send_peer(*pskb);
+	return NF_ACCEPT;
+}
+
+
+#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0)
+
+static inline void dnrmg_receive_user_skb(struct sk_buff *skb)
+{
+	struct nlmsghdr *nlh = (struct nlmsghdr *)skb->data;
+
+	if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)
+		return;
+
+	if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
+		RCV_SKB_FAIL(-EPERM);
+
+	/* Eventually we might send routing messages too */
+
+	RCV_SKB_FAIL(-EINVAL);
+}
+
+static void dnrmg_receive_user_sk(struct sock *sk, int len)
+{
+	struct sk_buff *skb;
+
+	while((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
+		dnrmg_receive_user_skb(skb);
+		kfree_skb(skb);
+	}
+}
+
+static struct nf_hook_ops dnrmg_ops = {
+	.hook		= dnrmg_hook,
+	.pf		= PF_DECnet,
+	.hooknum	= NF_DN_ROUTE,
+	.priority	= NF_DN_PRI_DNRTMSG,
+};
+
+static int __init init(void)
+{
+	int rv = 0;
+
+	dnrmg = netlink_kernel_create(NETLINK_DNRTMSG, dnrmg_receive_user_sk);
+	if (dnrmg == NULL) {
+		printk(KERN_ERR "dn_rtmsg: Cannot create netlink socket");
+		return -ENOMEM;
+	}
+
+	rv = nf_register_hook(&dnrmg_ops);
+	if (rv) {
+		sock_release(dnrmg->socket);
+	}
+
+	return rv;
+}
+
+static void __exit fini(void)
+{
+	nf_unregister_hook(&dnrmg_ops);
+	sock_release(dnrmg->socket);
+}
+
+
+MODULE_DESCRIPTION("DECnet Routing Message Grabulator");
+MODULE_AUTHOR("Steven Whitehouse <steve@chygwyn.com>");
+MODULE_LICENSE("GPL");
+
+module_init(init);
+module_exit(fini);
+
diff -urN linux-2.5.69-bk1/net/ipv4/netfilter/ip_nat_core.c linux-2.5.69-bk2/net/ipv4/netfilter/ip_nat_core.c
--- linux-2.5.69-bk1/net/ipv4/netfilter/ip_nat_core.c	2003-05-04 16:53:02.000000000 -0700
+++ linux-2.5.69-bk2/net/ipv4/netfilter/ip_nat_core.c	2003-05-07 04:41:17.000000000 -0700
@@ -13,6 +13,8 @@
 #include <net/icmp.h>
 #include <net/ip.h>
 #include <net/tcp.h>  /* For tcp_prot in getorigdst */
+#include <linux/icmp.h>
+#include <linux/udp.h>
 
 #define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock)
 #define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock)
@@ -698,14 +700,26 @@
 	list_prepend(&byipsproto[ipsprotohash], &info->byipsproto);
 }
 
-static void
-manip_pkt(u_int16_t proto, struct iphdr *iph, size_t len,
+/* Returns true if succeeded. */
+static int
+manip_pkt(u_int16_t proto,
+	  struct sk_buff **pskb,
+	  unsigned int iphdroff,
 	  const struct ip_conntrack_manip *manip,
-	  enum ip_nat_manip_type maniptype,
-	  __u32 *nfcache)
+	  enum ip_nat_manip_type maniptype)
 {
-	*nfcache |= NFC_ALTERED;
-	find_nat_proto(proto)->manip_pkt(iph, len, manip, maniptype);
+	struct iphdr *iph;
+
+	(*pskb)->nfcache |= NFC_ALTERED;
+	if (!skb_ip_make_writable(pskb, iphdroff+sizeof(iph)))
+		return 0;
+
+	iph = (void *)(*pskb)->data + iphdroff;
+
+	/* Manipulate protcol part. */
+	if (!find_nat_proto(proto)->manip_pkt(pskb, iphdroff + iph->ihl*4,
+					      manip, maniptype))
+		return 0;
 
 	if (maniptype == IP_NAT_MANIP_SRC) {
 		iph->check = ip_nat_cheat_check(~iph->saddr, manip->ip,
@@ -716,17 +730,7 @@
 						iph->check);
 		iph->daddr = manip->ip;
 	}
-#if 0
-	if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)
-		DEBUGP("IP: checksum on packet bad.\n");
-
-	if (proto == IPPROTO_TCP) {
-		void *th = (u_int32_t *)iph + iph->ihl;
-		if (tcp_v4_check(th, len - 4*iph->ihl, iph->saddr, iph->daddr,
-				 csum_partial((char *)th, len-4*iph->ihl, 0)))
-			DEBUGP("TCP: checksum on packet bad\n");
-	}
-#endif
+	return 1;
 }
 
 static inline int exp_for_packet(struct ip_conntrack_expect *exp,
@@ -754,25 +758,13 @@
 	unsigned int i;
 	struct ip_nat_helper *helper;
 	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
-	int is_tcp = (*pskb)->nh.iph->protocol == IPPROTO_TCP;
+	int proto = (*pskb)->nh.iph->protocol;
 
 	/* Need nat lock to protect against modification, but neither
 	   conntrack (referenced) and helper (deleted with
 	   synchronize_bh()) can vanish. */
 	READ_LOCK(&ip_nat_lock);
 	for (i = 0; i < info->num_manips; i++) {
-		/* raw socket (tcpdump) may have clone of incoming
-                   skb: don't disturb it --RR */
-		if (skb_cloned(*pskb) && !(*pskb)->sk) {
-			struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
-			if (!nskb) {
-				READ_UNLOCK(&ip_nat_lock);
-				return NF_DROP;
-			}
-			kfree_skb(*pskb);
-			*pskb = nskb;
-		}
-
 		if (info->manips[i].direction == dir
 		    && info->manips[i].hooknum == hooknum) {
 			DEBUGP("Mangling %p: %s to %u.%u.%u.%u %u\n",
@@ -781,12 +773,12 @@
 			       ? "SRC" : "DST",
 			       NIPQUAD(info->manips[i].manip.ip),
 			       htons(info->manips[i].manip.u.all));
-			manip_pkt((*pskb)->nh.iph->protocol,
-				  (*pskb)->nh.iph,
-				  (*pskb)->len,
-				  &info->manips[i].manip,
-				  info->manips[i].maniptype,
-				  &(*pskb)->nfcache);
+			if (manip_pkt(proto, pskb, 0,
+				      &info->manips[i].manip,
+				      info->manips[i].maniptype) < 0) {
+				READ_UNLOCK(&ip_nat_lock);
+				return NF_DROP;
+			}
 		}
 	}
 	helper = info->helper;
@@ -839,12 +831,14 @@
 		
 		/* Adjust sequence number only once per packet 
 		 * (helper is called at all hooks) */
-		if (is_tcp && (hooknum == NF_IP_POST_ROUTING
-			       || hooknum == NF_IP_LOCAL_IN)) {
+		if (proto == IPPROTO_TCP
+		    && (hooknum == NF_IP_POST_ROUTING
+			|| hooknum == NF_IP_LOCAL_IN)) {
 			DEBUGP("ip_nat_core: adjusting sequence number\n");
 			/* future: put this in a l4-proto specific function,
 			 * and call this function here. */
-			ip_nat_seq_adjust(*pskb, ct, ctinfo);
+			if (!ip_nat_seq_adjust(pskb, ct, ctinfo))
+				ret = NF_DROP;
 		}
 
 		return ret;
@@ -855,39 +849,51 @@
 	/* not reached */
 }
 
-unsigned int
-icmp_reply_translation(struct sk_buff *skb,
+int
+icmp_reply_translation(struct sk_buff **pskb,
 		       struct ip_conntrack *conntrack,
 		       unsigned int hooknum,
 		       int dir)
 {
-	struct iphdr *iph = skb->nh.iph;
-	struct icmphdr *hdr = (struct icmphdr *)((u_int32_t *)iph + iph->ihl);
-	struct iphdr *inner = (struct iphdr *)(hdr + 1);
-	size_t datalen = skb->len - ((void *)inner - (void *)iph);
+	struct {
+		struct icmphdr icmp;
+		struct iphdr ip;
+	} *inside;
 	unsigned int i;
 	struct ip_nat_info *info = &conntrack->nat.info;
 
-	IP_NF_ASSERT(skb->len >= iph->ihl*4 + sizeof(struct icmphdr));
+	if (!skb_ip_make_writable(pskb,(*pskb)->nh.iph->ihl*4+sizeof(*inside)))
+		return 0;
+	inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4;
+
+	/* We're actually going to mangle it beyond trivial checksum
+	   adjustment, so make sure the current checksum is correct. */
+	if ((*pskb)->ip_summed != CHECKSUM_UNNECESSARY
+	    && (u16)csum_fold(skb_checksum(*pskb, (*pskb)->nh.iph->ihl*4,
+					   (*pskb)->len, 0)))
+		return 0;
+
 	/* Must be RELATED */
-	IP_NF_ASSERT(skb->nfct - (struct ip_conntrack *)skb->nfct->master
+	IP_NF_ASSERT((*pskb)->nfct
+		     - (struct ip_conntrack *)(*pskb)->nfct->master
 		     == IP_CT_RELATED
-		     || skb->nfct - (struct ip_conntrack *)skb->nfct->master
+		     || (*pskb)->nfct
+		     - (struct ip_conntrack *)(*pskb)->nfct->master
 		     == IP_CT_RELATED+IP_CT_IS_REPLY);
 
 	/* Redirects on non-null nats must be dropped, else they'll
            start talking to each other without our translation, and be
            confused... --RR */
-	if (hdr->type == ICMP_REDIRECT) {
+	if (inside->icmp.type == ICMP_REDIRECT) {
 		/* Don't care about races here. */
 		if (info->initialized
 		    != ((1 << IP_NAT_MANIP_SRC) | (1 << IP_NAT_MANIP_DST))
 		    || info->num_manips != 0)
-			return NF_DROP;
+			return 0;
 	}
 
 	DEBUGP("icmp_reply_translation: translating error %p hook %u dir %s\n",
-	       skb, hooknum, dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY");
+	       *pskb, hooknum, dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY");
 	/* Note: May not be from a NAT'd host, but probably safest to
 	   do translation always as if it came from the host itself
 	   (even though a "host unreachable" coming from the host
@@ -918,11 +924,13 @@
 			       ? "DST" : "SRC",
 			       NIPQUAD(info->manips[i].manip.ip),
 			       ntohs(info->manips[i].manip.u.udp.port));
-			manip_pkt(inner->protocol, inner,
-				  skb->len - ((void *)inner - (void *)iph),
-				  &info->manips[i].manip,
-				  !info->manips[i].maniptype,
-				  &skb->nfcache);
+			if (manip_pkt(inside->ip.protocol, pskb,
+				      (*pskb)->nh.iph->ihl*4
+				      + sizeof(inside->icmp),
+				      &info->manips[i].manip,
+				      !info->manips[i].maniptype) < 0)
+				goto unlock_fail;
+
 			/* Outer packet needs to have IP header NATed like
 	                   it's a reply. */
 
@@ -932,22 +940,82 @@
 			       info->manips[i].maniptype == IP_NAT_MANIP_SRC
 			       ? "SRC" : "DST",
 			       NIPQUAD(info->manips[i].manip.ip));
-			manip_pkt(0, iph, skb->len,
-				  &info->manips[i].manip,
-				  info->manips[i].maniptype,
-				  &skb->nfcache);
+			if (manip_pkt(0, pskb, 0,
+				      &info->manips[i].manip,
+				      info->manips[i].maniptype) < 0)
+				goto unlock_fail;
 		}
 	}
 	READ_UNLOCK(&ip_nat_lock);
 
-	/* Since we mangled inside ICMP packet, recalculate its
-	   checksum from scratch.  (Hence the handling of incorrect
-	   checksums in conntrack, so we don't accidentally fix one.)  */
-	hdr->checksum = 0;
-	hdr->checksum = ip_compute_csum((unsigned char *)hdr,
-					sizeof(*hdr) + datalen);
+	inside->icmp.checksum = 0;
+	inside->icmp.checksum = csum_fold(skb_checksum(*pskb,
+						       (*pskb)->nh.iph->ihl*4,
+						       (*pskb)->len, 0));
+	return 1;
 
-	return NF_ACCEPT;
+ unlock_fail:
+	READ_UNLOCK(&ip_nat_lock);
+	return 0;
+}
+
+int skb_ip_make_writable(struct sk_buff **pskb, unsigned int writable_len)
+{
+	struct sk_buff *nskb;
+	unsigned int iplen;
+
+	if (writable_len > (*pskb)->len)
+		return 0;
+
+	/* Not exclusive use of packet?  Must copy. */
+	if (skb_shared(*pskb) || skb_cloned(*pskb))
+		goto copy_skb;
+
+	/* Alexey says IP hdr is always modifiable and linear, so ok. */
+	if (writable_len <= (*pskb)->nh.iph->ihl*4)
+		return 1;
+
+	iplen = writable_len - (*pskb)->nh.iph->ihl*4;
+
+	/* DaveM says protocol headers are also modifiable. */
+	switch ((*pskb)->nh.iph->protocol) {
+	case IPPROTO_TCP: {
+		struct tcphdr hdr;
+		if (skb_copy_bits(*pskb, (*pskb)->nh.iph->ihl*4,
+				  &hdr, sizeof(hdr)) != 0)
+			goto copy_skb;
+		if (writable_len <= (*pskb)->nh.iph->ihl*4 + hdr.doff*4)
+			goto pull_skb;
+		goto copy_skb;
+	}
+	case IPPROTO_UDP:
+		if (writable_len<=(*pskb)->nh.iph->ihl*4+sizeof(struct udphdr))
+			goto pull_skb;
+		goto copy_skb;
+	case IPPROTO_ICMP:
+		if (writable_len
+		    <= (*pskb)->nh.iph->ihl*4 + sizeof(struct icmphdr))
+			goto pull_skb;
+		goto copy_skb;
+	/* Insert other cases here as desired */
+	}
+
+copy_skb:
+	nskb = skb_copy(*pskb, GFP_ATOMIC);
+	if (!nskb)
+		return 0;
+	BUG_ON(skb_is_nonlinear(nskb));
+
+	/* Rest of kernel will get very unhappy if we pass it a
+	   suddenly-orphaned skbuff */
+	if ((*pskb)->sk)
+		skb_set_owner_w(nskb, (*pskb)->sk);
+	kfree_skb(*pskb);
+	*pskb = nskb;
+	return 1;
+
+pull_skb:
+	return pskb_may_pull(*pskb, writable_len);
 }
 
 int __init ip_nat_init(void)
diff -urN linux-2.5.69-bk1/net/ipv4/netfilter/ip_nat_helper.c linux-2.5.69-bk2/net/ipv4/netfilter/ip_nat_helper.c
--- linux-2.5.69-bk1/net/ipv4/netfilter/ip_nat_helper.c	2003-05-04 16:53:02.000000000 -0700
+++ linux-2.5.69-bk2/net/ipv4/netfilter/ip_nat_helper.c	2003-05-07 04:41:17.000000000 -0700
@@ -46,14 +46,14 @@
 #endif
 
 DECLARE_LOCK(ip_nat_seqofs_lock);
-			 
-static inline int 
-ip_nat_resize_packet(struct sk_buff **skb,
-		     struct ip_conntrack *ct, 
-		     enum ip_conntrack_info ctinfo,
-		     int new_size)
+
+/* Setup TCP sequence correction given this change at this sequence */
+static inline void 
+adjust_tcp_sequence(u32 seq,
+		    int sizediff,
+		    struct ip_conntrack *ct, 
+		    enum ip_conntrack_info ctinfo)
 {
-	struct iphdr *iph;
 	int dir;
 	struct ip_nat_seq *this_way, *other_way;
 
@@ -65,52 +65,89 @@
 	this_way = &ct->nat.info.seq[dir];
 	other_way = &ct->nat.info.seq[!dir];
 
-	if (new_size > (*skb)->len + skb_tailroom(*skb)) {
-		struct sk_buff *newskb;
-		newskb = skb_copy_expand(*skb, skb_headroom(*skb),
-					 new_size - (*skb)->len,
-					 GFP_ATOMIC);
-
-		if (!newskb) {
-			printk("ip_nat_resize_packet: oom\n");
-			return 0;
-		} else {
-			kfree_skb(*skb);
-			*skb = newskb;
-		}
+	DEBUGP("ip_nat_resize_packet: Seq_offset before: ");
+	DUMP_OFFSET(this_way);
+
+	LOCK_BH(&ip_nat_seqofs_lock);
+
+	/* SYN adjust. If it's uninitialized, of this is after last
+	 * correction, record it: we don't handle more than one
+	 * adjustment in the window, but do deal with common case of a
+	 * retransmit */
+	if (this_way->offset_before == this_way->offset_after
+	    || before(this_way->correction_pos, seq)) {
+		    this_way->correction_pos = seq;
+		    this_way->offset_before = this_way->offset_after;
+		    this_way->offset_after += sizediff;
 	}
+	UNLOCK_BH(&ip_nat_seqofs_lock);
 
-	iph = (*skb)->nh.iph;
-	if (iph->protocol == IPPROTO_TCP) {
-		struct tcphdr *tcph = (void *)iph + iph->ihl*4;
-
-		DEBUGP("ip_nat_resize_packet: Seq_offset before: ");
-		DUMP_OFFSET(this_way);
-
-		LOCK_BH(&ip_nat_seqofs_lock);
-
-		/* SYN adjust. If it's uninitialized, of this is after last 
-		 * correction, record it: we don't handle more than one 
-		 * adjustment in the window, but do deal with common case of a 
-		 * retransmit */
-		if (this_way->offset_before == this_way->offset_after
-		    || before(this_way->correction_pos, ntohl(tcph->seq))) {
-			this_way->correction_pos = ntohl(tcph->seq);
-			this_way->offset_before = this_way->offset_after;
-			this_way->offset_after = (int32_t)
-				this_way->offset_before + new_size -
-				(*skb)->len;
-		}
+	DEBUGP("ip_nat_resize_packet: Seq_offset after: ");
+	DUMP_OFFSET(this_way);
+}
+
+/* Frobs data inside this packet, which is linear. */
+static void mangle_contents(struct sk_buff *skb,
+			    unsigned int dataoff,
+			    unsigned int match_offset,
+			    unsigned int match_len,
+			    const char *rep_buffer,
+			    unsigned int rep_len)
+{
+	unsigned char *data;
 
-		UNLOCK_BH(&ip_nat_seqofs_lock);
+	BUG_ON(skb_is_nonlinear(skb));
+	data = (unsigned char *)skb->nh.iph + dataoff;
 
-		DEBUGP("ip_nat_resize_packet: Seq_offset after: ");
-		DUMP_OFFSET(this_way);
+	/* move post-replacement */
+	memmove(data + match_offset + rep_len,
+		data + match_offset + match_len,
+		skb->tail - (data + match_offset + match_len));
+
+	/* insert data from buffer */
+	memcpy(data + match_offset, rep_buffer, rep_len);
+
+	/* update skb info */
+	if (rep_len > match_len) {
+		DEBUGP("ip_nat_mangle_packet: Extending packet by "
+			"%u from %u bytes\n", rep_len - match_len,
+		       skb->len);
+		skb_put(skb, rep_len - match_len);
+	} else {
+		DEBUGP("ip_nat_mangle_packet: Shrinking packet from "
+			"%u from %u bytes\n", match_len - rep_len,
+		       skb->len);
+		__skb_trim(skb, skb->len + rep_len - match_len);
 	}
-	
-	return 1;
+
+	/* fix IP hdr checksum information */
+	skb->nh.iph->tot_len = htons(skb->len);
+	ip_send_check(skb->nh.iph);
+	skb->csum = csum_partial(data, skb->len - dataoff, 0);
 }
 
+/* Unusual, but possible case. */
+static int enlarge_skb(struct sk_buff **pskb, unsigned int extra)
+{
+	struct sk_buff *nskb;
+
+	if ((*pskb)->len + extra > 65535)
+		return 0;
+
+	nskb = skb_copy_expand(*pskb, skb_headroom(*pskb), extra, GFP_ATOMIC);
+	if (!nskb)
+		return 0;
+
+	/* Transfer socket to new skb. */
+	if ((*pskb)->sk)
+		skb_set_owner_w(nskb, (*pskb)->sk);
+#ifdef CONFIG_NETFILTER_DEBUG
+	nskb->nf_debug = (*pskb)->nf_debug;
+#endif
+	kfree_skb(*pskb);
+	*pskb = nskb;
+	return 1;
+}
 
 /* Generic function for mangling variable-length address changes inside
  * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX
@@ -121,91 +158,41 @@
  *
  * */
 int 
-ip_nat_mangle_tcp_packet(struct sk_buff **skb,
+ip_nat_mangle_tcp_packet(struct sk_buff **pskb,
 			 struct ip_conntrack *ct,
 			 enum ip_conntrack_info ctinfo,
 			 unsigned int match_offset,
 			 unsigned int match_len,
-			 char *rep_buffer,
+			 const char *rep_buffer,
 			 unsigned int rep_len)
 {
-	struct iphdr *iph = (*skb)->nh.iph;
+	struct iphdr *iph;
 	struct tcphdr *tcph;
-	unsigned char *data;
-	u_int32_t tcplen, newlen, newtcplen;
 
-	tcplen = (*skb)->len - iph->ihl*4;
-	newtcplen = tcplen - match_len + rep_len;
-	newlen = iph->ihl*4 + newtcplen;
-
-	if (newlen > 65535) {
-		if (net_ratelimit())
-			printk("ip_nat_mangle_tcp_packet: nat'ed packet "
-				"exceeds maximum packet size\n");
+	if (!skb_ip_make_writable(pskb, (*pskb)->len))
 		return 0;
-	}
 
-	if ((*skb)->len != newlen) {
-		if (!ip_nat_resize_packet(skb, ct, ctinfo, newlen)) {
-			printk("resize_packet failed!!\n");
-			return 0;
-		}
-	}
+	if (rep_len > match_len
+	    && rep_len - match_len > skb_tailroom(*pskb)
+	    && !enlarge_skb(pskb, rep_len - match_len))
+		return 0;
 
-	/* Alexey says: if a hook changes _data_ ... it can break
-	   original packet sitting in tcp queue and this is fatal */
-	if (skb_cloned(*skb)) {
-		struct sk_buff *nskb = skb_copy(*skb, GFP_ATOMIC);
-		if (!nskb) {
-			if (net_ratelimit())
-				printk("Out of memory cloning TCP packet\n");
-			return 0;
-		}
-		/* Rest of kernel will get very unhappy if we pass it
-		   a suddenly-orphaned skbuff */
-		if ((*skb)->sk)
-			skb_set_owner_w(nskb, (*skb)->sk);
-		kfree_skb(*skb);
-		*skb = nskb;
-	}
+	SKB_LINEAR_ASSERT(*pskb);
 
-	/* skb may be copied !! */
-	iph = (*skb)->nh.iph;
+	iph = (*pskb)->nh.iph;
 	tcph = (void *)iph + iph->ihl*4;
-	data = (void *)tcph + tcph->doff*4;
-
-	if (rep_len != match_len)
-		/* move post-replacement */
-		memmove(data + match_offset + rep_len,
-			data + match_offset + match_len,
-			(*skb)->tail - (data + match_offset + match_len));
-
-	/* insert data from buffer */
-	memcpy(data + match_offset, rep_buffer, rep_len);
-
-	/* update skb info */
-	if (newlen > (*skb)->len) {
-		DEBUGP("ip_nat_mangle_tcp_packet: Extending packet by "
-			"%u to %u bytes\n", newlen - (*skb)->len, newlen);
-		skb_put(*skb, newlen - (*skb)->len);
-	} else {
-		DEBUGP("ip_nat_mangle_tcp_packet: Shrinking packet from "
-			"%u to %u bytes\n", (*skb)->len, newlen);
-		skb_trim(*skb, newlen);
-	}
-
-	/* fix checksum information */
 
-	iph->tot_len = htons(newlen);
-	(*skb)->csum = csum_partial((char *)tcph + tcph->doff*4,
-				    newtcplen - tcph->doff*4, 0);
+	mangle_contents(*pskb, iph->ihl*4 + tcph->doff*4,
+			match_offset, match_len, rep_buffer, rep_len);
 
 	tcph->check = 0;
-	tcph->check = tcp_v4_check(tcph, newtcplen, iph->saddr, iph->daddr,
+	tcph->check = tcp_v4_check(tcph, (*pskb)->len - iph->ihl*4,
+				   iph->saddr, iph->daddr,
 				   csum_partial((char *)tcph, tcph->doff*4,
-					   (*skb)->csum));
-	ip_send_check(iph);
-
+						(*pskb)->csum));
+	adjust_tcp_sequence(ntohl(tcph->seq),
+			    (int)match_len - (int)rep_len,
+			    ct, ctinfo);
 	return 1;
 }
 			
@@ -220,219 +207,164 @@
  *       should be fairly easy to do.
  */
 int 
-ip_nat_mangle_udp_packet(struct sk_buff **skb,
+ip_nat_mangle_udp_packet(struct sk_buff **pskb,
 			 struct ip_conntrack *ct,
 			 enum ip_conntrack_info ctinfo,
 			 unsigned int match_offset,
 			 unsigned int match_len,
-			 char *rep_buffer,
+			 const char *rep_buffer,
 			 unsigned int rep_len)
 {
-	struct iphdr *iph = (*skb)->nh.iph;
-	struct udphdr *udph = (void *)iph + iph->ihl * 4;
-	unsigned char *data;
-	u_int32_t udplen, newlen, newudplen;
+	struct iphdr *iph;
+	struct udphdr *udph;
+	int need_csum = ((*pskb)->csum != 0);
 
-	udplen = (*skb)->len - iph->ihl*4;
-	newudplen = udplen - match_len + rep_len;
-	newlen = iph->ihl*4 + newudplen;
-
-	if (newlen > 65535) {
-		if (net_ratelimit())
-			printk("ip_nat_mangle_udp_packet: nat'ed packet "
-				"exceeds maximum packet size\n");
+	if (!skb_ip_make_writable(pskb, (*pskb)->len))
 		return 0;
-	}
 
-	if ((*skb)->len != newlen) {
-		if (!ip_nat_resize_packet(skb, ct, ctinfo, newlen)) {
-			printk("resize_packet failed!!\n");
-			return 0;
-		}
-	}
-
-	/* Alexey says: if a hook changes _data_ ... it can break
-	   original packet sitting in tcp queue and this is fatal */
-	if (skb_cloned(*skb)) {
-		struct sk_buff *nskb = skb_copy(*skb, GFP_ATOMIC);
-		if (!nskb) {
-			if (net_ratelimit())
-				printk("Out of memory cloning TCP packet\n");
-			return 0;
-		}
-		/* Rest of kernel will get very unhappy if we pass it
-		   a suddenly-orphaned skbuff */
-		if ((*skb)->sk)
-			skb_set_owner_w(nskb, (*skb)->sk);
-		kfree_skb(*skb);
-		*skb = nskb;
-	}
+	if (rep_len > match_len
+	    && rep_len - match_len > skb_tailroom(*pskb)
+	    && !enlarge_skb(pskb, rep_len - match_len))
+		return 0;
 
-	/* skb may be copied !! */
-	iph = (*skb)->nh.iph;
+	iph = (*pskb)->nh.iph;
 	udph = (void *)iph + iph->ihl*4;
-	data = (void *)udph + sizeof(struct udphdr);
-
-	if (rep_len != match_len)
-		/* move post-replacement */
-		memmove(data + match_offset + rep_len,
-			data + match_offset + match_len,
-			(*skb)->tail - (data + match_offset + match_len));
+	mangle_contents(*pskb, iph->ihl*4 + sizeof(*udph),
+			match_offset, match_len, rep_buffer, rep_len);
 
-	/* insert data from buffer */
-	memcpy(data + match_offset, rep_buffer, rep_len);
-
-	/* update skb info */
-	if (newlen > (*skb)->len) {
-		DEBUGP("ip_nat_mangle_udp_packet: Extending packet by "
-			"%u to %u bytes\n", newlen - (*skb)->len, newlen);
-		skb_put(*skb, newlen - (*skb)->len);
-	} else {
-		DEBUGP("ip_nat_mangle_udp_packet: Shrinking packet from "
-			"%u to %u bytes\n", (*skb)->len, newlen);
-		skb_trim(*skb, newlen);
-	}
-
-	/* update the length of the UDP and IP packets to the new values*/
-	udph->len = htons((*skb)->len - iph->ihl*4);
-	iph->tot_len = htons(newlen);
+	/* update the length of the UDP packet */
+	udph->len = htons((*pskb)->len - iph->ihl*4);
 
 	/* fix udp checksum if udp checksum was previously calculated */
-	if ((*skb)->csum != 0) {
-		(*skb)->csum = csum_partial((char *)udph +
-					    sizeof(struct udphdr),
-					    newudplen - sizeof(struct udphdr),
-					    0);
-
+	if (need_csum) {
 		udph->check = 0;
-		udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
-						newudplen, IPPROTO_UDP,
-						csum_partial((char *)udph,
+		udph->check
+			= csum_tcpudp_magic(iph->saddr, iph->daddr,
+					    (*pskb)->len - iph->ihl*4,
+					    IPPROTO_UDP,
+					    csum_partial((char *)udph,
 							 sizeof(struct udphdr),
-							(*skb)->csum));
-	}
-
-	ip_send_check(iph);
-
+							 (*pskb)->csum));
+	} else
+		(*pskb)->csum = 0;
 	return 1;
 }
 
 /* Adjust one found SACK option including checksum correction */
 static void
-sack_adjust(struct tcphdr *tcph, 
-	    unsigned char *ptr, 
+sack_adjust(struct sk_buff *skb,
+	    struct tcphdr *tcph, 
+	    unsigned int sackoff,
+	    unsigned int sackend,
 	    struct ip_nat_seq *natseq)
 {
-	struct tcp_sack_block *sp = (struct tcp_sack_block *)(ptr+2);
-	int num_sacks = (ptr[1] - TCPOLEN_SACK_BASE)>>3;
-	int i;
-
-	for (i = 0; i < num_sacks; i++, sp++) {
+	while (sackoff < sackend) {
+		struct tcp_sack_block *sack;
 		u_int32_t new_start_seq, new_end_seq;
 
-		if (after(ntohl(sp->start_seq) - natseq->offset_before,
+		sack = (void *)skb->data + sackoff;
+		if (after(ntohl(sack->start_seq) - natseq->offset_before,
 			  natseq->correction_pos))
-			new_start_seq = ntohl(sp->start_seq) 
+			new_start_seq = ntohl(sack->start_seq) 
 					- natseq->offset_after;
 		else
-			new_start_seq = ntohl(sp->start_seq) 
+			new_start_seq = ntohl(sack->start_seq) 
 					- natseq->offset_before;
 		new_start_seq = htonl(new_start_seq);
 
-		if (after(ntohl(sp->end_seq) - natseq->offset_before,
+		if (after(ntohl(sack->end_seq) - natseq->offset_before,
 			  natseq->correction_pos))
-			new_end_seq = ntohl(sp->end_seq)
+			new_end_seq = ntohl(sack->end_seq)
 				      - natseq->offset_after;
 		else
-			new_end_seq = ntohl(sp->end_seq)
+			new_end_seq = ntohl(sack->end_seq)
 				      - natseq->offset_before;
 		new_end_seq = htonl(new_end_seq);
 
 		DEBUGP("sack_adjust: start_seq: %d->%d, end_seq: %d->%d\n",
-			ntohl(sp->start_seq), new_start_seq,
-			ntohl(sp->end_seq), new_end_seq);
+			ntohl(sack->start_seq), new_start_seq,
+			ntohl(sack->end_seq), new_end_seq);
 
 		tcph->check = 
-			ip_nat_cheat_check(~sp->start_seq, new_start_seq,
-					   ip_nat_cheat_check(~sp->end_seq, 
+			ip_nat_cheat_check(~sack->start_seq, new_start_seq,
+					   ip_nat_cheat_check(~sack->end_seq, 
 						   	      new_end_seq,
 							      tcph->check));
-
-		sp->start_seq = new_start_seq;
-		sp->end_seq = new_end_seq;
+		sack->start_seq = new_start_seq;
+		sack->end_seq = new_end_seq;
+		sackoff += sizeof(*sack);
 	}
 }
-			
 
-/* TCP SACK sequence number adjustment, return 0 if sack found and adjusted */
-static inline int
-ip_nat_sack_adjust(struct sk_buff *skb,
-			struct ip_conntrack *ct,
-			enum ip_conntrack_info ctinfo)
+/* TCP SACK sequence number adjustment */
+static inline unsigned int
+ip_nat_sack_adjust(struct sk_buff **pskb,
+		   struct tcphdr *tcph,
+		   struct ip_conntrack *ct,
+		   enum ip_conntrack_info ctinfo)
 {
-	struct iphdr *iph;
-	struct tcphdr *tcph;
-	unsigned char *ptr;
-	int length, dir, sack_adjusted = 0;
+	unsigned int dir, optoff, optend;
 
-	iph = skb->nh.iph;
-	tcph = (void *)iph + iph->ihl*4;
-	length = (tcph->doff*4)-sizeof(struct tcphdr);
-	ptr = (unsigned char *)(tcph+1);
+	optoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct tcphdr);
+	optend = (*pskb)->nh.iph->ihl*4 + tcph->doff*4;
+
+	if (!skb_ip_make_writable(pskb, optend))
+		return 0;
 
 	dir = CTINFO2DIR(ctinfo);
 
-	while (length > 0) {
-		int opcode = *ptr++;
-		int opsize;
+	while (optoff < optend) {
+		/* Usually: option, length. */
+		unsigned char *op = (*pskb)->data + optoff;
 
-		switch (opcode) {
+		switch (op[0]) {
 		case TCPOPT_EOL:
-			return !sack_adjusted;
+			return 1;
 		case TCPOPT_NOP:
-			length--;
+			optoff++;
 			continue;
 		default:
-			opsize = *ptr++;
-			if (opsize > length) /* no partial opts */
-				return !sack_adjusted;
-			if (opcode == TCPOPT_SACK) {
-				/* found SACK */
-				if((opsize >= (TCPOLEN_SACK_BASE
-					       +TCPOLEN_SACK_PERBLOCK)) &&
-				   !((opsize - TCPOLEN_SACK_BASE)
-				     % TCPOLEN_SACK_PERBLOCK))
-					sack_adjust(tcph, ptr-2,
-						    &ct->nat.info.seq[!dir]);
-				
-				sack_adjusted = 1;
-			}
-			ptr += opsize-2;
-			length -= opsize;
+			/* no partial options */
+			if (optoff + 1 == optend
+			    || optoff + op[1] > optend
+			    || op[1] < 2)
+				return 0;
+			if (op[0] == TCPOPT_SACK
+			    && op[1] >= 2+TCPOLEN_SACK_PERBLOCK
+			    && ((op[1] - 2) % TCPOLEN_SACK_PERBLOCK) == 0)
+				sack_adjust(*pskb, tcph, optoff+2,
+					    optoff+op[1],
+					    &ct->nat.info.seq[!dir]);
+			optoff += op[1];
 		}
 	}
-	return !sack_adjusted;
+	return 1;
 }
 
-/* TCP sequence number adjustment */
-int 
-ip_nat_seq_adjust(struct sk_buff *skb, 
+/* TCP sequence number adjustment.  Returns true or false.  */
+int
+ip_nat_seq_adjust(struct sk_buff **pskb, 
 		  struct ip_conntrack *ct, 
 		  enum ip_conntrack_info ctinfo)
 {
-	struct iphdr *iph;
 	struct tcphdr *tcph;
 	int dir, newseq, newack;
 	struct ip_nat_seq *this_way, *other_way;	
-	
-	iph = skb->nh.iph;
-	tcph = (void *)iph + iph->ihl*4;
 
 	dir = CTINFO2DIR(ctinfo);
 
 	this_way = &ct->nat.info.seq[dir];
 	other_way = &ct->nat.info.seq[!dir];
-	
+
+	/* No adjustments to make?  Very common case. */
+	if (!this_way->offset_before && !this_way->offset_after
+	    && !other_way->offset_before && !other_way->offset_after)
+		return 1;
+
+	if (!skb_ip_make_writable(pskb, (*pskb)->nh.iph->ihl*4+sizeof(*tcph)))
+		return 0;
+
+	tcph = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4;
 	if (after(ntohl(tcph->seq), this_way->correction_pos))
 		newseq = ntohl(tcph->seq) + this_way->offset_after;
 	else
@@ -458,9 +390,7 @@
 	tcph->seq = newseq;
 	tcph->ack_seq = newack;
 
-	ip_nat_sack_adjust(skb, ct, ctinfo);
-
-	return 0;
+	return ip_nat_sack_adjust(pskb, tcph, ct, ctinfo);
 }
 
 static inline int
diff -urN linux-2.5.69-bk1/net/ipv4/netfilter/ip_nat_proto_icmp.c linux-2.5.69-bk2/net/ipv4/netfilter/ip_nat_proto_icmp.c
--- linux-2.5.69-bk1/net/ipv4/netfilter/ip_nat_proto_icmp.c	2003-05-04 16:53:09.000000000 -0700
+++ linux-2.5.69-bk2/net/ipv4/netfilter/ip_nat_proto_icmp.c	2003-05-07 04:41:17.000000000 -0700
@@ -6,6 +6,7 @@
 #include <linux/if.h>
 
 #include <linux/netfilter_ipv4/ip_nat.h>
+#include <linux/netfilter_ipv4/ip_nat_core.h>
 #include <linux/netfilter_ipv4/ip_nat_rule.h>
 #include <linux/netfilter_ipv4/ip_nat_protocol.h>
 
@@ -42,17 +43,24 @@
 	return 0;
 }
 
-static void
-icmp_manip_pkt(struct iphdr *iph, size_t len,
+static int
+icmp_manip_pkt(struct sk_buff **pskb,
+	       unsigned int hdroff,
 	       const struct ip_conntrack_manip *manip,
 	       enum ip_nat_manip_type maniptype)
 {
-	struct icmphdr *hdr = (struct icmphdr *)((u_int32_t *)iph + iph->ihl);
+	struct icmphdr *hdr;
+
+	if (!skb_ip_make_writable(pskb, hdroff + sizeof(*hdr)))
+		return 0;
+
+	hdr = (void *)(*pskb)->data + hdroff;
 
 	hdr->checksum = ip_nat_cheat_check(hdr->un.echo.id ^ 0xFFFF,
-					   manip->u.icmp.id,
-					   hdr->checksum);
+					    manip->u.icmp.id,
+					    hdr->checksum);
 	hdr->un.echo.id = manip->u.icmp.id;
+	return 1;
 }
 
 static unsigned int
diff -urN linux-2.5.69-bk1/net/ipv4/netfilter/ip_nat_proto_tcp.c linux-2.5.69-bk2/net/ipv4/netfilter/ip_nat_proto_tcp.c
--- linux-2.5.69-bk1/net/ipv4/netfilter/ip_nat_proto_tcp.c	2003-05-04 16:52:49.000000000 -0700
+++ linux-2.5.69-bk2/net/ipv4/netfilter/ip_nat_proto_tcp.c	2003-05-07 04:41:17.000000000 -0700
@@ -7,6 +7,7 @@
 #include <linux/netfilter_ipv4/ip_nat.h>
 #include <linux/netfilter_ipv4/ip_nat_rule.h>
 #include <linux/netfilter_ipv4/ip_nat_protocol.h>
+#include <linux/netfilter_ipv4/ip_nat_core.h>
 
 static int
 tcp_in_range(const struct ip_conntrack_tuple *tuple,
@@ -73,36 +74,49 @@
 	return 0;
 }
 
-static void
-tcp_manip_pkt(struct iphdr *iph, size_t len,
+static int
+tcp_manip_pkt(struct sk_buff **pskb,
+	      unsigned int hdroff,
 	      const struct ip_conntrack_manip *manip,
 	      enum ip_nat_manip_type maniptype)
 {
-	struct tcphdr *hdr = (struct tcphdr *)((u_int32_t *)iph + iph->ihl);
+	struct tcphdr *hdr;
 	u_int32_t oldip;
-	u_int16_t *portptr;
+	u_int16_t *portptr, oldport;
+	int hdrsize = 8; /* TCP connection tracking guarantees this much */
+
+	/* this could be a inner header returned in icmp packet; in such
+	   cases we cannot update the checksum field since it is outside of
+	   the 8 bytes of transport layer headers we are guaranteed */
+	if ((*pskb)->len >= hdroff + sizeof(struct tcphdr))
+		hdrsize = sizeof(struct tcphdr);
+
+	if (!skb_ip_make_writable(pskb, hdroff + hdrsize))
+		return 0;
+
+	hdr = (void *)(*pskb)->data + hdroff;
 
 	if (maniptype == IP_NAT_MANIP_SRC) {
 		/* Get rid of src ip and src pt */
-		oldip = iph->saddr;
+		oldip = (*pskb)->nh.iph->saddr;
 		portptr = &hdr->source;
 	} else {
 		/* Get rid of dst ip and dst pt */
-		oldip = iph->daddr;
+		oldip = (*pskb)->nh.iph->daddr;
 		portptr = &hdr->dest;
 	}
 
-	/* this could be a inner header returned in icmp packet; in such
-	   cases we cannot update the checksum field since it is outside of
-	   the 8 bytes of transport layer headers we are guaranteed */
-	if(((void *)&hdr->check + sizeof(hdr->check) - (void *)iph) <= len) {
-		hdr->check = ip_nat_cheat_check(~oldip, manip->ip,
-					ip_nat_cheat_check(*portptr ^ 0xFFFF,
+	oldport = *portptr;
+	*portptr = manip->u.tcp.port;
+
+	if (hdrsize < sizeof(*hdr))
+		return 1;
+
+	hdr->check = ip_nat_cheat_check(~oldip, manip->ip,
+					ip_nat_cheat_check(oldport ^ 0xFFFF,
 							   manip->u.tcp.port,
 							   hdr->check));
-	}
-
-	*portptr = manip->u.tcp.port;
+	return 1;
 }
 
 static unsigned int
diff -urN linux-2.5.69-bk1/net/ipv4/netfilter/ip_nat_proto_udp.c linux-2.5.69-bk2/net/ipv4/netfilter/ip_nat_proto_udp.c
--- linux-2.5.69-bk1/net/ipv4/netfilter/ip_nat_proto_udp.c	2003-05-04 16:53:03.000000000 -0700
+++ linux-2.5.69-bk2/net/ipv4/netfilter/ip_nat_proto_udp.c	2003-05-07 04:41:17.000000000 -0700
@@ -6,6 +6,7 @@
 #include <linux/if.h>
 
 #include <linux/netfilter_ipv4/ip_nat.h>
+#include <linux/netfilter_ipv4/ip_nat_core.h>
 #include <linux/netfilter_ipv4/ip_nat_rule.h>
 #include <linux/netfilter_ipv4/ip_nat_protocol.h>
 
@@ -72,22 +73,27 @@
 	return 0;
 }
 
-static void
-udp_manip_pkt(struct iphdr *iph, size_t len,
+static int
+udp_manip_pkt(struct sk_buff **pskb,
+	      unsigned int hdroff,
 	      const struct ip_conntrack_manip *manip,
 	      enum ip_nat_manip_type maniptype)
 {
-	struct udphdr *hdr = (struct udphdr *)((u_int32_t *)iph + iph->ihl);
+	struct udphdr *hdr;
 	u_int32_t oldip;
 	u_int16_t *portptr;
 
+	if (!skb_ip_make_writable(pskb, hdroff + sizeof(hdr)))
+		return 0;
+
+	hdr = (void *)(*pskb)->data + hdroff;
 	if (maniptype == IP_NAT_MANIP_SRC) {
 		/* Get rid of src ip and src pt */
-		oldip = iph->saddr;
+		oldip = (*pskb)->nh.iph->saddr;
 		portptr = &hdr->source;
 	} else {
 		/* Get rid of dst ip and dst pt */
-		oldip = iph->daddr;
+		oldip = (*pskb)->nh.iph->daddr;
 		portptr = &hdr->dest;
 	}
 	if (hdr->check) /* 0 is a special case meaning no checksum */
@@ -96,6 +102,7 @@
 							   manip->u.udp.port,
 							   hdr->check));
 	*portptr = manip->u.udp.port;
+	return 1;
 }
 
 static unsigned int
diff -urN linux-2.5.69-bk1/net/ipv4/netfilter/ip_nat_proto_unknown.c linux-2.5.69-bk2/net/ipv4/netfilter/ip_nat_proto_unknown.c
--- linux-2.5.69-bk1/net/ipv4/netfilter/ip_nat_proto_unknown.c	2003-05-04 16:53:31.000000000 -0700
+++ linux-2.5.69-bk2/net/ipv4/netfilter/ip_nat_proto_unknown.c	2003-05-07 04:41:17.000000000 -0700
@@ -29,12 +29,13 @@
 	return 0;
 }
 
-static void
-unknown_manip_pkt(struct iphdr *iph, size_t len,
+static int
+unknown_manip_pkt(struct sk_buff **pskb,
+		  unsigned int hdroff,
 		  const struct ip_conntrack_manip *manip,
 		  enum ip_nat_manip_type maniptype)
 {
-	return;
+	return 1;
 }
 
 static unsigned int
diff -urN linux-2.5.69-bk1/net/ipv4/netfilter/ip_nat_standalone.c linux-2.5.69-bk2/net/ipv4/netfilter/ip_nat_standalone.c
--- linux-2.5.69-bk1/net/ipv4/netfilter/ip_nat_standalone.c	2003-05-04 16:53:37.000000000 -0700
+++ linux-2.5.69-bk2/net/ipv4/netfilter/ip_nat_standalone.c	2003-05-07 04:41:17.000000000 -0700
@@ -71,10 +71,6 @@
 	/* maniptype == SRC for postrouting. */
 	enum ip_nat_manip_type maniptype = HOOK2MANIP(hooknum);
 
-	/* FIXME: Push down to extensions --RR */
-	if (skb_is_nonlinear(*pskb) && skb_linearize(*pskb, GFP_ATOMIC) != 0)
-		return NF_DROP;
-
 	/* We never see fragments: conntrack defrags on pre-routing
 	   and local-out, and ip_nat_out protects post-routing. */
 	IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off
@@ -95,12 +91,14 @@
 		/* Exception: ICMP redirect to new connection (not in
                    hash table yet).  We must not let this through, in
                    case we're doing NAT to the same network. */
-		struct iphdr *iph = (*pskb)->nh.iph;
-		struct icmphdr *hdr = (struct icmphdr *)
-			((u_int32_t *)iph + iph->ihl);
-		if (iph->protocol == IPPROTO_ICMP
-		    && hdr->type == ICMP_REDIRECT)
-			return NF_DROP;
+		if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) {
+			struct icmphdr hdr;
+
+			if (skb_copy_bits(*pskb, (*pskb)->nh.iph->ihl*4,
+					  &hdr, sizeof(hdr)) == 0
+			    && hdr.type == ICMP_REDIRECT)
+				return NF_DROP;
+		}
 		return NF_ACCEPT;
 	}
 
@@ -108,8 +106,11 @@
 	case IP_CT_RELATED:
 	case IP_CT_RELATED+IP_CT_IS_REPLY:
 		if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) {
-			return icmp_reply_translation(*pskb, ct, hooknum,
-						      CTINFO2DIR(ctinfo));
+			if (!icmp_reply_translation(pskb, ct, hooknum,
+						    CTINFO2DIR(ctinfo)))
+				return NF_DROP;
+			else
+				return NF_ACCEPT;
 		}
 		/* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */
 	case IP_CT_NEW:
@@ -174,10 +175,6 @@
 	   const struct net_device *out,
 	   int (*okfn)(struct sk_buff *))
 {
-	/* FIXME: Push down to extensions --RR */
-	if (skb_is_nonlinear(*pskb) && skb_linearize(*pskb, GFP_ATOMIC) != 0)
-		return NF_DROP;
-
 	/* root is playing with raw sockets. */
 	if ((*pskb)->len < sizeof(struct iphdr)
 	    || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
@@ -213,10 +210,6 @@
 	u_int32_t saddr, daddr;
 	unsigned int ret;
 
-	/* FIXME: Push down to extensions --RR */
-	if (skb_is_nonlinear(*pskb) && skb_linearize(*pskb, GFP_ATOMIC) != 0)
-		return NF_DROP;
-
 	/* root is playing with raw sockets. */
 	if ((*pskb)->len < sizeof(struct iphdr)
 	    || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
@@ -387,4 +380,5 @@
 EXPORT_SYMBOL(ip_nat_mangle_tcp_packet);
 EXPORT_SYMBOL(ip_nat_mangle_udp_packet);
 EXPORT_SYMBOL(ip_nat_used_tuple);
+EXPORT_SYMBOL(skb_ip_make_writable);
 MODULE_LICENSE("GPL");
diff -urN linux-2.5.69-bk1/net/ipv4/netfilter/ip_nat_tftp.c linux-2.5.69-bk2/net/ipv4/netfilter/ip_nat_tftp.c
--- linux-2.5.69-bk1/net/ipv4/netfilter/ip_nat_tftp.c	2003-05-04 16:53:09.000000000 -0700
+++ linux-2.5.69-bk2/net/ipv4/netfilter/ip_nat_tftp.c	2003-05-07 04:41:17.000000000 -0700
@@ -57,9 +57,7 @@
 	      struct sk_buff **pskb)
 {
 	int dir = CTINFO2DIR(ctinfo);
-	struct iphdr *iph = (*pskb)->nh.iph;
-	struct udphdr *udph = (void *)iph + iph->ihl * 4;
-	struct tftphdr *tftph = (void *)udph + 8;
+	struct tftphdr tftph;
 	struct ip_conntrack_tuple repl;
 
 	if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)
@@ -71,7 +69,11 @@
 		return NF_ACCEPT;
 	}
 
-	switch (ntohs(tftph->opcode)) {
+	if (skb_copy_bits(*pskb, (*pskb)->nh.iph->ihl*4+sizeof(struct udphdr),
+			  &tftph, sizeof(tftph)) != 0)
+		return NF_DROP;
+
+	switch (ntohs(tftph.opcode)) {
 	/* RRQ and WRQ works the same way */
 	case TFTP_OPCODE_READ:
 	case TFTP_OPCODE_WRITE:
@@ -104,8 +106,10 @@
 #if 0
 	const struct ip_conntrack_tuple *repl =
 			&master->tuplehash[IP_CT_DIR_REPLY].tuple;
-	struct iphdr *iph = (*pskb)->nh.iph;
-	struct udphdr *udph = (void *)iph + iph->ihl*4;
+	struct udphdr udph;
+
+	if (skb_copy_bits(*pskb,(*pskb)->nh.iph->ihl*4,&udph,sizeof(udph))!=0)
+		return NF_DROP;
 #endif
 
 	IP_NF_ASSERT(info);
@@ -119,8 +123,8 @@
 		mr.range[0].min_ip = mr.range[0].max_ip = orig->dst.ip; 
 		DEBUGP("orig: %u.%u.%u.%u:%u <-> %u.%u.%u.%u:%u "
 			"newsrc: %u.%u.%u.%u\n",
-                        NIPQUAD((*pskb)->nh.iph->saddr), ntohs(udph->source),
-			NIPQUAD((*pskb)->nh.iph->daddr), ntohs(udph->dest),
+                        NIPQUAD((*pskb)->nh.iph->saddr), ntohs(udph.source),
+ 			NIPQUAD((*pskb)->nh.iph->daddr), ntohs(udph.dest),
 			NIPQUAD(orig->dst.ip));
 	} else {
 		mr.range[0].min_ip = mr.range[0].max_ip = orig->src.ip;
@@ -130,8 +134,8 @@
 
 		DEBUGP("orig: %u.%u.%u.%u:%u <-> %u.%u.%u.%u:%u "
 			"newdst: %u.%u.%u.%u:%u\n",
-                        NIPQUAD((*pskb)->nh.iph->saddr), ntohs(udph->source),
-                        NIPQUAD((*pskb)->nh.iph->daddr), ntohs(udph->dest),
+                        NIPQUAD((*pskb)->nh.iph->saddr), ntohs(udph.source),
+                        NIPQUAD((*pskb)->nh.iph->daddr), ntohs(udph.dest),
                         NIPQUAD(orig->src.ip), ntohs(orig->src.u.udp.port));
 	}
 
diff -urN linux-2.5.69-bk1/net/ipv4/netfilter/ipchains_core.c linux-2.5.69-bk2/net/ipv4/netfilter/ipchains_core.c
--- linux-2.5.69-bk1/net/ipv4/netfilter/ipchains_core.c	2003-05-04 16:53:40.000000000 -0700
+++ linux-2.5.69-bk2/net/ipv4/netfilter/ipchains_core.c	2003-05-07 04:41:17.000000000 -0700
@@ -839,7 +839,9 @@
 			i->branch->refcount--;
 		kfree(i);
 		i = tmp;
-		MOD_DEC_USE_COUNT;
+		/* We will block in cleanup's unregister sockopt if unloaded,
+		   so this is safe. */
+		module_put(THIS_MODULE);
 	}
 	return 0;
 }
@@ -870,6 +872,11 @@
 	struct ip_fwkernel *i;
 
 	FWC_HAVE_LOCK(fwc_wlocks);
+
+	/* Are we unloading now?  We will block on nf_unregister_sockopt */
+	if (!try_module_get(THIS_MODULE))
+		return ENOPROTOOPT;
+
 	/* Special case if no rules already present */
 	if (chainptr->chain == NULL) {
 
@@ -886,7 +893,6 @@
 	if (rule->branch) rule->branch->refcount++;
 
 append_successful:
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
@@ -900,6 +906,11 @@
 	struct ip_fwkernel *f = chainptr->chain;
 
 	FWC_HAVE_LOCK(fwc_wlocks);
+
+	/* Are we unloading now?  We will block on nf_unregister_sockopt */
+	if (!try_module_get(THIS_MODULE))
+		return ENOPROTOOPT;
+
 	/* special case if the position is number 1 */
 	if (position == 1) {
 		frwl->next = chainptr->chain;
@@ -917,7 +928,6 @@
 	f->next = frwl;
 
 insert_successful:
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
@@ -952,7 +962,9 @@
 		kfree(tmp);
 	}
 
-	MOD_DEC_USE_COUNT;
+	/* We will block in cleanup's unregister sockopt if unloaded,
+	   so this is safe. */
+	module_put(THIS_MODULE);
 	return 0;
 }
 
@@ -1059,7 +1071,9 @@
 		else
 			chainptr->chain = ftmp->next;
 		kfree(ftmp);
-		MOD_DEC_USE_COUNT;
+		/* We will block in cleanup's unregister sockopt if unloaded,
+		   so this is safe. */
+		module_put(THIS_MODULE);
 		break;
 	}
 
@@ -1101,7 +1115,9 @@
 	tmp->next = tmp2->next;
 	kfree(tmp2);
 
-	MOD_DEC_USE_COUNT;
+	/* We will block in cleanup's unregister sockopt if unloaded,
+	   so this is safe. */
+	module_put(THIS_MODULE);
 	return 0;
 }
 
@@ -1149,12 +1165,15 @@
 	if (strcmp(tmp->label,label) == 0)
 		return EEXIST;
 
+	/* Are we unloading now?  We will block on nf_unregister_sockopt */
+	if (!try_module_get(THIS_MODULE))
+		return ENOPROTOOPT;
+
 	tmp->next = ip_init_chain(label, 0, FW_SKIP); /* refcount is
 					      * zero since this is a
 					      * user defined chain *
 					      * and therefore can be
 					      * deleted */
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
diff -urN linux-2.5.69-bk1/net/ipv4/netfilter/ipfwadm_core.c linux-2.5.69-bk2/net/ipv4/netfilter/ipfwadm_core.c
--- linux-2.5.69-bk1/net/ipv4/netfilter/ipfwadm_core.c	2003-05-04 16:53:13.000000000 -0700
+++ linux-2.5.69-bk2/net/ipv4/netfilter/ipfwadm_core.c	2003-05-07 04:41:17.000000000 -0700
@@ -707,7 +707,9 @@
 		ftmp = *chainptr;
 		*chainptr = ftmp->fw_next;
 		kfree(ftmp);
-		MOD_DEC_USE_COUNT;
+		/* We will block in cleanup's unregister sockopt if unloaded,
+		   so this is safe. */
+		module_put(THIS_MODULE);
 	}
 	WRITE_UNLOCK(&ip_fw_lock);
 }
@@ -718,6 +720,10 @@
 {
 	struct ip_fw *ftmp;
 
+	/* Are we unloading now?  We will block on nf_unregister_sockopt */
+	if (!try_module_get(THIS_MODULE))
+		return ENOPROTOOPT;
+
 	ftmp = kmalloc( sizeof(struct ip_fw), GFP_KERNEL );
 	if ( ftmp == NULL )
 	{
@@ -748,7 +754,6 @@
 	ftmp->fw_next = *chainptr;
        	*chainptr=ftmp;
 	WRITE_UNLOCK(&ip_fw_lock);
-	MOD_INC_USE_COUNT;
 	return(0);
 }
 
@@ -758,6 +763,10 @@
 	struct ip_fw *chtmp=NULL;
 	struct ip_fw *volatile chtmp_prev=NULL;
 
+	/* Are we unloading now?  We will block on nf_unregister_sockopt */
+	if (!try_module_get(THIS_MODULE))
+		return ENOPROTOOPT;
+
 	ftmp = kmalloc( sizeof(struct ip_fw), GFP_KERNEL );
 	if ( ftmp == NULL )
 	{
@@ -796,7 +805,6 @@
 	else
         	*chainptr=ftmp;
 	WRITE_UNLOCK(&ip_fw_lock);
-	MOD_INC_USE_COUNT;
 	return(0);
 }
 
@@ -869,7 +877,9 @@
 	}
 	WRITE_UNLOCK(&ip_fw_lock);
 	if (was_found) {
-		MOD_DEC_USE_COUNT;
+		/* We will block in cleanup's unregister sockopt if unloaded,
+		   so this is safe. */
+		module_put(THIS_MODULE);
 		return 0;
 	} else
 		return(EINVAL);
diff -urN linux-2.5.69-bk1/net/ipv6/af_inet6.c linux-2.5.69-bk2/net/ipv6/af_inet6.c
--- linux-2.5.69-bk1/net/ipv6/af_inet6.c	2003-05-04 16:53:32.000000000 -0700
+++ linux-2.5.69-bk2/net/ipv6/af_inet6.c	2003-05-07 04:41:17.000000000 -0700
@@ -111,7 +111,6 @@
 #ifdef INET_REFCNT_DEBUG
 	atomic_dec(&inet6_sock_nr);
 #endif
-	module_put(THIS_MODULE);
 }
 
 static __inline__ kmem_cache_t *inet6_sk_slab(int protocol)
@@ -243,11 +242,6 @@
 	atomic_inc(&inet6_sock_nr);
 	atomic_inc(&inet_sock_nr);
 #endif
-	if (!try_module_get(THIS_MODULE)) {
-		inet_sock_release(sk);
-		return -EBUSY;
-	}
-
 	if (inet->num) {
 		/* It assumes that any protocol which allows
 		 * the user to assign a number at socket
@@ -259,7 +253,6 @@
 	if (sk->prot->init) {
 		int err = sk->prot->init(sk);
 		if (err != 0) {
-			module_put(THIS_MODULE);
 			inet_sock_release(sk);
 			return err;
 		}
diff -urN linux-2.5.69-bk1/net/ipv6/exthdrs.c linux-2.5.69-bk2/net/ipv6/exthdrs.c
--- linux-2.5.69-bk1/net/ipv6/exthdrs.c	2003-05-04 16:53:00.000000000 -0700
+++ linux-2.5.69-bk2/net/ipv6/exthdrs.c	2003-05-07 04:41:17.000000000 -0700
@@ -252,8 +252,13 @@
 		return 1;
 	}
 
-	if (hdr->type != IPV6_SRCRT_TYPE_0 || (hdr->hdrlen & 0x01)) {
-		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, hdr->type != IPV6_SRCRT_TYPE_0 ? 2 : 1);
+	if (hdr->type != IPV6_SRCRT_TYPE_0) {
+		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb->nh.raw);
+		return -1;
+	}
+	
+	if (hdr->hdrlen & 0x01) {
+		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->hdrlen) - skb->nh.raw);
 		return -1;
 	}
 
diff -urN linux-2.5.69-bk1/net/ipv6/netfilter/ip6t_ah.c linux-2.5.69-bk2/net/ipv6/netfilter/ip6t_ah.c
--- linux-2.5.69-bk1/net/ipv6/netfilter/ip6t_ah.c	2003-05-04 16:53:02.000000000 -0700
+++ linux-2.5.69-bk2/net/ipv6/netfilter/ip6t_ah.c	2003-05-07 04:41:17.000000000 -0700
@@ -19,13 +19,6 @@
 #define DEBUGP(format, args...)
 #endif
 
-struct ahhdr {
-       __u8    nexthdr;
-       __u8    hdrlen;
-       __u16   reserved;
-       __u32   spi;
-};
-
 /* Returns 1 if the spi is matched by the range, 0 otherwise */
 static inline int
 spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
@@ -48,7 +41,7 @@
       u_int16_t datalen,
       int *hotdrop)
 {
-       struct ahhdr *ah = NULL;
+       struct ip_auth_hdr *ah = NULL;
        const struct ip6t_ah *ahinfo = matchinfo;
        unsigned int temp;
        int len;
@@ -128,12 +121,12 @@
        /* AH header not found */
        if ( temp != MASK_AH ) return 0;
 
-       if (len < (int)sizeof(struct ahhdr)){
+       if (len < (int)sizeof(struct ip_auth_hdr)){
 	       *hotdrop = 1;
        		return 0;
        }
 
-       ah=skb->data+ptr;
+       ah = (struct ip_auth_hdr *) (skb->data + ptr);
 
        DEBUGP("IPv6 AH LEN %u %u ", hdrlen, ah->hdrlen);
        DEBUGP("RES %04X ", ah->reserved);
diff -urN linux-2.5.69-bk1/net/ipv6/netfilter/ip6t_esp.c linux-2.5.69-bk2/net/ipv6/netfilter/ip6t_esp.c
--- linux-2.5.69-bk1/net/ipv6/netfilter/ip6t_esp.c	2003-05-04 16:53:32.000000000 -0700
+++ linux-2.5.69-bk2/net/ipv6/netfilter/ip6t_esp.c	2003-05-07 04:41:17.000000000 -0700
@@ -19,10 +19,6 @@
 #define DEBUGP(format, args...)
 #endif
 
-struct esphdr {
-	__u32   spi;
-};
-
 /* Returns 1 if the spi is matched by the range, 0 otherwise */
 static inline int
 spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
@@ -45,7 +41,7 @@
       u_int16_t datalen,
       int *hotdrop)
 {
-	struct esphdr *esp = NULL;
+	struct ip_esp_hdr *esp = NULL;
 	const struct ip6t_esp *espinfo = matchinfo;
 	unsigned int temp;
 	int len;
@@ -118,12 +114,12 @@
 	/* ESP header not found */
 	if ( temp != MASK_ESP ) return 0;
 
-       if (len < (int)sizeof(struct esphdr)){
+       if (len < (int)sizeof(struct ip_esp_hdr)){
 	       *hotdrop = 1;
        		return 0;
        }
 
-	esp=skb->data+ptr;
+	esp = (struct ip_esp_hdr *) (skb->data + ptr);
 
 	DEBUGP("IPv6 ESP SPI %u %08X\n", ntohl(esp->spi), ntohl(esp->spi));
 
diff -urN linux-2.5.69-bk1/net/ipv6/netfilter/ip6t_frag.c linux-2.5.69-bk2/net/ipv6/netfilter/ip6t_frag.c
--- linux-2.5.69-bk1/net/ipv6/netfilter/ip6t_frag.c	2003-05-04 16:53:07.000000000 -0700
+++ linux-2.5.69-bk2/net/ipv6/netfilter/ip6t_frag.c	2003-05-07 04:41:17.000000000 -0700
@@ -147,7 +147,7 @@
        		return 0;
        }
 
-       frag=skb->data+ptr;
+       frag = (struct fraghdr *) (skb->data + ptr);
 
        DEBUGP("IPv6 FRAG LEN %u %u ", hdrlen, frag->hdrlen);
        DEBUGP("INFO %04X ", frag->info);
diff -urN linux-2.5.69-bk1/net/ipv6/netfilter/ip6t_ipv6header.c linux-2.5.69-bk2/net/ipv6/netfilter/ip6t_ipv6header.c
--- linux-2.5.69-bk1/net/ipv6/netfilter/ip6t_ipv6header.c	2003-05-04 16:53:57.000000000 -0700
+++ linux-2.5.69-bk2/net/ipv6/netfilter/ip6t_ipv6header.c	2003-05-07 04:41:17.000000000 -0700
@@ -18,12 +18,6 @@
 MODULE_DESCRIPTION("IPv6 headers match");
 MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
 
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
 static int
 ipv6header_match(const struct sk_buff *skb,
 		 const struct net_device *in,
@@ -39,10 +33,8 @@
 	int len;
 	u8 nexthdr;
 	unsigned int ptr;
-        struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
 
 	/* Make sure this isn't an evil packet */
-	DEBUGP("ipv6_header entered \n");
 
 	/* type of the 1st exthdr */
 	nexthdr = skb->nh.ipv6h->nexthdr;
@@ -52,44 +44,10 @@
 	len = skb->len - ptr;
 	temp = 0;
 
-	DEBUGP("ipv6_header nexthdr %02X \n",nexthdr);
-	DEBUGP("ipv6_header ptr %08X \n",ptr);
-	DEBUGP("ipv6_header skblen %04X \n",skb->len);
-	DEBUGP("ipv6_header skbdatalen %04X \n",skb->data_len);
-	DEBUGP("ipv6_header len %04X \n",len);
-#if 0
-	for (temp=0;temp<skb->len;temp++){
-		if (!(temp % 16 )) DEBUGP("\nipv6_header data ");
-		DEBUGP("%02X ",skb->data[temp]);
-	}
-#endif
-	DEBUGP("\nipv6_header h.raw %02X %02X %02X %02X \n",
-			skb->h.raw[0],
-			skb->h.raw[1],
-			skb->h.raw[2],
-			skb->h.raw[3]);
-	DEBUGP("ipv6_header nh.raw %02X %02X %02X %02X \n",
-			skb->nh.raw[0],
-			skb->nh.raw[1],
-			skb->nh.raw[2],
-			skb->nh.raw[3]);
-	DEBUGP("ipv6_header CB %02X %02X %02X %02X %02X %02X %02X \n",
-			opt->iif,
-			opt->ra,
-			opt->hop,
-			opt->auth,
-			opt->dst0,
-			opt->srcrt,
-			opt->dst1);
-
-	temp = 0;
-
         while (ip6t_ext_hdr(nexthdr)) {
         	struct ipv6_opt_hdr *hdr;
         	int hdrlen;
 
-		DEBUGP("ipv6_header header iteration \n");
-
 		/* Is there enough space for the next ext header? */
                 if (len < (int)sizeof(struct ipv6_opt_hdr))
                         return 0;
@@ -114,8 +72,6 @@
                 else
                         hdrlen = ipv6_optlen(hdr);
 
-		DEBUGP("ipv6_header hdrlen %04X \n",hdrlen);
-
 		/* set the flag */
 		switch (nexthdr){
 			case NEXTHDR_HOP:
@@ -134,7 +90,6 @@
 				temp |= MASK_DSTOPTS;
 				break;
 			default:
-				DEBUGP("IPV6HEADER match: unknown nextheader %u\n",nexthdr);
 				return 0;
 				break;
 		}
@@ -142,17 +97,13 @@
                 nexthdr = hdr->nexthdr;
                 len -= hdrlen;
                 ptr += hdrlen;
-		if ( ptr > skb->len ) {
-			DEBUGP("ipv6_header new ptr %04X \n",ptr);
+		if (ptr > skb->len)
 			break;
-		}
         }
 
 	if ( (nexthdr != NEXTHDR_NONE ) && (nexthdr != NEXTHDR_ESP) )
 		temp |= MASK_PROTO;
 
-	DEBUGP ("ipv6header: %02X %02X \n", temp, info->matchflags);
-
 	if (info->modeflag)
 		return (!( (temp & info->matchflags)
 			^ info->matchflags) ^ info->invflags);
@@ -169,11 +120,8 @@
 {
 	/* Check for obvious errors */
 	/* This match is valid in all hooks! */
-	if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_ipv6header_info))) {
-		DEBUGP("ip6t_ipv6header: matchsize != %u\n",
-			 IP6T_ALIGN(sizeof(struct ip6t_ipv6header_info)));
+	if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_ipv6header_info)))
 		return 0;
-	}
 
 	return 1;
 }
diff -urN linux-2.5.69-bk1/net/ipv6/netfilter/ip6t_rt.c linux-2.5.69-bk2/net/ipv6/netfilter/ip6t_rt.c
--- linux-2.5.69-bk1/net/ipv6/netfilter/ip6t_rt.c	2003-05-04 16:53:08.000000000 -0700
+++ linux-2.5.69-bk2/net/ipv6/netfilter/ip6t_rt.c	2003-05-07 04:41:17.000000000 -0700
@@ -130,7 +130,7 @@
        		return 0;
        }
 
-       route=skb->data+ptr;
+       route = (struct ipv6_rt_hdr *) (skb->data + ptr);
 
        DEBUGP("IPv6 RT LEN %u %u ", hdrlen, route->hdrlen);
        DEBUGP("TYPE %04X ", route->type);
diff -urN linux-2.5.69-bk1/net/ipv6/route.c linux-2.5.69-bk2/net/ipv6/route.c
--- linux-2.5.69-bk1/net/ipv6/route.c	2003-05-04 16:53:36.000000000 -0700
+++ linux-2.5.69-bk2/net/ipv6/route.c	2003-05-07 04:41:17.000000000 -0700
@@ -1173,7 +1173,7 @@
 int ip6_pkt_discard(struct sk_buff *skb)
 {
 	IP6_INC_STATS(Ip6OutNoRoutes);
-	icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, skb->dev);
+	icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_NOROUTE, 0, skb->dev);
 	kfree_skb(skb);
 	return 0;
 }
diff -urN linux-2.5.69-bk1/net/ipx/af_ipx.c linux-2.5.69-bk2/net/ipx/af_ipx.c
--- linux-2.5.69-bk1/net/ipx/af_ipx.c	2003-05-04 16:53:02.000000000 -0700
+++ linux-2.5.69-bk2/net/ipx/af_ipx.c	2003-05-07 04:41:17.000000000 -0700
@@ -81,10 +81,10 @@
 
 static struct proto_ops ipx_dgram_ops;
 
-struct ipx_route *ipx_routes;
+LIST_HEAD(ipx_routes);
 rwlock_t ipx_routes_lock = RW_LOCK_UNLOCKED;
 
-struct ipx_interface *ipx_interfaces;
+LIST_HEAD(ipx_interfaces);
 spinlock_t ipx_interfaces_lock = SPIN_LOCK_UNLOCKED;
 
 struct ipx_interface *ipx_primary_net;
@@ -95,11 +95,21 @@
 atomic_t ipx_sock_nr;
 #endif
 
+struct ipx_interface *ipx_interfaces_head(void)
+{
+	struct ipx_interface *rc = NULL;
+
+	if (!list_empty(&ipx_interfaces))
+		rc = list_entry(ipx_interfaces.next,
+				struct ipx_interface, node);
+	return rc;
+}
+
 static void ipxcfg_set_auto_select(char val)
 {
 	ipxcfg_auto_select_primary = val;
 	if (val && !ipx_primary_net)
-		ipx_primary_net = ipx_interfaces;
+		ipx_primary_net = ipx_interfaces_head();
 }
 
 static int ipxcfg_get_config_data(struct ipx_config_data *arg)
@@ -197,17 +207,21 @@
 
 static void ipxitf_clear_primary_net(void)
 {
-	ipx_primary_net = ipxcfg_auto_select_primary ? ipx_interfaces : NULL;
+	ipx_primary_net = NULL;
+	if (ipxcfg_auto_select_primary)
+		ipx_primary_net = ipx_interfaces_head();
 }
 
 static struct ipx_interface *__ipxitf_find_using_phys(struct net_device *dev,
 						      unsigned short datalink)
 {
-	struct ipx_interface *i = ipx_interfaces;
-
-	while (i && (i->if_dev != dev || i->if_dlink_type != datalink))
-		i = i->if_next;
+	struct ipx_interface *i;
 
+	list_for_each_entry(i, &ipx_interfaces, node)
+		if (i->if_dev == dev && i->if_dlink_type == datalink)
+			goto out;
+	i = NULL;
+out:
 	return i;
 }
 
@@ -229,16 +243,20 @@
 	struct ipx_interface *i;
 
 	spin_lock_bh(&ipx_interfaces_lock);
-	if (net)
-		for (i = ipx_interfaces; i && i->if_netnum != net;
-		     i = i->if_next)
-		;
-	else
-		i = ipx_primary_net;
+	if (net) {
+		list_for_each_entry(i, &ipx_interfaces, node)
+			if (i->if_netnum == net)
+				goto hold;
+		i = NULL;
+		goto unlock;
+	}
+
+	i = ipx_primary_net;
 	if (i)
+hold:
 		ipxitf_hold(i);
+unlock:
 	spin_unlock_bh(&ipx_interfaces_lock);
-
 	return i;
 }
 
@@ -342,15 +360,7 @@
 	spin_unlock_bh(&intrfc->if_sklist_lock);
 
 	/* remove this interface from list */
-	if (intrfc == ipx_interfaces)
-		ipx_interfaces = intrfc->if_next;
-	else {
-		struct ipx_interface *i = ipx_interfaces;
-		while (i && i->if_next != intrfc)
-		     i = i->if_next;
-		if (i && i->if_next == intrfc)
-			i->if_next = intrfc->if_next;
-	}
+	list_del(&intrfc->node);
 
 	/* remove this interface from *special* networks */
 	if (intrfc == ipx_primary_net)
@@ -380,16 +390,13 @@
 		goto out;
 
 	spin_lock_bh(&ipx_interfaces_lock);
-	for (i = ipx_interfaces; i;) {
-		tmp = i->if_next;
+	list_for_each_entry_safe(i, tmp, &ipx_interfaces, node)
 		if (i->if_dev == dev) {
 			if (event == NETDEV_UP)
 				ipxitf_hold(i);
 			else
 				__ipxitf_put(i);
 		}
-		i = tmp;
-	}
 	spin_unlock_bh(&ipx_interfaces_lock);
 out:
 	return NOTIFY_DONE;
@@ -872,7 +879,7 @@
 	IPX_SKB_CB(skb)->last_hop.netnum = intrfc->if_netnum;
 	/* xmit on all other interfaces... */
 	spin_lock_bh(&ipx_interfaces_lock);
-	for (ifcs = ipx_interfaces; ifcs; ifcs = ifcs->if_next) {
+	list_for_each_entry(ifcs, &ipx_interfaces, node) {
 		/* Except unconfigured interfaces */
 		if (!ifcs->if_netnum)
 			continue;
@@ -902,16 +909,8 @@
 
 static void ipxitf_insert(struct ipx_interface *intrfc)
 {
-	intrfc->if_next = NULL;
 	spin_lock_bh(&ipx_interfaces_lock);
-	if (!ipx_interfaces)
-		ipx_interfaces = intrfc;
-	else {
-		struct ipx_interface *i = ipx_interfaces;
-		while (i->if_next)
-			i = i->if_next;
-		i->if_next = intrfc;
-	}
+	list_add_tail(&intrfc->node, &ipx_interfaces);
 	spin_unlock_bh(&ipx_interfaces_lock);
 
 	if (ipxcfg_auto_select_primary && !ipx_primary_net)
@@ -1278,12 +1277,14 @@
 	struct ipx_route *r;
 
 	read_lock_bh(&ipx_routes_lock);
-	for (r = ipx_routes; r && r->ir_net != net; r = r->ir_next)
-		;
-	if (r)
-		ipxrtr_hold(r);
+	list_for_each_entry(r, &ipx_routes, node)
+		if (r->ir_net == net) {
+			ipxrtr_hold(r);
+			goto unlock;
+		}
+	r = NULL;
+unlock:
 	read_unlock_bh(&ipx_routes_lock);
-
 	return r;
 }
 
@@ -1306,8 +1307,7 @@
 		atomic_set(&rt->refcnt, 1);
 		ipxrtr_hold(rt);
 		write_lock_bh(&ipx_routes_lock);
-		rt->ir_next	= ipx_routes;
-		ipx_routes	= rt;
+		list_add(&rt->node, &ipx_routes);
 		write_unlock_bh(&ipx_routes_lock);
 	} else {
 		rc = -EEXIST;
@@ -1334,16 +1334,14 @@
 
 static void ipxrtr_del_routes(struct ipx_interface *intrfc)
 {
-	struct ipx_route **r, *tmp;
+	struct ipx_route *r, *tmp;
 
 	write_lock_bh(&ipx_routes_lock);
-	for (r = &ipx_routes; (tmp = *r) != NULL;) {
-		if (tmp->ir_intrfc == intrfc) {
-			*r = tmp->ir_next;
-			ipxrtr_put(tmp);
-		} else
-			r = &(tmp->ir_next);
-	}
+	list_for_each_entry_safe(r, tmp, &ipx_routes, node)
+		if (r->ir_intrfc == intrfc) {
+			list_del(&r->node);
+			ipxrtr_put(r);
+		}
 	write_unlock_bh(&ipx_routes_lock);
 }
 
@@ -1364,26 +1362,21 @@
 
 static int ipxrtr_delete(long net)
 {
-	struct ipx_route **r;
-	struct ipx_route *tmp;
+	struct ipx_route *r, *tmp;
 	int rc;
 
 	write_lock_bh(&ipx_routes_lock);
-	for (r = &ipx_routes; (tmp = *r) != NULL;) {
-		if (tmp->ir_net == net) {
+	list_for_each_entry_safe(r, tmp, &ipx_routes, node)
+		if (r->ir_net == net) {
 			/* Directly connected; can't lose route */
 			rc = -EPERM;
-			if (!tmp->ir_routed)
+			if (!r->ir_routed)
 				goto out;
-
-			*r = tmp->ir_next;
-			ipxrtr_put(tmp);
+			list_del(&r->node);
+			ipxrtr_put(r);
 			rc = 0;
 			goto out;
 		}
-
-		r = &(tmp->ir_next);
-	}
 	rc = -ENOENT;
 out:
 	write_unlock_bh(&ipx_routes_lock);
diff -urN linux-2.5.69-bk1/net/ipx/ipx_proc.c linux-2.5.69-bk2/net/ipx/ipx_proc.c
--- linux-2.5.69-bk1/net/ipx/ipx_proc.c	2003-05-04 16:52:48.000000000 -0700
+++ linux-2.5.69-bk2/net/ipx/ipx_proc.c	2003-05-07 04:41:17.000000000 -0700
@@ -17,12 +17,23 @@
 {
 	struct ipx_interface *i;
 
-	for (i = ipx_interfaces; pos && i; i = i->if_next)
-		--pos;
-
+	list_for_each_entry(i, &ipx_interfaces, node)
+		if (!pos--)
+			goto out;
+	i = NULL;
+out:
 	return i;
 }
 
+static struct ipx_interface *ipx_interfaces_next(struct ipx_interface *i)
+{
+	struct ipx_interface *rc = NULL;
+
+	if (i->node.next != &ipx_interfaces)
+		rc = list_entry(i->node.next, struct ipx_interface, node);
+	return rc;
+}
+
 static void *ipx_seq_interface_start(struct seq_file *seq, loff_t *pos)
 {
 	loff_t l = *pos;
@@ -36,15 +47,10 @@
 	struct ipx_interface *i;
 
 	++*pos;
-	if (v == (void *)1) {
-		i = NULL;
-		if (ipx_interfaces)
-			i = ipx_interfaces;
-		goto out;
-	}
-	i = v;
-	i = i->if_next;
-out:
+	if (v == (void *)1)
+		i = ipx_interfaces_head();
+	else
+		i = ipx_interfaces_next(v);
 	return i;
 }
 
@@ -83,13 +89,33 @@
 	return 0;
 }
 
+static struct ipx_route *ipx_routes_head(void)
+{
+	struct ipx_route *rc = NULL;
+
+	if (!list_empty(&ipx_routes))
+		rc = list_entry(ipx_routes.next, struct ipx_route, node);
+	return rc;
+}
+
+static struct ipx_route *ipx_routes_next(struct ipx_route *r)
+{
+	struct ipx_route *rc = NULL;
+
+	if (r->node.next != &ipx_routes)
+		rc = list_entry(r->node.next, struct ipx_route, node);
+	return rc;
+}
+
 static __inline__ struct ipx_route *ipx_get_route_idx(loff_t pos)
 {
 	struct ipx_route *r;
 
-	for (r = ipx_routes; pos && r; r = r->ir_next)
-		--pos;
-
+	list_for_each_entry(r, &ipx_routes, node)
+		if (!pos--)
+			goto out;
+	r = NULL;
+out:
 	return r;
 }
 
@@ -105,15 +131,10 @@
 	struct ipx_route *r;
 
 	++*pos;
-	if (v == (void *)1) {
-		r = NULL;
-		if (ipx_routes)
-			r = ipx_routes;
-		goto out;
-	}
-	r = v;
-	r = r->ir_next;
-out:
+	if (v == (void *)1)
+		r = ipx_routes_head();
+	else
+		r = ipx_routes_next(v);
 	return r;
 }
 
@@ -149,7 +170,9 @@
 	struct sock *s = NULL;
 	struct ipx_interface *i;
 
-	for (i = ipx_interfaces; pos && i; i = i->if_next) {
+	list_for_each_entry(i, &ipx_interfaces, node) {
+		if (!pos)
+			break;
 		spin_lock_bh(&i->if_sklist_lock);
 		for (s = i->if_sklist; pos && s; s = s->next)
 			--pos;
@@ -181,11 +204,12 @@
 	++*pos;
 	if (v == (void *)1) {
 		sk = NULL;
-		if (!ipx_interfaces)
+		i = ipx_interfaces_head();
+		if (!i)
 			goto out;
-		sk = ipx_interfaces->if_sklist;
+		sk = i->if_sklist;
 		if (sk)
-			spin_lock_bh(&ipx_interfaces->if_sklist_lock);
+			spin_lock_bh(&i->if_sklist_lock);
 		goto out;
 	}
 	sk = v;
@@ -198,9 +222,9 @@
 	spin_unlock_bh(&i->if_sklist_lock);
 	sk = NULL;
 	for (;;) {
-		if (!i->if_next)
+		i = ipx_interfaces_next(i);
+		if (!i)
 			break;
-		i = i->if_next;
 		spin_lock_bh(&i->if_sklist_lock);
 		if (i->if_sklist) {
 			sk = i->if_sklist;
