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

diff -urN linux-2.5.66-bk10/Makefile linux-2.5.66-bk11/Makefile
--- linux-2.5.66-bk10/Makefile	2003-04-05 04:32:12.000000000 -0800
+++ linux-2.5.66-bk11/Makefile	2003-04-05 04:32:16.000000000 -0800
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 5
 SUBLEVEL = 66
-EXTRAVERSION = -bk10
+EXTRAVERSION = -bk11
 
 # *DOCUMENTATION*
 # To see a list of typical targets execute "make help"
diff -urN linux-2.5.66-bk10/README linux-2.5.66-bk11/README
--- linux-2.5.66-bk10/README	2003-03-24 14:01:24.000000000 -0800
+++ linux-2.5.66-bk11/README	2003-04-05 04:32:16.000000000 -0800
@@ -123,7 +123,8 @@
 
  - Alternate configuration commands are:
 	"make menuconfig"  Text based color menus, radiolists & dialogs.
-	"make xconfig"     X windows based configuration tool.
+	"make xconfig"     X windows (Qt) based configuration tool.
+	"make gconfig"     X windows (Gtk) based configuration tool.
 	"make oldconfig"   Default all questions based on the contents of
 			   your existing ./.config file.
    
diff -urN linux-2.5.66-bk10/arch/alpha/oprofile/common.c linux-2.5.66-bk11/arch/alpha/oprofile/common.c
--- linux-2.5.66-bk10/arch/alpha/oprofile/common.c	2003-03-24 14:00:00.000000000 -0800
+++ linux-2.5.66-bk11/arch/alpha/oprofile/common.c	2003-04-05 04:32:16.000000000 -0800
@@ -186,3 +186,9 @@
 
 	return 0;
 }
+
+
+void __exit
+oprofile_arch_exit(void)
+{
+}
diff -urN linux-2.5.66-bk10/arch/i386/Makefile linux-2.5.66-bk11/arch/i386/Makefile
--- linux-2.5.66-bk10/arch/i386/Makefile	2003-03-24 14:00:16.000000000 -0800
+++ linux-2.5.66-bk11/arch/i386/Makefile	2003-04-05 04:32:16.000000000 -0800
@@ -84,7 +84,7 @@
 					   arch/i386/$(mcore-y)/
 drivers-$(CONFIG_MATH_EMULATION)	+= arch/i386/math-emu/
 drivers-$(CONFIG_PCI)			+= arch/i386/pci/
-# FIXME: is drivers- right ?
+# must be linked after kernel/
 drivers-$(CONFIG_OPROFILE)		+= arch/i386/oprofile/
 
 CFLAGS += $(mflags-y)
diff -urN linux-2.5.66-bk10/arch/i386/kernel/smp.c linux-2.5.66-bk11/arch/i386/kernel/smp.c
--- linux-2.5.66-bk10/arch/i386/kernel/smp.c	2003-03-24 14:00:00.000000000 -0800
+++ linux-2.5.66-bk11/arch/i386/kernel/smp.c	2003-04-05 04:32:16.000000000 -0800
@@ -522,7 +522,8 @@
 
 	spin_lock(&call_lock);
 	call_data = &data;
-	wmb();
+	mb();
+	
 	/* Send a message to all other CPUs and wait for them to respond */
 	send_IPI_allbutself(CALL_FUNCTION_VECTOR);
 
diff -urN linux-2.5.66-bk10/arch/i386/kernel/sys_i386.c linux-2.5.66-bk11/arch/i386/kernel/sys_i386.c
--- linux-2.5.66-bk10/arch/i386/kernel/sys_i386.c	2003-03-24 14:01:46.000000000 -0800
+++ linux-2.5.66-bk11/arch/i386/kernel/sys_i386.c	2003-04-05 04:32:16.000000000 -0800
@@ -204,7 +204,7 @@
 		return sys_shmctl (first, second,
 				   (struct shmid_ds *) ptr);
 	default:
-		return -EINVAL;
+		return -ENOSYS;
 	}
 }
 
diff -urN linux-2.5.66-bk10/arch/i386/mach-visws/mpparse.c linux-2.5.66-bk11/arch/i386/mach-visws/mpparse.c
--- linux-2.5.66-bk10/arch/i386/mach-visws/mpparse.c	2003-03-24 14:00:10.000000000 -0800
+++ linux-2.5.66-bk11/arch/i386/mach-visws/mpparse.c	2003-04-05 04:32:16.000000000 -0800
@@ -4,8 +4,6 @@
 #include <linux/smp.h>
 
 #include <asm/smp.h>
-#include <asm/apic.h>
-#include <asm/mpspec.h>
 #include <asm/io.h>
 
 #include "cobalt.h"
@@ -19,21 +17,6 @@
  * MP-table.
  */
 int apic_version [MAX_APICS];
-int mp_bus_id_to_type [MAX_MP_BUSSES];
-int mp_bus_id_to_node [MAX_MP_BUSSES];
-int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 };
-int mp_current_pci_id;
-
-/* I/O APIC entries */
-struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS];
-
-/* # of MP IRQ source entries */
-struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES];
-
-/* MP IRQ source entries */
-int mp_irq_entries;
-
-int nr_ioapics;
 
 int pic_mode;
 unsigned long mp_lapic_addr;
@@ -42,13 +25,9 @@
 unsigned int boot_cpu_physical_apicid = -1U;
 unsigned int boot_cpu_logical_apicid = -1U;
 
-/* Internal processor count */
-static unsigned int num_processors;
-
 /* Bitmask of physically existing CPUs */
 unsigned long phys_cpu_present_map;
 
-u8 raw_phys_apicid[NR_CPUS] = { [0 ... NR_CPUS - 1] = BAD_APICID };
 
 /*
  * The Visual Workstation is Intel MP compliant in the hardware
@@ -76,12 +55,9 @@
 		boot_cpu_logical_apicid = logical_apicid;
 	}
 
-	num_processors++;
-
 	if (m->mpc_apicid > MAX_APICS) {
 		printk(KERN_ERR "Processor #%d INVALID. (Max ID: %d).\n",
 			m->mpc_apicid, MAX_APICS);
-		--num_processors;
 		return;
 	}
 	ver = m->mpc_apicver;
@@ -97,7 +73,6 @@
 		ver = 0x10;
 	}
 	apic_version[m->mpc_apicid] = ver;
-	raw_phys_apicid[num_processors - 1] = m->mpc_apicid;
 }
 
 void __init find_smp_config(void)
diff -urN linux-2.5.66-bk10/arch/i386/oprofile/init.c linux-2.5.66-bk11/arch/i386/oprofile/init.c
--- linux-2.5.66-bk10/arch/i386/oprofile/init.c	2003-03-24 14:00:48.000000000 -0800
+++ linux-2.5.66-bk11/arch/i386/oprofile/init.c	2003-04-05 04:32:16.000000000 -0800
@@ -17,6 +17,7 @@
  */
  
 extern int nmi_init(struct oprofile_operations ** ops);
+extern void nmi_exit(void);
 extern void timer_init(struct oprofile_operations ** ops);
 
 int __init oprofile_arch_init(struct oprofile_operations ** ops)
@@ -27,3 +28,11 @@
 		timer_init(ops);
 	return 0;
 }
+
+
+void __exit oprofile_arch_exit(void)
+{
+#ifdef CONFIG_X86_LOCAL_APIC
+	nmi_exit();
+#endif
+}
diff -urN linux-2.5.66-bk10/arch/i386/oprofile/nmi_int.c linux-2.5.66-bk11/arch/i386/oprofile/nmi_int.c
--- linux-2.5.66-bk10/arch/i386/oprofile/nmi_int.c	2003-04-05 04:32:12.000000000 -0800
+++ linux-2.5.66-bk11/arch/i386/oprofile/nmi_int.c	2003-04-05 04:32:16.000000000 -0800
@@ -67,15 +67,22 @@
 };
 
 
-static int __init init_nmi_driverfs(void)
+static int __init init_driverfs(void)
 {
 	driver_register(&nmi_driver);
 	return device_register(&device_nmi);
 }
 
 
-late_initcall(init_nmi_driverfs);
+static void __exit exit_driverfs(void)
+{
+	device_unregister(&device_nmi);
+	driver_unregister(&nmi_driver);
+}
 
+#else
+#define init_driverfs() do { } while (0)
+#define exit_driverfs() do { } while (0)
 #endif /* CONFIG_PM */
 
 
@@ -297,6 +304,10 @@
 
 #endif /* !CONFIG_X86_64 */
  
+
+/* in order to get driverfs right */
+static int using_nmi;
+
 int __init nmi_init(struct oprofile_operations ** ops)
 {
 	__u8 vendor = current_cpu_data.x86_vendor;
@@ -339,7 +350,16 @@
 			return 0;
 	}
 
+	init_driverfs();
+	using_nmi = 1;
 	*ops = &nmi_ops;
 	printk(KERN_INFO "oprofile: using NMI interrupt.\n");
 	return 1;
 }
+
+
+void __exit nmi_exit(void)
+{
+	if (using_nmi)
+		exit_driverfs();
+}
diff -urN linux-2.5.66-bk10/arch/parisc/oprofile/init.c linux-2.5.66-bk11/arch/parisc/oprofile/init.c
--- linux-2.5.66-bk10/arch/parisc/oprofile/init.c	2003-03-24 14:00:38.000000000 -0800
+++ linux-2.5.66-bk11/arch/parisc/oprofile/init.c	2003-04-05 04:32:16.000000000 -0800
@@ -18,3 +18,8 @@
 	timer_init(ops);
 	return 0;
 }
+
+
+void __exit oprofile_arch_exit()
+{
+}
diff -urN linux-2.5.66-bk10/arch/ppc64/oprofile/init.c linux-2.5.66-bk11/arch/ppc64/oprofile/init.c
--- linux-2.5.66-bk10/arch/ppc64/oprofile/init.c	2003-03-24 14:00:48.000000000 -0800
+++ linux-2.5.66-bk11/arch/ppc64/oprofile/init.c	2003-04-05 04:32:16.000000000 -0800
@@ -18,3 +18,8 @@
 	timer_init(ops);
 	return 0;
 }
+
+
+void __exit oprofile_arch_exit(void)
+{
+}
diff -urN linux-2.5.66-bk10/arch/sparc/kernel/module.c linux-2.5.66-bk11/arch/sparc/kernel/module.c
--- linux-2.5.66-bk10/arch/sparc/kernel/module.c	2003-03-24 13:59:53.000000000 -0800
+++ linux-2.5.66-bk11/arch/sparc/kernel/module.c	2003-04-05 04:32:16.000000000 -0800
@@ -36,12 +36,31 @@
            table entries. */
 }
 
-/* We don't need anything special. */
+/* Make generic code ignore STT_REGISTER dummy undefined symbols.  */
 int module_frob_arch_sections(Elf_Ehdr *hdr,
 			      Elf_Shdr *sechdrs,
 			      char *secstrings,
 			      struct module *mod)
 {
+	unsigned int symidx;
+	Elf32_Sym *sym;
+	const char *strtab;
+	int i;
+
+	for (symidx = 0; sechdrs[symidx].sh_type != SHT_SYMTAB; symidx++) {
+		if (symidx == hdr->e_shnum-1) {
+			printk("%s: no symtab found.\n", mod->name);
+			return -ENOEXEC;
+		}
+	}
+	sym = (Elf32_Sym *)sechdrs[symidx].sh_addr;
+	strtab = (char *)sechdrs[sechdrs[symidx].sh_link].sh_addr;
+
+	for (i = 1; i < sechdrs[symidx].sh_size / sizeof(Elf_Sym); i++) {
+		if (sym[i].st_shndx == SHN_UNDEF &&
+		    ELF32_ST_TYPE(sym[i].st_info) == STT_REGISTER)
+			sym[i].st_shndx = SHN_ABS;
+	}
 	return 0;
 }
 
diff -urN linux-2.5.66-bk10/arch/sparc64/kernel/module.c linux-2.5.66-bk11/arch/sparc64/kernel/module.c
--- linux-2.5.66-bk10/arch/sparc64/kernel/module.c	2003-04-05 04:32:12.000000000 -0800
+++ linux-2.5.66-bk11/arch/sparc64/kernel/module.c	2003-04-05 04:32:16.000000000 -0800
@@ -143,12 +143,31 @@
            table entries. */
 }
 
-/* We don't need anything special. */
+/* Make generic code ignore STT_REGISTER dummy undefined symbols.  */
 int module_frob_arch_sections(Elf_Ehdr *hdr,
 			      Elf_Shdr *sechdrs,
 			      char *secstrings,
 			      struct module *mod)
 {
+	unsigned int symidx;
+	Elf64_Sym *sym;
+	const char *strtab;
+	int i;
+
+	for (symidx = 0; sechdrs[symidx].sh_type != SHT_SYMTAB; symidx++) {
+		if (symidx == hdr->e_shnum-1) {
+			printk("%s: no symtab found.\n", mod->name);
+			return -ENOEXEC;
+		}
+	}
+	sym = (Elf64_Sym *)sechdrs[symidx].sh_addr;
+	strtab = (char *)sechdrs[sechdrs[symidx].sh_link].sh_addr;
+
+	for (i = 1; i < sechdrs[symidx].sh_size / sizeof(Elf_Sym); i++) {
+		if (sym[i].st_shndx == SHN_UNDEF &&
+		    ELF64_ST_TYPE(sym[i].st_info) == STT_REGISTER)
+			sym[i].st_shndx = SHN_ABS;
+	}
 	return 0;
 }
 
diff -urN linux-2.5.66-bk10/arch/sparc64/oprofile/init.c linux-2.5.66-bk11/arch/sparc64/oprofile/init.c
--- linux-2.5.66-bk10/arch/sparc64/oprofile/init.c	2003-03-24 14:00:50.000000000 -0800
+++ linux-2.5.66-bk11/arch/sparc64/oprofile/init.c	2003-04-05 04:32:16.000000000 -0800
@@ -18,3 +18,8 @@
 	timer_init(ops);
 	return 0;
 }
+
+
+void __exit oprofile_arch_exit(void)
+{
+}
diff -urN linux-2.5.66-bk10/drivers/acpi/osl.c linux-2.5.66-bk11/drivers/acpi/osl.c
--- linux-2.5.66-bk10/drivers/acpi/osl.c	2003-04-05 04:32:12.000000000 -0800
+++ linux-2.5.66-bk11/drivers/acpi/osl.c	2003-04-05 04:32:16.000000000 -0800
@@ -736,7 +736,7 @@
 	if (flags & ACPI_NOT_ISR)
 		ACPI_DISABLE_IRQS();
 
-	spin_lock(handle);
+	spin_lock((spinlock_t *)handle);
 
 	return_VOID;
 }
@@ -755,7 +755,7 @@
 	ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Releasing spinlock[%p] from %s level\n", handle,
 		((flags & ACPI_NOT_ISR) ? "non-interrupt" : "interrupt")));
 
-	spin_unlock(handle);
+	spin_unlock((spinlock_t *)handle);
 
 	if (flags & ACPI_NOT_ISR)
 		ACPI_ENABLE_IRQS();
diff -urN linux-2.5.66-bk10/drivers/char/ipmi/ipmi_kcs_intf.c linux-2.5.66-bk11/drivers/char/ipmi/ipmi_kcs_intf.c
--- linux-2.5.66-bk10/drivers/char/ipmi/ipmi_kcs_intf.c	2003-04-05 04:32:12.000000000 -0800
+++ linux-2.5.66-bk11/drivers/char/ipmi/ipmi_kcs_intf.c	2003-04-05 04:32:16.000000000 -0800
@@ -61,6 +61,14 @@
 /* Measure times between events in the driver. */
 #undef DEBUG_TIMING
 
+/* Timing parameters.  Call every 10 ms when not doing anything,
+   otherwise call every KCS_SHORT_TIMEOUT_USEC microseconds. */
+#define KCS_TIMEOUT_TIME_USEC	10000
+#define KCS_USEC_PER_JIFFY	(1000000/HZ)
+#define KCS_TIMEOUT_JIFFIES	(KCS_TIMEOUT_TIME_USEC/KCS_USEC_PER_JIFFY)
+#define KCS_SHORT_TIMEOUT_USEC  250 /* .25ms when the SM request a
+                                       short timeout */
+
 #ifdef CONFIG_IPMI_KCS
 /* This forces a dependency to the config file for this option. */
 #endif
@@ -132,6 +140,8 @@
 	int                 interrupt_disabled;
 };
 
+static void kcs_restart_short_timer(struct kcs_info *kcs_info);
+
 static void deliver_recv_msg(struct kcs_info *kcs_info, struct ipmi_smi_msg *msg)
 {
 	/* Deliver the message to the upper layer with the lock
@@ -309,6 +319,9 @@
 #endif
 	switch (kcs_info->kcs_state) {
 	case KCS_NORMAL:
+		if (!kcs_info->curr_msg)
+			break;
+			
 		kcs_info->curr_msg->rsp_size
 			= kcs_get_result(kcs_info->kcs_sm,
 					 kcs_info->curr_msg->rsp,
@@ -563,8 +576,9 @@
 		spin_lock_irqsave(&(kcs_info->kcs_lock), flags);
 		result = kcs_event_handler(kcs_info, 0);
 		while (result != KCS_SM_IDLE) {
-			udelay(500);
-			result = kcs_event_handler(kcs_info, 500);
+			udelay(KCS_SHORT_TIMEOUT_USEC);
+			result = kcs_event_handler(kcs_info,
+						   KCS_SHORT_TIMEOUT_USEC);
 		}
 		spin_unlock_irqrestore(&(kcs_info->kcs_lock), flags);
 		return;
@@ -582,6 +596,7 @@
 	    && (kcs_info->curr_msg == NULL))
 	{
 		start_next_msg(kcs_info);
+		kcs_restart_short_timer(kcs_info);
 	}
 	spin_unlock_irqrestore(&(kcs_info->kcs_lock), flags);
 }
@@ -598,8 +613,9 @@
 	if (i_run_to_completion) {
 		result = kcs_event_handler(kcs_info, 0);
 		while (result != KCS_SM_IDLE) {
-			udelay(500);
-			result = kcs_event_handler(kcs_info, 500);
+			udelay(KCS_SHORT_TIMEOUT_USEC);
+			result = kcs_event_handler(kcs_info,
+						   KCS_SHORT_TIMEOUT_USEC);
 		}
 	}
 
@@ -613,14 +629,42 @@
 	atomic_set(&kcs_info->req_events, 1);
 }
 
-/* Call every 10 ms. */
-#define KCS_TIMEOUT_TIME_USEC	10000
-#define KCS_USEC_PER_JIFFY	(1000000/HZ)
-#define KCS_TIMEOUT_JIFFIES	(KCS_TIMEOUT_TIME_USEC/KCS_USEC_PER_JIFFY)
-#define KCS_SHORT_TIMEOUT_USEC  500 /* .5ms when the SM request a
-                                       short timeout */
 static int initialized = 0;
 
+/* Must be called with interrupts off and with the kcs_lock held. */
+static void kcs_restart_short_timer(struct kcs_info *kcs_info)
+{
+	if (del_timer(&(kcs_info->kcs_timer))) {
+#ifdef CONFIG_HIGH_RES_TIMERS
+		unsigned long jiffies_now;
+
+		/* If we don't delete the timer, then it will go off
+		   immediately, anyway.  So we only process if we
+		   actually delete the timer. */
+
+		/* We already have irqsave on, so no need for it
+                   here. */
+		read_lock(&xtime_lock);
+		jiffies_now = jiffies;
+		kcs_info->kcs_timer.expires = jiffies_now;
+
+		kcs_info->kcs_timer.sub_expires
+			= quick_update_jiffies_sub(jiffies_now);
+		read_unlock(&xtime_lock);
+
+		kcs_info->kcs_timer.sub_expires
+			+= usec_to_arch_cycles(KCS_SHORT_TIMEOUT_USEC);
+		while (kcs_info->kcs_timer.sub_expires >= cycles_per_jiffies) {
+			kcs_info->kcs_timer.expires++;
+			kcs_info->kcs_timer.sub_expires -= cycles_per_jiffies;
+		}
+#else
+		kcs_info->kcs_timer.expires = jiffies + 1;
+#endif
+		add_timer(&(kcs_info->kcs_timer));
+	}
+}
+
 static void kcs_timeout(unsigned long data)
 {
 	struct kcs_info *kcs_info = (struct kcs_info *) data;
@@ -643,12 +687,11 @@
 	printk("**Timer: %d.%9.9d\n", t.tv_sec, t.tv_usec);
 #endif
 	jiffies_now = jiffies;
+
 	time_diff = ((jiffies_now - kcs_info->last_timeout_jiffies)
 		     * KCS_USEC_PER_JIFFY);
 	kcs_result = kcs_event_handler(kcs_info, time_diff);
 
-	spin_unlock_irqrestore(&(kcs_info->kcs_lock), flags);
-
 	kcs_info->last_timeout_jiffies = jiffies_now;
 
 	if ((kcs_info->irq) && (! kcs_info->interrupt_disabled)) {
@@ -669,6 +712,7 @@
 		}
 	} else {
 		kcs_info->kcs_timer.expires = jiffies + KCS_TIMEOUT_JIFFIES;
+		kcs_info->kcs_timer.sub_expires = 0;
 	}
 #else
 	/* If requested, take the shortest delay possible */
@@ -681,6 +725,7 @@
 
  do_add_timer:
 	add_timer(&(kcs_info->kcs_timer));
+	spin_unlock_irqrestore(&(kcs_info->kcs_lock), flags);
 }
 
 static void kcs_irq_handler(int irq, void *data, struct pt_regs *regs)
diff -urN linux-2.5.66-bk10/drivers/char/ipmi/ipmi_msghandler.c linux-2.5.66-bk11/drivers/char/ipmi/ipmi_msghandler.c
--- linux-2.5.66-bk10/drivers/char/ipmi/ipmi_msghandler.c	2003-03-24 14:00:45.000000000 -0800
+++ linux-2.5.66-bk11/drivers/char/ipmi/ipmi_msghandler.c	2003-04-05 04:32:16.000000000 -0800
@@ -1765,9 +1765,13 @@
 }
 
 
+static atomic_t smi_msg_inuse_count = ATOMIC_INIT(0);
+static atomic_t recv_msg_inuse_count = ATOMIC_INIT(0);
+
 /* FIXME - convert these to slabs. */
 static void free_smi_msg(struct ipmi_smi_msg *msg)
 {
+	atomic_dec(&smi_msg_inuse_count);
 	kfree(msg);
 }
 
@@ -1775,13 +1779,16 @@
 {
 	struct ipmi_smi_msg *rv;
 	rv = kmalloc(sizeof(struct ipmi_smi_msg), GFP_ATOMIC);
-	if (rv)
+	if (rv) {
 		rv->done = free_smi_msg;
+		atomic_inc(&smi_msg_inuse_count);
+	}
 	return rv;
 }
 
 static void free_recv_msg(struct ipmi_recv_msg *msg)
 {
+	atomic_dec(&recv_msg_inuse_count);
 	kfree(msg);
 }
 
@@ -1790,8 +1797,10 @@
 	struct ipmi_recv_msg *rv;
 
 	rv = kmalloc(sizeof(struct ipmi_recv_msg), GFP_ATOMIC);
-	if (rv)
+	if (rv) {
 		rv->done = free_recv_msg;
+		atomic_inc(&recv_msg_inuse_count);
+	}
 	return rv;
 }
 
@@ -1924,6 +1933,8 @@
 
 static __exit void cleanup_ipmi(void)
 {
+	int count;
+
 	if (!initialized)
 		return;
 
@@ -1940,6 +1951,16 @@
 	}
 
 	initialized = 0;
+
+	/* Check for buffer leaks. */
+	count = atomic_read(&smi_msg_inuse_count);
+	if (count != 0)
+		printk("ipmi_msghandler: SMI message count %d at exit\n",
+		       count);
+	count = atomic_read(&recv_msg_inuse_count);
+	if (count != 0)
+		printk("ipmi_msghandler: recv message count %d at exit\n",
+		       count);
 }
 module_exit(cleanup_ipmi);
 
diff -urN linux-2.5.66-bk10/drivers/char/tty_io.c linux-2.5.66-bk11/drivers/char/tty_io.c
--- linux-2.5.66-bk10/drivers/char/tty_io.c	2003-04-05 04:32:12.000000000 -0800
+++ linux-2.5.66-bk11/drivers/char/tty_io.c	2003-04-05 04:32:16.000000000 -0800
@@ -506,8 +506,8 @@
 				p->tty = NULL;
 			if (!p->leader)
 				continue;
-			send_sig(SIGHUP, p, 1);
-			send_sig(SIGCONT, p, 1);
+			send_group_sig_info(SIGHUP, SEND_SIG_PRIV, p);
+			send_group_sig_info(SIGCONT, SEND_SIG_PRIV, p);
 			if (tty->pgrp > 0)
 				p->tty_old_pgrp = tty->pgrp;
 		}
diff -urN linux-2.5.66-bk10/drivers/isdn/hisax/hisax_fcpcipnp.c linux-2.5.66-bk11/drivers/isdn/hisax/hisax_fcpcipnp.c
--- linux-2.5.66-bk10/drivers/isdn/hisax/hisax_fcpcipnp.c	2003-03-24 14:01:14.000000000 -0800
+++ linux-2.5.66-bk11/drivers/isdn/hisax/hisax_fcpcipnp.c	2003-04-05 04:32:16.000000000 -0800
@@ -909,7 +909,7 @@
 #ifdef CONFIG_PNP_CARD
 
 static int __devinit fcpnp_probe(struct pnp_card *card,
-				 const struct pnp_card_id *card_id)
+				 const struct pnp_card_device_id *card_id)
 {
 	struct fritz_adapter *adapter;
 	struct pnp_dev *pnp_dev;
@@ -955,7 +955,7 @@
 	delete_adapter(adapter);
 }
 
-static struct pnp_card_id fcpnp_ids[] __devinitdata = {
+static struct pnp_card_device_id fcpnp_ids[] __devinitdata = {
 	{ .id          = "AVM0900", 
 	  .driver_data = (unsigned long) "Fritz!Card PnP",
 	  .devs        = { { "AVM0900" } },
diff -urN linux-2.5.66-bk10/drivers/isdn/i4l/isdn_tty.c linux-2.5.66-bk11/drivers/isdn/i4l/isdn_tty.c
--- linux-2.5.66-bk10/drivers/isdn/i4l/isdn_tty.c	2003-03-24 14:01:12.000000000 -0800
+++ linux-2.5.66-bk11/drivers/isdn/i4l/isdn_tty.c	2003-04-05 04:32:16.000000000 -0800
@@ -2036,7 +2036,7 @@
 	memcpy(m->pmsn, m->msn, ISDN_MSNLEN);
 	memcpy(m->plmsn, m->lmsn, ISDN_LMSNLEN);
 	if (dev->profd)
-		send_sig(SIGIO, dev->profd, 1);
+		group_send_sig_info(SIGIO, SEND_SIG_PRIV, dev->profd);
 }
 
 int
diff -urN linux-2.5.66-bk10/drivers/oprofile/buffer_sync.c linux-2.5.66-bk11/drivers/oprofile/buffer_sync.c
--- linux-2.5.66-bk10/drivers/oprofile/buffer_sync.c	2003-04-05 04:32:12.000000000 -0800
+++ linux-2.5.66-bk11/drivers/oprofile/buffer_sync.c	2003-04-05 04:32:16.000000000 -0800
@@ -68,8 +68,12 @@
 }
 
  
+/* We need to be told about new modules so we don't attribute to a previously
+ * loaded module, or drop the samples on the floor.
+ */
 static int module_load_notify(struct notifier_block * self, unsigned long val, void * data)
 {
+#ifdef CONFIG_MODULES
 	if (val != MODULE_STATE_COMING)
 		return 0;
 
@@ -78,9 +82,11 @@
 	add_event_entry(ESCAPE_CODE);
 	add_event_entry(MODULE_LOADED_CODE);
 	up(&buffer_sem);
+#endif
 	return 0;
 }
 
+ 
 static struct notifier_block exit_task_nb = {
 	.notifier_call	= exit_task_notify,
 };
@@ -92,7 +98,7 @@
 static struct notifier_block exit_mmap_nb = {
 	.notifier_call	= mm_notify,
 };
- 
+
 static struct notifier_block module_load_nb = {
 	.notifier_call = module_load_notify,
 };
diff -urN linux-2.5.66-bk10/drivers/oprofile/oprof.c linux-2.5.66-bk11/drivers/oprofile/oprof.c
--- linux-2.5.66-bk10/drivers/oprofile/oprof.c	2003-03-24 14:00:10.000000000 -0800
+++ linux-2.5.66-bk11/drivers/oprofile/oprof.c	2003-04-05 04:32:16.000000000 -0800
@@ -148,6 +148,7 @@
 static void __exit oprofile_exit(void)
 {
 	oprofilefs_unregister();
+	oprofile_arch_exit();
 }
 
  
diff -urN linux-2.5.66-bk10/drivers/pnp/card.c linux-2.5.66-bk11/drivers/pnp/card.c
--- linux-2.5.66-bk10/drivers/pnp/card.c	2003-03-24 14:01:43.000000000 -0800
+++ linux-2.5.66-bk11/drivers/pnp/card.c	2003-04-05 04:32:16.000000000 -0800
@@ -19,11 +19,12 @@
 #include "base.h"
 
 LIST_HEAD(pnp_cards);
+LIST_HEAD(pnp_card_drivers);
 
 
-static const struct pnp_card_id * match_card(struct pnp_card_driver * drv, struct pnp_card * card)
+static const struct pnp_card_device_id * match_card(struct pnp_card_driver * drv, struct pnp_card * card)
 {
-	const struct pnp_card_id * drv_id = drv->id_table;
+	const struct pnp_card_device_id * drv_id = drv->id_table;
 	while (*drv_id->id){
 		if (compare_pnp_id(card->id,drv_id->id))
 			return drv_id;
@@ -32,21 +33,41 @@
 	return NULL;
 }
 
-static void generic_card_remove(struct pnp_dev * dev)
+static void card_remove(struct pnp_dev * dev)
 {
 	dev->card_link = NULL;
 }
-
-static void generic_card_remove_first(struct pnp_dev * dev)
+ 
+static void card_remove_first(struct pnp_dev * dev)
 {
 	struct pnp_card_driver * drv = to_pnp_card_driver(dev->driver);
 	if (!dev->card || !drv)
 		return;
 	if (drv->remove)
 		drv->remove(dev->card_link);
-	drv->link.remove = &generic_card_remove;
+	drv->link.remove = &card_remove;
 	kfree(dev->card_link);
-	generic_card_remove(dev);
+	card_remove(dev);
+}
+
+static int card_probe(struct pnp_card * card, struct pnp_card_driver * drv)
+{
+	const struct pnp_card_device_id *id = match_card(drv,card);
+	if (id) {
+		struct pnp_card_link * clink = pnp_alloc(sizeof(struct pnp_card_link));
+		if (!clink)
+			return 0;
+		clink->card = card;
+		clink->driver = drv;
+		if (drv->probe) {
+			if (drv->probe(clink, id)>=0)
+				return 1;
+			else
+				kfree(clink);
+		} else
+			return 1;
+	}
+	return 0;
 }
 
 /**
@@ -103,7 +124,7 @@
 int pnp_add_card(struct pnp_card * card)
 {
 	int error;
-	struct list_head * pos;
+	struct list_head * pos, * temp;
 	if (!card || !card->protocol)
 		return -EINVAL;
 
@@ -112,6 +133,7 @@
 	card->dev.bus = NULL;
 	card->dev.release = &pnp_release_card;
 	error = device_register(&card->dev);
+
 	if (error == 0) {
 		spin_lock(&pnp_lock);
 		list_add_tail(&card->global_list, &pnp_cards);
@@ -125,6 +147,12 @@
 			struct pnp_dev *dev = card_to_pnp_dev(pos);
 			__pnp_add_device(dev);
 		}
+
+		/* match with card drivers */
+		list_for_each_safe(pos,temp,&pnp_card_drivers){
+			struct pnp_card_driver * drv = list_entry(pos, struct pnp_card_driver, global_list);
+			card_probe(card,drv);
+		}
 	} else
 		pnp_err("sysfs failure, card '%s' will be unavailable", card->dev.bus_id);
 	return error;
@@ -248,9 +276,9 @@
 	if (!drv)
 		return;
 	down_write(&dev->dev.bus->subsys.rwsem);
-	drv->link.remove = &generic_card_remove;
+	drv->link.remove = &card_remove;
 	device_release_driver(&dev->dev);
-	drv->link.remove = &generic_card_remove_first;
+	drv->link.remove = &card_remove_first;
 	up_write(&dev->dev.bus->subsys.rwsem);
 }
 
@@ -268,25 +296,16 @@
 	drv->link.id_table = NULL;	/* this will disable auto matching */
 	drv->link.flags = drv->flags;
 	drv->link.probe = NULL;
-	drv->link.remove = &generic_card_remove_first;
+	drv->link.remove = &card_remove_first;
 
+	spin_lock(&pnp_lock);
+	list_add_tail(&drv->global_list, &pnp_card_drivers);
+	spin_unlock(&pnp_lock);
 	pnp_register_driver(&drv->link);
 
 	list_for_each_safe(pos,temp,&pnp_cards){
 		struct pnp_card *card = list_entry(pos, struct pnp_card, global_list);
-		const struct pnp_card_id *id = match_card(drv,card);
-		if (id) {
-			struct pnp_card_link * clink = pnp_alloc(sizeof(struct pnp_card_link));
-			if (!clink)
-				continue;
-			clink->card = card;
-			clink->driver = drv;
-			if (drv->probe) {
-				if (drv->probe(clink, id)>=0)
-					count++;
-			} else
-				count++;
-		}
+		count += card_probe(card,drv);
 	}
 	return count;
 }
@@ -298,9 +317,10 @@
 
 void pnp_unregister_card_driver(struct pnp_card_driver * drv)
 {
+	spin_lock(&pnp_lock);
+	list_del(&drv->global_list);
+	spin_unlock(&pnp_lock);
 	pnp_unregister_driver(&drv->link);
-
-	pnp_dbg("the card driver '%s' has been unregistered", drv->name);
 }
 
 EXPORT_SYMBOL(pnp_add_card);
diff -urN linux-2.5.66-bk10/drivers/pnp/core.c linux-2.5.66-bk11/drivers/pnp/core.c
--- linux-2.5.66-bk10/drivers/pnp/core.c	2003-03-24 14:00:08.000000000 -0800
+++ linux-2.5.66-bk11/drivers/pnp/core.c	2003-04-05 04:32:16.000000000 -0800
@@ -170,7 +170,7 @@
 
 static int __init pnp_init(void)
 {
-	printk(KERN_INFO "Linux Plug and Play Support v0.95 (c) Adam Belay\n");
+	printk(KERN_INFO "Linux Plug and Play Support v0.96 (c) Adam Belay\n");
 	return bus_register(&pnp_bus_type);
 }
 
diff -urN linux-2.5.66-bk10/drivers/pnp/manager.c linux-2.5.66-bk11/drivers/pnp/manager.c
--- linux-2.5.66-bk10/drivers/pnp/manager.c	2003-03-24 14:01:45.000000000 -0800
+++ linux-2.5.66-bk11/drivers/pnp/manager.c	2003-04-05 04:32:16.000000000 -0800
@@ -632,8 +632,7 @@
 	if (!dev)
 		return -EINVAL;
 	if (dev->active) {
-		pnp_info("res: The PnP device '%s' is already active.", dev->dev.bus_id);
-		return -EBUSY;
+		return 0; /* the device is already active */
 	}
 	/* If this condition is true, advanced configuration failed, we need to get this device up and running
 	 * so we use the simple config engine which ignores cold conflicts, this of course may lead to new failures */
@@ -698,8 +697,7 @@
         if (!dev)
                 return -EINVAL;
 	if (!dev->active) {
-		pnp_info("res: The PnP device '%s' is already disabled.", dev->dev.bus_id);
-		return -EINVAL;
+		return 0; /* the device is already disabled */
 	}
 	if (dev->status != PNP_READY){
 		pnp_info("res: Disable failed becuase the PnP device '%s' is busy.", dev->dev.bus_id);
diff -urN linux-2.5.66-bk10/drivers/pnp/pnpbios/core.c linux-2.5.66-bk11/drivers/pnp/pnpbios/core.c
--- linux-2.5.66-bk10/drivers/pnp/pnpbios/core.c	2003-03-24 13:59:55.000000000 -0800
+++ linux-2.5.66-bk11/drivers/pnp/pnpbios/core.c	2003-04-05 04:32:16.000000000 -0800
@@ -32,6 +32,18 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
+ 
+/* Change Log
+ *
+ * Adam Belay - <ambx1@neo.rr.com> - March 16, 2003
+ * rev 1.01	Only call pnp_bios_dev_node_info once
+ *		Added pnpbios_print_status
+ *		Added several new error messages and info messages
+ *		Added pnpbios_interface_attach_device
+ *		integrated core and proc init system
+ *		Introduced PNPMODE flags
+ *		Removed some useless includes
+ */
 
 #include <linux/types.h>
 #include <linux/module.h>
@@ -46,9 +58,7 @@
 #include <linux/mm.h>
 #include <linux/smp.h>
 #include <asm/desc.h>
-#include <linux/ioport.h>
 #include <linux/slab.h>
-#include <linux/pci.h>
 #include <linux/kmod.h>
 #include <linux/completion.h>
 #include <linux/spinlock.h>
@@ -93,6 +103,7 @@
 } pnp_bios_callpoint;
 
 static union pnp_bios_expansion_header * pnp_bios_hdr = NULL;
+struct pnp_dev_node_info node_info;
 
 /* The PnP BIOS entries in the GDT */
 #define PNP_GDT    (GDT_ENTRY_PNPBIOS_BASE * 8)
@@ -237,9 +248,46 @@
  *
  */
 
-static void pnpbios_warn_unexpected_status(const char * module, u16 status)
+static void pnpbios_print_status(const char * module, u16 status)
 {
-	printk(KERN_ERR "PnPBIOS: %s: Unexpected status 0x%x\n", module, status);
+	switch(status) {
+	case PNP_SUCCESS:
+	printk(KERN_ERR "PnPBIOS: %s: function successful\n", module);
+	case PNP_NOT_SET_STATICALLY:
+	printk(KERN_ERR "PnPBIOS: %s: unable to set static resources\n", module);
+	case PNP_UNKNOWN_FUNCTION:
+	printk(KERN_ERR "PnPBIOS: %s: invalid function number passed\n", module);
+	case PNP_FUNCTION_NOT_SUPPORTED:
+	printk(KERN_ERR "PnPBIOS: %s: function not supported on this system\n", module);
+	case PNP_INVALID_HANDLE:
+	printk(KERN_ERR "PnPBIOS: %s: invalid handle\n", module);
+	case PNP_BAD_PARAMETER:
+	printk(KERN_ERR "PnPBIOS: %s: invalid parameters were passed\n", module);
+	case PNP_SET_FAILED:
+	printk(KERN_ERR "PnPBIOS: %s: unable to set resources\n", module);
+	case PNP_EVENTS_NOT_PENDING:
+	printk(KERN_ERR "PnPBIOS: %s: no events are pending\n", module);
+	case PNP_SYSTEM_NOT_DOCKED:
+	printk(KERN_ERR "PnPBIOS: %s: the system is not docked\n", module);
+	case PNP_NO_ISA_PNP_CARDS:
+	printk(KERN_ERR "PnPBIOS: %s: no isapnp cards are installed on this system\n", module);
+	case PNP_UNABLE_TO_DETERMINE_DOCK_CAPABILITIES:
+	printk(KERN_ERR "PnPBIOS: %s: cannot determine the capabilities of the docking station\n", module);
+	case PNP_CONFIG_CHANGE_FAILED_NO_BATTERY:
+	printk(KERN_ERR "PnPBIOS: %s: unable to undock, the system does not have a battery\n", module);
+	case PNP_CONFIG_CHANGE_FAILED_RESOURCE_CONFLICT:
+	printk(KERN_ERR "PnPBIOS: %s: could not dock due to resource conflicts\n", module);
+	case PNP_BUFFER_TOO_SMALL:
+	printk(KERN_ERR "PnPBIOS: %s: the buffer passed is too small\n", module);
+	case PNP_USE_ESCD_SUPPORT:
+	printk(KERN_ERR "PnPBIOS: %s: use ESCD instead\n", module);
+	case PNP_MESSAGE_NOT_SUPPORTED:
+	printk(KERN_ERR "PnPBIOS: %s: the message is unsupported\n", module);
+	case PNP_HARDWARE_ERROR:
+	printk(KERN_ERR "PnPBIOS: %s: a hardware failure has occured\n", module);
+	default:
+	printk(KERN_ERR "PnPBIOS: %s: unexpected status 0x%x\n", module, status);
+	}
 }
 
 void *pnpbios_kmalloc(size_t size, int f)
@@ -299,7 +347,7 @@
 {
 	int status = __pnp_bios_dev_node_info( data );
 	if ( status )
-		pnpbios_warn_unexpected_status( "dev_node_info", status );
+		pnpbios_print_status( "dev_node_info", status );
 	return status;
 }
 
@@ -334,7 +382,7 @@
 	int status;
 	status =  __pnp_bios_get_dev_node( nodenum, boot, data );
 	if ( status )
-		pnpbios_warn_unexpected_status( "get_dev_node", status );
+		pnpbios_print_status( "get_dev_node", status );
 	return status;
 }
 
@@ -362,7 +410,7 @@
 	int status;
 	status =  __pnp_bios_set_dev_node( nodenum, boot, data );
 	if ( status ) {
-		pnpbios_warn_unexpected_status( "set_dev_node", status );
+		pnpbios_print_status( "set_dev_node", status );
 		return status;
 	}
 	if ( !boot ) { /* Update devlist */
@@ -452,7 +500,7 @@
 	int status;
 	status = __pnp_bios_get_stat_res( info );
 	if ( status )
-		pnpbios_warn_unexpected_status( "get_stat_res", status );
+		pnpbios_print_status( "get_stat_res", status );
 	return status;
 }
 
@@ -489,7 +537,7 @@
 	int status;
 	status = __pnp_bios_isapnp_config( data );
 	if ( status )
-		pnpbios_warn_unexpected_status( "isapnp_config", status );
+		pnpbios_print_status( "isapnp_config", status );
 	return status;
 }
 
@@ -511,7 +559,7 @@
 	int status;
 	status = __pnp_bios_escd_info( data );
 	if ( status )
-		pnpbios_warn_unexpected_status( "escd_info", status );
+		pnpbios_print_status( "escd_info", status );
 	return status;
 }
 
@@ -534,7 +582,7 @@
 	int status;
 	status = __pnp_bios_read_escd( data, nvram_base );
 	if ( status )
-		pnpbios_warn_unexpected_status( "read_escd", status );
+		pnpbios_print_status( "read_escd", status );
 	return status;
 }
 
@@ -658,7 +706,7 @@
 				d = 1;
 				break;
 			default:
-				pnpbios_warn_unexpected_status( "pnp_dock_thread", status );
+				pnpbios_print_status( "pnp_dock_thread", status );
 				continue;
 		}
 		if(d != docked)
@@ -753,19 +801,17 @@
 
 static int pnpbios_get_resources(struct pnp_dev * dev, struct pnp_resource_table * res)
 {
-	struct pnp_dev_node_info node_info;
 	u8 nodenum = dev->number;
 	struct pnp_bios_node * node;
 
 	/* just in case */
 	if(!pnpbios_is_dynamic(dev))
 		return -EPERM;
-	if (pnp_bios_dev_node_info(&node_info) != 0)
-		return -ENODEV;
+
 	node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
 	if (!node)
 		return -1;
-	if (pnp_bios_get_dev_node(&nodenum, (char )0, node)) {
+	if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_DYNAMIC, node)) {
 		kfree(node);
 		return -ENODEV;
 	}
@@ -777,7 +823,6 @@
 
 static int pnpbios_set_resources(struct pnp_dev * dev, struct pnp_resource_table * res)
 {
-	struct pnp_dev_node_info node_info;
 	u8 nodenum = dev->number;
 	struct pnp_bios_node * node;
 	int ret;
@@ -785,18 +830,17 @@
 	/* just in case */
 	if (!pnpbios_is_dynamic(dev))
 		return -EPERM;
-	if (pnp_bios_dev_node_info(&node_info) != 0)
-		return -ENODEV;
+
 	node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
 	if (!node)
 		return -1;
-	if (pnp_bios_get_dev_node(&nodenum, (char )1, node))
+	if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_STATIC, node))
 		return -ENODEV;
 	if(!pnp_write_resources((char *)node->data,(char *)node->data + node->size,res)){
 		kfree(node);
 		return -1;
 	}
-	ret = pnp_bios_set_dev_node(node->handle, (char)0, node);
+	ret = pnp_bios_set_dev_node(node->handle, (char)PNPMODE_DYNAMIC, node);
 	kfree(node);
 	if (ret > 0)
 		ret = -1;
@@ -805,23 +849,18 @@
 
 static int pnpbios_disable_resources(struct pnp_dev *dev)
 {
-	struct pnp_dev_node_info node_info;
 	struct pnp_bios_node * node;
 	int ret;
 	
 	/* just in case */
 	if(dev->flags & PNPBIOS_NO_DISABLE || !pnpbios_is_dynamic(dev))
 		return -EPERM;
-	if (!dev || !dev->active)
-		return -EINVAL;
-	if (pnp_bios_dev_node_info(&node_info) != 0)
-		return -ENODEV;
+
 	/* the value of this will be zero */
 	node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
 	if (!node)
 		return -ENOMEM;
-	ret = pnp_bios_set_dev_node(dev->number, (char)0, node);
-	dev->active = 0;
+	ret = pnp_bios_set_dev_node(dev->number, (char)PNPMODE_DYNAMIC, node);
 	kfree(node);
 	if (ret > 0)
 		ret = -1;
@@ -879,6 +918,8 @@
 	dev->protocol = &pnpbios_protocol;
 
 	pnp_add_device(dev);
+	pnpbios_interface_attach_device(node);
+
 	return 0;
 }
 
@@ -903,8 +944,16 @@
 
 	for(nodenum=0; nodenum<0xff; ) {
 		u8 thisnodenum = nodenum;
-		if (pnp_bios_get_dev_node(&nodenum, (char )0, node))
-			break;
+		/* eventually we will want to use PNPMODE_STATIC here but for now
+		 * dynamic will help us catch buggy bioses to add to the blacklist.
+		 */
+		if (!pnpbios_dont_use_current_config) {
+			if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_DYNAMIC, node))
+				break;
+		} else {
+			if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_STATIC, node))
+				break;
+		}
 		nodes_got++;
 		dev =  pnpbios_kmalloc(sizeof (struct pnp_dev), GFP_KERNEL);
 		if (!dev)
@@ -972,7 +1021,8 @@
 	if(pnpbios_disabled || (dmi_broken & BROKEN_PNP_BIOS)) {
 		printk(KERN_INFO "PnPBIOS: Disabled\n");
 		return -ENODEV;
-	}
+	} else
+		printk(KERN_INFO "PnPBIOS: Scanning system for PnP BIOS support...\n");
 
 	/*
  	 * Search the defined area (0xf0000-0xffff0) for a valid PnP BIOS
@@ -1016,17 +1066,34 @@
 		}
 		break;
 	}
-	if (!pnp_bios_present())
+	if (!pnp_bios_present()) {
+		printk(KERN_INFO "PnPBIOS: A PnP BIOS was not detected.\n");
 		return -ENODEV;
+	}
+
+	/*
+	 * we found a pnpbios, now let's load the rest of the driver
+	 */
+
+	/* read the node info */
+	if (pnp_bios_dev_node_info(&node_info)) {
+		printk(KERN_ERR "PnPBIOS: Unable to get node info.  Aborting.\n");
+		return -EIO;
+	}
+
+	/* register with the pnp layer */
 	pnp_register_protocol(&pnpbios_protocol);
-	build_devlist();
-	/*if ( ! dont_reserve_resources )*/
-		/*reserve_resources();*/
+
 #ifdef CONFIG_PROC_FS
+	/* start the proc interface */
 	r = pnpbios_proc_init();
 	if (r)
 		return r;
 #endif
+
+	/* scan for pnpbios devices */
+	build_devlist();
+
 	return 0;
 }
 
diff -urN linux-2.5.66-bk10/drivers/pnp/pnpbios/proc.c linux-2.5.66-bk11/drivers/pnp/pnpbios/proc.c
--- linux-2.5.66-bk10/drivers/pnp/pnpbios/proc.c	2003-03-24 14:01:43.000000000 -0800
+++ linux-2.5.66-bk11/drivers/pnp/pnpbios/proc.c	2003-04-05 04:32:16.000000000 -0800
@@ -31,7 +31,6 @@
 
 static struct proc_dir_entry *proc_pnp = NULL;
 static struct proc_dir_entry *proc_pnp_boot = NULL;
-static struct pnp_dev_node_info node_info;
 
 static int proc_read_pnpconfig(char *buf, char **start, off_t pos,
                                int count, int *eof, void *data)
@@ -136,7 +135,7 @@
 		/* 26 = the number of characters per line sprintf'ed */
 		if ((p - buf + 26) > count)
 			break;
-		if (pnp_bios_get_dev_node(&nodenum, 1, node))
+		if (pnp_bios_get_dev_node(&nodenum, PNPMODE_STATIC, node))
 			break;
 		p += sprintf(p, "%02x\t%08x\t%02x:%02x:%02x\t%04x\n",
 			     node->handle, node->eisa_id,
@@ -193,6 +192,30 @@
 	return count;
 }
 
+int pnpbios_interface_attach_device(struct pnp_bios_node * node)
+{
+	char name[3];
+	struct proc_dir_entry *ent;
+
+	sprintf(name, "%02x", node->handle);
+	if ( !pnpbios_dont_use_current_config ) {
+		ent = create_proc_entry(name, 0, proc_pnp);
+		if (ent) {
+			ent->read_proc = proc_read_node;
+			ent->write_proc = proc_write_node;
+			ent->data = (void *)(long)(node->handle);
+		}
+	}
+	ent = create_proc_entry(name, 0, proc_pnp_boot);
+	if (ent) {
+		ent->read_proc = proc_read_node;
+		ent->write_proc = proc_write_node;
+		ent->data = (void *)(long)(node->handle+0x100);
+		return 0;
+	}
+	return -EIO;
+}
+
 /*
  * When this is called, pnpbios functions are assumed to
  * work and the pnpbios_dont_use_current_config flag
@@ -200,14 +223,6 @@
  */
 int __init pnpbios_proc_init( void )
 {
-	struct pnp_bios_node *node;
-	struct proc_dir_entry *ent;
-	char name[3];
-	u8 nodenum;
-
-	if (pnp_bios_dev_node_info(&node_info))
-		return -EIO;
-	
 	proc_pnp = proc_mkdir("pnp", proc_bus);
 	if (!proc_pnp)
 		return -EIO;
@@ -219,36 +234,6 @@
 	create_proc_read_entry("escd_info", 0, proc_pnp, proc_read_escdinfo, NULL);
 	create_proc_read_entry("escd", S_IRUSR, proc_pnp, proc_read_escd, NULL);
 	create_proc_read_entry("legacy_device_resources", 0, proc_pnp, proc_read_legacyres, NULL);
-	
-	node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
-	if (!node)
-		return -ENOMEM;
-
-	for (nodenum=0; nodenum<0xff; ) {
-		u8 thisnodenum = nodenum;
-		if (pnp_bios_get_dev_node(&nodenum, 1, node) != 0)
-			break;
-		sprintf(name, "%02x", node->handle);
-		if ( !pnpbios_dont_use_current_config ) {
-			ent = create_proc_entry(name, 0, proc_pnp);
-			if (ent) {
-				ent->read_proc = proc_read_node;
-				ent->write_proc = proc_write_node;
-				ent->data = (void *)(long)(node->handle);
-			}
-		}
-		ent = create_proc_entry(name, 0, proc_pnp_boot);
-		if (ent) {
-			ent->read_proc = proc_read_node;
-			ent->write_proc = proc_write_node;
-			ent->data = (void *)(long)(node->handle+0x100);
-		}
-		if (nodenum <= thisnodenum) {
-			printk(KERN_ERR "%s Node number 0x%x is out of sequence following node 0x%x. Aborting.\n", "PnPBIOS: proc_init:", (unsigned int)nodenum, (unsigned int)thisnodenum);
-			break;
-		}
-	}
-	kfree(node);
 
 	return 0;
 }
diff -urN linux-2.5.66-bk10/drivers/video/fbmem.c linux-2.5.66-bk11/drivers/video/fbmem.c
--- linux-2.5.66-bk10/drivers/video/fbmem.c	2003-04-05 04:32:13.000000000 -0800
+++ linux-2.5.66-bk11/drivers/video/fbmem.c	2003-04-05 04:32:16.000000000 -0800
@@ -670,6 +670,7 @@
 	case FB_VISUAL_MONO10:
 		fb_logo.needs_logo = 1;
 		break;
+	case FB_VISUAL_PSEUDOCOLOR:
 	case FB_VISUAL_STATIC_PSEUDOCOLOR:
 		if (fb_logo.depth >= 8) {
 			fb_logo.needs_logo = 8;
diff -urN linux-2.5.66-bk10/drivers/video/logo/Kconfig linux-2.5.66-bk11/drivers/video/logo/Kconfig
--- linux-2.5.66-bk10/drivers/video/logo/Kconfig	2003-03-24 14:00:21.000000000 -0800
+++ linux-2.5.66-bk11/drivers/video/logo/Kconfig	2003-04-05 04:32:16.000000000 -0800
@@ -40,7 +40,7 @@
 
 config LOGO_SGI_CLUT224
 	bool "224-color SGI Linux logo"
-	depends on LOGO && (SGI_IP22 || SGI_IP27 || SGI_IP32)
+	depends on LOGO && (SGI_IP22 || SGI_IP27 || SGI_IP32 || X86_VISWS)
 	default y
 
 config LOGO_SUN_CLUT224
diff -urN linux-2.5.66-bk10/drivers/video/logo/logo.c linux-2.5.66-bk11/drivers/video/logo/logo.c
--- linux-2.5.66-bk10/drivers/video/logo/logo.c	2003-03-24 14:00:48.000000000 -0800
+++ linux-2.5.66-bk11/drivers/video/logo/logo.c	2003-04-05 04:32:16.000000000 -0800
@@ -80,8 +80,10 @@
 			logo = &logo_parisc_clut224;
 #endif
 #ifdef CONFIG_LOGO_SGI_CLUT224
-			/* SGI Linux logo on MIPS/MIPS64 */
+			/* SGI Linux logo on MIPS/MIPS64 ans VisWs 320/540 */
+#ifndef CONFIG_X86_VISWS
 			if (mips_machgroup == MACH_GROUP_SGI)
+#endif
 				logo = &logo_sgi_clut224;
 #endif
 #ifdef CONFIG_LOGO_SUN_CLUT224
diff -urN linux-2.5.66-bk10/drivers/video/sgivwfb.c linux-2.5.66-bk11/drivers/video/sgivwfb.c
--- linux-2.5.66-bk10/drivers/video/sgivwfb.c	2003-03-24 14:00:35.000000000 -0800
+++ linux-2.5.66-bk11/drivers/video/sgivwfb.c	2003-04-05 04:32:16.000000000 -0800
@@ -12,6 +12,7 @@
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/mm.h>
 #include <linux/errno.h>
 #include <linux/delay.h>
 #include <linux/fb.h>
diff -urN linux-2.5.66-bk10/fs/fcntl.c linux-2.5.66-bk11/fs/fcntl.c
--- linux-2.5.66-bk10/fs/fcntl.c	2003-03-24 14:00:01.000000000 -0800
+++ linux-2.5.66-bk11/fs/fcntl.c	2003-04-05 04:32:16.000000000 -0800
@@ -465,7 +465,7 @@
 				break;
 		/* fall-through: fall back on the old plain SIGIO signal */
 		case 0:
-			send_sig(SIGIO, p, 1);
+			send_group_sig_info(SIGIO, SEND_SIG_PRIV, p);
 	}
 }
 
@@ -501,7 +501,7 @@
                                 struct fown_struct *fown)
 {
 	if (sigio_perm(p, fown))
-		send_sig(SIGURG, p, 1);
+		send_group_sig_info(SIGURG, SEND_SIG_PRIV, p);
 }
 
 int send_sigurg(struct fown_struct *fown)
diff -urN linux-2.5.66-bk10/include/linux/oprofile.h linux-2.5.66-bk11/include/linux/oprofile.h
--- linux-2.5.66-bk10/include/linux/oprofile.h	2003-03-24 14:00:49.000000000 -0800
+++ linux-2.5.66-bk11/include/linux/oprofile.h	2003-04-05 04:32:16.000000000 -0800
@@ -46,6 +46,11 @@
 int oprofile_arch_init(struct oprofile_operations ** ops);
  
 /**
+ * One-time exit/cleanup for the arch.
+ */
+void oprofile_arch_exit(void);
+
+/**
  * Add a sample. This may be called from any context. Pass
  * smp_processor_id() as cpu.
  */
diff -urN linux-2.5.66-bk10/include/linux/pnp.h linux-2.5.66-bk11/include/linux/pnp.h
--- linux-2.5.66-bk10/include/linux/pnp.h	2003-03-24 14:01:47.000000000 -0800
+++ linux-2.5.66-bk11/include/linux/pnp.h	2003-04-05 04:32:16.000000000 -0800
@@ -295,7 +295,7 @@
 	unsigned long driver_data;	/* data private to the driver */
 };
 
-struct pnp_card_id {
+struct pnp_card_device_id {
 	char id[PNP_ID_LEN];
 	unsigned long driver_data;	/* data private to the driver */
 	struct {
@@ -315,10 +315,11 @@
 #define	to_pnp_driver(drv) container_of(drv, struct pnp_driver, driver)
 
 struct pnp_card_driver {
+	struct list_head global_list;
 	char * name;
-	const struct pnp_card_id *id_table;
+	const struct pnp_card_device_id *id_table;
 	unsigned int flags;
-	int  (*probe)  (struct pnp_card_link *card, const struct pnp_card_id *card_id);
+	int  (*probe)  (struct pnp_card_link *card, const struct pnp_card_device_id *card_id);
 	void (*remove) (struct pnp_card_link *card);
 	struct pnp_driver link;
 };
diff -urN linux-2.5.66-bk10/include/linux/pnpbios.h linux-2.5.66-bk11/include/linux/pnpbios.h
--- linux-2.5.66-bk10/include/linux/pnpbios.h	2003-03-24 14:00:18.000000000 -0800
+++ linux-2.5.66-bk11/include/linux/pnpbios.h	2003-04-05 04:32:16.000000000 -0800
@@ -29,7 +29,7 @@
 #include <linux/pci.h>
 
 /*
- * Status codes (warnings and errors)
+ * Return codes
  */
 #define PNP_SUCCESS                     0x00
 #define PNP_NOT_SET_STATICALLY          0x7f
@@ -75,6 +75,7 @@
 #define PNPMSG_POWER_OFF		0x41
 #define PNPMSG_PNP_OS_ACTIVE		0x42
 #define PNPMSG_PNP_OS_INACTIVE		0x43
+
 /*
  * Plug and Play BIOS flags
  */
@@ -88,6 +89,12 @@
 #define pnpbios_is_static(x) (((x)->flags & 0x0100) == 0x0000)
 #define pnpbios_is_dynamic(x) ((x)->flags & 0x0080)
 
+/*
+ * Function Parameters
+ */
+#define PNPMODE_STATIC 1
+#define PNPMODE_DYNAMIC 0
+
 /* 0x8000 through 0xffff are OEM defined */
 
 #pragma pack(1)
@@ -125,8 +132,10 @@
 
 /* non-exported */
 extern int  pnpbios_dont_use_current_config;
+extern struct pnp_dev_node_info node_info;
 extern void *pnpbios_kmalloc(size_t size, int f);
 extern int pnpbios_init (void);
+extern int pnpbios_interface_attach_device(struct pnp_bios_node * node);
 extern int pnpbios_proc_init (void);
 extern void pnpbios_proc_exit (void);
 
diff -urN linux-2.5.66-bk10/include/linux/sched.h linux-2.5.66-bk11/include/linux/sched.h
--- linux-2.5.66-bk10/include/linux/sched.h	2003-03-24 14:00:00.000000000 -0800
+++ linux-2.5.66-bk11/include/linux/sched.h	2003-04-05 04:32:16.000000000 -0800
@@ -541,6 +541,7 @@
 extern void unblock_all_signals(void);
 extern void release_task(struct task_struct * p);
 extern int send_sig_info(int, struct siginfo *, struct task_struct *);
+extern int send_group_sig_info(int, struct siginfo *, struct task_struct *);
 extern int force_sig_info(int, struct siginfo *, struct task_struct *);
 extern int __kill_pg_info(int sig, struct siginfo *info, pid_t pgrp);
 extern int kill_pg_info(int, struct siginfo *, pid_t);
@@ -558,6 +559,11 @@
 extern int do_sigaction(int, const struct k_sigaction *, struct k_sigaction *);
 extern int do_sigaltstack(const stack_t *, stack_t *, unsigned long);
 
+/* These can be the second arg to send_sig_info/send_group_sig_info.  */
+#define SEND_SIG_NOINFO ((struct siginfo *) 0)
+#define SEND_SIG_PRIV	((struct siginfo *) 1)
+#define SEND_SIG_FORCED	((struct siginfo *) 2)
+
 /* True if we are on the alternate signal stack.  */
 
 static inline int on_sig_stack(unsigned long sp)
diff -urN linux-2.5.66-bk10/include/net/sctp/constants.h linux-2.5.66-bk11/include/net/sctp/constants.h
--- linux-2.5.66-bk10/include/net/sctp/constants.h	2003-03-24 14:00:15.000000000 -0800
+++ linux-2.5.66-bk11/include/net/sctp/constants.h	2003-04-05 04:32:16.000000000 -0800
@@ -138,12 +138,10 @@
  */
 
 typedef union {
-
 	sctp_cid_t chunk;
 	sctp_event_timeout_t timeout;
 	sctp_event_other_t other;
 	sctp_event_primitive_t primitive;
-
 } sctp_subtype_t;
 
 #define SCTP_SUBTYPE_CONSTRUCTOR(_name, _type, _elt) \
@@ -421,9 +419,9 @@
 
 /* Reasons to retransmit. */
 typedef enum {
-	SCTP_RETRANSMIT_T3_RTX,
-	SCTP_RETRANSMIT_FAST_RTX,
-	SCTP_RETRANSMIT_PMTU_DISCOVERY,
+	SCTP_RTXR_T3_RTX,
+	SCTP_RTXR_FAST_RTX,
+	SCTP_RTXR_PMTUD,
 } sctp_retransmit_reason_t;
 
 /* Reasons to lower cwnd. */
diff -urN linux-2.5.66-bk10/include/net/sctp/sctp.h linux-2.5.66-bk11/include/net/sctp/sctp.h
--- linux-2.5.66-bk10/include/net/sctp/sctp.h	2003-04-05 04:32:13.000000000 -0800
+++ linux-2.5.66-bk11/include/net/sctp/sctp.h	2003-04-05 04:32:16.000000000 -0800
@@ -123,14 +123,14 @@
  */
 extern struct sctp_protocol sctp_proto;
 extern struct sock *sctp_get_ctl_sock(void);
-extern int sctp_copy_local_addr_list(struct sctp_protocol  *, 
+extern int sctp_copy_local_addr_list(struct sctp_protocol  *,
 				     struct sctp_bind_addr *,
 				     sctp_scope_t, int priority, int flags);
 extern struct sctp_pf *sctp_get_pf_specific(sa_family_t family);
 extern int sctp_register_pf(struct sctp_pf *, sa_family_t);
 
 /*
- * sctp_socket.c
+ * sctp/socket.c
  */
 extern int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb);
 extern int sctp_inet_listen(struct socket *sock, int backlog);
@@ -139,7 +139,7 @@
 		poll_table *wait);
 
 /*
- * sctp_primitive.c
+ * sctp/primitive.c
  */
 extern int sctp_primitive_ASSOCIATE(sctp_association_t *, void *arg);
 extern int sctp_primitive_SHUTDOWN(sctp_association_t *, void *arg);
@@ -148,14 +148,14 @@
 extern int sctp_primitive_REQUESTHEARTBEAT(sctp_association_t *, void *arg);
 
 /*
- * sctp_crc32c.c
+ * sctp/crc32c.c
  */
 extern __u32 sctp_start_cksum(__u8 *ptr, __u16 count);
 extern __u32 sctp_update_cksum(__u8 *ptr, __u16 count, __u32 cksum);
 extern __u32 sctp_end_cksum(__u32 cksum);
 
 /*
- * sctp_input.c
+ * sctp/input.c
  */
 extern int sctp_rcv(struct sk_buff *skb);
 extern void sctp_v4_err(struct sk_buff *skb, u32 info);
@@ -170,9 +170,16 @@
 extern sctp_association_t *__sctp_lookup_association(const union sctp_addr *,
 						     const union sctp_addr *,
 						     struct sctp_transport **);
-
+extern struct sock *sctp_err_lookup(int family, struct sk_buff *,
+				    struct sctphdr *, struct sctp_endpoint **, 
+				    struct sctp_association **, 
+				    struct sctp_transport **);
+extern void sctp_err_finish(struct sock *, struct sctp_endpoint *, 
+			    struct sctp_association *);
+extern void sctp_icmp_frag_needed(struct sock *, struct sctp_association *,
+				  struct sctp_transport *t, __u32 pmtu);
 /*
- * sctp_hashdriver.c
+ * sctp/hashdriver.c
  */
 extern void sctp_hash_digest(const char *secret, const int secret_len,
 			     const char *text, const int text_len,
@@ -184,9 +191,7 @@
 
 
 #ifdef TEST_FRAME
-
 #include <test_frame.h>
-
 #else
 
 /* spin lock wrappers. */
@@ -194,28 +199,28 @@
 #define sctp_spin_unlock_irqrestore(lock, flags)  \
        spin_unlock_irqrestore(lock, flags)
 #define sctp_local_bh_disable() local_bh_disable()
-#define sctp_local_bh_enable() local_bh_enable()
-#define sctp_spin_lock(lock) spin_lock(lock)
-#define sctp_spin_unlock(lock) spin_unlock(lock)
-#define sctp_write_lock(lock) write_lock(lock)
+#define sctp_local_bh_enable()  local_bh_enable()
+#define sctp_spin_lock(lock)    spin_lock(lock)
+#define sctp_spin_unlock(lock)  spin_unlock(lock)
+#define sctp_write_lock(lock)   write_lock(lock)
 #define sctp_write_unlock(lock) write_unlock(lock)
-#define sctp_read_lock(lock) read_lock(lock)
-#define sctp_read_unlock(lock) read_unlock(lock)
+#define sctp_read_lock(lock)    read_lock(lock)
+#define sctp_read_unlock(lock)  read_unlock(lock)
 
 /* sock lock wrappers. */
-#define sctp_lock_sock(sk) lock_sock(sk)
-#define sctp_release_sock(sk) release_sock(sk)
-#define sctp_bh_lock_sock(sk) bh_lock_sock(sk)
-#define sctp_bh_unlock_sock(sk) bh_unlock_sock(sk)
-#define SCTP_SOCK_SLEEP_PRE(sk) SOCK_SLEEP_PRE(sk)
+#define sctp_lock_sock(sk)       lock_sock(sk)
+#define sctp_release_sock(sk)    release_sock(sk)
+#define sctp_bh_lock_sock(sk)    bh_lock_sock(sk)
+#define sctp_bh_unlock_sock(sk)  bh_unlock_sock(sk)
+#define SCTP_SOCK_SLEEP_PRE(sk)  SOCK_SLEEP_PRE(sk)
 #define SCTP_SOCK_SLEEP_POST(sk) SOCK_SLEEP_POST(sk)
 
 /* SCTP SNMP MIB stats handlers */
 DECLARE_SNMP_STAT(struct sctp_mib, sctp_statistics);
-#define SCTP_INC_STATS(field)		SNMP_INC_STATS(sctp_statistics, field)
-#define SCTP_INC_STATS_BH(field)	SNMP_INC_STATS_BH(sctp_statistics, field)
-#define SCTP_INC_STATS_USER(field)	SNMP_INC_STATS_USER(sctp_statistics, field)
-#define SCTP_DEC_STATS(field)		SNMP_DEC_STATS(sctp_statistics, field)
+#define SCTP_INC_STATS(field)      SNMP_INC_STATS(sctp_statistics, field)
+#define SCTP_INC_STATS_BH(field)   SNMP_INC_STATS_BH(sctp_statistics, field)
+#define SCTP_INC_STATS_USER(field) SNMP_INC_STATS_USER(sctp_statistics, field)
+#define SCTP_DEC_STATS(field)      SNMP_DEC_STATS(sctp_statistics, field)
 
 /* Determine if this is a valid kernel address.  */
 static inline int sctp_is_valid_kaddr(unsigned long addr)
@@ -312,7 +317,6 @@
 static inline void sctp_sysctl_unregister(void) { return; }
 #endif
 
-
 /* Size of Supported Address Parameter for 'x' address types. */
 #define SCTP_SAT_LEN(x) (sizeof(struct sctp_paramhdr) + (x) * sizeof(__u16))
 
@@ -320,19 +324,15 @@
 
 extern int sctp_v6_init(void);
 extern void sctp_v6_exit(void);
-static inline int sctp_ipv6_addr_type(const struct in6_addr *addr)
-{
-	return ipv6_addr_type((struct in6_addr*) addr);
-}
+extern void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+			int type, int code, int offset, __u32 info);
 
-#else /* #ifdef defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
+#else /* #ifdef defined(CONFIG_IPV6) */
 
-#define sctp_ipv6_addr_type(a) 0
 static inline int sctp_v6_init(void) { return 0; }
 static inline void sctp_v6_exit(void) { return; }
 
-#endif /* #ifdef defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
-
+#endif /* #if defined(CONFIG_IPV6) */
 
 /* Map an association to an assoc_id. */
 static inline sctp_assoc_t sctp_assoc2id(const sctp_association_t *asoc)
@@ -414,13 +414,22 @@
 	sctp_rand ^= (sctp_rand << 12);
 	sctp_rand ^= (sctp_rand >> 20);
 
-	/* Choose random number from 0 to rto, then move to -50% ~ +50% 
-	 * of rto. 
+	/* Choose random number from 0 to rto, then move to -50% ~ +50%
+	 * of rto.
 	 */
 	ret = sctp_rand % rto - (rto >> 1);
 	return ret;
 }
 
+/* Break down data chunks at this point.  */
+static inline int sctp_frag_point(int pmtu)
+{
+	pmtu -= SCTP_IP_OVERHEAD + sizeof(struct sctp_data_chunk);
+	pmtu -= sizeof(struct sctp_sack_chunk);
+
+	return pmtu;
+}
+
 /* Walk through a list of TLV parameters.  Don't trust the
  * individual parameter lengths and instead depend on
  * the chunk length to indicate when to stop.  Make sure
@@ -479,21 +488,24 @@
 /* Convert from an IP version number to an Address Family symbol.  */
 static inline int ipver2af(__u8 ipver)
 {
-	int family;
-
 	switch (ipver) {
 	case 4:
-		family = AF_INET;
-		break;
+	        return  AF_INET;
 	case 6:
-		family = AF_INET6;
-		break;
+		return AF_INET6;
 	default:
-		family = 0;
-		break;
+		return 0;
 	};
+}
 
-	return family;
+/* Perform some sanity checks. */
+static inline int sctp_sanity_check(void)
+{
+	SCTP_ASSERT(sizeof(struct sctp_ulpevent) <= 
+		    sizeof(((struct sk_buff *)0)->cb),
+		    "SCTP: ulpevent does not fit in skb!\n", return 0);
+	
+	return 1;
 }
 
 /* Warning: The following hash functions assume a power of two 'size'. */
@@ -537,7 +549,7 @@
 	struct sock	  sk;
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 	struct ipv6_pinfo *pinet6;
-#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */
+#endif /* CONFIG_IPV6 */
 	struct inet_opt	  inet;
 	struct sctp_opt	  sctp;
 };
@@ -550,7 +562,7 @@
 	struct sctp_opt	  sctp;
 	struct ipv6_pinfo inet6;
 };
-#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */
+#endif /* CONFIG_IPV6 */
 
 #define sctp_sk(__sk) (&((struct sctp_sock *)__sk)->sctp)
 
diff -urN linux-2.5.66-bk10/include/net/sctp/sm.h linux-2.5.66-bk11/include/net/sctp/sm.h
--- linux-2.5.66-bk10/include/net/sctp/sm.h	2003-03-24 14:00:21.000000000 -0800
+++ linux-2.5.66-bk11/include/net/sctp/sm.h	2003-04-05 04:32:16.000000000 -0800
@@ -197,15 +197,14 @@
 sctp_state_fn_t sctp_addip_do_asconf_ack;
 
 /* Prototypes for utility support functions.  */
-__u8 sctp_get_chunk_type(sctp_chunk_t *chunk);
+__u8 sctp_get_chunk_type(struct sctp_chunk *chunk);
 sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
 					    sctp_state_t state,
 					    sctp_subtype_t event_subtype);
-
-time_t timeval_sub(struct timeval *, struct timeval *);
-sctp_association_t *sctp_make_temp_asoc(const sctp_endpoint_t *,
-					sctp_chunk_t *,
-					const int priority);
+int sctp_chunk_iif(const struct sctp_chunk *);
+struct sctp_association *sctp_make_temp_asoc(const struct sctp_endpoint *,
+					     struct sctp_chunk *,
+					     int gfp);
 __u32 sctp_generate_verification_tag(void);
 void sctp_populate_tie_tags(__u8 *cookie, __u32 curTag, __u32 hisTag);
 
@@ -344,7 +343,7 @@
 
 /* 4th level prototypes */
 void sctp_param2sockaddr(union sctp_addr *addr, sctp_addr_param_t *,
-			 __u16 port);
+			 __u16 port, int iif);
 int sctp_addr2sockaddr(const union sctp_params, union sctp_addr *);
 int sockaddr2sctp_addr(const union sctp_addr *, sctp_addr_param_t *);
 
diff -urN linux-2.5.66-bk10/include/net/sctp/structs.h linux-2.5.66-bk11/include/net/sctp/structs.h
--- linux-2.5.66-bk10/include/net/sctp/structs.h	2003-03-24 14:01:48.000000000 -0800
+++ linux-2.5.66-bk11/include/net/sctp/structs.h	2003-04-05 04:32:16.000000000 -0800
@@ -242,6 +242,7 @@
 	void            (*inaddr_any)   (union sctp_addr *, unsigned short);
 	int             (*is_any)       (const union sctp_addr *);
 	int             (*available)    (const union sctp_addr *);
+	int             (*skb_iif)      (const struct sk_buff *sk);
 	__u16		net_header_len;
 	int		sockaddr_len;
 	sa_family_t	sa_family;
@@ -260,6 +261,7 @@
 			  const union sctp_addr *,
 			  struct sctp_opt *);
 	int  (*bind_verify) (struct sctp_opt *, union sctp_addr *);
+	int  (*send_verify) (struct sctp_opt *, union sctp_addr *);
 	int  (*supported_addrs)(const struct sctp_opt *, __u16 *);
 	struct sock *(*create_accept_sk) (struct sock *sk,
 					  struct sctp_association *asoc);
@@ -430,7 +432,7 @@
 };
 
 struct sctp_ssnmap *sctp_ssnmap_init(struct sctp_ssnmap *, __u16, __u16);
-struct sctp_ssnmap *sctp_ssnmap_new(__u16 in, __u16 out, int priority);
+struct sctp_ssnmap *sctp_ssnmap_new(__u16 in, __u16 out, int gfp);
 void sctp_ssnmap_free(struct sctp_ssnmap *map);
 void sctp_ssnmap_clear(struct sctp_ssnmap *map);
 
@@ -509,7 +511,7 @@
 	struct sctp_sndrcvinfo sinfo;
 
 	/* Which association does this belong to?  */
-	sctp_association_t *asoc;
+	struct sctp_association *asoc;
 
 	/* What endpoint received this chunk? */
 	sctp_endpoint_common_t *rcvr;
@@ -541,11 +543,11 @@
 	struct sctp_transport *transport;
 };
 
-sctp_chunk_t *sctp_make_chunk(const sctp_association_t *, __u8 type,
+sctp_chunk_t *sctp_make_chunk(const struct sctp_association *, __u8 type,
 			      __u8 flags, int size);
 void sctp_free_chunk(sctp_chunk_t *);
 void  *sctp_addto_chunk(sctp_chunk_t *chunk, int len, const void *data);
-sctp_chunk_t *sctp_chunkify(struct sk_buff *, const sctp_association_t *,
+sctp_chunk_t *sctp_chunkify(struct sk_buff *, const struct sctp_association *,
 			    struct sock *);
 void sctp_init_addrs(sctp_chunk_t *, union sctp_addr *, union sctp_addr *);
 const union sctp_addr *sctp_source(const sctp_chunk_t *chunk);
@@ -560,7 +562,7 @@
 	union sctp_addr a;
 };
 
-typedef sctp_chunk_t *(sctp_packet_phandler_t)(sctp_association_t *);
+typedef sctp_chunk_t *(sctp_packet_phandler_t)(struct sctp_association *);
 
 /* This structure holds lists of chunks as we are assembling for
  * transmission.
@@ -590,13 +592,16 @@
 	/* This packet should advertise ECN capability to the network
 	 * via the ECT bit.
 	 */
-	int ecn_capable;
+	char ecn_capable;
 
 	/* This packet contains a COOKIE-ECHO chunk. */
-	int has_cookie_echo;
+	char has_cookie_echo;
+
+	/* This packet containsa SACK chunk. */
+	char has_sack;
 
 	/* SCTP cannot fragment this packet. So let ip fragment it. */
-	int ipfragok;
+	char ipfragok;
 
 	int malloced;
 };
@@ -660,7 +665,7 @@
 	struct sctp_af *af_specific;
 
 	/* Which association do we belong to?  */
-	sctp_association_t *asoc;
+	struct sctp_association *asoc;
 
 	/* RFC2960
 	 *
@@ -799,7 +804,8 @@
 struct sctp_transport *sctp_transport_new(const union sctp_addr *, int);
 struct sctp_transport *sctp_transport_init(struct sctp_transport *,
 					   const union sctp_addr *, int);
-void sctp_transport_set_owner(struct sctp_transport *, sctp_association_t *);
+void sctp_transport_set_owner(struct sctp_transport *,
+			      struct sctp_association *);
 void sctp_transport_route(struct sctp_transport *, union sctp_addr *,
 			  struct sctp_opt *);
 void sctp_transport_pmtu(struct sctp_transport *);
@@ -862,13 +868,16 @@
  * When free()'d, it empties itself out via output_handler().
  */
 struct sctp_outq {
-	sctp_association_t *asoc;
+	struct sctp_association *asoc;
 
 	/* Data pending that has never been transmitted.  */
 	struct sk_buff_head out;
 
 	unsigned out_qlen;	/* Total length of queued data chunks. */
 
+	/* Error of send failed, may used in SCTP_SEND_FAILED event. */
+	unsigned error;
+
 	/* These are control chunks we want to send.  */
 	struct sk_buff_head control;
 
@@ -902,8 +911,8 @@
 	int malloced;
 };
 
-struct sctp_outq *sctp_outq_new(sctp_association_t *);
-void sctp_outq_init(sctp_association_t *, struct sctp_outq *);
+struct sctp_outq *sctp_outq_new(struct sctp_association *);
+void sctp_outq_init(struct sctp_association *, struct sctp_outq *);
 void sctp_outq_teardown(struct sctp_outq *);
 void sctp_outq_free(struct sctp_outq*);
 int sctp_outq_tail(struct sctp_outq *, sctp_chunk_t *chunk);
@@ -947,20 +956,16 @@
 void sctp_bind_addr_init(sctp_bind_addr_t *, __u16 port);
 void sctp_bind_addr_free(sctp_bind_addr_t *);
 int sctp_bind_addr_copy(sctp_bind_addr_t *dest, const sctp_bind_addr_t *src,
-			sctp_scope_t scope, int priority,int flags);
+			sctp_scope_t scope, int gfp,int flags);
 int sctp_add_bind_addr(sctp_bind_addr_t *, union sctp_addr *,
-		       int priority);
+		       int gfp);
 int sctp_del_bind_addr(sctp_bind_addr_t *, union sctp_addr *);
 int sctp_bind_addr_match(sctp_bind_addr_t *, const union sctp_addr *,
 			 struct sctp_opt *);
-union sctp_params sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp,
-					 int *addrs_len,
-					 int priority);
-int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp,
-			   __u8 *raw_addr_list,
-			   int addrs_len,
-			   unsigned short port,
-			   int priority);
+union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp,
+					 int *addrs_len, int gfp);
+int sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw, int len,
+			   __u16 port, int gfp);
 
 sctp_scope_t sctp_scope(const union sctp_addr *);
 int sctp_in_scope(const union sctp_addr *addr, const sctp_scope_t scope);
@@ -1063,7 +1068,7 @@
 	 *            pointer, or table pointers dependent on how SCTP
 	 *            is implemented.
 	 */
-	/* This is really a list of sctp_association_t entries. */
+	/* This is really a list of struct sctp_association entries. */
 	struct list_head asocs;
 
 	/* Secret Key: A secret key used by this endpoint to compute
@@ -1099,12 +1104,12 @@
 sctp_endpoint_t *sctp_endpoint_new(struct sctp_protocol *, struct sock *, int);
 sctp_endpoint_t *sctp_endpoint_init(struct sctp_endpoint *,
 				    struct sctp_protocol *,
-				    struct sock *, int priority);
+				    struct sock *, int gfp);
 void sctp_endpoint_free(sctp_endpoint_t *);
 void sctp_endpoint_put(sctp_endpoint_t *);
 void sctp_endpoint_hold(sctp_endpoint_t *);
-void sctp_endpoint_add_asoc(sctp_endpoint_t *, sctp_association_t *asoc);
-sctp_association_t *sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep,
+void sctp_endpoint_add_asoc(sctp_endpoint_t *, struct sctp_association *asoc);
+struct sctp_association *sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep,
 					       const union sctp_addr *paddr,
 					       struct sctp_transport **);
 int sctp_endpoint_is_peeled_off(sctp_endpoint_t *, const union sctp_addr *);
@@ -1113,18 +1118,16 @@
 int sctp_has_association(const union sctp_addr *laddr,
 			 const union sctp_addr *paddr);
 
-int sctp_verify_init(const sctp_association_t *asoc,
-		     sctp_cid_t cid,
-		     sctp_init_chunk_t *peer_init,
-		     sctp_chunk_t *chunk,
-		     sctp_chunk_t **err_chunk);
-int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
-		      const union sctp_addr *peer_addr,
-		      sctp_init_chunk_t *peer_init, int priority);
-int sctp_process_param(sctp_association_t *asoc, union sctp_params param,
-		       const union sctp_addr *peer_addr, int priority);
-__u32 sctp_generate_tag(const sctp_endpoint_t *ep);
-__u32 sctp_generate_tsn(const sctp_endpoint_t *ep);
+int sctp_verify_init(const struct sctp_association *asoc, sctp_cid_t,
+		     sctp_init_chunk_t *peer_init, struct sctp_chunk *chunk,
+		     struct sctp_chunk **err_chunk);
+int sctp_process_init(struct sctp_association *, sctp_cid_t cid,
+		      const union sctp_addr *peer,
+		      sctp_init_chunk_t *init, int gfp);
+int sctp_process_param(struct sctp_association *, union sctp_params param,
+		       const union sctp_addr *from, int gfp);
+__u32 sctp_generate_tag(const sctp_endpoint_t *);
+__u32 sctp_generate_tsn(const sctp_endpoint_t *);
 
 
 /* RFC2960
@@ -1153,7 +1156,7 @@
 	struct list_head asocs;
 
 	/* This is a signature that lets us know that this is a
-	 * sctp_association_t data structure.  Used for mapping an
+	 * struct sctp_association data structure.  Used for mapping an
 	 * association id to an association.
 	 */
 	__u32 eyecatcher;
@@ -1556,44 +1559,46 @@
 };
 
 /* Recover the outter association structure. */
-static inline sctp_association_t *sctp_assoc(sctp_endpoint_common_t *base)
+static inline struct sctp_association *sctp_assoc(sctp_endpoint_common_t *base)
 {
-	sctp_association_t *asoc;
+	struct sctp_association *asoc;
 
-	asoc = container_of(base, sctp_association_t, base);
+	asoc = container_of(base, struct sctp_association, base);
 	return asoc;
 }
 
 /* These are function signatures for manipulating associations.  */
 
 
-sctp_association_t *
+struct sctp_association *
 sctp_association_new(const sctp_endpoint_t *, const struct sock *,
-		     sctp_scope_t scope, int priority);
-sctp_association_t *
-sctp_association_init(sctp_association_t *, const sctp_endpoint_t *,
+		     sctp_scope_t scope, int gfp);
+struct sctp_association *
+sctp_association_init(struct sctp_association *, const sctp_endpoint_t *,
 		      const struct sock *, sctp_scope_t scope,
-		      int priority);
-void sctp_association_free(sctp_association_t *);
-void sctp_association_put(sctp_association_t *);
-void sctp_association_hold(sctp_association_t *);
-
-struct sctp_transport *sctp_assoc_choose_shutdown_transport(sctp_association_t *);
-void sctp_assoc_update_retran_path(sctp_association_t *);
-struct sctp_transport *sctp_assoc_lookup_paddr(const sctp_association_t *,
+		      int gfp);
+void sctp_association_free(struct sctp_association *);
+void sctp_association_put(struct sctp_association *);
+void sctp_association_hold(struct sctp_association *);
+
+struct sctp_transport *sctp_assoc_choose_shutdown_transport(
+	struct sctp_association *);
+void sctp_assoc_update_retran_path(struct sctp_association *);
+struct sctp_transport *sctp_assoc_lookup_paddr(const struct sctp_association *,
 					  const union sctp_addr *);
-struct sctp_transport *sctp_assoc_add_peer(sctp_association_t *,
+struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *,
 				     const union sctp_addr *address,
-				     const int priority);
+				     const int gfp);
 void sctp_assoc_control_transport(struct sctp_association *,
 				  struct sctp_transport *,
 				  sctp_transport_cmd_t, sctp_sn_error_t);
-struct sctp_transport *sctp_assoc_lookup_tsn(sctp_association_t *, __u32);
-struct sctp_transport *sctp_assoc_is_match(sctp_association_t *,
+struct sctp_transport *sctp_assoc_lookup_tsn(struct sctp_association *, __u32);
+struct sctp_transport *sctp_assoc_is_match(struct sctp_association *,
 					   const union sctp_addr *,
 					   const union sctp_addr *);
-void sctp_assoc_migrate(sctp_association_t *, struct sock *);
-void sctp_assoc_update(sctp_association_t *dst, sctp_association_t *src);
+void sctp_assoc_migrate(struct sctp_association *, struct sock *);
+void sctp_assoc_update(struct sctp_association *old,
+		       struct sctp_association *new);
 
 __u32 sctp_association_get_next_tsn(struct sctp_association *);
 __u32 sctp_association_get_tsn_block(struct sctp_association *, int);
@@ -1603,14 +1608,14 @@
 void sctp_assoc_rwnd_decrease(struct sctp_association *, int);
 void sctp_assoc_set_primary(struct sctp_association *,
 			    struct sctp_transport *);
-int sctp_assoc_set_bind_addr_from_ep(sctp_association_t *, int);
-int sctp_assoc_set_bind_addr_from_cookie(sctp_association_t *,
-					 sctp_cookie_t *, int);
+int sctp_assoc_set_bind_addr_from_ep(struct sctp_association *, int);
+int sctp_assoc_set_bind_addr_from_cookie(struct sctp_association *,
+					 sctp_cookie_t *, int gfp);
 
 int sctp_cmp_addr_exact(const union sctp_addr *ss1,
 		        const union sctp_addr *ss2);
-sctp_chunk_t *sctp_get_ecne_prepend(sctp_association_t *asoc);
-sctp_chunk_t *sctp_get_no_prepend(sctp_association_t *asoc);
+sctp_chunk_t *sctp_get_ecne_prepend(struct sctp_association *asoc);
+sctp_chunk_t *sctp_get_no_prepend(struct sctp_association *asoc);
 
 /* A convenience structure to parse out SCTP specific CMSGs. */
 typedef struct sctp_cmsgs {
diff -urN linux-2.5.66-bk10/include/net/sctp/ulpevent.h linux-2.5.66-bk11/include/net/sctp/ulpevent.h
--- linux-2.5.66-bk10/include/net/sctp/ulpevent.h	2003-03-24 14:00:01.000000000 -0800
+++ linux-2.5.66-bk11/include/net/sctp/ulpevent.h	2003-04-05 04:32:16.000000000 -0800
@@ -38,7 +38,6 @@
  * be incorporated into the next SCTP release.
  */
 
-
 #ifndef __sctp_ulpevent_h__
 #define __sctp_ulpevent_h__
 
@@ -50,6 +49,7 @@
 	struct sctp_association *asoc;
 	struct sctp_sndrcvinfo sndrcvinfo;
 	int msg_flags;
+	int iif;
 };
 
 /* Retrieve the skb this event sits inside of. */
@@ -61,9 +61,9 @@
 /* Retrieve & cast the event sitting inside the skb. */
 static inline struct sctp_ulpevent *sctp_skb2event(struct sk_buff *skb)
 {
-	return (struct sctp_ulpevent *)skb->cb; 
+	return (struct sctp_ulpevent *)skb->cb;
 }
-	
+
 struct sctp_ulpevent *sctp_ulpevent_new(int size, int flags, int priority);
 struct sctp_ulpevent *sctp_ulpevent_init(struct sctp_ulpevent *, int flags);
 void sctp_ulpevent_free(struct sctp_ulpevent *);
diff -urN linux-2.5.66-bk10/kernel/exit.c linux-2.5.66-bk11/kernel/exit.c
--- linux-2.5.66-bk10/kernel/exit.c	2003-03-24 14:01:24.000000000 -0800
+++ linux-2.5.66-bk11/kernel/exit.c	2003-04-05 04:32:16.000000000 -0800
@@ -488,7 +488,7 @@
 	p->self_exec_id++;
 
 	if (p->pdeath_signal)
-		send_sig(p->pdeath_signal, p, 0);
+		send_group_sig_info(p->pdeath_signal, 0, p);
 
 	/* Move the child from its dying parent to the new one.  */
 	if (unlikely(traced)) {
diff -urN linux-2.5.66-bk10/kernel/itimer.c linux-2.5.66-bk11/kernel/itimer.c
--- linux-2.5.66-bk10/kernel/itimer.c	2003-03-24 14:00:20.000000000 -0800
+++ linux-2.5.66-bk11/kernel/itimer.c	2003-04-05 04:32:16.000000000 -0800
@@ -67,7 +67,7 @@
 	struct task_struct * p = (struct task_struct *) __data;
 	unsigned long interval;
 
-	send_sig(SIGALRM, p, 1);
+	send_group_sig_info(SIGALRM, SEND_SIG_PRIV, p);
 	interval = p->it_real_incr;
 	if (interval) {
 		if (interval > (unsigned long) LONG_MAX)
diff -urN linux-2.5.66-bk10/kernel/module.c linux-2.5.66-bk11/kernel/module.c
--- linux-2.5.66-bk10/kernel/module.c	2003-04-05 04:32:13.000000000 -0800
+++ linux-2.5.66-bk11/kernel/module.c	2003-04-05 04:32:16.000000000 -0800
@@ -974,11 +974,6 @@
 			/* Ok if weak.  */
 			if (ELF_ST_BIND(sym[i].st_info) == STB_WEAK)
 				break;
-#if defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64)
-			/* Ok if Sparc register directive. */
-			if (ELF_ST_TYPE(sym[i].st_info) == STT_REGISTER)
-				break;
-#endif
 
 			printk(KERN_WARNING "%s: Unknown symbol %s\n",
 			       mod->name, strtab + sym[i].st_name);
diff -urN linux-2.5.66-bk10/kernel/signal.c linux-2.5.66-bk11/kernel/signal.c
--- linux-2.5.66-bk10/kernel/signal.c	2003-03-24 14:00:19.000000000 -0800
+++ linux-2.5.66-bk11/kernel/signal.c	2003-04-05 04:32:16.000000000 -0800
@@ -33,64 +33,79 @@
 atomic_t nr_queued_signals;
 int max_queued_signals = 1024;
 
-/*********************************************************
-
-    POSIX thread group signal behavior:
-
-----------------------------------------------------------
-|                    |  userspace       |  kernel        |
-----------------------------------------------------------
-|  SIGHUP            |  load-balance    |  kill-all      |
-|  SIGINT            |  load-balance    |  kill-all      |
-|  SIGQUIT           |  load-balance    |  kill-all+core |
-|  SIGILL            |  specific        |  kill-all+core |
-|  SIGTRAP           |  specific        |  kill-all+core |
-|  SIGABRT/SIGIOT    |  specific        |  kill-all+core |
-|  SIGBUS            |  specific        |  kill-all+core |
-|  SIGFPE            |  specific        |  kill-all+core |
-|  SIGKILL           |  n/a             |  kill-all      |
-|  SIGUSR1           |  load-balance    |  kill-all      |
-|  SIGSEGV           |  specific        |  kill-all+core |
-|  SIGUSR2           |  load-balance    |  kill-all      |
-|  SIGPIPE           |  specific        |  kill-all      |
-|  SIGALRM           |  load-balance    |  kill-all      |
-|  SIGTERM           |  load-balance    |  kill-all      |
-|  SIGCHLD           |  load-balance    |  ignore        |
-|  SIGCONT           |  load-balance    |  ignore        |
-|  SIGSTOP           |  n/a             |  stop-all      |
-|  SIGTSTP           |  load-balance    |  stop-all      |
-|  SIGTTIN           |  load-balance    |  stop-all      |
-|  SIGTTOU           |  load-balance    |  stop-all      |
-|  SIGURG            |  load-balance    |  ignore        |
-|  SIGXCPU           |  specific        |  kill-all+core |
-|  SIGXFSZ           |  specific        |  kill-all+core |
-|  SIGVTALRM         |  load-balance    |  kill-all      |
-|  SIGPROF           |  specific        |  kill-all      |
-|  SIGPOLL/SIGIO     |  load-balance    |  kill-all      |
-|  SIGSYS/SIGUNUSED  |  specific        |  kill-all+core |
-|  SIGSTKFLT         |  specific        |  kill-all      |
-|  SIGWINCH          |  load-balance    |  ignore        |
-|  SIGPWR            |  load-balance    |  kill-all      |
-|  SIGRTMIN-SIGRTMAX |  load-balance    |  kill-all      |
-----------------------------------------------------------
-
-    non-POSIX signal thread group behavior:
-
-----------------------------------------------------------
-|                    |  userspace       |  kernel        |
-----------------------------------------------------------
-|  SIGEMT            |  specific        |  kill-all+core |
-----------------------------------------------------------
-*/
-
-/* Some systems do not have a SIGSTKFLT and the kernel never
- * generates such signals anyways.
+/*
+ * In POSIX a signal is sent either to a specific thread (Linux task)
+ * or to the process as a whole (Linux thread group).  How the signal
+ * is sent determines whether it's to one thread or the whole group,
+ * which determines which signal mask(s) are involved in blocking it
+ * from being delivered until later.  When the signal is delivered,
+ * either it's caught or ignored by a user handler or it has a default
+ * effect that applies to the whole thread group (POSIX process).
+ *
+ * The possible effects an unblocked signal set to SIG_DFL can have are:
+ *   ignore	- Nothing Happens
+ *   terminate	- kill the process, i.e. all threads in the group,
+ * 		  similar to exit_group.  The group leader (only) reports
+ *		  WIFSIGNALED status to its parent.
+ *   coredump	- write a core dump file describing all threads using
+ *		  the same mm and then kill all those threads
+ *   stop 	- stop all the threads in the group, i.e. TASK_STOPPED state
+ *
+ * SIGKILL and SIGSTOP cannot be caught, blocked, or ignored.
+ * Other signals when not blocked and set to SIG_DFL behaves as follows.
+ * The job control signals also have other special effects.
+ *
+ *	+--------------------+------------------+
+ *	|  POSIX signal      |  default action  |
+ *	+--------------------+------------------+
+ *	|  SIGHUP            |  terminate	|
+ *	|  SIGINT            |	terminate	|
+ *	|  SIGQUIT           |	coredump 	|
+ *	|  SIGILL            |	coredump 	|
+ *	|  SIGTRAP           |	coredump 	|
+ *	|  SIGABRT/SIGIOT    |	coredump 	|
+ *	|  SIGBUS            |	coredump 	|
+ *	|  SIGFPE            |	coredump 	|
+ *	|  SIGKILL           |	terminate(+)	|
+ *	|  SIGUSR1           |	terminate	|
+ *	|  SIGSEGV           |	coredump 	|
+ *	|  SIGUSR2           |	terminate	|
+ *	|  SIGPIPE           |	terminate	|
+ *	|  SIGALRM           |	terminate	|
+ *	|  SIGTERM           |	terminate	|
+ *	|  SIGCHLD           |	ignore   	|
+ *	|  SIGCONT           |	ignore(*)	|
+ *	|  SIGSTOP           |	stop(*)(+)  	|
+ *	|  SIGTSTP           |	stop(*)  	|
+ *	|  SIGTTIN           |	stop(*)  	|
+ *	|  SIGTTOU           |	stop(*)  	|
+ *	|  SIGURG            |	ignore   	|
+ *	|  SIGXCPU           |	coredump 	|
+ *	|  SIGXFSZ           |	coredump 	|
+ *	|  SIGVTALRM         |	terminate	|
+ *	|  SIGPROF           |	terminate	|
+ *	|  SIGPOLL/SIGIO     |	terminate	|
+ *	|  SIGSYS/SIGUNUSED  |	coredump 	|
+ *	|  SIGSTKFLT         |	terminate	|
+ *	|  SIGWINCH          |	ignore   	|
+ *	|  SIGPWR            |	terminate	|
+ *	|  SIGRTMIN-SIGRTMAX |	terminate       |
+ *	+--------------------+------------------+
+ *	|  non-POSIX signal  |  default action  |
+ *	+--------------------+------------------+
+ *	|  SIGEMT            |  coredump	|
+ *	+--------------------+------------------+
+ *
+ * (+) For SIGKILL and SIGSTOP the action is "always", not just "default".
+ * (*) Special job control effects:
+ * When SIGCONT is sent, it resumes the process (all threads in the group)
+ * from TASK_STOPPED state and also clears any pending/queued stop signals
+ * (any of those marked with "stop(*)").  This happens regardless of blocking,
+ * catching, or ignoring SIGCONT.  When any stop signal is sent, it clears
+ * any pending/queued SIGCONT signals; this happens regardless of blocking,
+ * catching, or ignored the stop signal, though (except for SIGSTOP) the
+ * default action of stopping the process may happen later or never.
  */
-#ifdef SIGSTKFLT
-#define M_SIGSTKFLT	M(SIGSTKFLT)
-#else
-#define M_SIGSTKFLT	0
-#endif
 
 #ifdef SIGEMT
 #define M_SIGEMT	M(SIGEMT)
@@ -105,16 +120,6 @@
 #endif
 #define T(sig, mask) (M(sig) & (mask))
 
-#define SIG_KERNEL_BROADCAST_MASK (\
-	M(SIGHUP)    |  M(SIGINT)    |  M(SIGQUIT)   |  M(SIGILL)    | \
-	M(SIGTRAP)   |  M(SIGABRT)   |  M(SIGBUS)    |  M(SIGFPE)    | \
-	M(SIGKILL)   |  M(SIGUSR1)   |  M(SIGSEGV)   |  M(SIGUSR2)   | \
-	M(SIGPIPE)   |  M(SIGALRM)   |  M(SIGTERM)   |  M(SIGXCPU)   | \
-	M(SIGXFSZ)   |  M(SIGVTALRM) |  M(SIGPROF)   |  M(SIGPOLL)   | \
-	M(SIGSYS)    |  M_SIGSTKFLT  |  M(SIGPWR)    |  M(SIGCONT)   | \
-        M(SIGSTOP)   |  M(SIGTSTP)   |  M(SIGTTIN)   |  M(SIGTTOU)   | \
-        M_SIGEMT )
-
 #define SIG_KERNEL_ONLY_MASK (\
 	M(SIGKILL)   |  M(SIGSTOP)                                   )
 
@@ -599,7 +604,7 @@
 				     struct task_struct *parent);
 
 /*
- * Handle magic process-wide effects of stop/continue signals, and SIGKILL.
+ * Handle magic process-wide effects of stop/continue signals.
  * Unlike the signal actions, these happen immediately at signal-generation
  * time regardless of blocking, ignoring, or handling.  This does the
  * actual continuing for SIGCONT, but not the actual stopping for stop
@@ -1134,9 +1139,8 @@
  */
 
 /*
- * XXX should probably nix these interfaces and update the kernel
- * to specify explicitly whether the signal is a group signal or
- * specific to a thread.
+ * These two are the most common entry points.  They send a signal
+ * just to the specific thread.
  */
 int
 send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
@@ -1150,13 +1154,9 @@
 	 * going away or changing from under us.
 	 */
 	read_lock(&tasklist_lock);  
-	if (T(sig, SIG_KERNEL_BROADCAST_MASK)) {
-		ret = group_send_sig_info(sig, info, p);
-	} else {
-		spin_lock_irq(&p->sighand->siglock);
-		ret = specific_send_sig_info(sig, info, p);
-		spin_unlock_irq(&p->sighand->siglock);
-	}
+	spin_lock_irq(&p->sighand->siglock);
+	ret = specific_send_sig_info(sig, info, p);
+	spin_unlock_irq(&p->sighand->siglock);
 	read_unlock(&tasklist_lock);
 	return ret;
 }
@@ -1167,6 +1167,20 @@
 	return send_sig_info(sig, (void*)(long)(priv != 0), p);
 }
 
+/*
+ * This is the entry point for "process-wide" signals.
+ * They will go to an appropriate thread in the thread group.
+ */
+int
+send_group_sig_info(int sig, struct siginfo *info, struct task_struct *p)
+{
+	int ret;
+	read_lock(&tasklist_lock);
+	ret = group_send_sig_info(sig, info, p);
+	read_unlock(&tasklist_lock);
+	return ret;
+}
+
 void
 force_sig(int sig, struct task_struct *p)
 {
@@ -1642,6 +1656,7 @@
 EXPORT_SYMBOL(notify_parent);
 EXPORT_SYMBOL(send_sig);
 EXPORT_SYMBOL(send_sig_info);
+EXPORT_SYMBOL(send_group_sig_info);
 EXPORT_SYMBOL(sigprocmask);
 EXPORT_SYMBOL(block_all_signals);
 EXPORT_SYMBOL(unblock_all_signals);
diff -urN linux-2.5.66-bk10/net/Kconfig linux-2.5.66-bk11/net/Kconfig
--- linux-2.5.66-bk10/net/Kconfig	2003-04-05 04:32:13.000000000 -0800
+++ linux-2.5.66-bk11/net/Kconfig	2003-04-05 04:32:16.000000000 -0800
@@ -620,7 +620,7 @@
 	  Differentiated Services (diffserv) and Resource Reservation Protocol
 	  (RSVP) on your Linux router if you also say Y to "QoS support",
 	  "Packet classifier API" and to some classifiers below. Documentation
-	  and software is at <http://icawww1.epfl.ch/linux-diffserv/>.
+	  and software is at <http://diffserv.sourceforge.net/>.
 
 	  If you say Y here and to "/proc file system" below, you will be able
 	  to read status information about packet schedulers from the file
diff -urN linux-2.5.66-bk10/net/ipv4/ip_output.c linux-2.5.66-bk11/net/ipv4/ip_output.c
--- linux-2.5.66-bk10/net/ipv4/ip_output.c	2003-03-24 14:01:47.000000000 -0800
+++ linux-2.5.66-bk11/net/ipv4/ip_output.c	2003-04-05 04:32:16.000000000 -0800
@@ -1293,11 +1293,10 @@
 
 static struct packet_type ip_packet_type =
 {
-	__constant_htons(ETH_P_IP),
-	NULL,	/* All devices */
-	ip_rcv,
-	(void*)1,
-	NULL,
+	.type = __constant_htons(ETH_P_IP),
+	.dev  = NULL,	/* All devices */
+	.func = ip_rcv,
+	.data = (void*)1,
 };
 
 /*
diff -urN linux-2.5.66-bk10/net/ipv4/netfilter/ip_nat_core.c linux-2.5.66-bk11/net/ipv4/netfilter/ip_nat_core.c
--- linux-2.5.66-bk10/net/ipv4/netfilter/ip_nat_core.c	2003-03-24 14:00:07.000000000 -0800
+++ linux-2.5.66-bk11/net/ipv4/netfilter/ip_nat_core.c	2003-04-05 04:32:16.000000000 -0800
@@ -8,7 +8,6 @@
 #include <linux/timer.h>
 #include <linux/skbuff.h>
 #include <linux/netfilter_ipv4.h>
-#include <linux/brlock.h>
 #include <linux/vmalloc.h>
 #include <net/checksum.h>
 #include <net/icmp.h>
diff -urN linux-2.5.66-bk10/net/ipv6/ipv6_sockglue.c linux-2.5.66-bk11/net/ipv6/ipv6_sockglue.c
--- linux-2.5.66-bk10/net/ipv6/ipv6_sockglue.c	2003-03-24 13:59:58.000000000 -0800
+++ linux-2.5.66-bk11/net/ipv6/ipv6_sockglue.c	2003-04-05 04:32:16.000000000 -0800
@@ -55,20 +55,18 @@
 
 static struct packet_type ipv6_packet_type =
 {
-	__constant_htons(ETH_P_IPV6), 
-	NULL,					/* All devices */
-	ipv6_rcv,
-	(void*)1,
-	NULL
+	.type = __constant_htons(ETH_P_IPV6), 
+	.dev  = NULL,				/* All devices */
+	.func = ipv6_rcv,
+	.data = (void*)1,
 };
 
 /*
- *	addrconf module should be notifyed of a device going up
+ *	addrconf module should be notified of a device going up
  */
 static struct notifier_block ipv6_dev_notf = {
-	addrconf_notify,
-	NULL,
-	0
+	.notifier_call = addrconf_notify,
+	.priority = 0
 };
 
 struct ip6_ra_chain *ip6_ra_chain;
diff -urN linux-2.5.66-bk10/net/ipv6/netfilter/ip6_queue.c linux-2.5.66-bk11/net/ipv6/netfilter/ip6_queue.c
--- linux-2.5.66-bk10/net/ipv6/netfilter/ip6_queue.c	2003-03-24 14:00:12.000000000 -0800
+++ linux-2.5.66-bk11/net/ipv6/netfilter/ip6_queue.c	2003-04-05 04:32:16.000000000 -0800
@@ -26,7 +26,6 @@
 #include <linux/netfilter.h>
 #include <linux/netlink.h>
 #include <linux/spinlock.h>
-#include <linux/brlock.h>
 #include <linux/sysctl.h>
 #include <linux/proc_fs.h>
 #include <net/sock.h>
@@ -682,8 +681,7 @@
 
 cleanup:
 	nf_unregister_queue_handler(PF_INET6);
-	br_write_lock_bh(BR_NETPROTO_LOCK);
-	br_write_unlock_bh(BR_NETPROTO_LOCK);
+	synchronize_net();
 	ipq_flush(NF_DROP);
 	
 cleanup_sysctl:
diff -urN linux-2.5.66-bk10/net/ipv6/proc.c linux-2.5.66-bk11/net/ipv6/proc.c
--- linux-2.5.66-bk10/net/ipv6/proc.c	2003-04-05 04:32:13.000000000 -0800
+++ linux-2.5.66-bk11/net/ipv6/proc.c	2003-04-05 04:32:16.000000000 -0800
@@ -156,7 +156,7 @@
 	int i;
 
 	for (i=0; i<sizeof(snmp6_list)/sizeof(snmp6_list[0]); i++)
-		seq_printf(seq, "%-32s\t%ld\n", snmp6_list[i].name,
+		seq_printf(seq, "%-32s\t%lu\n", snmp6_list[i].name,
 			       fold_field(snmp6_list[i].mib, snmp6_list[i].offset));
 
 	return 0;
diff -urN linux-2.5.66-bk10/net/sched/Kconfig linux-2.5.66-bk11/net/sched/Kconfig
--- linux-2.5.66-bk10/net/sched/Kconfig	2003-03-24 14:01:24.000000000 -0800
+++ linux-2.5.66-bk11/net/sched/Kconfig	2003-04-05 04:32:16.000000000 -0800
@@ -167,7 +167,7 @@
 	tristate "Diffserv field marker"
 	depends on NET_SCHED
 	help
-	  Say Y if you want to schedule packets avccording to the
+	  Say Y if you want to schedule packets according to the
 	  Differentiated Services architecture proposed in RFC 2475.
 	  Technical information on this method, with pointers to associated
 	  RFCs, is available at <http://www.gta.ufrj.br/diffserv/>.
@@ -202,7 +202,7 @@
 	  Differentiated Services (diffserv) and Resource Reservation Protocol
 	  (RSVP) on your Linux router if you also say Y to "Packet classifier
 	  API" and to some classifiers below. Documentation and software is at
-	  <http://icawww1.epfl.ch/linux-diffserv/>.
+	  <http://diffserv.sourceforge.net/>.
 
 	  Note that the answer to this question won't directly affect the
 	  kernel: saying N will just cause the configurator to skip all
@@ -229,7 +229,7 @@
 	  This will enable you to use Differentiated Services (diffserv) and
 	  Resource Reservation Protocol (RSVP) on your Linux router.
 	  Documentation and software is at
-	  <http://icawww1.epfl.ch/linux-diffserv/>.
+	  <http://diffserv.sourceforge.net/>.
 
 config NET_CLS_TCINDEX
 	tristate "TC index classifier"
diff -urN linux-2.5.66-bk10/net/sctp/associola.c linux-2.5.66-bk11/net/sctp/associola.c
--- linux-2.5.66-bk10/net/sctp/associola.c	2003-03-24 13:59:55.000000000 -0800
+++ linux-2.5.66-bk11/net/sctp/associola.c	2003-04-05 04:32:16.000000000 -0800
@@ -290,14 +290,18 @@
  */
 void sctp_association_free(sctp_association_t *asoc)
 {
+	struct sock *sk = asoc->base.sk;
 	struct sctp_transport *transport;
-	sctp_endpoint_t *ep;
 	struct list_head *pos, *temp;
 	int i;
 
-	ep = asoc->ep;
 	list_del(&asoc->asocs);
 
+	/* Decrement the backlog value for a TCP-style listening socket. */
+	if ((SCTP_SOCKET_TCP == sctp_sk(sk)->type) &&
+	    (SCTP_SS_LISTENING == sk->state))
+		sk->ack_backlog--;
+
 	/* Mark as dead, so other users can know this structure is
 	 * going away.
 	 */
@@ -421,8 +425,7 @@
 	SCTP_DEBUG_PRINTK("sctp_assoc_add_peer:association %p PMTU set to "
 			  "%d\n", asoc, asoc->pmtu);
 
-	asoc->frag_point = asoc->pmtu;
-	asoc->frag_point -= SCTP_IP_OVERHEAD + sizeof(struct sctp_data_chunk);
+	asoc->frag_point = sctp_frag_point(asoc->pmtu);
 
 	/* The asoc->peer.port might not be meaningful yet, but
 	 * initialize the packet structure anyway.
@@ -642,8 +645,6 @@
 
 /* Compare two addresses to see if they match.  Wildcard addresses
  * only match themselves.
- *
- * FIXME: We do not match address scopes correctly.
  */
 int sctp_cmp_addr_exact(const union sctp_addr *ss1,
 			const union sctp_addr *ss2)
@@ -651,38 +652,27 @@
 	struct sctp_af *af;
 
 	af = sctp_get_af_specific(ss1->sa.sa_family);
-	if (!af)
+	if (unlikely(!af))
 		return 0;
 
 	return af->cmp_addr(ss1, ss2);
 }
 
 /* Return an ecne chunk to get prepended to a packet.
- * Note:  We are sly and return a shared, prealloced chunk.
+ * Note:  We are sly and return a shared, prealloced chunk.  FIXME:
+ * No we don't, but we could/should.
  */
-sctp_chunk_t *sctp_get_ecne_prepend(sctp_association_t *asoc)
+sctp_chunk_t *sctp_get_ecne_prepend(struct sctp_association *asoc)
 {
-	sctp_chunk_t *chunk;
-	int need_ecne;
-	__u32 lowest_tsn;
+	struct sctp_chunk *chunk;
 
-	/* Can be called from task or bh.   Both need_ecne and
-	 * last_ecne_tsn are written during bh.
+	/* Send ECNE if needed.
+	 * Not being able to allocate a chunk here is not deadly.
 	 */
-	need_ecne = asoc->need_ecne;
-	lowest_tsn = asoc->last_ecne_tsn;
-
-	if (need_ecne) {
-		chunk = sctp_make_ecne(asoc, lowest_tsn);
-
-		/* ECNE is not mandatory to the flow.  Being unable to
-		 * alloc mem is not deadly.  We are just unable to help
-		 * out the network.  If we run out of memory, just return
-		 * NULL.
-		 */
-	} else {
+	if (asoc->need_ecne)
+		chunk = sctp_make_ecne(asoc, asoc->last_ecne_tsn);
+	else
 		chunk = NULL;
-	}
 
 	return chunk;
 }
@@ -832,12 +822,17 @@
 void sctp_assoc_migrate(sctp_association_t *assoc, struct sock *newsk)
 {
 	struct sctp_opt *newsp = sctp_sk(newsk);
+	struct sock *oldsk = assoc->base.sk;
 
 	/* Delete the association from the old endpoint's list of
 	 * associations.
 	 */
 	list_del(&assoc->asocs);
 
+	/* Decrement the backlog value for a TCP-style socket. */
+	if (SCTP_SOCKET_TCP == sctp_sk(oldsk)->type)
+		oldsk->ack_backlog--;
+
 	/* Release references to the old endpoint and the sock.  */
 	sctp_endpoint_put(assoc->ep);
 	sock_put(assoc->base.sk);
@@ -986,8 +981,7 @@
 
 	if (pmtu) {
 		asoc->pmtu = pmtu;
-		asoc->frag_point = pmtu - (SCTP_IP_OVERHEAD +
-					   sizeof(sctp_data_chunk_t));
+		asoc->frag_point = sctp_frag_point(pmtu);
 	}
 
 	SCTP_DEBUG_PRINTK("%s: asoc:%p, pmtu:%d, frag_point:%d\n",
@@ -1001,9 +995,9 @@
 	case SCTP_STATE_ESTABLISHED:
 	case SCTP_STATE_SHUTDOWN_PENDING:
 	case SCTP_STATE_SHUTDOWN_RECEIVED:
-		if ((asoc->rwnd > asoc->a_rwnd) && 
+		if ((asoc->rwnd > asoc->a_rwnd) &&
 		    ((asoc->rwnd - asoc->a_rwnd) >=
-		     min_t(__u32, (asoc->base.sk->rcvbuf >> 1), asoc->pmtu))) 
+		     min_t(__u32, (asoc->base.sk->rcvbuf >> 1), asoc->pmtu)))
 			return 1;
 		break;
 	default:
@@ -1070,14 +1064,14 @@
 		asoc->rwnd = 0;
 	}
 	SCTP_DEBUG_PRINTK("%s: asoc %p rwnd decreased by %d to (%u, %u)\n",
-			  __FUNCTION__, asoc, len, asoc->rwnd, 
+			  __FUNCTION__, asoc, len, asoc->rwnd,
 			  asoc->rwnd_over);
 }
 
 /* Build the bind address list for the association based on info from the
  * local endpoint and the remote peer.
  */
-int sctp_assoc_set_bind_addr_from_ep(sctp_association_t *asoc, int priority)
+int sctp_assoc_set_bind_addr_from_ep(struct sctp_association *asoc, int gfp)
 {
 	sctp_scope_t scope;
 	int flags;
@@ -1094,19 +1088,17 @@
 
 	return sctp_bind_addr_copy(&asoc->base.bind_addr,
 				   &asoc->ep->base.bind_addr,
-				   scope, priority, flags);
+				   scope, gfp, flags);
 }
 
 /* Build the association's bind address list from the cookie.  */
 int sctp_assoc_set_bind_addr_from_cookie(sctp_association_t *asoc,
-					 sctp_cookie_t *cookie, int priority)
+					 sctp_cookie_t *cookie, int gfp)
 {
 	int var_size2 = ntohs(cookie->peer_init->chunk_hdr.length);
 	int var_size3 = cookie->raw_addr_list_len;
-	__u8 *raw_addr_list = (__u8 *)cookie + sizeof(sctp_cookie_t) +
-				      var_size2;
+	__u8 *raw = (__u8 *)cookie + sizeof(sctp_cookie_t) + var_size2;
 
-	return sctp_raw_to_bind_addrs(&asoc->base.bind_addr, raw_addr_list,
-				      var_size3, asoc->ep->base.bind_addr.port,
-				      priority);
+	return sctp_raw_to_bind_addrs(&asoc->base.bind_addr, raw, var_size3,
+				      asoc->ep->base.bind_addr.port, gfp);
 }
diff -urN linux-2.5.66-bk10/net/sctp/bind_addr.c linux-2.5.66-bk11/net/sctp/bind_addr.c
--- linux-2.5.66-bk10/net/sctp/bind_addr.c	2003-03-24 14:01:23.000000000 -0800
+++ linux-2.5.66-bk11/net/sctp/bind_addr.c	2003-04-05 04:32:16.000000000 -0800
@@ -53,7 +53,7 @@
 
 /* Forward declarations for internal helpers. */
 static int sctp_copy_one_addr(sctp_bind_addr_t *, union sctp_addr *,
-			      sctp_scope_t scope, int priority, int flags);
+			      sctp_scope_t scope, int gfp, int flags);
 static void sctp_bind_addr_clean(sctp_bind_addr_t *);
 
 /* First Level Abstractions. */
@@ -62,7 +62,7 @@
  * in 'src' which have a broader scope than 'scope'.
  */
 int sctp_bind_addr_copy(sctp_bind_addr_t *dest, const sctp_bind_addr_t *src,
-			sctp_scope_t scope, int priority, int flags)
+			sctp_scope_t scope, int gfp, int flags)
 {
 	struct sockaddr_storage_list *addr;
 	struct list_head *pos;
@@ -75,7 +75,7 @@
 	list_for_each(pos, &src->address_list) {
 		addr = list_entry(pos, struct sockaddr_storage_list, list);
 		error = sctp_copy_one_addr(dest, &addr->a, scope,
-					   priority, flags);
+					   gfp, flags);
 		if (error < 0)
 			goto out;
 	}
@@ -88,11 +88,11 @@
 }
 
 /* Create a new SCTP_bind_addr from nothing.  */
-sctp_bind_addr_t *sctp_bind_addr_new(int priority)
+sctp_bind_addr_t *sctp_bind_addr_new(int gfp)
 {
 	sctp_bind_addr_t *retval;
 
-	retval = t_new(sctp_bind_addr_t, priority);
+	retval = t_new(sctp_bind_addr_t, gfp);
 	if (!retval)
 		goto nomem;
 
@@ -144,12 +144,12 @@
 
 /* Add an address to the bind address list in the SCTP_bind_addr structure. */
 int sctp_add_bind_addr(sctp_bind_addr_t *bp, union sctp_addr *new,
-		       int priority)
+		       int gfp)
 {
 	struct sockaddr_storage_list *addr;
 
 	/* Add the address to the bind address list.  */
-	addr = t_new(struct sockaddr_storage_list, priority);
+	addr = t_new(struct sockaddr_storage_list, gfp);
 	if (!addr)
 		return -ENOMEM;
 
@@ -197,7 +197,7 @@
  * The second argument is the return value for the length.
  */
 union sctp_params sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp,
-					 int *addrs_len, int priority)
+					 int *addrs_len, int gfp)
 {
 	union sctp_params addrparms;
 	union sctp_params retval;
@@ -214,7 +214,7 @@
 		len += sizeof(sctp_addr_param_t);
 	}
 
-	retval.v = kmalloc(len, priority);
+	retval.v = kmalloc(len, gfp);
 	if (!retval.v)
 		goto end_raw;
 
@@ -238,7 +238,7 @@
  * address parameters).
  */
 int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, __u8 *raw_addr_list,
-			   int addrs_len, __u16 port, int priority)
+			   int addrs_len, __u16 port, int gfp)
 {
 	sctp_addr_param_t *rawaddr;
 	sctp_paramhdr_t *param;
@@ -254,8 +254,8 @@
 		switch (param->type) {
 		case SCTP_PARAM_IPV4_ADDRESS:
 		case SCTP_PARAM_IPV6_ADDRESS:
-			sctp_param2sockaddr(&addr, rawaddr, port);
-			retval = sctp_add_bind_addr(bp, &addr, priority);
+			sctp_param2sockaddr(&addr, rawaddr, port, 0);
+			retval = sctp_add_bind_addr(bp, &addr, gfp);
 			if (retval) {
 				/* Can't finish building the list, clean up. */
 				sctp_bind_addr_clean(bp);
@@ -300,14 +300,14 @@
 
 /* Copy out addresses from the global local address list. */
 static int sctp_copy_one_addr(sctp_bind_addr_t *dest, union sctp_addr *addr,
-			      sctp_scope_t scope, int priority, int flags)
+			      sctp_scope_t scope, int gfp, int flags)
 {
 	struct sctp_protocol *proto = sctp_get_protocol();
 	int error = 0;
 
 	if (sctp_is_any(addr)) {
 		error = sctp_copy_local_addr_list(proto, dest, scope,
-						  priority, flags);
+						  gfp, flags);
 	} else if (sctp_in_scope(addr, scope)) {
 		/* Now that the address is in scope, check to see if
 		 * the address type is supported by local sock as
@@ -318,7 +318,7 @@
 		    (((AF_INET6 == addr->sa.sa_family) &&
 		      (flags & SCTP_ADDR6_ALLOWED) &&
 		      (flags & SCTP_ADDR6_PEERSUPP))))
-			error = sctp_add_bind_addr(dest, addr, priority);
+			error = sctp_add_bind_addr(dest, addr, gfp);
 	}
 
 	return error;
diff -urN linux-2.5.66-bk10/net/sctp/endpointola.c linux-2.5.66-bk11/net/sctp/endpointola.c
--- linux-2.5.66-bk10/net/sctp/endpointola.c	2003-03-24 14:00:02.000000000 -0800
+++ linux-2.5.66-bk11/net/sctp/endpointola.c	2003-04-05 04:32:16.000000000 -0800
@@ -177,8 +177,15 @@
 /* Add an association to an endpoint.  */
 void sctp_endpoint_add_asoc(sctp_endpoint_t *ep, sctp_association_t *asoc)
 {
+	struct sock *sk = ep->base.sk;
+
 	/* Now just add it to our list of asocs */
 	list_add_tail(&asoc->asocs, &ep->asocs);
+
+	/* Increment the backlog value for a TCP-style listening socket. */
+	if ((SCTP_SOCKET_TCP == sctp_sk(sk)->type) &&
+	    (SCTP_SS_LISTENING == sk->state))
+		sk->ack_backlog++;
 }
 
 /* Free the endpoint structure.  Delay cleanup until
diff -urN linux-2.5.66-bk10/net/sctp/input.c linux-2.5.66-bk11/net/sctp/input.c
--- linux-2.5.66-bk10/net/sctp/input.c	2003-03-24 13:59:55.000000000 -0800
+++ linux-2.5.66-bk11/net/sctp/input.c	2003-04-05 04:32:16.000000000 -0800
@@ -207,21 +207,19 @@
 	 */
 	sctp_bh_lock_sock(sk);
 
-	if (sock_owned_by_user(sk)) {
+	if (sock_owned_by_user(sk))
 		sk_add_backlog(sk, (struct sk_buff *) chunk);
-	} else {
+	else
 		sctp_backlog_rcv(sk, (struct sk_buff *) chunk);
-	}
 
 	/* Release the sock and any reference counts we took in the
 	 * lookup calls.
 	 */
 	sctp_bh_unlock_sock(sk);
-	if (asoc) {
+	if (asoc)
 		sctp_association_put(asoc);
-	} else {
+	else
 		sctp_endpoint_put(ep);
-	}
 	sock_put(sk);
 	return ret;
 
@@ -268,10 +266,8 @@
 }
 
 /* Handle icmp frag needed error. */
-static inline void sctp_icmp_frag_needed(struct sock *sk,
-					 sctp_association_t *asoc,
-					 struct sctp_transport *transport,
-					 __u32 pmtu)
+void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc,
+			   struct sctp_transport *t, __u32 pmtu)
 {
 	if (unlikely(pmtu < SCTP_DEFAULT_MINSEGMENT)) {
 		printk(KERN_WARNING "%s: Reported pmtu %d too low, "
@@ -280,54 +276,38 @@
 		pmtu = SCTP_DEFAULT_MINSEGMENT;
 	}
 
-	if (!sock_owned_by_user(sk) && transport && (transport->pmtu != pmtu)) {
-		transport->pmtu = pmtu;
+	if (!sock_owned_by_user(sk) && t && (t->pmtu != pmtu)) {
+		t->pmtu = pmtu;
 		sctp_assoc_sync_pmtu(asoc);
-		sctp_retransmit(&asoc->outqueue, transport,
-				SCTP_RETRANSMIT_PMTU_DISCOVERY );
+		sctp_retransmit(&asoc->outqueue, t, SCTP_RTXR_PMTUD);
 	}
 }
 
-/*
- * This routine is called by the ICMP module when it gets some
- * sort of error condition.  If err < 0 then the socket should
- * be closed and the error returned to the user.  If err > 0
- * it's just the icmp type << 8 | icmp code.  After adjustment
- * header points to the first 8 bytes of the sctp header.  We need
- * to find the appropriate port.
- *
- * The locking strategy used here is very "optimistic". When
- * someone else accesses the socket the ICMP is just dropped
- * and for some paths there is no check at all.
- * A more general error queue to queue errors for later handling
- * is probably better.
- *
- */
-void sctp_v4_err(struct sk_buff *skb, __u32 info)
+/* Common lookup code for icmp/icmpv6 error handler. */
+struct sock *sctp_err_lookup(int family, struct sk_buff *skb,
+			     struct sctphdr *sctphdr,
+			     struct sctp_endpoint **epp, 
+			     struct sctp_association **app, 
+			     struct sctp_transport **tpp)
 {
-	struct iphdr *iph = (struct iphdr *)skb->data;
-	struct sctphdr *sh = (struct sctphdr *)(skb->data + (iph->ihl <<2));
-	int type = skb->h.icmph->type;
-	int code = skb->h.icmph->code;
-	union sctp_addr saddr, daddr;
-	struct inet_opt *inet;
+	union sctp_addr saddr;
+	union sctp_addr daddr;
+	struct sctp_af *af;
 	struct sock *sk = NULL;
-	sctp_endpoint_t *ep = NULL;
-	sctp_association_t *asoc = NULL;
-	struct sctp_transport *transport;
-	int err;
+	struct sctp_endpoint *ep = NULL;
+	struct sctp_association *asoc = NULL;
+	struct sctp_transport *transport = NULL;
 
-	if (skb->len < ((iph->ihl << 2) + 8)) {
-		ICMP_INC_STATS_BH(IcmpInErrors);
-		return;
+	*app = NULL; *epp = NULL; *tpp = NULL;
+
+	af = sctp_get_af_specific(family);
+	if (unlikely(!af)) {
+		return NULL;
 	}
 
-	saddr.v4.sin_family = AF_INET;
-	saddr.v4.sin_port = ntohs(sh->source);
-	memcpy(&saddr.v4.sin_addr.s_addr, &iph->saddr, sizeof(struct in_addr));	
-	daddr.v4.sin_family = AF_INET;
-	daddr.v4.sin_port = ntohs(sh->dest);
-	memcpy(&daddr.v4.sin_addr.s_addr, &iph->daddr, sizeof(struct in_addr));	
+	/* Initialize local addresses for lookups. */
+	af->from_skb(&saddr, skb, 1);
+	af->from_skb(&daddr, skb, 0);
 
 	/* Look for an association that matches the incoming ICMP error 
 	 * packet.
@@ -340,13 +320,12 @@
 		 */ 
 		ep = __sctp_rcv_lookup_endpoint(&daddr);
 		if (!ep) {
-			ICMP_INC_STATS_BH(IcmpInErrors);
-			return;
+			return NULL;
 		}
 	}
 
 	if (asoc) {
-		if (ntohl(sh->vtag) != asoc->c.peer_vtag) {
+		if (ntohl(sctphdr->vtag) != asoc->c.peer_vtag) {
 			ICMP_INC_STATS_BH(IcmpInErrors);
 			goto out;
 		}
@@ -355,12 +334,90 @@
 		sk = ep->base.sk;
 
 	sctp_bh_lock_sock(sk);
+
 	/* If too many ICMPs get dropped on busy
 	 * servers this needs to be solved differently.
 	 */
 	if (sock_owned_by_user(sk))
 		NET_INC_STATS_BH(LockDroppedIcmps);
 
+	*epp = ep;
+	*app = asoc;
+	*tpp = transport;
+	return sk;
+	
+out:
+	sock_put(sk);
+	if (asoc)
+		sctp_association_put(asoc);
+	if (ep)	
+		sctp_endpoint_put(ep);
+	return NULL;
+}
+
+/* Common cleanup code for icmp/icmpv6 error handler. */
+void sctp_err_finish(struct sock *sk, struct sctp_endpoint *ep, 
+		     struct sctp_association *asoc)
+{
+	sctp_bh_unlock_sock(sk);
+	sock_put(sk);
+	if (asoc)
+		sctp_association_put(asoc);
+	if (ep)	
+		sctp_endpoint_put(ep);
+}
+
+/*
+ * This routine is called by the ICMP module when it gets some
+ * sort of error condition.  If err < 0 then the socket should
+ * be closed and the error returned to the user.  If err > 0
+ * it's just the icmp type << 8 | icmp code.  After adjustment
+ * header points to the first 8 bytes of the sctp header.  We need
+ * to find the appropriate port.
+ *
+ * The locking strategy used here is very "optimistic". When
+ * someone else accesses the socket the ICMP is just dropped
+ * and for some paths there is no check at all.
+ * A more general error queue to queue errors for later handling
+ * is probably better.
+ *
+ */
+void sctp_v4_err(struct sk_buff *skb, __u32 info)
+{
+	struct iphdr *iph = (struct iphdr *)skb->data;
+	struct sctphdr *sh = (struct sctphdr *)(skb->data + (iph->ihl <<2));
+	int type = skb->h.icmph->type;
+	int code = skb->h.icmph->code;
+	struct sock *sk;
+	sctp_endpoint_t *ep;
+	sctp_association_t *asoc;
+	struct sctp_transport *transport;
+	struct inet_opt *inet;
+	char *saveip, *savesctp;
+	int err;
+
+	if (skb->len < ((iph->ihl << 2) + 8)) {
+		ICMP_INC_STATS_BH(IcmpInErrors);
+		return;
+	}
+
+	/* Fix up skb to look at the embedded net header. */
+	saveip = skb->nh.raw;
+	savesctp  = skb->h.raw;
+	skb->nh.iph = iph;
+	skb->h.raw = (char *)sh;
+	sk = sctp_err_lookup(AF_INET, skb, sh, &ep, &asoc, &transport);
+	/* Put back, the original pointers. */
+	skb->nh.raw = saveip;
+	skb->h.raw = savesctp;
+	if (!sk) {
+		ICMP_INC_STATS_BH(IcmpInErrors);
+		return;
+	}
+	/* Warning:  The sock lock is held.  Remember to call 
+	 * sctp_err_finish!
+	 */
+
 	switch (type) {
 	case ICMP_PARAMETERPROB:
 		err = EPROTO;
@@ -399,13 +456,7 @@
 	}
 
 out_unlock:
-	sctp_bh_unlock_sock(sk);
-out:
-	sock_put(sk);
-	if (asoc)
-		sctp_association_put(asoc);
-	if (ep)	
-		sctp_endpoint_put(ep);
+	sctp_err_finish(sk, ep, asoc);
 }
 
 /*
@@ -623,9 +674,9 @@
 }
 
 /* Look up an association. */
-sctp_association_t *__sctp_lookup_association(const union sctp_addr *laddr,
-					      const union sctp_addr *paddr,
-					      struct sctp_transport **transportp)
+sctp_association_t *__sctp_lookup_association(const union sctp_addr *local,
+					      const union sctp_addr *peer,
+					      struct sctp_transport **pt)
 {
 	sctp_hashbucket_t *head;
 	sctp_endpoint_common_t *epb;
@@ -636,12 +687,12 @@
 	/* Optimize here for direct hit, only listening connections can
 	 * have wildcards anyways.
 	 */
-	hash = sctp_assoc_hashfn(laddr->v4.sin_port, paddr->v4.sin_port);
+	hash = sctp_assoc_hashfn(local->v4.sin_port, peer->v4.sin_port);
 	head = &sctp_proto.assoc_hashbucket[hash];
 	read_lock(&head->lock);
 	for (epb = head->chain; epb; epb = epb->next) {
 		asoc = sctp_assoc(epb);
-		transport = sctp_assoc_is_match(asoc, laddr, paddr);
+		transport = sctp_assoc_is_match(asoc, local, peer);
 		if (transport)
 			goto hit;
 	}
@@ -651,7 +702,7 @@
 	return NULL;
 
 hit:
-	*transportp = transport;
+	*pt = transport;
 	sctp_association_hold(asoc);
 	sock_hold(epb->sk);
 	read_unlock(&head->lock);
@@ -754,7 +805,7 @@
 		    (SCTP_PARAM_IPV6_ADDRESS != params.p->type))
 			continue;
 
-		sctp_param2sockaddr(paddr, params.addr, ntohs(sh->source));
+		sctp_param2sockaddr(paddr, params.addr, ntohs(sh->source), 0);
 		asoc = __sctp_lookup_association(laddr, paddr, transportp);
 		if (asoc)
 			return asoc;
@@ -782,8 +833,3 @@
 
 	return asoc;
 }
-
-
-
-
-
diff -urN linux-2.5.66-bk10/net/sctp/ipv6.c linux-2.5.66-bk11/net/sctp/ipv6.c
--- linux-2.5.66-bk10/net/sctp/ipv6.c	2003-04-05 04:32:13.000000000 -0800
+++ linux-2.5.66-bk11/net/sctp/ipv6.c	2003-04-05 04:32:16.000000000 -0800
@@ -1,7 +1,7 @@
 /* SCTP kernel reference Implementation
  * Copyright (c) 2001 Nokia, Inc.
  * Copyright (c) 2001 La Monte H.P. Yarroll
- * Copyright (c) 2002 International Business Machines, Corp.
+ * Copyright (c) 2002-2003 International Business Machines, Corp.
  *
  * This file is part of the SCTP kernel reference Implementation
  *
@@ -88,17 +88,62 @@
         ntohs((addr)->s6_addr16[6]), \
         ntohs((addr)->s6_addr16[7])
 
-/* FIXME: Comments. */
-static inline void sctp_v6_err(struct sk_buff *skb,
-			       struct inet6_skb_parm *opt,
-			       int type, int code, int offset, __u32 info)
-{
-	/* BUG.  WRITE ME.  */
+/* ICMP error handler. */
+void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+		 int type, int code, int offset, __u32 info)
+{
+	struct ipv6hdr *iph = (struct ipv6hdr *)skb->data;
+	struct sctphdr *sh = (struct sctphdr *)(skb->data + offset);
+	struct sock *sk;
+	sctp_endpoint_t *ep;
+	sctp_association_t *asoc;
+	struct sctp_transport *transport;
+	struct ipv6_pinfo *np;
+	char *saveip, *savesctp;
+	int err;
+
+	/* Fix up skb to look at the embedded net header. */
+	saveip = skb->nh.raw;
+	savesctp  = skb->h.raw;
+	skb->nh.ipv6h = iph;
+	skb->h.raw = (char *)sh;
+	sk = sctp_err_lookup(AF_INET6, skb, sh, &ep, &asoc, &transport);
+	/* Put back, the original pointers. */
+	skb->nh.raw = saveip;
+	skb->h.raw = savesctp;
+	if (!sk) {
+		ICMP6_INC_STATS_BH(Icmp6InErrors);
+		return;
+	}
+
+	/* Warning:  The sock lock is held.  Remember to call 
+	 * sctp_err_finish!
+	 */
+
+	switch (type) {
+	case ICMPV6_PKT_TOOBIG:
+		sctp_icmp_frag_needed(sk, asoc, transport, ntohl(info));
+		goto out_unlock;
+	default:
+		break;
+	}
+
+	np = inet6_sk(sk);
+	icmpv6_err_convert(type, code, &err);
+	if (!sock_owned_by_user(sk) && np->recverr) {
+		sk->err = err;
+		sk->error_report(sk);
+	} else {  /* Only an error on timeout */
+		sk->err_soft = err;
+	}
+
+out_unlock:
+	sctp_err_finish(sk, ep, asoc);
 }
 
 /* Based on tcp_v6_xmit() in tcp_ipv6.c. */
-static inline int sctp_v6_xmit(struct sk_buff *skb,
-			       struct sctp_transport *transport, int ipfragok)
+static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport, 
+			int ipfragok)
 {
 	struct sock *sk = skb->sk;
 	struct ipv6_pinfo *np = inet6_sk(sk);
@@ -110,15 +155,18 @@
 
 	/* Fill in the dest address from the route entry passed with the skb
 	 * and the source address from the transport.
-	 */ 
+	 */
 	fl.fl6_dst = &rt6->rt6i_dst.addr;
-	fl.fl6_src = &transport->saddr.v6.sin6_addr; 
+	fl.fl6_src = &transport->saddr.v6.sin6_addr;
 
 	fl.fl6_flowlabel = np->flow_label;
 	IP6_ECN_flow_xmit(sk, fl.fl6_flowlabel);
-	fl.oif = sk->bound_dev_if;
+	if (ipv6_addr_type(fl.fl6_src) & IPV6_ADDR_LINKLOCAL)
+		fl.oif = transport->saddr.v6.sin6_scope_id;
+	else
+		fl.oif = sk->bound_dev_if;
 	fl.uli_u.ports.sport = inet_sk(sk)->sport;
-	fl.uli_u.ports.dport = inet_sk(sk)->dport;
+	fl.uli_u.ports.dport = transport->ipaddr.v6.sin6_port;
 
 	if (np->opt && np->opt->srcrt) {
 		struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
@@ -174,7 +222,7 @@
 
 /* Returns the number of consecutive initial bits that match in the 2 ipv6
  * addresses.
- */ 
+ */
 static inline int sctp_v6_addr_match_len(union sctp_addr *s1,
 					 union sctp_addr *s2)
 {
@@ -186,7 +234,7 @@
 		__u32 a1xora2;
 
 		a1xora2 = a1->s6_addr32[i] ^ a2->s6_addr32[i];
-		
+
 		if ((j = fls(ntohl(a1xora2))))
 			return (i * 32 + 32 - j);
 	}
@@ -196,7 +244,7 @@
 
 /* Fills in the source address(saddr) based on the destination address(daddr)
  * and asoc's bind address list.
- */   
+ */
 void sctp_v6_get_saddr(sctp_association_t *asoc, struct dst_entry *dst,
 		       union sctp_addr *daddr, union sctp_addr *saddr)
 {
@@ -214,7 +262,7 @@
 			  __FUNCTION__, asoc, dst, NIP6(&daddr->v6.sin6_addr));
 
 	if (!asoc) {
-		ipv6_get_saddr(dst, &daddr->v6.sin6_addr, &saddr->v6.sin6_addr);
+		ipv6_get_saddr(dst, &daddr->v6.sin6_addr,&saddr->v6.sin6_addr);
 		SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: "
 				  "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
 				  NIP6(&saddr->v6.sin6_addr));
@@ -279,6 +327,7 @@
 			addr->a.v6.sin6_family = AF_INET6;
 			addr->a.v6.sin6_port = 0;
 			addr->a.v6.sin6_addr = ifp->addr;
+			addr->a.v6.sin6_scope_id = dev->ifindex;
 			INIT_LIST_HEAD(&addr->list);
 			list_add_tail(&addr->list, addrlist);
 		}
@@ -299,7 +348,7 @@
 	port = &addr->v6.sin6_port;
 	addr->v6.sin6_family = AF_INET6;
 	addr->v6.sin6_flowinfo = 0; /* FIXME */
-	addr->v6.sin6_scope_id = 0; /* FIXME */
+	addr->v6.sin6_scope_id = ((struct inet6_skb_parm *)skb->cb)->iif;
 
 	sh = (struct sctphdr *) skb->h.raw;
 	if (is_saddr) {
@@ -336,19 +385,25 @@
 	ipv6_addr_copy(&addr->v6.sin6_addr, &rt->rt6i_src.addr);
 }
 
-/* Compare addresses exactly.  Well.. almost exactly; ignore scope_id
- * for now.  FIXME: v4-mapped-v6.
+/* Compare addresses exactly.  
+ * FIXME: v4-mapped-v6.
  */
 static int sctp_v6_cmp_addr(const union sctp_addr *addr1,
 			    const union sctp_addr *addr2)
 {
-	int match;
 	if (addr1->sa.sa_family != addr2->sa.sa_family)
 		return 0;
-	match = !ipv6_addr_cmp((struct in6_addr *)&addr1->v6.sin6_addr,
-			       (struct in6_addr *)&addr2->v6.sin6_addr);
+	if (ipv6_addr_cmp(&addr1->v6.sin6_addr, &addr2->v6.sin6_addr))
+		return 0;
+	/* If this is a linklocal address, compare the scope_id. */
+	if (ipv6_addr_type(&addr1->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) {
+		if (addr1->v6.sin6_scope_id && addr2->v6.sin6_scope_id &&
+		    (addr1->v6.sin6_scope_id != addr2->v6.sin6_scope_id)) {
+			return 0;
+		}
+	}
 
-	return match;
+	return 1;
 }
 
 /* Initialize addr struct to INADDR_ANY. */
@@ -382,7 +437,6 @@
 	return ipv6_chk_addr(in6, NULL);
 }
 
-
 /* This function checks if the address is a valid address to be used for
  * SCTP.
  *
@@ -432,7 +486,7 @@
 	return retval;
 }
 
-/* Create and initialize a new sk for the socket to be returned by accept(). */ 
+/* Create and initialize a new sk for the socket to be returned by accept(). */
 struct sock *sctp_v6_create_accept_sk(struct sock *sk,
 				      struct sctp_association *asoc)
 {
@@ -469,11 +523,11 @@
 
 	memcpy(newnp, np, sizeof(struct ipv6_pinfo));
 
-	ipv6_addr_copy(&newnp->daddr, &asoc->peer.primary_addr.v6.sin6_addr); 
+	ipv6_addr_copy(&newnp->daddr, &asoc->peer.primary_addr.v6.sin6_addr);
 
 	newinet->sport = inet->sport;
 	newinet->dport = asoc->peer.port;
-	
+
 #ifdef INET_REFCNT_DEBUG
 	atomic_inc(&inet6_sock_nr);
 	atomic_inc(&inet_sock_nr);
@@ -488,6 +542,13 @@
 	return newsk;
 }
 
+/* Where did this skb come from?  */
+static int sctp_v6_skb_iif(const struct sk_buff *skb)
+{
+	struct inet6_skb_parm *opt = (struct inet6_skb_parm *) skb->cb;
+	return opt->iif;
+}
+
 /* Initialize a PF_INET6 socket msg_name. */
 static void sctp_inet6_msgname(char *msgname, int *addr_len)
 {
@@ -496,13 +557,13 @@
 	sin6 = (struct sockaddr_in6 *)msgname;
 	sin6->sin6_family = AF_INET6;
 	sin6->sin6_flowinfo = 0;
-	sin6->sin6_scope_id = 0;
+	sin6->sin6_scope_id = 0; /*FIXME */
 	*addr_len = sizeof(struct sockaddr_in6);
 }
 
 /* Initialize a PF_INET msgname from a ulpevent. */
-static void sctp_inet6_event_msgname(struct sctp_ulpevent *event, char *msgname,
-				     int *addrlen)
+static void sctp_inet6_event_msgname(struct sctp_ulpevent *event, 
+				     char *msgname, int *addrlen)
 {
 	struct sockaddr_in6 *sin6, *sin6from;
 
@@ -528,6 +589,8 @@
 
 		sin6from = &event->asoc->peer.primary_addr.v6;
 		ipv6_addr_copy(&sin6->sin6_addr, &sin6from->sin6_addr);
+		if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) 
+			sin6->sin6_scope_id = sin6from->sin6_scope_id;
 	}
 }
 
@@ -546,8 +609,8 @@
 
 		/* FIXME: Map ipv4 address into v4-mapped-on-v6 address. */
 		if (__constant_htons(ETH_P_IP) == skb->protocol) {
-			/* FIXME: Easy, but there was no way to test this
-			 * yet.
+			/* FIXME:  The latest I-D added options for two
+			 * behaviors.
 			 */
 			return;
 		}
@@ -556,9 +619,8 @@
 
 		ipv6_addr_copy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr);
 		if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) {
-			struct inet6_skb_parm *opt =
-				(struct inet6_skb_parm *) skb->cb;
-			sin6->sin6_scope_id = opt->iif;
+			struct sctp_ulpevent *ev = sctp_skb2event(skb);
+			sin6->sin6_scope_id = ev->iif;
 		}
 	}
 }
@@ -612,22 +674,67 @@
 	struct sctp_af *af;
 
 	/* ASSERT: address family has already been verified. */
-	if (addr->sa.sa_family != AF_INET6) {
+	if (addr->sa.sa_family != AF_INET6)
 		af = sctp_get_af_specific(addr->sa.sa_family);
-	} else
-		af = opt->pf->af;
+	else {
+		struct sock *sk;
+		int type = ipv6_addr_type(&addr->v6.sin6_addr);
+		sk = &container_of(opt, struct sctp6_sock, sctp)->sk;
+		if (type & IPV6_ADDR_LINKLOCAL) {
+			/* Note: Behavior similar to af_inet6.c:
+			 *  1) Overrides previous bound_dev_if
+			 *  2) Destructive even if bind isn't successful.
+			 */
 
+			if (addr->v6.sin6_scope_id)
+				sk->bound_dev_if = addr->v6.sin6_scope_id;
+			if (!sk->bound_dev_if)
+				return 0;			
+		}
+		af = opt->pf->af;
+	}
 	return af->available(addr);
 }
 
+/* Verify that the provided sockaddr looks bindable.   Common verification,
+ * has already been taken care of.
+ */
+static int sctp_inet6_send_verify(struct sctp_opt *opt, union sctp_addr *addr)
+{
+	struct sctp_af *af = NULL;
+
+	/* ASSERT: address family has already been verified. */
+	if (addr->sa.sa_family != AF_INET6)
+		af = sctp_get_af_specific(addr->sa.sa_family);
+	else {
+		struct sock *sk;
+		int type = ipv6_addr_type(&addr->v6.sin6_addr);
+		sk = &container_of(opt, struct sctp6_sock, sctp)->sk;
+		if (type & IPV6_ADDR_LINKLOCAL) {
+			/* Note: Behavior similar to af_inet6.c:
+			 *  1) Overrides previous bound_dev_if
+			 *  2) Destructive even if bind isn't successful.
+			 */
+
+			if (addr->v6.sin6_scope_id)
+				sk->bound_dev_if = addr->v6.sin6_scope_id;
+			if (!sk->bound_dev_if)
+				return 0;			
+		}
+		af = opt->pf->af;
+	}
+	
+	return af != NULL;
+}
+
 /* Fill in Supported Address Type information for INIT and INIT-ACK
  * chunks.   Note: In the future, we may want to look at sock options
  * to determine whether a PF_INET6 socket really wants to have IPV4
- * addresses.  
+ * addresses.
  * Returns number of addresses supported.
  */
 static int sctp_inet6_supported_addrs(const struct sctp_opt *opt,
-				      __u16 *types) 
+				      __u16 *types)
 {
 	types[0] = SCTP_PARAM_IPV4_ADDRESS;
 	types[1] = SCTP_PARAM_IPV6_ADDRESS;
@@ -700,6 +807,7 @@
 	.inaddr_any      = sctp_v6_inaddr_any,
 	.is_any          = sctp_v6_is_any,
 	.available       = sctp_v6_available,
+	.skb_iif         = sctp_v6_skb_iif,
 	.net_header_len  = sizeof(struct ipv6hdr),
 	.sockaddr_len    = sizeof(struct sockaddr_in6),
 	.sa_family       = AF_INET6,
@@ -711,6 +819,7 @@
 	.af_supported  = sctp_inet6_af_supported,
 	.cmp_addr      = sctp_inet6_cmp_addr,
 	.bind_verify   = sctp_inet6_bind_verify,
+	.send_verify   = sctp_inet6_send_verify,
 	.supported_addrs = sctp_inet6_supported_addrs,
 	.create_accept_sk = sctp_v6_create_accept_sk,
 	.af            = &sctp_ipv6_specific,
diff -urN linux-2.5.66-bk10/net/sctp/output.c linux-2.5.66-bk11/net/sctp/output.c
--- linux-2.5.66-bk10/net/sctp/output.c	2003-03-24 14:00:09.000000000 -0800
+++ linux-2.5.66-bk11/net/sctp/output.c	2003-04-05 04:32:16.000000000 -0800
@@ -79,6 +79,7 @@
 	packet->ecn_capable = ecn_capable;
 	packet->get_prepend_chunk = prepend_handler;
 	packet->has_cookie_echo = 0;
+	packet->has_sack = 0;
 	packet->ipfragok = 0;
 
 	/* We might need to call the prepend_handler right away.  */
@@ -100,6 +101,7 @@
 	packet->ecn_capable = 0;
 	packet->get_prepend_chunk = NULL;
 	packet->has_cookie_echo = 0;
+	packet->has_sack = 0;
 	packet->ipfragok = 0;
 	packet->malloced = 0;
 	sctp_packet_reset(packet);
@@ -155,6 +157,37 @@
 	return retval;
 }
 
+/* Try to bundle a SACK with the packet. */
+static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
+					   struct sctp_chunk *chunk)
+{
+	sctp_xmit_t retval = SCTP_XMIT_OK;
+
+	/* If sending DATA and haven't aleady bundled a SACK, try to
+	 * bundle one in to the packet.
+	 */
+	if (sctp_chunk_is_data(chunk) && !pkt->has_sack && 
+	    !pkt->has_cookie_echo) {
+		struct sctp_association *asoc;
+		asoc = pkt->transport->asoc;
+			
+		if (asoc->a_rwnd > asoc->rwnd) {
+			struct sctp_chunk *sack;
+			asoc->a_rwnd = asoc->rwnd;
+			sack = sctp_make_sack(asoc);
+			if (sack) {
+				struct timer_list *timer;
+				retval = sctp_packet_append_chunk(pkt, sack);
+				asoc->peer.sack_needed = 0;
+				timer = &asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
+				if (timer_pending(timer) && del_timer(timer))
+					sctp_association_put(asoc);
+			}
+		}
+	}
+	return retval;
+}
+
 /* Append a chunk to the offered packet reporting back any inability to do
  * so.
  */
@@ -163,10 +196,16 @@
 {
 	sctp_xmit_t retval = SCTP_XMIT_OK;
 	__u16 chunk_len = WORD_ROUND(ntohs(chunk->chunk_hdr->length));
-	size_t psize = packet->size;
+	size_t psize;
 	size_t pmtu;
 	int too_big;
 
+	retval = sctp_packet_bundle_sack(packet, chunk);
+	psize = packet->size;
+
+	if (retval != SCTP_XMIT_OK)
+		goto finish;
+		
 	pmtu  = ((packet->transport->asoc) ?
 		 (packet->transport->asoc->pmtu) :
 		 (packet->transport->pmtu));
@@ -214,11 +253,14 @@
 	 */
 	if (sctp_chunk_is_data(chunk)) {
 		retval = sctp_packet_append_data(packet, chunk);
+		/* Disallow SACK bundling after DATA. */
+		packet->has_sack = 1;
 		if (SCTP_XMIT_OK != retval)
 			goto finish;
-	} else if (SCTP_CID_COOKIE_ECHO == chunk->chunk_hdr->type) {
+	} else if (SCTP_CID_COOKIE_ECHO == chunk->chunk_hdr->type)
 		packet->has_cookie_echo = 1;
-	}
+	else if (SCTP_CID_SACK == chunk->chunk_hdr->type) 
+		packet->has_sack = 1;
 
 	/* It is OK to send this chunk.  */
 	__skb_queue_tail(&packet->chunks, (struct sk_buff *)chunk);
diff -urN linux-2.5.66-bk10/net/sctp/outqueue.c linux-2.5.66-bk11/net/sctp/outqueue.c
--- linux-2.5.66-bk10/net/sctp/outqueue.c	2003-03-24 14:00:15.000000000 -0800
+++ linux-2.5.66-bk11/net/sctp/outqueue.c	2003-04-05 04:32:16.000000000 -0800
@@ -138,13 +138,13 @@
 }
 
 /* Free the outqueue structure and any related pending chunks.
- * FIXME: Add SEND_FAILED support.
  */
 void sctp_outq_teardown(struct sctp_outq *q)
 {
 	struct sctp_transport *transport;
 	struct list_head *lchunk, *pos, *temp;
 	sctp_chunk_t *chunk;
+	struct sctp_ulpevent *ev;
 
 	/* Throw away unacknowledged chunks. */
 	list_for_each(pos, &q->asoc->peer.transport_addr_list) {
@@ -152,6 +152,14 @@
 		while ((lchunk = sctp_list_dequeue(&transport->transmitted))) {
 			chunk = list_entry(lchunk, sctp_chunk_t,
 					   transmitted_list);
+
+			/* Generate a SEND FAILED event. */
+			ev = sctp_ulpevent_make_send_failed(q->asoc,
+					chunk, SCTP_DATA_SENT,
+					q->error, GFP_ATOMIC);
+			if (ev)
+				sctp_ulpq_tail_event(&q->asoc->ulpq, ev);
+
 			sctp_free_chunk(chunk);
 		}
 	}
@@ -171,8 +179,19 @@
 	}
 
 	/* Throw away any leftover data chunks. */
-	while ((chunk = sctp_outq_dequeue_data(q)))
+	while ((chunk = sctp_outq_dequeue_data(q))) {
+
+		/* Generate a SEND FAILED event. */
+		ev = sctp_ulpevent_make_send_failed(q->asoc,
+				chunk, SCTP_DATA_UNSENT,
+				q->error, GFP_ATOMIC);
+		if (ev)
+			sctp_ulpq_tail_event(&q->asoc->ulpq, ev);
+
 		sctp_free_chunk(chunk);
+	}
+
+	q->error = 0;
 
 	/* Throw away any leftover control chunks. */
 	while ((chunk = (sctp_chunk_t *) skb_dequeue(&q->control)))
@@ -357,7 +376,7 @@
 	__u8 fast_retransmit = 0;
 
 	switch(reason) {
-	case SCTP_RETRANSMIT_T3_RTX:
+	case SCTP_RTXR_T3_RTX:
 		sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_T3_RTX);
 		/* Update the retran path if the T3-rtx timer has expired for
 		 * the current retran path.
@@ -365,10 +384,11 @@
 		if (transport == transport->asoc->peer.retran_path)
 			sctp_assoc_update_retran_path(transport->asoc);
 		break;
-	case SCTP_RETRANSMIT_FAST_RTX:
+	case SCTP_RTXR_FAST_RTX:
 		sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_FAST_RTX);
 		fast_retransmit = 1;
 		break;
+	case SCTP_RTXR_PMTUD:
 	default:
 		break;
 	}
@@ -876,7 +896,7 @@
 		start_timer = 0;
 		queue = &q->out;
 
-		while (NULL != (chunk = sctp_outq_dequeue_data(q))) {
+		while ((chunk = sctp_outq_dequeue_data(q))) {
 			/* RFC 2960 6.5 Every DATA chunk MUST carry a valid
 			 * stream identifier.
 			 */
@@ -891,9 +911,7 @@
 				if (ev)
 					sctp_ulpq_tail_event(&asoc->ulpq, ev);
 
-				/* Free the chunk. This chunk is not on any
-				 * list yet, just free it.
-				 */
+				/* Free the chunk. */
 				sctp_free_chunk(chunk);
 				continue;
 			}
@@ -1572,7 +1590,7 @@
 
 	if (transport) {
 		if (do_fast_retransmit)
-			sctp_retransmit(q, transport, SCTP_RETRANSMIT_FAST_RTX);
+			sctp_retransmit(q, transport, SCTP_RTXR_FAST_RTX);
 
 		SCTP_DEBUG_PRINTK("%s: transport: %p, cwnd: %d, "
 				  "ssthresh: %d, flight_size: %d, pba: %d\n",
diff -urN linux-2.5.66-bk10/net/sctp/protocol.c linux-2.5.66-bk11/net/sctp/protocol.c
--- linux-2.5.66-bk10/net/sctp/protocol.c	2003-04-05 04:32:13.000000000 -0800
+++ linux-2.5.66-bk11/net/sctp/protocol.c	2003-04-05 04:32:16.000000000 -0800
@@ -170,7 +170,7 @@
 
 static void sctp_get_local_addr_list(struct sctp_protocol *proto)
 {
-	long flags __attribute__ ((unused));
+	unsigned long flags;
 
 	sctp_spin_lock_irqsave(&sctp_proto.local_addr_lock, flags);
 	__sctp_get_local_addr_list(&sctp_proto);
@@ -193,7 +193,7 @@
 /* Free the existing local addresses.  */
 static void sctp_free_local_addr_list(struct sctp_protocol *proto)
 {
-	long flags __attribute__ ((unused));
+	unsigned long flags;
 
 	sctp_spin_lock_irqsave(&proto->local_addr_lock, flags);
 	__sctp_free_local_addr_list(proto);
@@ -208,7 +208,7 @@
 	struct sockaddr_storage_list *addr;
 	int error = 0;
 	struct list_head *pos;
-	long flags __attribute__ ((unused));
+	unsigned long flags;
 
 	sctp_spin_lock_irqsave(&proto->local_addr_lock, flags);
 	list_for_each(pos, &proto->local_addr_list) {
@@ -233,7 +233,6 @@
 
 end_copy:
 	sctp_spin_unlock_irqrestore(&proto->local_addr_lock, flags);
-
 	return error;
 }
 
@@ -383,7 +382,7 @@
  * addresses. If an association is passed, trys to get a dst entry with a
  * source adddress that matches an address in the bind address list.
  */
-struct dst_entry *sctp_v4_get_dst(sctp_association_t *asoc,
+struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
 				  union sctp_addr *daddr,
 				  union sctp_addr *saddr)
 {
@@ -480,6 +479,12 @@
 
 }
 
+/* What interface did this skb arrive on? */
+int sctp_v4_skb_iif(const struct sk_buff *skb) 
+{
+     	return ((struct rtable *)skb->dst)->rt_iif;  
+}
+
 /* Create and initialize a new sk for the socket returned by accept(). */ 
 struct sock *sctp_v4_create_accept_sk(struct sock *sk,
 				      struct sctp_association *asoc)
@@ -538,10 +543,10 @@
 /* Event handler for inet address addition/deletion events.
  * Basically, whenever there is an event, we re-build our local address list.
  */
-static int sctp_inetaddr_event(struct notifier_block *this, unsigned long event,
+static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev,
 			       void *ptr)
 {
-	long flags __attribute__ ((unused));
+	unsigned long flags;
 
 	sctp_spin_lock_irqsave(&sctp_proto.local_addr_lock, flags);
 	__sctp_free_local_addr_list(&sctp_proto);
@@ -689,6 +694,14 @@
 	return sctp_v4_available(addr);
 }
 
+/* Verify that sockaddr looks sendable.  Common verification has already 
+ * been taken care of.
+ */
+static int sctp_inet_send_verify(struct sctp_opt *opt, union sctp_addr *addr)
+{
+	return 1;
+}
+
 /* Fill in Supported Address Type information for INIT and INIT-ACK
  * chunks.  Returns number of addresses supported.
  */
@@ -721,6 +734,7 @@
 	.af_supported  = sctp_inet_af_supported,
 	.cmp_addr      = sctp_inet_cmp_addr,
 	.bind_verify   = sctp_inet_bind_verify,
+	.send_verify   = sctp_inet_send_verify,
 	.supported_addrs = sctp_inet_supported_addrs,
 	.create_accept_sk = sctp_v4_create_accept_sk,
 	.af            = &sctp_ipv4_specific,
@@ -797,6 +811,7 @@
 	.is_any         = sctp_v4_is_any,
 	.available      = sctp_v4_available,
 	.scope          = sctp_v4_scope,
+	.skb_iif        = sctp_v4_skb_iif,
 	.net_header_len = sizeof(struct iphdr),
 	.sockaddr_len   = sizeof(struct sockaddr_in),
 	.sa_family      = AF_INET,
@@ -874,6 +889,10 @@
 	int i;
 	int status = 0;
 
+	/* SCTP_DEBUG sanity check. */
+	if (!sctp_sanity_check())
+		return -EINVAL;
+
 	/* Add SCTP to inet_protos hash table.  */
 	if (inet_add_protocol(&sctp_protocol, IPPROTO_SCTP) < 0)
 		return -EAGAIN;
diff -urN linux-2.5.66-bk10/net/sctp/sm_make_chunk.c linux-2.5.66-bk11/net/sctp/sm_make_chunk.c
--- linux-2.5.66-bk10/net/sctp/sm_make_chunk.c	2003-03-24 14:00:03.000000000 -0800
+++ linux-2.5.66-bk11/net/sctp/sm_make_chunk.c	2003-04-05 04:32:16.000000000 -0800
@@ -66,6 +66,19 @@
 #include <net/sctp/sctp.h>
 #include <net/sctp/sm.h>
 
+/* What was the inbound interface for this chunk? */
+int sctp_chunk_iif(const struct sctp_chunk *chunk)
+{
+	struct sctp_af *af;
+	int iif = 0;
+
+	af = sctp_get_af_specific(ipver2af(chunk->skb->nh.iph->version));
+	if (af)
+		iif = af->skb_iif(chunk->skb);
+
+	return iif;
+}
+
 /* RFC 2960 3.3.2 Initiation (INIT) (1)
  *
  * Note 2: The ECN capable field is reserved for future use of
@@ -145,7 +158,7 @@
  */
 sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc,
 			     const sctp_bind_addr_t *bp,
-			     int priority, int vparam_len)
+			     int gfp, int vparam_len)
 {
 	sctp_inithdr_t init;
 	union sctp_params addrs;
@@ -165,7 +178,7 @@
 	addrs.v = NULL;
 
 	/* Convert the provided bind address list to raw format */
-	addrs = sctp_bind_addrs_to_raw(bp, &addrs_len, priority);
+	addrs = sctp_bind_addrs_to_raw(bp, &addrs_len, gfp);
 	if (!addrs.v)
 		goto nodata;
 
@@ -225,7 +238,7 @@
 
 sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc,
 				 const sctp_chunk_t *chunk,
-				 int priority, int unkparam_len)
+				 int gfp, int unkparam_len)
 {
 	sctp_inithdr_t initack;
 	sctp_chunk_t *retval;
@@ -237,8 +250,7 @@
 
 	retval = NULL;
 
-	addrs = sctp_bind_addrs_to_raw(&asoc->base.bind_addr, &addrs_len, 
-				       priority);
+	addrs = sctp_bind_addrs_to_raw(&asoc->base.bind_addr, &addrs_len, gfp);
 	if (!addrs.v)
 		goto nomem_rawaddr;
 
@@ -1019,21 +1031,18 @@
 	struct sk_buff *skb;
 	struct sock *sk;
 
-	skb = dev_alloc_skb(WORD_ROUND(sizeof(sctp_chunkhdr_t) + paylen));
+	/* No need to allocate LL here, as this is only a chunk. */
+	skb = alloc_skb(WORD_ROUND(sizeof(sctp_chunkhdr_t) + paylen), 
+			GFP_ATOMIC);
 	if (!skb)
 		goto nodata;
 
 	/* Make room for the chunk header.  */
 	chunk_hdr = (sctp_chunkhdr_t *)skb_put(skb, sizeof(sctp_chunkhdr_t));
-	skb_pull(skb, sizeof(sctp_chunkhdr_t));
-
 	chunk_hdr->type	  = type;
 	chunk_hdr->flags  = flags;
 	chunk_hdr->length = htons(sizeof(sctp_chunkhdr_t));
 
-	/* Move the data pointer back up to the start of the chunk.  */
-	skb_push(skb, sizeof(sctp_chunkhdr_t));
-
 	sk = asoc ? asoc->base.sk : NULL;
 	retval = sctp_chunkify(skb, asoc, sk);
 	if (!retval) {
@@ -1162,7 +1171,7 @@
 			msg_len -= first_len;
 			whole = 1;
 		}
-	} 
+	}
 
 	/* How many full sized?  How many bytes leftover? */
 	whole += msg_len / max;
@@ -1198,7 +1207,7 @@
 
 		__skb_queue_tail(chunks, (struct sk_buff *)chunk);
 
-		/* The first chunk, the first chunk was likely short 
+		/* The first chunk, the first chunk was likely short
 		 * to allow bundling, so reset to full size.
 		 */
 		if (0 == i)
@@ -1282,26 +1291,26 @@
 }
 
 /* Create a CLOSED association to use with an incoming packet.  */
-sctp_association_t *sctp_make_temp_asoc(const sctp_endpoint_t *ep,
-					sctp_chunk_t *chunk,
-					int priority)
+sctp_association_t *sctp_make_temp_asoc(const struct sctp_endpoint *ep,
+					struct sctp_chunk *chunk, int gfp)
 {
 	sctp_association_t *asoc;
+	struct sk_buff *skb;
 	sctp_scope_t scope;
 
 	/* Create the bare association.  */
 	scope = sctp_scope(sctp_source(chunk));
-	asoc = sctp_association_new(ep, ep->base.sk, scope, priority);
+	asoc = sctp_association_new(ep, ep->base.sk, scope, gfp);
 	if (!asoc)
 		goto nodata;
-
+	skb = chunk->skb;
 	/* Create an entry for the source address of the packet.  */
-	switch (chunk->skb->nh.iph->version) {
+	/* FIXME: Use the af specific helpers. */
+	switch (skb->nh.iph->version) {
 	case 4:
 		asoc->c.peer_addr.v4.sin_family     = AF_INET;
 		asoc->c.peer_addr.v4.sin_port = ntohs(chunk->sctp_hdr->source);
-		asoc->c.peer_addr.v4.sin_addr.s_addr =
-			chunk->skb->nh.iph->saddr;
+		asoc->c.peer_addr.v4.sin_addr.s_addr = skb->nh.iph->saddr;
                 break;
 
 	case 6:
@@ -1309,8 +1318,9 @@
 		asoc->c.peer_addr.v6.sin6_port
 			= ntohs(chunk->sctp_hdr->source);
 		asoc->c.peer_addr.v6.sin6_flowinfo = 0; /* BUG BUG BUG */
-		asoc->c.peer_addr.v6.sin6_addr = chunk->skb->nh.ipv6h->saddr;
-		asoc->c.peer_addr.v6.sin6_scope_id = 0; /* BUG BUG BUG */
+		asoc->c.peer_addr.v6.sin6_addr = skb->nh.ipv6h->saddr;
+		asoc->c.peer_addr.v6.sin6_scope_id =
+			((struct inet6_skb_parm *)skb->cb)->iif;
 		break;
 
         default:
@@ -1397,7 +1407,7 @@
 /* Unpack the cookie from COOKIE ECHO chunk, recreating the association.  */
 sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep,
 				       const sctp_association_t *asoc,
-				       sctp_chunk_t *chunk, int priority,
+				       sctp_chunk_t *chunk, int gfp,
 				       int *error, sctp_chunk_t **err_chk_p)
 {
 	sctp_association_t *retval = NULL;
@@ -1408,6 +1418,7 @@
 	__u8 digest_buf[SCTP_SIGNATURE_SIZE];
 	int secret;
 	sctp_scope_t scope;
+	struct sk_buff *skb = chunk->skb;
 
 	headersize = sizeof(sctp_chunkhdr_t) + SCTP_SECRET_SIZE;
 	bodysize = ntohs(chunk->chunk_hdr->length) - headersize;
@@ -1450,7 +1461,7 @@
 	 * an association, there is no need to check cookie's expiration
 	 * for init collision case of lost COOKIE ACK.
 	 */
-	if (!asoc && tv_lt(bear_cookie->expiration, chunk->skb->stamp)) {
+	if (!asoc && tv_lt(bear_cookie->expiration, skb->stamp)) {
 		__u16 len;
 		/*
 		 * Section 3.3.10.3 Stale Cookie Error (3)
@@ -1463,9 +1474,9 @@
 		len = ntohs(chunk->chunk_hdr->length);
 		*err_chk_p = sctp_make_op_error_space(asoc, chunk, len);
 		if (*err_chk_p) {
-			suseconds_t usecs = (chunk->skb->stamp.tv_sec -
+			suseconds_t usecs = (skb->stamp.tv_sec -
 				bear_cookie->expiration.tv_sec) * 1000000L +
-				chunk->skb->stamp.tv_usec -
+				skb->stamp.tv_usec -
 				bear_cookie->expiration.tv_usec;
 
 			usecs = htonl(usecs);
@@ -1480,7 +1491,7 @@
 
 	/* Make a new base association.  */
 	scope = sctp_scope(sctp_source(chunk));
-	retval = sctp_association_new(ep, ep->base.sk, scope, priority);
+	retval = sctp_association_new(ep, ep->base.sk, scope, gfp);
 	if (!retval) {
 		*error = -SCTP_IERROR_NOMEM;
 		goto fail;
@@ -1522,13 +1533,14 @@
  * 3rd Level Abstractions
  ********************************************************************/
 
-/*
- * Report a missing mandatory parameter.
- */
 struct __sctp_missing {
 	__u32 num_missing;
 	__u16 type;
 }  __attribute__((packed));;
+
+/*
+ * Report a missing mandatory parameter.
+ */
 static int sctp_process_missing_param(const sctp_association_t *asoc,
 				      sctp_param_t paramtype,
 				      sctp_chunk_t *chunk,
@@ -1774,8 +1786,7 @@
  */
 int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
 		      const union sctp_addr *peer_addr,
-		      sctp_init_chunk_t *peer_init,
-		      int priority)
+		      sctp_init_chunk_t *peer_init, int gfp)
 {
 	union sctp_params param;
 	struct sctp_transport *transport;
@@ -1793,14 +1804,14 @@
 	 * be a a better choice than any of the embedded addresses.
 	 */
 	if (peer_addr)
-		if(!sctp_assoc_add_peer(asoc, peer_addr, priority))
+		if(!sctp_assoc_add_peer(asoc, peer_addr, gfp))
 			goto nomem;
 
 	/* Process the initialization parameters.  */
 
 	sctp_walk_params(param, peer_init, init_hdr.params) {
 
-		if (!sctp_process_param(asoc, param, peer_addr, priority))
+		if (!sctp_process_param(asoc, param, peer_addr, gfp))
                         goto clean_up;
 	}
 
@@ -1842,7 +1853,7 @@
 	/* Copy cookie in case we need to resend COOKIE-ECHO. */
 	cookie = asoc->peer.cookie;
 	if (cookie) {
-		asoc->peer.cookie = kmalloc(asoc->peer.cookie_len, priority);
+		asoc->peer.cookie = kmalloc(asoc->peer.cookie_len, gfp);
 		if (!asoc->peer.cookie)
 			goto clean_up;
 		memcpy(asoc->peer.cookie, cookie, asoc->peer.cookie_len);
@@ -1871,8 +1882,7 @@
 
 	/* Allocate storage for the negotiated streams. */
 	asoc->ssnmap = sctp_ssnmap_new(asoc->peer.i.num_outbound_streams,
-				       asoc->c.sinit_num_ostreams,
-				       priority);
+				       asoc->c.sinit_num_ostreams, gfp);
 	if (!asoc->ssnmap)
 		goto nomem_ssnmap;
 
@@ -1914,7 +1924,7 @@
  * structures for the addresses.
  */
 int sctp_process_param(sctp_association_t *asoc, union sctp_params param,
-		       const union sctp_addr *peer_addr, int priority)
+		       const union sctp_addr *peer_addr, int gfp)
 {
 	union sctp_addr addr;
 	int i;
@@ -1933,10 +1943,10 @@
 			break;
 		/* Fall through. */
 	case SCTP_PARAM_IPV4_ADDRESS:
-		sctp_param2sockaddr(&addr, param.addr, asoc->peer.port);
+		sctp_param2sockaddr(&addr, param.addr, asoc->peer.port, 0);
 		scope = sctp_scope(peer_addr);
 		if (sctp_in_scope(&addr, scope))
-			if (!sctp_assoc_add_peer(asoc, &addr, priority))
+			if (!sctp_assoc_add_peer(asoc, &addr, gfp))
 				return 0;
 		break;
 
@@ -2051,7 +2061,7 @@
 
 /* Convert from an SCTP IP parameter to a union sctp_addr.  */
 void sctp_param2sockaddr(union sctp_addr *addr, sctp_addr_param_t *param,
-			 __u16 port)
+			 __u16 port, int iif)
 {
 	switch(param->v4.param_hdr.type) {
 	case SCTP_PARAM_IPV4_ADDRESS:
@@ -2065,7 +2075,7 @@
 		addr->v6.sin6_port = port;
 		addr->v6.sin6_flowinfo = 0; /* BUG */
 		addr->v6.sin6_addr = param->v6.addr;
-		addr->v6.sin6_scope_id = 0; /* BUG */
+		addr->v6.sin6_scope_id = iif;
 		break;
 
 	default:
diff -urN linux-2.5.66-bk10/net/sctp/sm_sideeffect.c linux-2.5.66-bk11/net/sctp/sm_sideeffect.c
--- linux-2.5.66-bk10/net/sctp/sm_sideeffect.c	2003-03-24 14:00:55.000000000 -0800
+++ linux-2.5.66-bk11/net/sctp/sm_sideeffect.c	2003-04-05 04:32:16.000000000 -0800
@@ -55,1202 +55,1106 @@
 #include <net/sctp/sctp.h>
 #include <net/sctp/sm.h>
 
-/* Do forward declarations of static functions.  */
-static void sctp_do_ecn_ce_work(sctp_association_t *,__u32 lowest_tsn);
-static sctp_chunk_t *sctp_do_ecn_ecne_work(sctp_association_t *asoc,
-					   __u32 lowest_tsn,
-					   sctp_chunk_t *);
-static void sctp_do_ecn_cwr_work(sctp_association_t *,__u32 lowest_tsn);
-static void sctp_do_8_2_transport_strike(sctp_association_t *,
-					 struct sctp_transport *);
-static void sctp_cmd_init_failed(sctp_cmd_seq_t *, sctp_association_t *);
-static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *, sctp_association_t *,
-				  sctp_event_t, sctp_subtype_t,
-				  sctp_chunk_t *chunk);
-static int sctp_cmd_process_init(sctp_cmd_seq_t *, sctp_association_t *,
-				 sctp_chunk_t *chunk,
-				 sctp_init_chunk_t *peer_init,
-				 int priority);
-static void sctp_cmd_hb_timers_start(sctp_cmd_seq_t *, sctp_association_t *);
-static void sctp_cmd_hb_timers_stop(sctp_cmd_seq_t *, sctp_association_t *);
-static void sctp_cmd_hb_timer_update(sctp_cmd_seq_t *, sctp_association_t *,
-				     struct sctp_transport *);
-static void sctp_cmd_transport_reset(sctp_cmd_seq_t *, sctp_association_t *,
-				     struct sctp_transport *);
-static void sctp_cmd_transport_on(sctp_cmd_seq_t *, sctp_association_t *,
-				  struct sctp_transport *, sctp_chunk_t *);
-static int sctp_cmd_process_sack(sctp_cmd_seq_t *, sctp_association_t *,
-				 sctp_sackhdr_t *);
-static void sctp_cmd_setup_t2(sctp_cmd_seq_t *, sctp_association_t *,
-			      sctp_chunk_t *);
-static void sctp_cmd_new_state(sctp_cmd_seq_t *, sctp_association_t *,
-			       sctp_state_t);
-
-/* These three macros allow us to pull the debugging code out of the
- * main flow of sctp_do_sm() to keep attention focused on the real
- * functionality there.
- */
-#define DEBUG_PRE \
-	SCTP_DEBUG_PRINTK("sctp_do_sm prefn: " \
-			  "ep %p, %s, %s, asoc %p[%s], %s\n", \
-			  ep, sctp_evttype_tbl[event_type], \
-			  (*debug_fn)(subtype), asoc, \
-			  sctp_state_tbl[state], state_fn->name)
+/********************************************************************
+ * Helper functions
+ ********************************************************************/
 
-#define DEBUG_POST \
-	SCTP_DEBUG_PRINTK("sctp_do_sm postfn: " \
-			  "asoc %p, status: %s\n", \
-			  asoc, sctp_status_tbl[status])
+/* A helper function for delayed processing of INET ECN CE bit. */
+static void sctp_do_ecn_ce_work(sctp_association_t *asoc, __u32 lowest_tsn)
+{
+	/* Save the TSN away for comparison when we receive CWR */
 
-#define DEBUG_POST_SFX \
-	SCTP_DEBUG_PRINTK("sctp_do_sm post sfx: error %d, asoc %p[%s]\n", \
-			  error, asoc, \
-			  sctp_state_tbl[(asoc && sctp_id2assoc(ep->base.sk, \
-			  sctp_assoc2id(asoc)))?asoc->state:SCTP_STATE_CLOSED])
+	asoc->last_ecne_tsn = lowest_tsn;
+	asoc->need_ecne = 1;
+}
 
-/*
- * This is the master state machine processing function.
+/* Helper function for delayed processing of SCTP ECNE chunk.  */
+/* RFC 2960 Appendix A
  *
- * If you want to understand all of lksctp, this is a
- * good place to start.
+ * RFC 2481 details a specific bit for a sender to send in
+ * the header of its next outbound TCP segment to indicate to
+ * its peer that it has reduced its congestion window.  This
+ * is termed the CWR bit.  For SCTP the same indication is made
+ * by including the CWR chunk.  This chunk contains one data
+ * element, i.e. the TSN number that was sent in the ECNE chunk.
+ * This element represents the lowest TSN number in the datagram
+ * that was originally marked with the CE bit.
  */
-int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype,
-	       sctp_state_t state,
-	       sctp_endpoint_t *ep,
-	       sctp_association_t *asoc,
-	       void *event_arg,
-	       int priority)
+static sctp_chunk_t *sctp_do_ecn_ecne_work(sctp_association_t *asoc,
+					   __u32 lowest_tsn,
+					   sctp_chunk_t *chunk)
 {
-	sctp_cmd_seq_t commands;
-	sctp_sm_table_entry_t *state_fn;
-	sctp_disposition_t status;
-	int error = 0;
-	typedef const char *(printfn_t)(sctp_subtype_t);
+	sctp_chunk_t *repl;
 
-	static printfn_t *table[] = {
-		NULL, sctp_cname, sctp_tname, sctp_oname, sctp_pname,
-	};
-	printfn_t *debug_fn  __attribute__ ((unused)) = table[event_type];
+	/* Our previously transmitted packet ran into some congestion
+	 * so we should take action by reducing cwnd and ssthresh
+	 * and then ACK our peer that we we've done so by
+	 * sending a CWR.
+	 */
 
-	/* Look up the state function, run it, and then process the
-	 * side effects.  These three steps are the heart of lksctp.
+	/* First, try to determine if we want to actually lower
+	 * our cwnd variables.  Only lower them if the ECNE looks more
+	 * recent than the last response.
 	 */
-	state_fn = sctp_sm_lookup_event(event_type, state, subtype);
+	if (TSN_lt(asoc->last_cwr_tsn, lowest_tsn)) {
+		struct sctp_transport *transport;
 
-	sctp_init_cmd_seq(&commands);
+		/* Find which transport's congestion variables
+		 * need to be adjusted.
+		 */
+		transport = sctp_assoc_lookup_tsn(asoc, lowest_tsn);
 
-	DEBUG_PRE;
-	status = (*state_fn->fn)(ep, asoc, subtype, event_arg, &commands);
-	DEBUG_POST;
+		/* Update the congestion variables. */
+		if (transport)
+			sctp_transport_lower_cwnd(transport,
+						  SCTP_LOWER_CWND_ECNE);
+		asoc->last_cwr_tsn = lowest_tsn;
+	}
 
-	error = sctp_side_effects(event_type, subtype, state,
-				  ep, asoc, event_arg,
-				  status, &commands,
-				  priority);
-	DEBUG_POST_SFX;
+	/* Always try to quiet the other end.  In case of lost CWR,
+	 * resend last_cwr_tsn.
+	 */
+	repl = sctp_make_cwr(asoc, asoc->last_cwr_tsn, chunk);
 
-	return error;
+	/* If we run out of memory, it will look like a lost CWR.  We'll
+	 * get back in sync eventually.
+	 */
+	return repl;
 }
 
-#undef DEBUG_PRE
-#undef DEBUG_POST
-
-/*****************************************************************
- * This the master state function side effect processing function.
- *****************************************************************/
-int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype,
-		      sctp_state_t state,
-		      sctp_endpoint_t *ep,
-		      sctp_association_t *asoc,
-		      void *event_arg,
-		      sctp_disposition_t status,
-		      sctp_cmd_seq_t *commands,
-		      int priority)
+/* Helper function to do delayed processing of ECN CWR chunk.  */
+static void sctp_do_ecn_cwr_work(sctp_association_t *asoc,
+				 __u32 lowest_tsn)
 {
-	int error;
-
-	/* FIXME - Most of the dispositions left today would be categorized
-	 * as "exceptional" dispositions.  For those dispositions, it
-	 * may not be proper to run through any of the commands at all.
-	 * For example, the command interpreter might be run only with
-	 * disposition SCTP_DISPOSITION_CONSUME.
+	/* Turn off ECNE getting auto-prepended to every outgoing
+	 * packet
 	 */
-	if (0 != (error = sctp_cmd_interpreter(event_type, subtype, state,
-					       ep, asoc,
-					       event_arg, status,
-					       commands, priority)))
-		goto bail;
-
-	switch (status) {
-	case SCTP_DISPOSITION_DISCARD:
-		SCTP_DEBUG_PRINTK("Ignored sctp protocol event - state %d, "
-				  "event_type %d, event_id %d\n",
-				  state, event_type, subtype.chunk);
-		break;
+	asoc->need_ecne = 0;
+}
 
-	case SCTP_DISPOSITION_NOMEM:
-		/* We ran out of memory, so we need to discard this
-		 * packet.
-		 */
-		/* BUG--we should now recover some memory, probably by
-		 * reneging...
-		 */
-		error = -ENOMEM;
-		break;
+/* Generate SACK if necessary.  We call this at the end of a packet.  */
+int sctp_gen_sack(struct sctp_association *asoc, int force,
+		  sctp_cmd_seq_t *commands)
+{
+	__u32 ctsn, max_tsn_seen;
+	struct sctp_chunk *sack;
+	int error = 0;
 
-        case SCTP_DISPOSITION_DELETE_TCB:
-		/* This should now be a command. */
-		break;
+	if (force)
+		asoc->peer.sack_needed = 1;
 
-	case SCTP_DISPOSITION_CONSUME:
-	case SCTP_DISPOSITION_ABORT:
-		/*
-		 * We should no longer have much work to do here as the
-		 * real work has been done as explicit commands above.
-		 */
-		break;
+	ctsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map);
+	max_tsn_seen = sctp_tsnmap_get_max_tsn_seen(&asoc->peer.tsn_map);
 
-	case SCTP_DISPOSITION_VIOLATION:
-		printk(KERN_ERR "sctp protocol violation state %d "
-		       "chunkid %d\n", state, subtype.chunk);
-		break;
+	/* From 12.2 Parameters necessary per association (i.e. the TCB):
+	 *
+	 * Ack State : This flag indicates if the next received packet
+	 * 	     : is to be responded to with a SACK. ...
+	 *	     : When DATA chunks are out of order, SACK's
+	 *           : are not delayed (see Section 6).
+	 *
+	 * [This is actually not mentioned in Section 6, but we
+	 * implement it here anyway. --piggy]
+	 */
+        if (max_tsn_seen != ctsn)
+		asoc->peer.sack_needed = 1;
 
-	case SCTP_DISPOSITION_NOT_IMPL:
-		printk(KERN_WARNING "sctp unimplemented feature in state %d, "
-		       "event_type %d, event_id %d\n",
-		       state, event_type, subtype.chunk);
-		break;
+	/* From 6.2  Acknowledgement on Reception of DATA Chunks:
+	 *
+	 * Section 4.2 of [RFC2581] SHOULD be followed. Specifically,
+	 * an acknowledgement SHOULD be generated for at least every
+	 * second packet (not every second DATA chunk) received, and
+	 * SHOULD be generated within 200 ms of the arrival of any
+	 * unacknowledged DATA chunk. ...
+	 */
+	if (!asoc->peer.sack_needed) {
+		/* We will need a SACK for the next packet.  */
+		asoc->peer.sack_needed = 1;
+		goto out;
+	} else {
+		if (asoc->a_rwnd > asoc->rwnd)
+			asoc->a_rwnd = asoc->rwnd;
+		sack = sctp_make_sack(asoc);
+		if (!sack)
+			goto nomem;
 
-	case SCTP_DISPOSITION_BUG:
-		printk(KERN_ERR "sctp bug in state %d, "
-		       "event_type %d, event_id %d\n",
-		       state, event_type, subtype.chunk);
-		BUG();
-		break;
+		asoc->peer.sack_needed = 0;
 
-	default:
-		printk(KERN_ERR "sctp impossible disposition %d "
-		       "in state %d, event_type %d, event_id %d\n",
-		       status, state, event_type, subtype.chunk);
-		BUG();
-		break;
-	};
+		error = sctp_outq_tail(&asoc->outqueue, sack);
 
-bail:
+		/* Stop the SACK timer.  */
+		sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
+				SCTP_TO(SCTP_EVENT_TIMEOUT_SACK));
+	}
+out:
+	return error;
+nomem:
+	error = -ENOMEM;
 	return error;
 }
 
-/********************************************************************
- * 2nd Level Abstractions
- ********************************************************************/
-
-/* This is the side-effect interpreter.  */
-int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
-			 sctp_state_t state, sctp_endpoint_t *ep,
-			 sctp_association_t *asoc, void *event_arg,
-			 sctp_disposition_t status, sctp_cmd_seq_t *commands,
-			 int priority)
+/* When the T3-RTX timer expires, it calls this function to create the
+ * relevant state machine event.
+ */
+void sctp_generate_t3_rtx_event(unsigned long peer)
 {
-	int error = 0;
-	int force;
-	sctp_cmd_t *cmd;
-	sctp_chunk_t *new_obj;
-	sctp_chunk_t *chunk = NULL;
-	struct sctp_packet *packet;
-	struct list_head *pos;
-	struct timer_list *timer;
-	unsigned long timeout;
-	struct sctp_transport *t;
-	sctp_sackhdr_t sackh;
+	int error;
+	struct sctp_transport *transport = (struct sctp_transport *) peer;
+	sctp_association_t *asoc = transport->asoc;
 
-	if(SCTP_EVENT_T_TIMEOUT != event_type)
-		chunk = (sctp_chunk_t *) event_arg;
+	/* Check whether a task is in the sock.  */
 
-	/* Note:  This whole file is a huge candidate for rework.
-	 * For example, each command could either have its own handler, so
-	 * the loop would look like:
-	 *     while (cmds)
-	 *         cmd->handle(x, y, z)
-	 * --jgrimm
-	 */
-	while (NULL != (cmd = sctp_next_cmd(commands))) {
-		switch (cmd->verb) {
-		case SCTP_CMD_NOP:
-			/* Do nothing. */
-			break;
+	sctp_bh_lock_sock(asoc->base.sk);
+	if (sock_owned_by_user(asoc->base.sk)) {
+		SCTP_DEBUG_PRINTK("%s:Sock is busy.\n", __FUNCTION__);
 
-		case SCTP_CMD_NEW_ASOC:
-			/* Register a new association.  */
-			asoc = cmd->obj.ptr;
-			/* Register with the endpoint.  */
-			sctp_endpoint_add_asoc(ep, asoc);
-			sctp_hash_established(asoc);
-			break;
+		/* Try again later.  */
+		if (!mod_timer(&transport->T3_rtx_timer, jiffies + (HZ/20)))
+			sctp_transport_hold(transport);
+		goto out_unlock;
+	}
 
-		case SCTP_CMD_UPDATE_ASSOC:
-		       sctp_assoc_update(asoc, cmd->obj.ptr);
-		       break;
+	/* Is this transport really dead and just waiting around for
+	 * the timer to let go of the reference?
+	 */
+	if (transport->dead)
+		goto out_unlock;
 
-		case SCTP_CMD_PURGE_OUTQUEUE:
-		       sctp_outq_teardown(&asoc->outqueue);
-		       break;
+	/* Run through the state machine.  */
+	error = sctp_do_sm(SCTP_EVENT_T_TIMEOUT,
+			   SCTP_ST_TIMEOUT(SCTP_EVENT_TIMEOUT_T3_RTX),
+			   asoc->state,
+			   asoc->ep, asoc,
+			   transport, GFP_ATOMIC);
 
-		case SCTP_CMD_DELETE_TCB:
-			/* Delete the current association.  */
-			sctp_unhash_established(asoc);
-			sctp_association_free(asoc);
-			asoc = NULL;
-			break;
+	if (error)
+		asoc->base.sk->err = -error;
 
-		case SCTP_CMD_NEW_STATE:
-			/* Enter a new state.  */
-			sctp_cmd_new_state(commands, asoc, cmd->obj.state);
-			break;
+out_unlock:
+	sctp_bh_unlock_sock(asoc->base.sk);
+	sctp_transport_put(transport);
+}
 
-		case SCTP_CMD_REPORT_TSN:
-			/* Record the arrival of a TSN.  */
-			sctp_tsnmap_mark(&asoc->peer.tsn_map, cmd->obj.u32);
-			break;
+/* This is a sa interface for producing timeout events.  It works
+ * for timeouts which use the association as their parameter.
+ */
+static void sctp_generate_timeout_event(sctp_association_t *asoc,
+					sctp_event_timeout_t timeout_type)
+{
+	int error = 0;
 
-		case SCTP_CMD_GEN_SACK:
-			/* Generate a Selective ACK.
-			 * The argument tells us whether to just count
-			 * the packet and MAYBE generate a SACK, or
-			 * force a SACK out.
-			 */
-			force = cmd->obj.i32;
-			error = sctp_gen_sack(asoc, force, commands);
-			break;
+	sctp_bh_lock_sock(asoc->base.sk);
+	if (sock_owned_by_user(asoc->base.sk)) {
+		SCTP_DEBUG_PRINTK("%s:Sock is busy: timer %d\n",
+				  __FUNCTION__,
+				  timeout_type);
 
-		case SCTP_CMD_PROCESS_SACK:
-			/* Process an inbound SACK.  */
-			error = sctp_cmd_process_sack(commands, asoc,
-						      cmd->obj.ptr);
-			break;
+		/* Try again later.  */
+		if (!mod_timer(&asoc->timers[timeout_type], jiffies + (HZ/20)))
+			sctp_association_hold(asoc);
+		goto out_unlock;
+	}
 
-		case SCTP_CMD_GEN_INIT_ACK:
-			/* Generate an INIT ACK chunk.  */
-			new_obj = sctp_make_init_ack(asoc, chunk, GFP_ATOMIC,
-						     0);
-			if (!new_obj)
-				goto nomem;
+	/* Is this association really dead and just waiting around for
+	 * the timer to let go of the reference?
+	 */
+	if (asoc->base.dead)
+		goto out_unlock;
 
-			sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
-					SCTP_CHUNK(new_obj));
-			break;
+	/* Run through the state machine.  */
+	error = sctp_do_sm(SCTP_EVENT_T_TIMEOUT,
+			   SCTP_ST_TIMEOUT(timeout_type),
+			   asoc->state, asoc->ep, asoc,
+			   (void *)timeout_type,
+			   GFP_ATOMIC);
 
-		case SCTP_CMD_PEER_INIT:
-			/* Process a unified INIT from the peer.
-			 * Note: Only used during INIT-ACK processing.  If
-			 * there is an error just return to the outter
-			 * layer which will bail.
-			 */
-			error = sctp_cmd_process_init(commands, asoc, chunk,
-						      cmd->obj.ptr, priority);
-			break;
+	if (error)
+		asoc->base.sk->err = -error;
 
-		case SCTP_CMD_GEN_COOKIE_ECHO:
-			/* Generate a COOKIE ECHO chunk.  */
-			new_obj = sctp_make_cookie_echo(asoc, chunk);
-			if (!new_obj) {
-				if (cmd->obj.ptr)
-					sctp_free_chunk(cmd->obj.ptr);
-				goto nomem;
-			}
-			sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
-					SCTP_CHUNK(new_obj));
+out_unlock:
+	sctp_bh_unlock_sock(asoc->base.sk);
+	sctp_association_put(asoc);
+}
 
-			/* If there is an ERROR chunk to be sent along with
-			 * the COOKIE_ECHO, send it, too.
-			 */
-			if (cmd->obj.ptr)
-				sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
-						SCTP_CHUNK(cmd->obj.ptr));
-			break;
+void sctp_generate_t1_cookie_event(unsigned long data)
+{
+	sctp_association_t *asoc = (sctp_association_t *) data;
+	sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T1_COOKIE);
+}
 
-		case SCTP_CMD_GEN_SHUTDOWN:
-			/* Generate SHUTDOWN when in SHUTDOWN_SENT state.
-			 * Reset error counts.
-			 */
-			asoc->overall_error_count = 0;
+void sctp_generate_t1_init_event(unsigned long data)
+{
+	sctp_association_t *asoc = (sctp_association_t *) data;
+	sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T1_INIT);
+}
 
-			/* Generate a SHUTDOWN chunk.  */
-			new_obj = sctp_make_shutdown(asoc);
-			if (!new_obj)
-				goto nomem;
-			sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
-					SCTP_CHUNK(new_obj));
-			break;
+void sctp_generate_t2_shutdown_event(unsigned long data)
+{
+	sctp_association_t *asoc = (sctp_association_t *) data;
+	sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T2_SHUTDOWN);
+}
 
-		case SCTP_CMD_CHUNK_ULP:
-			/* Send a chunk to the sockets layer.  */
-			SCTP_DEBUG_PRINTK("sm_sideff: %s %p, %s %p.\n",
-					  "chunk_up:", cmd->obj.ptr,
-					  "ulpq:", &asoc->ulpq);
-			sctp_ulpq_tail_data(&asoc->ulpq, cmd->obj.ptr,
-					    GFP_ATOMIC);
-			break;
+void sctp_generate_t5_shutdown_guard_event(unsigned long data)
+{
+        sctp_association_t *asoc = (sctp_association_t *)data;
+        sctp_generate_timeout_event(asoc,
+				    SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD);
 
-		case SCTP_CMD_EVENT_ULP:
-			/* Send a notification to the sockets layer.  */
-			SCTP_DEBUG_PRINTK("sm_sideff: %s %p, %s %p.\n",
-					  "event_up:",cmd->obj.ptr,
-					  "ulpq:",&asoc->ulpq);
-			sctp_ulpq_tail_event(&asoc->ulpq, cmd->obj.ptr);
-			break;
+} /* sctp_generate_t5_shutdown_guard_event() */
 
-		case SCTP_CMD_REPLY:
-			/* Send a chunk to our peer.  */
-			error = sctp_outq_tail(&asoc->outqueue,
-					       cmd->obj.ptr);
-			break;
+void sctp_generate_autoclose_event(unsigned long data)
+{
+	sctp_association_t *asoc = (sctp_association_t *) data;
+	sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_AUTOCLOSE);
+}
 
-		case SCTP_CMD_SEND_PKT:
-			/* Send a full packet to our peer.  */
-			packet = cmd->obj.ptr;
-			sctp_packet_transmit(packet);
-			sctp_ootb_pkt_free(packet);
-			break;
+/* Generate a heart beat event.  If the sock is busy, reschedule.   Make
+ * sure that the transport is still valid.
+ */
+void sctp_generate_heartbeat_event(unsigned long data)
+{
+	int error = 0;
+	struct sctp_transport *transport = (struct sctp_transport *) data;
+	sctp_association_t *asoc = transport->asoc;
 
-		case SCTP_CMD_RETRAN:
-			/* Mark a transport for retransmission.  */
-			sctp_retransmit(&asoc->outqueue, cmd->obj.transport,
-					SCTP_RETRANSMIT_T3_RTX);
-			break;
+	sctp_bh_lock_sock(asoc->base.sk);
+	if (sock_owned_by_user(asoc->base.sk)) {
+		SCTP_DEBUG_PRINTK("%s:Sock is busy.\n", __FUNCTION__);
 
-		case SCTP_CMD_TRANSMIT:
-			/* Kick start transmission. */
-			error = sctp_outq_flush(&asoc->outqueue, 0);
-			break;
+		/* Try again later.  */
+		if (!mod_timer(&transport->hb_timer, jiffies + (HZ/20)))
+			sctp_transport_hold(transport);
+		goto out_unlock;
+	}
 
-		case SCTP_CMD_ECN_CE:
-			/* Do delayed CE processing.   */
-			sctp_do_ecn_ce_work(asoc, cmd->obj.u32);
-			break;
+	/* Is this structure just waiting around for us to actually
+	 * get destroyed?
+	 */
+	if (transport->dead)
+		goto out_unlock;
 
-		case SCTP_CMD_ECN_ECNE:
-			/* Do delayed ECNE processing. */
-			new_obj = sctp_do_ecn_ecne_work(asoc, cmd->obj.u32,
-							chunk);
-			if (new_obj)
-				sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
-						SCTP_CHUNK(new_obj));
-			break;
-
-		case SCTP_CMD_ECN_CWR:
-			/* Do delayed CWR processing.  */
-			sctp_do_ecn_cwr_work(asoc, cmd->obj.u32);
-			break;
+	error = sctp_do_sm(SCTP_EVENT_T_TIMEOUT,
+			   SCTP_ST_TIMEOUT(SCTP_EVENT_TIMEOUT_HEARTBEAT),
+			   asoc->state,
+			   asoc->ep, asoc,
+			   transport, GFP_ATOMIC);
 
-		case SCTP_CMD_SETUP_T2:
-			sctp_cmd_setup_t2(commands, asoc, cmd->obj.ptr);
-			break;
+         if (error)
+		 asoc->base.sk->err = -error;
 
-		case SCTP_CMD_TIMER_START:
-			timer = &asoc->timers[cmd->obj.to];
-			timeout = asoc->timeouts[cmd->obj.to];
-			if (!timeout)
-				BUG();
+out_unlock:
+	sctp_bh_unlock_sock(asoc->base.sk);
+	sctp_transport_put(transport);
+}
 
-			timer->expires = jiffies + timeout;
-			sctp_association_hold(asoc);
-			add_timer(timer);
-			break;
+/* Inject a SACK Timeout event into the state machine.  */
+void sctp_generate_sack_event(unsigned long data)
+{
+	sctp_association_t *asoc = (sctp_association_t *) data;
+	sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_SACK);
+}
 
-		case SCTP_CMD_TIMER_RESTART:
-			timer = &asoc->timers[cmd->obj.to];
-			timeout = asoc->timeouts[cmd->obj.to];
-			if (!mod_timer(timer, jiffies + timeout))
-				sctp_association_hold(asoc);
-			break;
+sctp_timer_event_t *sctp_timer_events[SCTP_NUM_TIMEOUT_TYPES] = {
+	NULL,
+	sctp_generate_t1_cookie_event,
+	sctp_generate_t1_init_event,
+	sctp_generate_t2_shutdown_event,
+	NULL,
+	sctp_generate_t5_shutdown_guard_event,
+	sctp_generate_heartbeat_event,
+	sctp_generate_sack_event,
+	sctp_generate_autoclose_event,
+};
 
-		case SCTP_CMD_TIMER_STOP:
-			timer = &asoc->timers[cmd->obj.to];
-			if (timer_pending(timer) && del_timer(timer))
-				sctp_association_put(asoc);
-			break;
 
-		case SCTP_CMD_INIT_RESTART:
-			/* Do the needed accounting and updates
-			 * associated with restarting an initialization
-			 * timer.
-			 */
-			asoc->counters[SCTP_COUNTER_INIT_ERROR]++;
-			asoc->timeouts[cmd->obj.to] *= 2;
-			if (asoc->timeouts[cmd->obj.to] >
-			    asoc->max_init_timeo) {
-				asoc->timeouts[cmd->obj.to] =
-					asoc->max_init_timeo;
-			}
+/* RFC 2960 8.2 Path Failure Detection
+ *
+ * When its peer endpoint is multi-homed, an endpoint should keep a
+ * error counter for each of the destination transport addresses of the
+ * peer endpoint.
+ *
+ * Each time the T3-rtx timer expires on any address, or when a
+ * HEARTBEAT sent to an idle address is not acknowledged within a RTO,
+ * the error counter of that destination address will be incremented.
+ * When the value in the error counter exceeds the protocol parameter
+ * 'Path.Max.Retrans' of that destination address, the endpoint should
+ * mark the destination transport address as inactive, and a
+ * notification SHOULD be sent to the upper layer.
+ *
+ */
+static void sctp_do_8_2_transport_strike(sctp_association_t *asoc,
+					 struct sctp_transport *transport)
+{
+	/* The check for association's overall error counter exceeding the
+	 * threshold is done in the state function.
+	 */
+	asoc->overall_error_count++;
 
-			/* If we've sent any data bundled with
-			 * COOKIE-ECHO we need to resend.
-			 */
-			list_for_each(pos, &asoc->peer.transport_addr_list) {
-				t = list_entry(pos, struct sctp_transport,
-					       transports);
-				sctp_retransmit_mark(&asoc->outqueue, t, 0);
-			}
+	if (transport->active &&
+	    (transport->error_count++ >= transport->error_threshold)) {
+		SCTP_DEBUG_PRINTK("transport_strike: transport "
+				  "IP:%d.%d.%d.%d failed.\n",
+				  NIPQUAD(transport->ipaddr.v4.sin_addr));
+		sctp_assoc_control_transport(asoc, transport,
+					     SCTP_TRANSPORT_DOWN,
+					     SCTP_FAILED_THRESHOLD);
+	}
 
-			sctp_add_cmd_sf(commands,
-					SCTP_CMD_TIMER_RESTART,
-					SCTP_TO(cmd->obj.to));
-			break;
+	/* E2) For the destination address for which the timer
+	 * expires, set RTO <- RTO * 2 ("back off the timer").  The
+	 * maximum value discussed in rule C7 above (RTO.max) may be
+	 * used to provide an upper bound to this doubling operation.
+	 */
+	transport->rto = min((transport->rto * 2), transport->asoc->rto_max);
+}
 
-		case SCTP_CMD_INIT_FAILED:
-			sctp_cmd_init_failed(commands, asoc);
-			break;
+/* Worker routine to handle INIT command failure.  */
+static void sctp_cmd_init_failed(sctp_cmd_seq_t *commands,
+				 sctp_association_t *asoc,
+				 unsigned error)
+{
+	struct sctp_ulpevent *event;
 
-		case SCTP_CMD_ASSOC_FAILED:
-			sctp_cmd_assoc_failed(commands, asoc, event_type,
-					      subtype, chunk);
-			break;
+	event = sctp_ulpevent_make_assoc_change(asoc,0, SCTP_CANT_STR_ASSOC,
+						0, 0, 0, GFP_ATOMIC);
 
-		case SCTP_CMD_COUNTER_INC:
-			asoc->counters[cmd->obj.counter]++;
-			break;
+	if (event)
+		sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
+				SCTP_ULPEVENT(event));
 
-		case SCTP_CMD_COUNTER_RESET:
-			asoc->counters[cmd->obj.counter] = 0;
-			break;
+	/* SEND_FAILED sent later when cleaning up the association. */
+	asoc->outqueue.error = error;
+	sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
+}
 
-		case SCTP_CMD_REPORT_DUP:
-			sctp_tsnmap_mark_dup(&asoc->peer.tsn_map, 
-					     cmd->obj.u32);
-			break;
+/* Worker routine to handle SCTP_CMD_ASSOC_FAILED.  */
+static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
+				  struct sctp_association *asoc,
+				  sctp_event_t event_type,
+				  sctp_subtype_t subtype,
+				  struct sctp_chunk *chunk,
+				  unsigned error)
+{
+	struct sctp_ulpevent *event;
 
-		case SCTP_CMD_REPORT_BAD_TAG:
-			SCTP_DEBUG_PRINTK("vtag mismatch!\n");
-			break;
+	/* Cancel any partial delivery in progress. */
+	sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC);
 
-		case SCTP_CMD_STRIKE:
-			/* Mark one strike against a transport.  */
-			sctp_do_8_2_transport_strike(asoc, cmd->obj.transport);
-			break;
+	event = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_LOST,
+						(__u16)error, 0, 0,
+						GFP_ATOMIC);
+	if (event)
+		sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
+				SCTP_ULPEVENT(event));
 
-		case SCTP_CMD_TRANSPORT_RESET:
-			t = cmd->obj.transport;
-			sctp_cmd_transport_reset(commands, asoc, t);
-			break;
+	sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
+			SCTP_STATE(SCTP_STATE_CLOSED));
 
-		case SCTP_CMD_TRANSPORT_ON:
-			t = cmd->obj.transport;
-			sctp_cmd_transport_on(commands, asoc, t, chunk);
-			break;
+	/* SEND_FAILED sent later when cleaning up the association. */
+	asoc->outqueue.error = error;
+	sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
+}
 
-		case SCTP_CMD_HB_TIMERS_START:
-			sctp_cmd_hb_timers_start(commands, asoc);
-			break;
+/* Process an init chunk (may be real INIT/INIT-ACK or an embedded INIT
+ * inside the cookie.  In reality, this is only used for INIT-ACK processing
+ * since all other cases use "temporary" associations and can do all
+ * their work in statefuns directly.
+ */
+static int sctp_cmd_process_init(sctp_cmd_seq_t *commands,
+				 struct sctp_association *asoc,
+				 struct sctp_chunk *chunk,
+				 sctp_init_chunk_t *peer_init, int gfp)
+{
+	int error;
 
-		case SCTP_CMD_HB_TIMER_UPDATE:
-			t = cmd->obj.transport;
-			sctp_cmd_hb_timer_update(commands, asoc, t);
-			break;
+	/* We only process the init as a sideeffect in a single
+	 * case.   This is when we process the INIT-ACK.   If we
+	 * fail during INIT processing (due to malloc problems),
+	 * just return the error and stop processing the stack.
+	 */
+	if (!sctp_process_init(asoc, chunk->chunk_hdr->type,
+			       sctp_source(chunk), peer_init, gfp))
+		error = -ENOMEM;
+	else
+		error = 0;
 
-		case SCTP_CMD_HB_TIMERS_STOP:
-			sctp_cmd_hb_timers_stop(commands, asoc);
-			break;
+	return error;
+}
 
-		case SCTP_CMD_REPORT_ERROR:
-			error = cmd->obj.error;
-			break;
+/* Helper function to break out starting up of heartbeat timers.  */
+static void sctp_cmd_hb_timers_start(sctp_cmd_seq_t *cmds,
+				     sctp_association_t *asoc)
+{
+	struct sctp_transport *t;
+	struct list_head *pos;
 
-		case SCTP_CMD_PROCESS_CTSN:
-			/* Dummy up a SACK for processing. */
-			sackh.cum_tsn_ack = cmd->obj.u32;
-			sackh.a_rwnd = 0;
-			sackh.num_gap_ack_blocks = 0;
-			sackh.num_dup_tsns = 0;
-			sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_SACK,
-					SCTP_SACKH(&sackh));
-			break;
+	/* Start a heartbeat timer for each transport on the association.
+	 * hold a reference on the transport to make sure none of
+	 * the needed data structures go away.
+	 */
+	list_for_each(pos, &asoc->peer.transport_addr_list) {
+		t = list_entry(pos, struct sctp_transport, transports);
 
-		case SCTP_CMD_DISCARD_PACKET:
-			/* We need to discard the whole packet.  */
-			chunk->pdiscard = 1;
-			break;
+		if (!mod_timer(&t->hb_timer, sctp_transport_timeout(t)))
+			sctp_transport_hold(t);
+	}
+}
 
-		case SCTP_CMD_RTO_PENDING:
-			t = cmd->obj.transport;
-			t->rto_pending = 1;
-			break;
+static void sctp_cmd_hb_timers_stop(sctp_cmd_seq_t *cmds,
+				    sctp_association_t *asoc)
+{
+	struct sctp_transport *t;
+	struct list_head *pos;
 
-		case SCTP_CMD_PART_DELIVER:
-			sctp_ulpq_partial_delivery(&asoc->ulpq, cmd->obj.ptr,
-						   GFP_ATOMIC);
-			break;
+	/* Stop all heartbeat timers. */
 
-		case SCTP_CMD_RENEGE:
-			sctp_ulpq_renege(&asoc->ulpq, cmd->obj.ptr,
-					 GFP_ATOMIC);
-			break;
-
-		default:
-			printk(KERN_WARNING "Impossible command: %u, %p\n",
-			       cmd->verb, cmd->obj.ptr);
-			break;
-		};
-		if (error)
-			return error;
+	list_for_each(pos, &asoc->peer.transport_addr_list) {
+		t = list_entry(pos, struct sctp_transport, transports);
+		if (del_timer(&t->hb_timer))
+			sctp_transport_put(t);
 	}
-
-	return error;
-
-nomem:
-	error = -ENOMEM;
-	return error;
 }
 
-/* A helper function for delayed processing of INET ECN CE bit. */
-static void sctp_do_ecn_ce_work(sctp_association_t *asoc, __u32 lowest_tsn)
+/* Helper function to update the heartbeat timer. */
+static void sctp_cmd_hb_timer_update(sctp_cmd_seq_t *cmds,
+				     sctp_association_t *asoc,
+				     struct sctp_transport *t)
 {
-	/* Save the TSN away for comparison when we receive CWR */
-
-	asoc->last_ecne_tsn = lowest_tsn;
-	asoc->need_ecne = 1;
+	/* Update the heartbeat timer.  */
+	if (!mod_timer(&t->hb_timer, sctp_transport_timeout(t)))
+		sctp_transport_hold(t);
 }
 
-/* Helper function for delayed processing of SCTP ECNE chunk.  */
-/* RFC 2960 Appendix A
- *
- * RFC 2481 details a specific bit for a sender to send in
- * the header of its next outbound TCP segment to indicate to
- * its peer that it has reduced its congestion window.  This
- * is termed the CWR bit.  For SCTP the same indication is made
- * by including the CWR chunk.  This chunk contains one data
- * element, i.e. the TSN number that was sent in the ECNE chunk.
- * This element represents the lowest TSN number in the datagram
- * that was originally marked with the CE bit.
- */
-static sctp_chunk_t *sctp_do_ecn_ecne_work(sctp_association_t *asoc,
-					   __u32 lowest_tsn,
-					   sctp_chunk_t *chunk)
+/* Helper function to handle the reception of an HEARTBEAT ACK.  */
+static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds,
+				  sctp_association_t *asoc,
+				  struct sctp_transport *t,
+				  sctp_chunk_t *chunk)
 {
-	sctp_chunk_t *repl;
-
-	/* Our previously transmitted packet ran into some congestion
-	 * so we should take action by reducing cwnd and ssthresh
-	 * and then ACK our peer that we we've done so by
-	 * sending a CWR.
-	 */
+	sctp_sender_hb_info_t *hbinfo;
 
-	/* First, try to determine if we want to actually lower
-	 * our cwnd variables.  Only lower them if the ECNE looks more
-	 * recent than the last response.
+	/* 8.3 Upon the receipt of the HEARTBEAT ACK, the sender of the
+	 * HEARTBEAT should clear the error counter of the destination
+	 * transport address to which the HEARTBEAT was sent.
+	 * The association's overall error count is also cleared.
 	 */
-	if (TSN_lt(asoc->last_cwr_tsn, lowest_tsn)) {
-		struct sctp_transport *transport;
-
-		/* Find which transport's congestion variables
-		 * need to be adjusted.
-		 */
-		transport = sctp_assoc_lookup_tsn(asoc, lowest_tsn);
-
-		/* Update the congestion variables. */
-		if (transport)
-			sctp_transport_lower_cwnd(transport,
-						  SCTP_LOWER_CWND_ECNE);
-		asoc->last_cwr_tsn = lowest_tsn;
-	}
+	t->error_count = 0;
+	t->asoc->overall_error_count = 0;
 
-	/* Always try to quiet the other end.  In case of lost CWR,
-	 * resend last_cwr_tsn.
+	/* Mark the destination transport address as active if it is not so
+	 * marked.
 	 */
-	repl = sctp_make_cwr(asoc, asoc->last_cwr_tsn, chunk);
+	if (!t->active)
+		sctp_assoc_control_transport(asoc, t, SCTP_TRANSPORT_UP,
+					     SCTP_HEARTBEAT_SUCCESS);
 
-	/* If we run out of memory, it will look like a lost CWR.  We'll
-	 * get back in sync eventually.
+	/* The receiver of the HEARTBEAT ACK should also perform an
+	 * RTT measurement for that destination transport address
+	 * using the time value carried in the HEARTBEAT ACK chunk.
 	 */
-	return repl;
+	hbinfo = (sctp_sender_hb_info_t *) chunk->skb->data;
+	sctp_transport_update_rto(t, (jiffies - hbinfo->sent_at));
 }
 
-/* Helper function to do delayed processing of ECN CWR chunk.  */
-static void sctp_do_ecn_cwr_work(sctp_association_t *asoc,
-				 __u32 lowest_tsn)
+/* Helper function to do a transport reset at the expiry of the hearbeat
+ * timer.
+ */
+static void sctp_cmd_transport_reset(sctp_cmd_seq_t *cmds,
+				     sctp_association_t *asoc,
+				     struct sctp_transport *t)
 {
-	/* Turn off ECNE getting auto-prepended to every outgoing
-	 * packet
-	 */
-	asoc->need_ecne = 0;
-}
+	sctp_transport_lower_cwnd(t, SCTP_LOWER_CWND_INACTIVE);
 
-/* This macro is to compress the text a bit...  */
-#define AP(v) asoc->peer.v
+	/* Mark one strike against a transport.  */
+	sctp_do_8_2_transport_strike(asoc, t);
+}
 
-/* Generate SACK if necessary.  We call this at the end of a packet.  */
-int sctp_gen_sack(sctp_association_t *asoc, int force, sctp_cmd_seq_t *commands)
+/* Helper function to process the process SACK command.  */
+static int sctp_cmd_process_sack(sctp_cmd_seq_t *cmds,
+				 sctp_association_t *asoc,
+				 sctp_sackhdr_t *sackh)
 {
-	__u32 ctsn, max_tsn_seen;
-	sctp_chunk_t *sack;
-	int error = 0;
-
-	if (force)
-		asoc->peer.sack_needed = 1;
-
-	ctsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map);
-	max_tsn_seen = sctp_tsnmap_get_max_tsn_seen(&asoc->peer.tsn_map);
-
-	/* From 12.2 Parameters necessary per association (i.e. the TCB):
-	 *
-	 * Ack State : This flag indicates if the next received packet
-	 * 	     : is to be responded to with a SACK. ...
-	 *	     : When DATA chunks are out of order, SACK's
-	 *           : are not delayed (see Section 6).
-	 *
-	 * [This is actually not mentioned in Section 6, but we
-	 * implement it here anyway. --piggy]
-	 */
-        if (max_tsn_seen != ctsn)
-		asoc->peer.sack_needed = 1;
+	int err;
 
-	/* From 6.2  Acknowledgement on Reception of DATA Chunks:
-	 *
-	 * Section 4.2 of [RFC2581] SHOULD be followed. Specifically,
-	 * an acknowledgement SHOULD be generated for at least every
-	 * second packet (not every second DATA chunk) received, and
-	 * SHOULD be generated within 200 ms of the arrival of any
-	 * unacknowledged DATA chunk. ...
-	 */
-	if (!asoc->peer.sack_needed) {
-		/* We will need a SACK for the next packet.  */
-		asoc->peer.sack_needed = 1;
-		goto out;
+	if (sctp_outq_sack(&asoc->outqueue, sackh)) {
+		/* There are no more TSNs awaiting SACK.  */
+		err = sctp_do_sm(SCTP_EVENT_T_OTHER,
+				 SCTP_ST_OTHER(SCTP_EVENT_NO_PENDING_TSN),
+				 asoc->state, asoc->ep, asoc, NULL,
+				 GFP_ATOMIC);
 	} else {
-		if (asoc->a_rwnd > asoc->rwnd)
-			asoc->a_rwnd = asoc->rwnd;
-		sack = sctp_make_sack(asoc);
-		if (!sack)
-			goto nomem;
-
-		asoc->peer.sack_needed = 0;
-
-		error = sctp_outq_tail(&asoc->outqueue, sack);
-
-		/* Stop the SACK timer.  */
-		sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
-				SCTP_TO(SCTP_EVENT_TIMEOUT_SACK));
+		/* Windows may have opened, so we need
+		 * to check if we have DATA to transmit
+		 */
+		err = sctp_outq_flush(&asoc->outqueue, 0);
 	}
 
-out:
-	return error;
-
-nomem:
-	error = -ENOMEM;
-	return error;
+	return err;
 }
 
-/* Handle a duplicate TSN.  */
-void sctp_do_TSNdup(sctp_association_t *asoc, sctp_chunk_t *chunk, long gap)
+/* Helper function to set the timeout value for T2-SHUTDOWN timer and to set
+ * the transport for a shutdown chunk.
+ */
+static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds, sctp_association_t *asoc,
+			      sctp_chunk_t *chunk)
 {
-#if 0
-	sctp_chunk_t *sack;
-
-	/* Caution:  gap < 2 * SCTP_TSN_MAP_SIZE
-	 * 	so gap can be negative.
-	 *
-	 *		--xguo
-	 */
-
-	/* Count this TSN.  */
-	if (gap < SCTP_TSN_MAP_SIZE) {
-		asoc->peer.tsn_map[gap]++;
-	} else {
-		asoc->peer.tsn_map_overflow[gap - SCTP_TSN_MAP_SIZE]++;
-	}
-
-	/* From 6.2  Acknowledgement on Reception of DATA Chunks
-	 *
-	 * When a packet arrives with duplicate DATA chunk(s)
-	 * and with no new DATA chunk(s), the endpoint MUST
-	 * immediately send a SACK with no delay. If a packet
-	 * arrives with duplicate DATA chunk(s) bundled with
-	 * new DATA chunks, the endpoint MAY immediately send a
-	 * SACK.  Normally receipt of duplicate DATA chunks
-	 * will occur when the original SACK chunk was lost and
-	 * the peer's RTO has expired. The duplicate TSN
-	 * number(s) SHOULD be reported in the SACK as
-	 * duplicate.
-	 */
-	asoc->counters[SctpCounterAckState] = 2;
-#endif /* 0 */
-} /* sctp_do_TSNdup() */
+	struct sctp_transport *t;
 
-#undef AP
+	t = sctp_assoc_choose_shutdown_transport(asoc);
+	asoc->shutdown_last_sent_to = t;
+	asoc->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = t->rto;
+	chunk->transport = t;
+}
 
-/* When the T3-RTX timer expires, it calls this function to create the
- * relevant state machine event.
- */
-void sctp_generate_t3_rtx_event(unsigned long peer)
+/* Helper function to change the state of an association. */
+static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds, sctp_association_t *asoc,
+			       sctp_state_t state)
 {
-	int error;
-	struct sctp_transport *transport = (struct sctp_transport *) peer;
-	sctp_association_t *asoc = transport->asoc;
 
-	/* Check whether a task is in the sock.  */
+	struct sock *sk = asoc->base.sk;
+	struct sctp_opt *sp = sctp_sk(sk);
 
-	sctp_bh_lock_sock(asoc->base.sk);
-	if (sock_owned_by_user(asoc->base.sk)) {
-		SCTP_DEBUG_PRINTK("%s:Sock is busy.\n", __FUNCTION__);
+	asoc->state = state;
+	asoc->state_timestamp = jiffies;
 
-		/* Try again later.  */
-		if (!mod_timer(&transport->T3_rtx_timer, jiffies + (HZ/20)))
-			sctp_transport_hold(transport);
-		goto out_unlock;
+	if ((SCTP_STATE_ESTABLISHED == asoc->state) ||
+	    (SCTP_STATE_CLOSED == asoc->state)) {
+		/* Wake up any processes waiting in the asoc's wait queue in
+		 * sctp_wait_for_connect() or sctp_wait_for_sndbuf().
+	 	 */
+		if (waitqueue_active(&asoc->wait))
+			wake_up_interruptible(&asoc->wait);
+
+		/* Wake up any processes waiting in the sk's sleep queue of
+		 * a TCP-style or UDP-style peeled-off socket in
+		 * sctp_wait_for_accept() or sctp_wait_for_packet().
+		 * For a UDP-style socket, the waiters are woken up by the
+		 * notifications.
+		 */
+		if (SCTP_SOCKET_UDP != sp->type)
+			sk->state_change(sk);
 	}
 
-	/* Is this transport really dead and just waiting around for
-	 * the timer to let go of the reference?
+	/* Change the sk->state of a TCP-style socket that has sucessfully
+	 * completed a connect() call.
 	 */
-	if (transport->dead)
-		goto out_unlock;
+	if ((SCTP_STATE_ESTABLISHED == asoc->state) &&
+	    (SCTP_SOCKET_TCP == sp->type) && (SCTP_SS_CLOSED == sk->state))
+	    sk->state = SCTP_SS_ESTABLISHED;
+}
 
-	/* Run through the state machine.  */
-	error = sctp_do_sm(SCTP_EVENT_T_TIMEOUT,
-			   SCTP_ST_TIMEOUT(SCTP_EVENT_TIMEOUT_T3_RTX),
-			   asoc->state,
-			   asoc->ep, asoc,
-			   transport, GFP_ATOMIC);
+/* These three macros allow us to pull the debugging code out of the
+ * main flow of sctp_do_sm() to keep attention focused on the real
+ * functionality there.
+ */
+#define DEBUG_PRE \
+	SCTP_DEBUG_PRINTK("sctp_do_sm prefn: " \
+			  "ep %p, %s, %s, asoc %p[%s], %s\n", \
+			  ep, sctp_evttype_tbl[event_type], \
+			  (*debug_fn)(subtype), asoc, \
+			  sctp_state_tbl[state], state_fn->name)
 
-	if (error)
-		asoc->base.sk->err = -error;
+#define DEBUG_POST \
+	SCTP_DEBUG_PRINTK("sctp_do_sm postfn: " \
+			  "asoc %p, status: %s\n", \
+			  asoc, sctp_status_tbl[status])
 
-out_unlock:
-	sctp_bh_unlock_sock(asoc->base.sk);
-	sctp_transport_put(transport);
-}
+#define DEBUG_POST_SFX \
+	SCTP_DEBUG_PRINTK("sctp_do_sm post sfx: error %d, asoc %p[%s]\n", \
+			  error, asoc, \
+			  sctp_state_tbl[(asoc && sctp_id2assoc(ep->base.sk, \
+			  sctp_assoc2id(asoc)))?asoc->state:SCTP_STATE_CLOSED])
 
-/* This is a sa interface for producing timeout events.  It works
- * for timeouts which use the association as their parameter.
+/*
+ * This is the master state machine processing function.
+ *
+ * If you want to understand all of lksctp, this is a
+ * good place to start.
  */
-static void sctp_generate_timeout_event(sctp_association_t *asoc,
-					sctp_event_timeout_t timeout_type)
+int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype,
+	       sctp_state_t state,
+	       sctp_endpoint_t *ep,
+	       sctp_association_t *asoc,
+	       void *event_arg,
+	       int priority)
 {
+	sctp_cmd_seq_t commands;
+	sctp_sm_table_entry_t *state_fn;
+	sctp_disposition_t status;
 	int error = 0;
+	typedef const char *(printfn_t)(sctp_subtype_t);
 
-	sctp_bh_lock_sock(asoc->base.sk);
-	if (sock_owned_by_user(asoc->base.sk)) {
-		SCTP_DEBUG_PRINTK("%s:Sock is busy: timer %d\n",
-				  __FUNCTION__,
-				  timeout_type);
-
-		/* Try again later.  */
-		if (!mod_timer(&asoc->timers[timeout_type], jiffies + (HZ/20)))
-			sctp_association_hold(asoc);
-		goto out_unlock;
-	}
+	static printfn_t *table[] = {
+		NULL, sctp_cname, sctp_tname, sctp_oname, sctp_pname,
+	};
+	printfn_t *debug_fn  __attribute__ ((unused)) = table[event_type];
 
-	/* Is this association really dead and just waiting around for
-	 * the timer to let go of the reference?
+	/* Look up the state function, run it, and then process the
+	 * side effects.  These three steps are the heart of lksctp.
 	 */
-	if (asoc->base.dead)
-		goto out_unlock;
-
-	/* Run through the state machine.  */
-	error = sctp_do_sm(SCTP_EVENT_T_TIMEOUT,
-			   SCTP_ST_TIMEOUT(timeout_type),
-			   asoc->state, asoc->ep, asoc,
-			   (void *)timeout_type,
-			   GFP_ATOMIC);
+	state_fn = sctp_sm_lookup_event(event_type, state, subtype);
 
-	if (error)
-		asoc->base.sk->err = -error;
+	sctp_init_cmd_seq(&commands);
 
-out_unlock:
-	sctp_bh_unlock_sock(asoc->base.sk);
-	sctp_association_put(asoc);
-}
+	DEBUG_PRE;
+	status = (*state_fn->fn)(ep, asoc, subtype, event_arg, &commands);
+	DEBUG_POST;
 
-void sctp_generate_t1_cookie_event(unsigned long data)
-{
-	sctp_association_t *asoc = (sctp_association_t *) data;
-	sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T1_COOKIE);
-}
+	error = sctp_side_effects(event_type, subtype, state,
+				  ep, asoc, event_arg,
+				  status, &commands,
+				  priority);
+	DEBUG_POST_SFX;
 
-void sctp_generate_t1_init_event(unsigned long data)
-{
-	sctp_association_t *asoc = (sctp_association_t *) data;
-	sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T1_INIT);
+	return error;
 }
 
-void sctp_generate_t2_shutdown_event(unsigned long data)
-{
-	sctp_association_t *asoc = (sctp_association_t *) data;
-	sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T2_SHUTDOWN);
-}
+#undef DEBUG_PRE
+#undef DEBUG_POST
 
-void sctp_generate_t5_shutdown_guard_event(unsigned long data)
+/*****************************************************************
+ * This the master state function side effect processing function.
+ *****************************************************************/
+int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype,
+		      sctp_state_t state,
+		      sctp_endpoint_t *ep,
+		      sctp_association_t *asoc,
+		      void *event_arg,
+		      sctp_disposition_t status,
+		      sctp_cmd_seq_t *commands,
+		      int priority)
 {
-        sctp_association_t *asoc = (sctp_association_t *)data;
-        sctp_generate_timeout_event(asoc,
-				    SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD);
+	int error;
 
-} /* sctp_generate_t5_shutdown_guard_event() */
+	/* FIXME - Most of the dispositions left today would be categorized
+	 * as "exceptional" dispositions.  For those dispositions, it
+	 * may not be proper to run through any of the commands at all.
+	 * For example, the command interpreter might be run only with
+	 * disposition SCTP_DISPOSITION_CONSUME.
+	 */
+	if (0 != (error = sctp_cmd_interpreter(event_type, subtype, state,
+					       ep, asoc,
+					       event_arg, status,
+					       commands, priority)))
+		goto bail;
 
-void sctp_generate_autoclose_event(unsigned long data)
-{
-	sctp_association_t *asoc = (sctp_association_t *) data;
-	sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_AUTOCLOSE);
-}
+	switch (status) {
+	case SCTP_DISPOSITION_DISCARD:
+		SCTP_DEBUG_PRINTK("Ignored sctp protocol event - state %d, "
+				  "event_type %d, event_id %d\n",
+				  state, event_type, subtype.chunk);
+		break;
 
-/* Generate a heart beat event.  If the sock is busy, reschedule.   Make
- * sure that the transport is still valid.
- */
-void sctp_generate_heartbeat_event(unsigned long data)
-{
-	int error = 0;
-	struct sctp_transport *transport = (struct sctp_transport *) data;
-	sctp_association_t *asoc = transport->asoc;
+	case SCTP_DISPOSITION_NOMEM:
+		/* We ran out of memory, so we need to discard this
+		 * packet.
+		 */
+		/* BUG--we should now recover some memory, probably by
+		 * reneging...
+		 */
+		error = -ENOMEM;
+		break;
 
-	sctp_bh_lock_sock(asoc->base.sk);
-	if (sock_owned_by_user(asoc->base.sk)) {
-		SCTP_DEBUG_PRINTK("%s:Sock is busy.\n", __FUNCTION__);
+        case SCTP_DISPOSITION_DELETE_TCB:
+		/* This should now be a command. */
+		break;
 
-		/* Try again later.  */
-		if (!mod_timer(&transport->hb_timer, jiffies + (HZ/20)))
-			sctp_transport_hold(transport);
-		goto out_unlock;
-	}
+	case SCTP_DISPOSITION_CONSUME:
+	case SCTP_DISPOSITION_ABORT:
+		/*
+		 * We should no longer have much work to do here as the
+		 * real work has been done as explicit commands above.
+		 */
+		break;
 
-	/* Is this structure just waiting around for us to actually
-	 * get destroyed?
-	 */
-	if (transport->dead)
-		goto out_unlock;
+	case SCTP_DISPOSITION_VIOLATION:
+		printk(KERN_ERR "sctp protocol violation state %d "
+		       "chunkid %d\n", state, subtype.chunk);
+		break;
 
-	error = sctp_do_sm(SCTP_EVENT_T_TIMEOUT,
-			   SCTP_ST_TIMEOUT(SCTP_EVENT_TIMEOUT_HEARTBEAT),
-			   asoc->state,
-			   asoc->ep, asoc,
-			   transport, GFP_ATOMIC);
+	case SCTP_DISPOSITION_NOT_IMPL:
+		printk(KERN_WARNING "sctp unimplemented feature in state %d, "
+		       "event_type %d, event_id %d\n",
+		       state, event_type, subtype.chunk);
+		break;
 
-         if (error)
-		 asoc->base.sk->err = -error;
+	case SCTP_DISPOSITION_BUG:
+		printk(KERN_ERR "sctp bug in state %d, "
+		       "event_type %d, event_id %d\n",
+		       state, event_type, subtype.chunk);
+		BUG();
+		break;
 
-out_unlock:
-	sctp_bh_unlock_sock(asoc->base.sk);
-	sctp_transport_put(transport);
-}
+	default:
+		printk(KERN_ERR "sctp impossible disposition %d "
+		       "in state %d, event_type %d, event_id %d\n",
+		       status, state, event_type, subtype.chunk);
+		BUG();
+		break;
+	};
 
-/* Inject a SACK Timeout event into the state machine.  */
-void sctp_generate_sack_event(unsigned long data)
-{
-	sctp_association_t *asoc = (sctp_association_t *) data;
-	sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_SACK);
+bail:
+	return error;
 }
 
-sctp_timer_event_t *sctp_timer_events[SCTP_NUM_TIMEOUT_TYPES] = {
-	NULL,
-	sctp_generate_t1_cookie_event,
-	sctp_generate_t1_init_event,
-	sctp_generate_t2_shutdown_event,
-	NULL,
-	sctp_generate_t5_shutdown_guard_event,
-	sctp_generate_heartbeat_event,
-	sctp_generate_sack_event,
-	sctp_generate_autoclose_event,
-};
-
 /********************************************************************
- * 3rd Level Abstractions
+ * 2nd Level Abstractions
  ********************************************************************/
 
-/* RFC 2960 8.2 Path Failure Detection
- *
- * When its peer endpoint is multi-homed, an endpoint should keep a
- * error counter for each of the destination transport addresses of the
- * peer endpoint.
- *
- * Each time the T3-rtx timer expires on any address, or when a
- * HEARTBEAT sent to an idle address is not acknowledged within a RTO,
- * the error counter of that destination address will be incremented.
- * When the value in the error counter exceeds the protocol parameter
- * 'Path.Max.Retrans' of that destination address, the endpoint should
- * mark the destination transport address as inactive, and a
- * notification SHOULD be sent to the upper layer.
- *
- */
-static void sctp_do_8_2_transport_strike(sctp_association_t *asoc,
-					 struct sctp_transport *transport)
+/* This is the side-effect interpreter.  */
+int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
+			 sctp_state_t state, sctp_endpoint_t *ep,
+			 sctp_association_t *asoc, void *event_arg,
+			 sctp_disposition_t status, sctp_cmd_seq_t *commands,
+			 int priority)
 {
-	/* The check for association's overall error counter exceeding the
-	 * threshold is done in the state function.
-	 */
-	asoc->overall_error_count++;
+	int error = 0;
+	int force;
+	sctp_cmd_t *cmd;
+	sctp_chunk_t *new_obj;
+	sctp_chunk_t *chunk = NULL;
+	struct sctp_packet *packet;
+	struct list_head *pos;
+	struct timer_list *timer;
+	unsigned long timeout;
+	struct sctp_transport *t;
+	sctp_sackhdr_t sackh;
 
-	if (transport->active &&
-	    (transport->error_count++ >= transport->error_threshold)) {
-		SCTP_DEBUG_PRINTK("transport_strike: transport "
-				  "IP:%d.%d.%d.%d failed.\n",
-				  NIPQUAD(transport->ipaddr.v4.sin_addr));
-		sctp_assoc_control_transport(asoc, transport,
-					     SCTP_TRANSPORT_DOWN,
-					     SCTP_FAILED_THRESHOLD);
-	}
+	if(SCTP_EVENT_T_TIMEOUT != event_type)
+		chunk = (sctp_chunk_t *) event_arg;
 
-	/* E2) For the destination address for which the timer
-	 * expires, set RTO <- RTO * 2 ("back off the timer").  The
-	 * maximum value discussed in rule C7 above (RTO.max) may be
-	 * used to provide an upper bound to this doubling operation.
+	/* Note:  This whole file is a huge candidate for rework.
+	 * For example, each command could either have its own handler, so
+	 * the loop would look like:
+	 *     while (cmds)
+	 *         cmd->handle(x, y, z)
+	 * --jgrimm
 	 */
-	transport->rto = min((transport->rto * 2), transport->asoc->rto_max);
-}
+	while (NULL != (cmd = sctp_next_cmd(commands))) {
+		switch (cmd->verb) {
+		case SCTP_CMD_NOP:
+			/* Do nothing. */
+			break;
 
-/* Worker routine to handle INIT command failure.  */
-static void sctp_cmd_init_failed(sctp_cmd_seq_t *commands,
-				 sctp_association_t *asoc)
-{
-	struct sctp_ulpevent *event;
+		case SCTP_CMD_NEW_ASOC:
+			/* Register a new association.  */
+			asoc = cmd->obj.ptr;
+			/* Register with the endpoint.  */
+			sctp_endpoint_add_asoc(ep, asoc);
+			sctp_hash_established(asoc);
+			break;
 
-	event = sctp_ulpevent_make_assoc_change(asoc,
-						0,
-						SCTP_CANT_STR_ASSOC,
-						0, 0, 0,
-						GFP_ATOMIC);
+		case SCTP_CMD_UPDATE_ASSOC:
+		       sctp_assoc_update(asoc, cmd->obj.ptr);
+		       break;
 
-	if (event)
-		sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
-				SCTP_ULPEVENT(event));
+		case SCTP_CMD_PURGE_OUTQUEUE:
+		       sctp_outq_teardown(&asoc->outqueue);
+		       break;
 
-	/* FIXME:  We need to handle data possibly either
-	 * sent via COOKIE-ECHO bundling or just waiting in
-	 * the transmit queue, if the user has enabled
-	 * SEND_FAILED notifications.
-	 */
-	sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
-}
+		case SCTP_CMD_DELETE_TCB:
+			/* Delete the current association.  */
+			sctp_unhash_established(asoc);
+			sctp_association_free(asoc);
+			asoc = NULL;
+			break;
 
-/* Worker routine to handle SCTP_CMD_ASSOC_FAILED.  */
-static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
-				  sctp_association_t *asoc,
-				  sctp_event_t event_type,
-				  sctp_subtype_t subtype,
-				  sctp_chunk_t *chunk)
-{
-	struct sctp_ulpevent *event;
-	__u16 error = 0;
+		case SCTP_CMD_NEW_STATE:
+			/* Enter a new state.  */
+			sctp_cmd_new_state(commands, asoc, cmd->obj.state);
+			break;
 
-	switch(event_type) {
-	case SCTP_EVENT_T_PRIMITIVE:
-		if (SCTP_PRIMITIVE_ABORT == subtype.primitive)
-			error = SCTP_ERROR_USER_ABORT;
-		break;
-	case SCTP_EVENT_T_CHUNK:
-		if (chunk && (SCTP_CID_ABORT == chunk->chunk_hdr->type) &&
-	    	    (ntohs(chunk->chunk_hdr->length) >=
-			(sizeof(struct sctp_chunkhdr) +
-				sizeof(struct sctp_errhdr)))) {
-			error = ((sctp_errhdr_t *)chunk->skb->data)->cause;
-		}
-		break;
-	default:
-		break;
-	}
+		case SCTP_CMD_REPORT_TSN:
+			/* Record the arrival of a TSN.  */
+			sctp_tsnmap_mark(&asoc->peer.tsn_map, cmd->obj.u32);
+			break;
 
-	/* Cancel any partial delivery in progress. */
-	sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC);
+		case SCTP_CMD_GEN_SACK:
+			/* Generate a Selective ACK.
+			 * The argument tells us whether to just count
+			 * the packet and MAYBE generate a SACK, or
+			 * force a SACK out.
+			 */
+			force = cmd->obj.i32;
+			error = sctp_gen_sack(asoc, force, commands);
+			break;
 
-	event = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_LOST,
-						error, 0, 0, GFP_ATOMIC);
-	if (event)
-		sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
-				SCTP_ULPEVENT(event));
+		case SCTP_CMD_PROCESS_SACK:
+			/* Process an inbound SACK.  */
+			error = sctp_cmd_process_sack(commands, asoc,
+						      cmd->obj.ptr);
+			break;
 
-	sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
-			SCTP_STATE(SCTP_STATE_CLOSED));
+		case SCTP_CMD_GEN_INIT_ACK:
+			/* Generate an INIT ACK chunk.  */
+			new_obj = sctp_make_init_ack(asoc, chunk, GFP_ATOMIC,
+						     0);
+			if (!new_obj)
+				goto nomem;
 
-	/* FIXME:  We need to handle data that could not be sent or was not
-	 * acked, if the user has enabled SEND_FAILED notifications.
-	 */
-	sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
-}
+			sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
+					SCTP_CHUNK(new_obj));
+			break;
 
-/* Process an init chunk (may be real INIT/INIT-ACK or an embedded INIT
- * inside the cookie.  In reality, this is only used for INIT-ACK processing
- * since all other cases use "temporary" associations and can do all
- * their work in statefuns directly.
- */
-static int sctp_cmd_process_init(sctp_cmd_seq_t *commands,
-				 sctp_association_t *asoc,
-				 sctp_chunk_t *chunk,
-				 sctp_init_chunk_t *peer_init,
-				 int priority)
-{
-	int error;
+		case SCTP_CMD_PEER_INIT:
+			/* Process a unified INIT from the peer.
+			 * Note: Only used during INIT-ACK processing.  If
+			 * there is an error just return to the outter
+			 * layer which will bail.
+			 */
+			error = sctp_cmd_process_init(commands, asoc, chunk,
+						      cmd->obj.ptr, priority);
+			break;
 
-	/* We only process the init as a sideeffect in a single
-	 * case.   This is when we process the INIT-ACK.   If we
-	 * fail during INIT processing (due to malloc problems),
-	 * just return the error and stop processing the stack.
-	 */
+		case SCTP_CMD_GEN_COOKIE_ECHO:
+			/* Generate a COOKIE ECHO chunk.  */
+			new_obj = sctp_make_cookie_echo(asoc, chunk);
+			if (!new_obj) {
+				if (cmd->obj.ptr)
+					sctp_free_chunk(cmd->obj.ptr);
+				goto nomem;
+			}
+			sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
+					SCTP_CHUNK(new_obj));
 
-	if (!sctp_process_init(asoc, chunk->chunk_hdr->type,
-			       sctp_source(chunk), peer_init,
-			       priority))
-		error = -ENOMEM;
-	else
-		error = 0;
+			/* If there is an ERROR chunk to be sent along with
+			 * the COOKIE_ECHO, send it, too.
+			 */
+			if (cmd->obj.ptr)
+				sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
+						SCTP_CHUNK(cmd->obj.ptr));
+			break;
+
+		case SCTP_CMD_GEN_SHUTDOWN:
+			/* Generate SHUTDOWN when in SHUTDOWN_SENT state.
+			 * Reset error counts.
+			 */
+			asoc->overall_error_count = 0;
+
+			/* Generate a SHUTDOWN chunk.  */
+			new_obj = sctp_make_shutdown(asoc);
+			if (!new_obj)
+				goto nomem;
+			sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
+					SCTP_CHUNK(new_obj));
+			break;
+
+		case SCTP_CMD_CHUNK_ULP:
+			/* Send a chunk to the sockets layer.  */
+			SCTP_DEBUG_PRINTK("sm_sideff: %s %p, %s %p.\n",
+					  "chunk_up:", cmd->obj.ptr,
+					  "ulpq:", &asoc->ulpq);
+			sctp_ulpq_tail_data(&asoc->ulpq, cmd->obj.ptr,
+					    GFP_ATOMIC);
+			break;
+
+		case SCTP_CMD_EVENT_ULP:
+			/* Send a notification to the sockets layer.  */
+			SCTP_DEBUG_PRINTK("sm_sideff: %s %p, %s %p.\n",
+					  "event_up:",cmd->obj.ptr,
+					  "ulpq:",&asoc->ulpq);
+			sctp_ulpq_tail_event(&asoc->ulpq, cmd->obj.ptr);
+			break;
+
+		case SCTP_CMD_REPLY:
+			/* Send a chunk to our peer.  */
+			error = sctp_outq_tail(&asoc->outqueue,
+					       cmd->obj.ptr);
+			break;
+
+		case SCTP_CMD_SEND_PKT:
+			/* Send a full packet to our peer.  */
+			packet = cmd->obj.ptr;
+			sctp_packet_transmit(packet);
+			sctp_ootb_pkt_free(packet);
+			break;
+
+		case SCTP_CMD_RETRAN:
+			/* Mark a transport for retransmission.  */
+			sctp_retransmit(&asoc->outqueue, cmd->obj.transport,
+					SCTP_RTXR_T3_RTX);
+			break;
+
+		case SCTP_CMD_TRANSMIT:
+			/* Kick start transmission. */
+			error = sctp_outq_flush(&asoc->outqueue, 0);
+			break;
+
+		case SCTP_CMD_ECN_CE:
+			/* Do delayed CE processing.   */
+			sctp_do_ecn_ce_work(asoc, cmd->obj.u32);
+			break;
+
+		case SCTP_CMD_ECN_ECNE:
+			/* Do delayed ECNE processing. */
+			new_obj = sctp_do_ecn_ecne_work(asoc, cmd->obj.u32,
+							chunk);
+			if (new_obj)
+				sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
+						SCTP_CHUNK(new_obj));
+			break;
+
+		case SCTP_CMD_ECN_CWR:
+			/* Do delayed CWR processing.  */
+			sctp_do_ecn_cwr_work(asoc, cmd->obj.u32);
+			break;
+
+		case SCTP_CMD_SETUP_T2:
+			sctp_cmd_setup_t2(commands, asoc, cmd->obj.ptr);
+			break;
+
+		case SCTP_CMD_TIMER_START:
+			timer = &asoc->timers[cmd->obj.to];
+			timeout = asoc->timeouts[cmd->obj.to];
+			if (!timeout)
+				BUG();
 
-	return error;
-}
+			timer->expires = jiffies + timeout;
+			sctp_association_hold(asoc);
+			add_timer(timer);
+			break;
 
-/* Helper function to break out starting up of heartbeat timers.  */
-static void sctp_cmd_hb_timers_start(sctp_cmd_seq_t *cmds,
-				     sctp_association_t *asoc)
-{
-	struct sctp_transport *t;
-	struct list_head *pos;
+		case SCTP_CMD_TIMER_RESTART:
+			timer = &asoc->timers[cmd->obj.to];
+			timeout = asoc->timeouts[cmd->obj.to];
+			if (!mod_timer(timer, jiffies + timeout))
+				sctp_association_hold(asoc);
+			break;
 
-	/* Start a heartbeat timer for each transport on the association.
-	 * hold a reference on the transport to make sure none of
-	 * the needed data structures go away.
-	 */
-	list_for_each(pos, &asoc->peer.transport_addr_list) {
-		t = list_entry(pos, struct sctp_transport, transports);
+		case SCTP_CMD_TIMER_STOP:
+			timer = &asoc->timers[cmd->obj.to];
+			if (timer_pending(timer) && del_timer(timer))
+				sctp_association_put(asoc);
+			break;
 
-		if (!mod_timer(&t->hb_timer, sctp_transport_timeout(t)))
-			sctp_transport_hold(t);
-	}
-}
+		case SCTP_CMD_INIT_RESTART:
+			/* Do the needed accounting and updates
+			 * associated with restarting an initialization
+			 * timer.
+			 */
+			asoc->counters[SCTP_COUNTER_INIT_ERROR]++;
+			asoc->timeouts[cmd->obj.to] *= 2;
+			if (asoc->timeouts[cmd->obj.to] >
+			    asoc->max_init_timeo) {
+				asoc->timeouts[cmd->obj.to] =
+					asoc->max_init_timeo;
+			}
 
-static void sctp_cmd_hb_timers_stop(sctp_cmd_seq_t *cmds,
-				    sctp_association_t *asoc)
-{
-	struct sctp_transport *t;
-	struct list_head *pos;
+			/* If we've sent any data bundled with
+			 * COOKIE-ECHO we need to resend.
+			 */
+			list_for_each(pos, &asoc->peer.transport_addr_list) {
+				t = list_entry(pos, struct sctp_transport,
+					       transports);
+				sctp_retransmit_mark(&asoc->outqueue, t, 0);
+			}
 
-	/* Stop all heartbeat timers. */
+			sctp_add_cmd_sf(commands,
+					SCTP_CMD_TIMER_RESTART,
+					SCTP_TO(cmd->obj.to));
+			break;
 
-	list_for_each(pos, &asoc->peer.transport_addr_list) {
-		t = list_entry(pos, struct sctp_transport, transports);
-		if (del_timer(&t->hb_timer))
-			sctp_transport_put(t);
-	}
-}
+		case SCTP_CMD_INIT_FAILED:
+			sctp_cmd_init_failed(commands, asoc, cmd->obj.u32);
+			break;
 
-/* Helper function to update the heartbeat timer. */
-static void sctp_cmd_hb_timer_update(sctp_cmd_seq_t *cmds,
-				     sctp_association_t *asoc,
-				     struct sctp_transport *t)
-{
-	/* Update the heartbeat timer.  */
-	if (!mod_timer(&t->hb_timer, sctp_transport_timeout(t)))
-		sctp_transport_hold(t);
-}
+		case SCTP_CMD_ASSOC_FAILED:
+			sctp_cmd_assoc_failed(commands, asoc, event_type,
+					      subtype, chunk, cmd->obj.u32);
+			break;
 
-/* Helper function to handle the reception of an HEARTBEAT ACK.  */
-static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds,
-				  sctp_association_t *asoc,
-				  struct sctp_transport *t,
-				  sctp_chunk_t *chunk)
-{
-	sctp_sender_hb_info_t *hbinfo;
+		case SCTP_CMD_COUNTER_INC:
+			asoc->counters[cmd->obj.counter]++;
+			break;
 
-	/* 8.3 Upon the receipt of the HEARTBEAT ACK, the sender of the
-	 * HEARTBEAT should clear the error counter of the destination
-	 * transport address to which the HEARTBEAT was sent.
-	 * The association's overall error count is also cleared.
-	 */
-	t->error_count = 0;
-	t->asoc->overall_error_count = 0;
+		case SCTP_CMD_COUNTER_RESET:
+			asoc->counters[cmd->obj.counter] = 0;
+			break;
 
-	/* Mark the destination transport address as active if it is not so
-	 * marked.
-	 */
-	if (!t->active)
-		sctp_assoc_control_transport(asoc, t, SCTP_TRANSPORT_UP,
-					     SCTP_HEARTBEAT_SUCCESS);
+		case SCTP_CMD_REPORT_DUP:
+			sctp_tsnmap_mark_dup(&asoc->peer.tsn_map,
+					     cmd->obj.u32);
+			break;
 
-	/* The receiver of the HEARTBEAT ACK should also perform an
-	 * RTT measurement for that destination transport address
-	 * using the time value carried in the HEARTBEAT ACK chunk.
-	 */
-	hbinfo = (sctp_sender_hb_info_t *) chunk->skb->data;
-	sctp_transport_update_rto(t, (jiffies - hbinfo->sent_at));
-}
+		case SCTP_CMD_REPORT_BAD_TAG:
+			SCTP_DEBUG_PRINTK("vtag mismatch!\n");
+			break;
 
-/* Helper function to do a transport reset at the expiry of the hearbeat
- * timer.
- */
-static void sctp_cmd_transport_reset(sctp_cmd_seq_t *cmds,
-				     sctp_association_t *asoc,
-				     struct sctp_transport *t)
-{
-	sctp_transport_lower_cwnd(t, SCTP_LOWER_CWND_INACTIVE);
+		case SCTP_CMD_STRIKE:
+			/* Mark one strike against a transport.  */
+			sctp_do_8_2_transport_strike(asoc, cmd->obj.transport);
+			break;
 
-	/* Mark one strike against a transport.  */
-	sctp_do_8_2_transport_strike(asoc, t);
-}
+		case SCTP_CMD_TRANSPORT_RESET:
+			t = cmd->obj.transport;
+			sctp_cmd_transport_reset(commands, asoc, t);
+			break;
 
-/* Helper function to process the process SACK command.  */
-static int sctp_cmd_process_sack(sctp_cmd_seq_t *cmds,
-				 sctp_association_t *asoc,
-				 sctp_sackhdr_t *sackh)
-{
-	int err;
+		case SCTP_CMD_TRANSPORT_ON:
+			t = cmd->obj.transport;
+			sctp_cmd_transport_on(commands, asoc, t, chunk);
+			break;
 
-	if (sctp_outq_sack(&asoc->outqueue, sackh)) {
-		/* There are no more TSNs awaiting SACK.  */
-		err = sctp_do_sm(SCTP_EVENT_T_OTHER,
-				 SCTP_ST_OTHER(SCTP_EVENT_NO_PENDING_TSN),
-				 asoc->state, asoc->ep, asoc, NULL,
-				 GFP_ATOMIC);
-	} else {
-		/* Windows may have opened, so we need
-		 * to check if we have DATA to transmit
-		 */
-		err = sctp_outq_flush(&asoc->outqueue, 0);
-	}
+		case SCTP_CMD_HB_TIMERS_START:
+			sctp_cmd_hb_timers_start(commands, asoc);
+			break;
 
-	return err;
-}
+		case SCTP_CMD_HB_TIMER_UPDATE:
+			t = cmd->obj.transport;
+			sctp_cmd_hb_timer_update(commands, asoc, t);
+			break;
 
-/* Helper function to set the timeout value for T2-SHUTDOWN timer and to set
- * the transport for a shutdown chunk.
- */
-static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds, sctp_association_t *asoc,
-			      sctp_chunk_t *chunk)
-{
-	struct sctp_transport *t;
+		case SCTP_CMD_HB_TIMERS_STOP:
+			sctp_cmd_hb_timers_stop(commands, asoc);
+			break;
 
-	t = sctp_assoc_choose_shutdown_transport(asoc);
-	asoc->shutdown_last_sent_to = t;
-	asoc->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = t->rto;
-	chunk->transport = t;
-}
+		case SCTP_CMD_REPORT_ERROR:
+			error = cmd->obj.error;
+			break;
 
-/* Helper function to change the state of an association. */
-static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds, sctp_association_t *asoc,
-			       sctp_state_t state)
-{
+		case SCTP_CMD_PROCESS_CTSN:
+			/* Dummy up a SACK for processing. */
+			sackh.cum_tsn_ack = cmd->obj.u32;
+			sackh.a_rwnd = 0;
+			sackh.num_gap_ack_blocks = 0;
+			sackh.num_dup_tsns = 0;
+			sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_SACK,
+					SCTP_SACKH(&sackh));
+			break;
 
-	struct sock *sk = asoc->base.sk;
-	struct sctp_opt *sp = sctp_sk(sk);
+		case SCTP_CMD_DISCARD_PACKET:
+			/* We need to discard the whole packet.  */
+			chunk->pdiscard = 1;
+			break;
 
-	asoc->state = state;
-	asoc->state_timestamp = jiffies;
+		case SCTP_CMD_RTO_PENDING:
+			t = cmd->obj.transport;
+			t->rto_pending = 1;
+			break;
 
-	if ((SCTP_STATE_ESTABLISHED == asoc->state) ||
-	    (SCTP_STATE_CLOSED == asoc->state)) { 
-		/* Wake up any processes waiting in the asoc's wait queue in
-		 * sctp_wait_for_connect() or sctp_wait_for_sndbuf(). 
-	 	 */
-		if (waitqueue_active(&asoc->wait))
-			wake_up_interruptible(&asoc->wait);
+		case SCTP_CMD_PART_DELIVER:
+			sctp_ulpq_partial_delivery(&asoc->ulpq, cmd->obj.ptr,
+						   GFP_ATOMIC);
+			break;
 
-		/* Wake up any processes waiting in the sk's sleep queue of
-		 * a TCP-style or UDP-style peeled-off socket in
-		 * sctp_wait_for_accept() or sctp_wait_for_packet().
-		 * For a UDP-style socket, the waiters are woken up by the
-		 * notifications.
-		 */
-		if (SCTP_SOCKET_UDP != sp->type)
-			sk->state_change(sk);
+		case SCTP_CMD_RENEGE:
+			sctp_ulpq_renege(&asoc->ulpq, cmd->obj.ptr,
+					 GFP_ATOMIC);
+			break;
+
+		default:
+			printk(KERN_WARNING "Impossible command: %u, %p\n",
+			       cmd->verb, cmd->obj.ptr);
+			break;
+		};
+		if (error)
+			return error;
 	}
 
-	/* Change the sk->state of a TCP-style socket that has sucessfully
-	 * completed a connect() call.
-	 */
-	if ((SCTP_STATE_ESTABLISHED == asoc->state) &&
-	    (SCTP_SOCKET_TCP == sp->type) && (SCTP_SS_CLOSED == sk->state))
-	    sk->state = SCTP_SS_ESTABLISHED;
+	return error;
+
+nomem:
+	error = -ENOMEM;
+	return error;
 }
+
diff -urN linux-2.5.66-bk10/net/sctp/sm_statefuns.c linux-2.5.66-bk11/net/sctp/sm_statefuns.c
--- linux-2.5.66-bk10/net/sctp/sm_statefuns.c	2003-03-24 13:59:56.000000000 -0800
+++ linux-2.5.66-bk11/net/sctp/sm_statefuns.c	2003-04-05 04:32:16.000000000 -0800
@@ -191,14 +191,9 @@
 	sctp_chunk_t *err_chunk;
 	struct sctp_packet *packet;
 	sctp_unrecognized_param_t *unk_param;
+	struct sock *sk;
 	int len;
 
-	/* If the packet is an OOTB packet which is temporarily on the
-	 * control endpoint, respond with an ABORT.
-	 */
-	if (ep == sctp_sk((sctp_get_ctl_sock()))->ep)
-		return sctp_sf_ootb(ep, asoc, type, arg, commands);
-
 	/* 6.10 Bundling
 	 * An endpoint MUST NOT bundle INIT, INIT ACK or
 	 * SHUTDOWN COMPLETE with any other chunks.
@@ -206,6 +201,22 @@
 	if (!chunk->singleton)
 		return SCTP_DISPOSITION_VIOLATION;
 
+	/* If the packet is an OOTB packet which is temporarily on the
+	 * control endpoint, respond with an ABORT.
+	 */
+	if (ep == sctp_sk((sctp_get_ctl_sock()))->ep)
+		return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
+
+	sk = ep->base.sk;
+	/* If the endpoint is not listening or if the number of associations
+	 * on the TCP-style socket exceed the max backlog, respond with an
+	 * ABORT.
+	 */
+	if ((SCTP_SS_LISTENING != sk->state) ||
+	    ((SCTP_SOCKET_TCP == sctp_sk(sk)->type) &&
+	     (sk->ack_backlog >= sk->max_ack_backlog)))
+		return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
+
 	/* Verify the INIT chunk before processing it. */
 	err_chunk = NULL;
 	if (!sctp_verify_init(asoc, chunk->chunk_hdr->type,
@@ -249,8 +260,8 @@
 
 	/* The call, sctp_process_init(), can fail on memory allocation.  */
 	if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type,
-			       sctp_source(chunk),
-			       (sctp_init_chunk_t *)chunk->chunk_hdr,
+			       sctp_source(chunk), 
+			       (sctp_init_chunk_t *)chunk->chunk_hdr, 
 			       GFP_ATOMIC))
 		goto nomem_init;
 
@@ -729,7 +740,8 @@
 
 	if (asoc->overall_error_count >= asoc->overall_error_threshold) {
 		/* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
-		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL());
+		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, 
+				SCTP_U32(SCTP_ERROR_NO_ERROR));
 		SCTP_INC_STATS(SctpAborteds);
 		SCTP_DEC_STATS(SctpCurrEstab);
 		return SCTP_DISPOSITION_DELETE_TCB;
@@ -1379,7 +1391,8 @@
 	peer_init = &chunk->subh.cookie_hdr->c.peer_init[0];
 
 	if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type,
-			       sctp_source(chunk), peer_init, GFP_ATOMIC))
+			       sctp_source(chunk), peer_init, 
+			       GFP_ATOMIC))
 		goto nomem;
 
 	/* Make sure no new addresses are being added during the
@@ -1444,7 +1457,8 @@
 	 */
 	peer_init = &chunk->subh.cookie_hdr->c.peer_init[0];
 	if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type,
-			       sctp_source(chunk), peer_init, GFP_ATOMIC))
+			       sctp_source(chunk), peer_init, 
+			       GFP_ATOMIC))
 		goto nomem;
 
 	/* Update the content of current association.  */
@@ -1772,14 +1786,16 @@
 	sctp_chunk_t *chunk = arg;
 	sctp_errhdr_t *err;
 
+	err = (sctp_errhdr_t *)(chunk->skb->data);
+
 	/* If we have gotten too many failures, give up.  */
 	if (1 + asoc->counters[SCTP_COUNTER_INIT_ERROR] >
 					 asoc->max_init_attempts) {
 		/* INIT_FAILED will issue an ulpevent.  */
-		sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_NULL());
+		sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, 
+				SCTP_U32(err->cause));
 		return SCTP_DISPOSITION_DELETE_TCB;
 	}
-	err = (sctp_errhdr_t *)(chunk->skb->data);
 
 	/* Process the error here */
 	switch (err->cause) {
@@ -1834,7 +1850,8 @@
 	attempts = asoc->counters[SCTP_COUNTER_INIT_ERROR] + 1;
 
 	if (attempts >= asoc->max_init_attempts) {
-		sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_NULL());
+		sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, 
+				SCTP_U32(SCTP_ERROR_STALE_COOKIE));
 		return SCTP_DISPOSITION_DELETE_TCB;
 	}
 
@@ -1936,12 +1953,18 @@
 					sctp_cmd_seq_t *commands)
 {
 	sctp_chunk_t *chunk = arg;
+	__u16 error = SCTP_ERROR_NO_ERROR;
 
 	if (!sctp_vtag_verify_either(chunk, asoc))
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+	if (chunk && (ntohs(chunk->chunk_hdr->length) >=
+			(sizeof(struct sctp_chunkhdr) + 
+			sizeof(struct sctp_errhdr))))
+		error = ((sctp_errhdr_t *)chunk->skb->data)->cause;
+
  	/* ASSOC_FAILED will DELETE_TCB. */
-	sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL());
+	sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(error));
 	SCTP_INC_STATS(SctpAborteds);
 	SCTP_DEC_STATS(SctpCurrEstab);
 
@@ -1961,6 +1984,7 @@
 					     sctp_cmd_seq_t *commands)
 {
 	sctp_chunk_t *chunk = arg;
+	__u16 error = SCTP_ERROR_NO_ERROR;
 
 	if (!sctp_vtag_verify_either(chunk, asoc))
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
@@ -1971,10 +1995,14 @@
 	sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
 			SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
 
+	if (chunk && (ntohs(chunk->chunk_hdr->length) >=
+			(sizeof(struct sctp_chunkhdr) + 
+			sizeof(struct sctp_errhdr))))
+		error = ((sctp_errhdr_t *)chunk->skb->data)->cause;
+
 	/* CMD_INIT_FAILED will DELETE_TCB. */
-	sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_NULL());
+	sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_U32(error));
 
-	/* BUG?  This does not look complete... */
 	return SCTP_DISPOSITION_ABORT;
 }
 
@@ -2381,7 +2409,8 @@
 		 * processing the rest of the chunks in the packet.
 		 */
 		sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL());
-		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL());
+		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, 
+				SCTP_U32(SCTP_ERROR_NO_DATA));
 		SCTP_INC_STATS(SctpAborteds);
 		SCTP_DEC_STATS(SctpCurrEstab);
 		return SCTP_DISPOSITION_CONSUME;
@@ -2596,7 +2625,8 @@
 		 * processing the rest of the chunks in the packet.
 		 */
 		sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL());
-		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL());
+		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, 
+				SCTP_U32(SCTP_ERROR_NO_DATA));
 		SCTP_INC_STATS(SctpAborteds);
 		SCTP_DEC_STATS(SctpCurrEstab);
 		return SCTP_DISPOSITION_CONSUME;
@@ -3547,7 +3577,8 @@
 	 */
 
 	/* Delete the established association. */
-	sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL());
+	sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, 
+			SCTP_U32(SCTP_ERROR_USER_ABORT));
 
 	SCTP_INC_STATS(SctpAborteds);
 	SCTP_DEC_STATS(SctpCurrEstab);
@@ -3686,7 +3717,8 @@
 	 */
 
 	/* Delete the established association. */
-	sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_NULL());
+	sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, 
+			SCTP_U32(SCTP_ERROR_USER_ABORT));
 
 	return retval;
 }
@@ -4012,7 +4044,8 @@
 
 	if (asoc->overall_error_count >= asoc->overall_error_threshold) {
 		/* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
-		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL());
+		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, 
+				SCTP_U32(SCTP_ERROR_NO_ERROR));
 		SCTP_INC_STATS(SctpAborteds);
 		SCTP_DEC_STATS(SctpCurrEstab);
 		return SCTP_DISPOSITION_DELETE_TCB;
@@ -4147,7 +4180,8 @@
 				SCTP_TO(timer));
 		sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
 	} else {
-		sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_NULL());
+		sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, 
+				SCTP_U32(SCTP_ERROR_NO_ERROR));
 		return SCTP_DISPOSITION_DELETE_TCB;
 	}
 
@@ -4181,7 +4215,8 @@
 	SCTP_DEBUG_PRINTK("Timer T2 expired.\n");
 	if (asoc->overall_error_count >= asoc->overall_error_threshold) {
 		/* Note:  CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
-		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL());
+		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, 
+				SCTP_U32(SCTP_ERROR_NO_ERROR));
 		SCTP_INC_STATS(SctpAborteds);
 		SCTP_DEC_STATS(SctpCurrEstab);
 		return SCTP_DISPOSITION_DELETE_TCB;
@@ -4244,7 +4279,8 @@
 		goto nomem;
 
 	sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));
-	sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL());
+	sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, 
+			SCTP_U32(SCTP_ERROR_NO_ERROR));
 
 	return SCTP_DISPOSITION_DELETE_TCB;
 nomem:
diff -urN linux-2.5.66-bk10/net/sctp/socket.c linux-2.5.66-bk11/net/sctp/socket.c
--- linux-2.5.66-bk10/net/sctp/socket.c	2003-03-24 14:01:53.000000000 -0800
+++ linux-2.5.66-bk11/net/sctp/socket.c	2003-04-05 04:32:16.000000000 -0800
@@ -244,9 +244,6 @@
 	if (!snum)
 		snum = inet_sk(sk)->num;
 
-
-
-
 	/* Add the address to the bind address list.  */
 	sctp_local_bh_disable();
 	sctp_write_lock(&ep->base.addr_lock);
@@ -257,7 +254,6 @@
 	addr->v4.sin_port = htons(addr->v4.sin_port);
 	if (!ret && !bp->port)
 		bp->port = snum;
-
 	sctp_write_unlock(&ep->base.addr_lock);
 	sctp_local_bh_enable();
 
@@ -2750,6 +2746,9 @@
 	err = -EINVAL;
 	if (sock->state != SS_UNCONNECTED)
 		goto out;
+	if (unlikely(backlog < 0))
+		goto out;
+
 	switch (sock->type) {
 	case SOCK_SEQPACKET:
 		err = sctp_seqpacket_listen(sk, backlog);
@@ -3152,7 +3151,10 @@
 		return -EINVAL;
 
 	/* Is this a valid SCTP address?  */
-	if (!af->addr_valid((union sctp_addr *)addr))
+	if (!af->addr_valid(addr))
+		return -EINVAL;
+
+	if (!sctp_sk(sk)->pf->send_verify(sctp_sk(sk), (addr)))
 		return -EINVAL;
 
 	return 0;
diff -urN linux-2.5.66-bk10/net/sctp/ulpevent.c linux-2.5.66-bk11/net/sctp/ulpevent.c
--- linux-2.5.66-bk10/net/sctp/ulpevent.c	2003-03-24 14:00:08.000000000 -0800
+++ linux-2.5.66-bk11/net/sctp/ulpevent.c	2003-04-05 04:32:16.000000000 -0800
@@ -628,6 +628,7 @@
 	if (!event)
 		goto fail_init;
 
+	event->iif = sctp_chunk_iif(chunk);
 	/* Note:  Not clearing the entire event struct as
 	 * this is just a fragment of the real event.  However,
 	 * we still need to do rwnd accounting. 
diff -urN linux-2.5.66-bk10/scripts/kconfig/gconf.c linux-2.5.66-bk11/scripts/kconfig/gconf.c
--- linux-2.5.66-bk10/scripts/kconfig/gconf.c	2003-03-24 14:01:43.000000000 -0800
+++ linux-2.5.66-bk11/scripts/kconfig/gconf.c	2003-04-05 04:32:16.000000000 -0800
@@ -72,7 +72,7 @@
 static void display_tree(struct menu *menu);
 static void display_tree_part(void);
 static void update_tree(struct menu *src, GtkTreeIter * dst);
-static void set_node2(GtkTreeIter * node, struct menu *menu, gchar ** row);
+static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row);
 static gchar **fill_row(struct menu *menu);
 
 
@@ -371,8 +371,8 @@
 					    "active", COL_BTNACT,
 					    "inconsistent", COL_BTNINC,
 					    "visible", COL_BTNVIS, NULL);
-	g_signal_connect(G_OBJECT(renderer), "toggled",
-			 G_CALLBACK(renderer_toggled), NULL);
+	/*g_signal_connect(G_OBJECT(renderer), "toggled",
+	   G_CALLBACK(renderer_toggled), NULL); */
 	renderer = gtk_cell_renderer_text_new();
 	gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
 					renderer, FALSE);
@@ -791,11 +791,11 @@
 
 void on_back_pressed(GtkButton * button, gpointer user_data)
 {
-	enum prop_type type;
+	enum prop_type ptype;
 
 	current = current->parent;
-	type = current->prompt ? current->prompt->type : P_UNKNOWN;
-	if ((type != P_ROOTMENU) && (type != P_MENU))
+	ptype = current->prompt ? current->prompt->type : P_UNKNOWN;
+	if ((ptype != P_ROOTMENU) && (ptype != P_MENU))
 		current = current->parent;
 	display_tree_part();
 
@@ -821,8 +821,6 @@
 	view_mode = SINGLE_VIEW;
 	gtk_paned_set_position(GTK_PANED(hpaned), 0);
 	gtk_widget_hide(tree1_w);
-	if (tree2)
-		gtk_tree_store_clear(tree2);
 	current = &rootmenu;
 	display_tree_part();
 }
@@ -835,8 +833,6 @@
 	gtk_widget_show(tree1_w);
 	gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
 	gtk_paned_set_position(GTK_PANED(hpaned), w / 2);
-	if (tree2)
-		gtk_tree_store_clear(tree2);
 	display_list();
 }
 
@@ -899,80 +895,89 @@
 static void change_sym_value(struct menu *menu, gint col)
 {
 	struct symbol *sym = menu->sym;
-	int stype;
 	tristate oldval, newval;
 
-	newval = no;
-	switch (col) {
-	case COL_OPTION:
-		return;
-	case COL_NAME:
+	if (!sym)
 		return;
-	case COL_NO:
+
+	if (col == COL_NO)
 		newval = no;
-		break;
-	case COL_MOD:
+	else if (col == COL_MOD)
 		newval = mod;
-		break;
-	case COL_YES:
+	else if (col == COL_YES)
 		newval = yes;
-		break;
-	default:
-		break;
-	}
-
-	if (!sym)
+	else
 		return;
 
-	stype = sym_get_type(sym);
-	switch (stype) {
+	switch (sym_get_type(sym)) {
 	case S_BOOLEAN:
 	case S_TRISTATE:
-		if (col == COL_VALUE)
-			return;
-		else {
-			oldval = sym_get_tristate_value(sym);
-			if (!sym_tristate_within_range(sym, newval))
-				newval = yes;
-			sym_set_tristate_value(sym, newval);
-			config_changed = TRUE;
-			if (view_mode == FULL_VIEW)
-				update_tree(&rootmenu, NULL);
-			else
-				//display_tree_part();  //fixme: keep exp/coll
-				update_tree(current, NULL);
-		}
+		oldval = sym_get_tristate_value(sym);
+		if (!sym_tristate_within_range(sym, newval))
+			newval = yes;
+		sym_set_tristate_value(sym, newval);
+		config_changed = TRUE;
+		if (view_mode == FULL_VIEW)
+			update_tree(&rootmenu, NULL);
+		else if (view_mode == SPLIT_VIEW)
+			update_tree(current, NULL);
+		else if (view_mode == SINGLE_VIEW)
+			display_tree_part();	//fixme: keep exp/coll
 		break;
 	case S_INT:
 	case S_HEX:
 	case S_STRING:
+	default:
 		break;
 	}
 }
 
-static void renderer_toggled(GtkCellRendererToggle * cellrenderertoggle,
+static void toggle_sym_value(struct menu *menu)
+{
+	const tristate next_val[3] = { no, mod, yes };
+	tristate newval;
+
+	if (!menu->sym)
+		return;
+
+	newval = next_val[(sym_get_tristate_value(menu->sym) + 1) % 3];
+	if (!sym_tristate_within_range(menu->sym, newval))
+		newval = yes;
+	sym_set_tristate_value(menu->sym, newval);
+	if (view_mode == FULL_VIEW)
+		update_tree(&rootmenu, NULL);
+	else if (view_mode == SPLIT_VIEW)
+		update_tree(current, NULL);
+	else if (view_mode == SINGLE_VIEW)
+		display_tree_part();	//fixme: keep exp/coll
+}
+
+static void renderer_toggled(GtkCellRendererToggle * cell,
 			     gchar * path_string, gpointer user_data)
 {
-	GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
-	GtkTreeIter iter;
-	gint col;
+	GtkTreePath *path, *sel_path = NULL;
+	GtkTreeIter iter, sel_iter;
+	GtkTreeSelection *sel;
 	struct menu *menu;
-	const int next_col[3] = { COL_NO, COL_MOD, COL_YES };
 
+	path = gtk_tree_path_new_from_string(path_string);
 	if (!gtk_tree_model_get_iter(model2, &iter, path))
 		return;
 
-	gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
-	gtk_tree_model_get(model2, &iter, COL_BTNINC, &col, -1);
-	if (col)
-		col = COL_MOD;
-	else {
-		gtk_tree_model_get(model2, &iter, COL_BTNACT, &col, -1);
-		col = col ? COL_YES : COL_NO;
-	}
+	sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree2_w));
+	if (gtk_tree_selection_get_selected(sel, NULL, &sel_iter))
+		sel_path = gtk_tree_model_get_path(model2, &sel_iter);
+	if (!sel_path)
+		goto out1;
+	if (gtk_tree_path_compare(path, sel_path))
+		goto out2;
 
-	change_sym_value(menu, next_col[((col - COL_NO) + 1) % 3]);
+	gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
+	toggle_sym_value(menu);
 
+      out2:
+	gtk_tree_path_free(sel_path);
+      out1:
 	gtk_tree_path_free(path);
 }
 
@@ -992,7 +997,7 @@
 }
 
 
-//#define GTK_BUG_FIXED // GTK+ 2.1.4 mini
+//#define GTK_BUG_FIXED // uncomment it for GTK+ >= 2.1.4 (2.2)
 
 /* User click: update choice (full) or goes down (single) */
 gboolean
@@ -1023,17 +1028,30 @@
 	gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
 
 	col = column2index(column);
-	if ((col == COL_OPTION) && (event->type == GDK_2BUTTON_PRESS) &&
-	    (view_mode != FULL_VIEW) && menu->list) {
-		enum prop_type type;
-		type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
-		if ((type != P_MENU) && (type != P_ROOTMENU))
-			return FALSE;
-		current = menu;
-		display_tree_part();
-		gtk_widget_set_sensitive(back_btn, TRUE);
-	} else
-		change_sym_value(menu, col);
+	if (event->type == GDK_2BUTTON_PRESS) {
+		enum prop_type ptype;
+		ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+
+		if (((ptype == P_MENU) || (ptype == P_ROOTMENU)) &&
+		    (view_mode == SINGLE_VIEW) && (col == COL_OPTION)) {
+			// goes down into menu
+			current = menu;
+			display_tree_part();
+			gtk_widget_set_sensitive(back_btn, TRUE);
+		} else if ((col == COL_OPTION)) {
+			toggle_sym_value(menu);
+			gtk_tree_view_expand_row(view, path, TRUE);
+		}
+	} else {
+		if (col == COL_VALUE) {
+			toggle_sym_value(menu);
+			gtk_tree_view_expand_row(view, path, TRUE);
+		} else if (col == COL_NO || col == COL_MOD
+			   || col == COL_YES) {
+			change_sym_value(menu, col);
+			gtk_tree_view_expand_row(view, path, TRUE);
+		}
+	}
 
 	return FALSE;
 }
@@ -1051,17 +1069,17 @@
 	gint col;
 
 	gtk_tree_view_get_cursor(view, &path, &column);
-	if (path == NULL) {
-		//g_warning("key_press_event: path is NULL !\n");
+	if (path == NULL)
 		return FALSE;
-	}
 
 	if (event->keyval == GDK_space) {
 		if (gtk_tree_view_row_expanded(view, path))
 			gtk_tree_view_collapse_row(view, path);
 		else
 			gtk_tree_view_expand_row(view, path, FALSE);
-		return FALSE;
+		return TRUE;
+	}
+	if (event->keyval == GDK_KP_Enter) {
 	}
 	if (widget == tree1_w)
 		return FALSE;
@@ -1075,11 +1093,8 @@
 		col = COL_MOD;
 	else if (!strcasecmp(event->string, "y"))
 		col = COL_YES;
-	else if (!strcasecmp(event->string, "e"))
-		col = COL_VALUE;
 	else
-		col = 0;
-
+		col = -1;
 	change_sym_value(menu, col);
 
 	return FALSE;
@@ -1125,8 +1140,18 @@
 	gtk_tree_model_get_iter(model1, &iter, path);
 	gtk_tree_model_get(model1, &iter, COL_MENU, &menu, -1);
 
-	current = menu;
-	display_tree_part();
+	if (event->type == GDK_2BUTTON_PRESS) {
+		toggle_sym_value(menu);
+		current = menu;
+		display_tree_part();
+	} else {
+		current = menu;
+		display_tree_part();
+	}
+
+	gtk_widget_realize(tree2_w);
+	gtk_tree_view_set_cursor(view, path, NULL, FALSE);
+	gtk_widget_grab_focus(GTK_TREE_VIEW(tree2_w));
 
 	return FALSE;
 }
@@ -1138,15 +1163,18 @@
 /* Fill a row of strings */
 static gchar **fill_row(struct menu *menu)
 {
-	static gchar **row;
+	static gchar *row[COL_NUMBER] = { 0 };
 	struct symbol *sym = menu->sym;
 	const char *def;
 	int stype;
 	tristate val;
-	enum prop_type type;
+	enum prop_type ptype;
+	int i;
+
+	for (i = COL_OPTION; i <= COL_COLOR; i++)
+		g_free(row[i]);
+	bzero(row, sizeof(row));
 
-	//g_strfreev(row); //to fix...
-	row = (gchar **) g_malloc0(COL_NUMBER * sizeof(gchar *));
 	row[COL_OPTION] =
 	    g_strdup_printf("%s %s", menu_get_prompt(menu),
 			    sym ? (sym->
@@ -1158,14 +1186,13 @@
 	else
 		row[COL_COLOR] = g_strdup("Black");
 
-	type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
-	switch (type) {
+	ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+	switch (ptype) {
 	case P_MENU:
 	case P_ROOTMENU:
-		row[COL_PIXBUF] =
-		    (gchar *) (view_mode !=
-			       FULL_VIEW ? xpm_menu : xpm_void);
-		row[COL_PIXVIS] = GINT_TO_POINTER(TRUE);
+		row[COL_PIXBUF] = (gchar *) xpm_menu;
+		if (view_mode != FULL_VIEW)
+			row[COL_PIXVIS] = GINT_TO_POINTER(TRUE);
 		row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
 		break;
 	case P_COMMENT:
@@ -1252,7 +1279,7 @@
 
 
 /* Set the node content with a row of strings */
-static void set_node2(GtkTreeIter * node, struct menu *menu, gchar ** row)
+static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row)
 {
 	GdkColor color;
 	gboolean success;
@@ -1283,18 +1310,17 @@
 			   -1);
 
 	g_object_unref(pix);
-	g_strfreev(row);
 }
 
 
 /* Add a node to the tree */
-static void place_node2(struct menu *menu, char **row)
+static void place_node(struct menu *menu, char **row)
 {
 	GtkTreeIter *parent = parents[indent - 1];
 	GtkTreeIter *node = parents[indent];
 
 	gtk_tree_store_append(tree, node, parent);
-	set_node2(node, menu, row);
+	set_node(node, menu, row);
 }
 
 
@@ -1348,6 +1374,7 @@
 	struct symbol *sym;
 	struct property *prop;
 	struct menu *menu1, *menu2;
+	static GtkTreePath *path = NULL;
 
 	if (src == &rootmenu)
 		indent = 1;
@@ -1395,7 +1422,7 @@
 				gtk_tree_store_insert_before(tree2,
 							     child2,
 							     dst, sibling);
-				set_node2(child2, menu1, fill_row(menu1));
+				set_node(child2, menu1, fill_row(menu1));
 				if (menu2 == NULL)
 					valid = TRUE;
 			} else {	// remove node
@@ -1409,7 +1436,7 @@
 					goto reparse;	// next child
 			}
 		} else if (sym && (sym->flags & SYMBOL_CHANGED)) {
-			set_node2(child2, menu1, fill_row(menu1));
+			set_node(child2, menu1, fill_row(menu1));
 		}
 
 		indent++;
@@ -1451,7 +1478,7 @@
 			continue;
 
 		if (menu_is_visible(child) || show_all)
-			place_node2(child, fill_row(child));
+			place_node(child, fill_row(child));
 #ifdef DEBUG
 		printf("%*c%s: ", indent, ' ', menu_get_prompt(child));
 		dbg_print_ptype(ptype);
@@ -1490,8 +1517,13 @@
 /* Display the list in the left frame (split view) */
 static void display_list(void)
 {
+	if (tree2)
+		gtk_tree_store_clear(tree2);
+	if (tree1)
+		gtk_tree_store_clear(tree1);
+
 	tree = tree1;
-	display_tree(&rootmenu);
+	display_tree(current = &rootmenu);
 	gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w));
 	tree = tree2;
 }
diff -urN linux-2.5.66-bk10/sound/isa/als100.c linux-2.5.66-bk11/sound/isa/als100.c
--- linux-2.5.66-bk10/sound/isa/als100.c	2003-03-24 14:00:00.000000000 -0800
+++ linux-2.5.66-bk11/sound/isa/als100.c	2003-04-05 04:32:16.000000000 -0800
@@ -98,7 +98,7 @@
 	struct pnp_dev *devopl;
 };
 
-static struct pnp_card_id snd_als100_pnpids[] __devinitdata = {
+static struct pnp_card_device_id snd_als100_pnpids[] __devinitdata = {
 	/* ALS100 - PRO16PNP */
 	{ .id = "ALS0001", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" }, } },
 	/* ALS110 - MF1000 - Digimate 3D Sound */
@@ -118,10 +118,10 @@
 
 static int __devinit snd_card_als100_isapnp(int dev, struct snd_card_als100 *acard,
 					    struct pnp_card_link *card,
-					    const struct pnp_card_id *id)
+					    const struct pnp_card_device_id *id)
 {
 	struct pnp_dev *pdev;
-	struct pnp_resource_table * cfg = kmalloc(GFP_ATOMIC, sizeof(struct pnp_resource_table));
+	struct pnp_resource_table *cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
 	int err;
 	if (!cfg)
 		return -ENOMEM;
@@ -151,6 +151,7 @@
 	err = pnp_activate_dev(pdev);
 	if (err < 0) {
 		printk(KERN_ERR PFX "AUDIO pnp configure failure\n");
+		kfree(cfg);
 		return err;
 	}
 	port[dev] = pnp_port_start(pdev, 0);
@@ -209,7 +210,7 @@
 
 static int __init snd_card_als100_probe(int dev,
 					struct pnp_card_link *pcard,
-					const struct pnp_card_id *pid)
+					const struct pnp_card_device_id *pid)
 {
 	int error;
 	sb_t *chip;
@@ -287,7 +288,7 @@
 }
 
 static int __devinit snd_als100_pnp_detect(struct pnp_card_link *card,
-					   const struct pnp_card_id *id)
+					   const struct pnp_card_device_id *id)
 {
 	static int dev;
 	int res;
diff -urN linux-2.5.66-bk10/sound/isa/azt2320.c linux-2.5.66-bk11/sound/isa/azt2320.c
--- linux-2.5.66-bk10/sound/isa/azt2320.c	2003-03-24 14:01:43.000000000 -0800
+++ linux-2.5.66-bk11/sound/isa/azt2320.c	2003-04-05 04:32:16.000000000 -0800
@@ -36,11 +36,7 @@
 #include <linux/init.h>
 #include <linux/time.h>
 #include <linux/wait.h>
-#ifndef LINUX_ISAPNP_H
-#include <linux/isapnp.h>
-#define isapnp_card pci_bus
-#define isapnp_dev pci_dev
-#endif
+#include <linux/pnp.h>
 #include <sound/core.h>
 #define SNDRV_GET_ID
 #include <sound/initval.h>
@@ -109,134 +105,112 @@
 MODULE_PARM_SYNTAX(dma2, SNDRV_DMA_DESC);
 
 struct snd_card_azt2320 {
-#ifdef __ISAPNP__
-	struct isapnp_dev *dev;
-	struct isapnp_dev *devmpu;
-#endif	/* __ISAPNP__ */
+#ifdef CONFIG_PNP
+	int dev_no;
+	struct pnp_dev *dev;
+	struct pnp_dev *devmpu;
+#endif	/* CONFIG_PNP */
 };
 
-static snd_card_t *snd_azt2320_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
-
-#ifdef __ISAPNP__
-
-static struct isapnp_card *snd_azt2320_isapnp_cards[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PTR;
-static const struct isapnp_card_id *snd_azt2320_isapnp_id[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PTR;
-
-#define ISAPNP_AZT2320(_va, _vb, _vc, _device, _audio, _mpu401) \
-	{ \
-		ISAPNP_CARD_ID(_va, _vb, _vc, _device), \
-		.devs = { ISAPNP_DEVICE_ID(_va, _vb, _vc, _audio), \
-			  ISAPNP_DEVICE_ID(_va, _vb, _vc, _mpu401), } \
-	}
-
-static struct isapnp_card_id snd_azt2320_pnpids[] __devinitdata = {
+static struct pnp_card_device_id snd_azt2320_pnpids[] __devinitdata = {
 	/* PRO16V */
-	ISAPNP_AZT2320('A','Z','T',0x1008,0x1008,0x2001),
+	{ .id = "AZT1008", .devs = { { "AZT1008" }, { "AZT2001" }, } },
 	/* Aztech Sound Galaxy 16 */
-	ISAPNP_AZT2320('A','Z','T',0x2320,0x0001,0x0002),
+	{ .id = "AZT2320", .devs = { { "AZT0001" }, { "AZT0002" }, } },
 	/* Packard Bell Sound III 336 AM/SP */
-	ISAPNP_AZT2320('A','Z','T',0x3000,0x1003,0x2001),
+	{ .id = "AZT3000", .devs = { { "AZT1003" }, { "AZT2001" }, } },
 	/* AT3300 */
-	ISAPNP_AZT2320('A','Z','T',0x3002,0x1004,0x2001),
+	{ .id = "AZT3002", .devs = { { "AZT1004" }, { "AZT2001" }, } },
 	/* --- */
-	ISAPNP_AZT2320('A','Z','T',0x3005,0x1003,0x2001),
+	{ .id = "AZT3005", .devs = { { "AZT1003" }, { "AZT2001" }, } },
 	/* --- */
-	ISAPNP_AZT2320('A','Z','T',0x3011,0x1003,0x2001),
-	{ ISAPNP_CARD_END, }	/* end */
+	{ .id = "AZT3011", .devs = { { "AZT1003" }, { "AZT2001" }, } },
+	{ .id = "" }	/* end */
 };
 
-ISAPNP_CARD_TABLE(snd_azt2320_pnpids);
-
-#endif	/* __ISAPNP__ */
+MODULE_DEVICE_TABLE(pnp_card, snd_azt2320_pnpids);
 
 #define	DRIVER_NAME	"snd-card-azt2320"
 
-
-#ifdef __ISAPNP__
-static int __init snd_card_azt2320_isapnp(int dev, struct snd_card_azt2320 *acard)
+static int __init snd_card_azt2320_isapnp(int dev, struct snd_card_azt2320 *acard,
+							     struct pnp_card_link *card,
+							     const struct pnp_card_device_id *id)
 {
-	const struct isapnp_card_id *id = snd_azt2320_isapnp_id[dev];
-	struct isapnp_card *card = snd_azt2320_isapnp_cards[dev];
-	struct isapnp_dev *pdev;
-
-	acard->dev = isapnp_find_dev(card, id->devs[0].vendor, id->devs[0].function, NULL);
-	if (acard->dev->active) {
-		acard->dev = NULL;
-		return -EBUSY;
-	}
-	acard->devmpu = isapnp_find_dev(card, id->devs[1].vendor, id->devs[1].function, NULL);
-	if (acard->devmpu->active) {
-		acard->dev = acard->devmpu = NULL;
-		return -EBUSY;
+	struct pnp_dev *pdev;
+	struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
+	int err;
+
+	if (!cfg)
+		return -ENOMEM;
+
+	acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
+	if (acard->dev == NULL) {
+		kfree(cfg);
+		return -ENODEV;
 	}
 
+	acard->devmpu = pnp_request_card_device(card, id->devs[1].id, NULL);
+
 	pdev = acard->dev;
-	if (pdev->prepare(pdev) < 0)
-		return -EAGAIN;
+	pnp_init_resource_table(cfg);
 
+	/* override resources */
 	if (port[dev] != SNDRV_AUTO_PORT)
-		isapnp_resource_change(&pdev->resource[0], port[dev], 16);
+		pnp_resource_change(&cfg->port_resource[0], port[dev], 16);
 	if (fm_port[dev] != SNDRV_AUTO_PORT)
-		isapnp_resource_change(&pdev->resource[1], fm_port[dev], 4);
+		pnp_resource_change(&cfg->port_resource[1], fm_port[dev], 4);
 	if (wss_port[dev] != SNDRV_AUTO_PORT)
-		isapnp_resource_change(&pdev->resource[2], wss_port[dev],
-			4);
+		pnp_resource_change(&cfg->port_resource[2], wss_port[dev], 4);
 	if (dma1[dev] != SNDRV_AUTO_DMA)
-		isapnp_resource_change(&pdev->dma_resource[0], dma1[dev],
-			1);
+		pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1);
 	if (dma2[dev] != SNDRV_AUTO_DMA)
-		isapnp_resource_change(&pdev->dma_resource[1], dma2[dev],
-			1);
+		pnp_resource_change(&cfg->dma_resource[1], dma2[dev], 1);
 	if (irq[dev] != SNDRV_AUTO_IRQ)
-		isapnp_resource_change(&pdev->irq_resource[0], irq[dev], 1);
-
-	if (pdev->activate(pdev) < 0) {
-		printk(KERN_ERR PFX "AUDIO isapnp configure failure\n");
-		return -EBUSY;
-	}
-
-	port[dev] = pdev->resource[0].start;
-	fm_port[dev] = pdev->resource[1].start;
-	wss_port[dev] = pdev->resource[2].start;
-	dma1[dev] = pdev->dma_resource[0].start;
-	dma2[dev] = pdev->dma_resource[1].start;
-	irq[dev] = pdev->irq_resource[0].start;
+		pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
+	if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0)
+		printk(KERN_ERR PFX "AUDIO the requested resources are invalid, using auto config\n");
+
+	err = pnp_activate_dev(pdev);
+	if (err < 0) {
+		printk(KERN_ERR PFX "AUDIO pnp configure failure\n");
+		kfree(cfg);
+		return err;
+	}
+	port[dev] = pnp_port_start(pdev, 0);
+	fm_port[dev] = pnp_port_start(pdev, 1);
+	wss_port[dev] = pnp_port_start(pdev, 2);
+	dma1[dev] = pnp_dma(pdev, 0);
+	dma2[dev] = pnp_dma(pdev, 1);
+	irq[dev] = pnp_irq(pdev, 0);
 
 	pdev = acard->devmpu;
-	if (pdev == NULL || pdev->prepare(pdev) < 0) {
-		mpu_port[dev] = -1;
-		return 0;
-	}
-
-	if (mpu_port[dev] != SNDRV_AUTO_PORT)
-		isapnp_resource_change(&pdev->resource[0], mpu_port[dev],
-			2);
-	if (mpu_irq[dev] != SNDRV_AUTO_IRQ)
-		isapnp_resource_change(&pdev->irq_resource[0], mpu_irq[dev],
-			1);
-
-	if (pdev->activate(pdev) < 0) {
-		/* not fatal error */
-		printk(KERN_ERR PFX "MPU-401 isapnp configure failure\n");
-		mpu_port[dev] = -1;
-		acard->devmpu = NULL;
+	if (pdev != NULL) {
+		pnp_init_resource_table(cfg);
+		if (mpu_port[dev] != SNDRV_AUTO_PORT)
+			pnp_resource_change(&cfg->port_resource[0], mpu_port[dev], 2);
+		if (mpu_irq[dev] != SNDRV_AUTO_IRQ)
+			pnp_resource_change(&cfg->irq_resource[0], mpu_irq[dev], 1);
+		if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0)
+			printk(KERN_ERR PFX "MPU401 the requested resources are invalid, using auto config\n");
+		err = pnp_activate_dev(pdev);
+		if (err < 0)
+			goto __mpu_error;
+		mpu_port[dev] = pnp_port_start(pdev, 0);
+		mpu_irq[dev] = pnp_irq(pdev, 0);
 	} else {
-		mpu_port[dev] = pdev->resource[0].start;
-		mpu_irq[dev] = pdev->irq_resource[0].start;
+	     __mpu_error:
+	     	if (pdev) {
+		     	pnp_release_card_device(pdev);
+	     		printk(KERN_ERR PFX "MPU401 pnp configure failure, skipping\n");
+	     	}
+	     	acard->devmpu = NULL;
+	     	mpu_port[dev] = -1;
 	}
 
+	kfree (cfg);
 	return 0;
 }
 
-static void snd_card_azt2320_deactivate(struct snd_card_azt2320 *acard)
-{
-	if (acard->dev)
-		acard->dev->deactivate(acard->dev);
-	if (acard->devmpu)
-		acard->devmpu->deactivate(acard->devmpu);
-}
-#endif	/* __ISAPNP__ */
-
 /* same of snd_sbdsp_command by Jaroslav Kysela */
 static int __init snd_card_azt2320_command(unsigned long port, unsigned char val)
 {
@@ -265,18 +239,9 @@
 	return 0;
 }
 
-static void snd_card_azt2320_free(snd_card_t *card)
-{
-	struct snd_card_azt2320 *acard = (struct snd_card_azt2320 *)card->private_data;
-
-	if (acard) {
-#ifdef __ISAPNP__
-		snd_card_azt2320_deactivate(acard);
-#endif	/* __ISAPNP__ */
-	}
-}
-
-static int __init snd_card_azt2320_probe(int dev)
+static int __init snd_card_azt2320_probe(int dev,
+							   struct pnp_card_link *pcard,
+							   const struct pnp_card_device_id *pid)
 {
 	int error;
 	snd_card_t *card;
@@ -288,14 +253,11 @@
 				 sizeof(struct snd_card_azt2320))) == NULL)
 		return -ENOMEM;
 	acard = (struct snd_card_azt2320 *)card->private_data;
-	card->private_free = snd_card_azt2320_free;
 
-#ifdef __ISAPNP__
-	if ((error = snd_card_azt2320_isapnp(dev, acard))) {
+	if ((error = snd_card_azt2320_isapnp(dev, acard, pcard, pid))) {
 		snd_card_free(card);
 		return error;
 	}
-#endif	/* __ISAPNP__ */
 
 	if ((error = snd_card_azt2320_enable_wss(port[dev]))) {
 		snd_card_free(card);
@@ -360,13 +322,12 @@
 		snd_card_free(card);
 		return error;
 	}
-	snd_azt2320_cards[dev] = card;
+	pnp_set_card_drvdata(pcard, card);
 	return 0;
 }
 
-#ifdef __ISAPNP__
-static int __init snd_azt2320_isapnp_detect(struct isapnp_card *card,
-                                            const struct isapnp_card_id *id)
+static int __init snd_azt2320_pnp_detect(struct pnp_card_link *card,
+                                            const struct pnp_card_device_id *id)
 {
 	static int dev;
 	int res;
@@ -374,9 +335,7 @@
 	for ( ; dev < SNDRV_CARDS; dev++) {
 		if (!enable[dev])
 			continue;
-		snd_azt2320_isapnp_cards[dev] = card;
-		snd_azt2320_isapnp_id[dev] = id;
-                res = snd_card_azt2320_probe(dev);
+		res = snd_card_azt2320_probe(dev,card,id);
 		if (res < 0)
 			return res;
 		dev++;
@@ -384,7 +343,22 @@
 	}
         return -ENODEV;
 }
-#endif
+
+static void __devexit snd_azt2320_pnp_remove(struct pnp_card_link * pcard)
+{
+	snd_card_t *card = (snd_card_t *) pnp_get_card_drvdata(pcard);
+
+	snd_card_disconnect(card);
+	snd_card_free_in_thread(card);
+}
+
+static struct pnp_card_driver azt2320_pnpc_driver = {
+	.flags          = PNP_DRIVER_RES_DISABLE,
+	.name           = "azt2320",
+	.id_table       = snd_azt2320_pnpids,
+	.probe          = snd_azt2320_pnp_detect,
+	.remove         = __devexit_p(snd_azt2320_pnp_remove),
+};
 
 static int __init alsa_card_azt2320_init(void)
 {
@@ -395,6 +369,7 @@
 #else
 	printk(KERN_ERR PFX "you have to enable ISA PnP support.\n");
 #endif
+	cards += pnp_register_card_driver(&azt2320_pnpc_driver);
 #ifdef MODULE
 	if (!cards)
 		printk(KERN_ERR "no AZT2320 based soundcards found\n");
@@ -404,10 +379,7 @@
 
 static void __exit alsa_card_azt2320_exit(void)
 {
-	int dev;
-
-	for (dev = 0; dev < SNDRV_CARDS; dev++)
-		snd_card_free(snd_azt2320_cards[dev]);
+	pnp_unregister_card_driver(&azt2320_pnpc_driver);
 }
 
 module_init(alsa_card_azt2320_init)
diff -urN linux-2.5.66-bk10/sound/isa/dt019x.c linux-2.5.66-bk11/sound/isa/dt019x.c
--- linux-2.5.66-bk10/sound/isa/dt019x.c	2003-03-24 14:00:19.000000000 -0800
+++ linux-2.5.66-bk11/sound/isa/dt019x.c	2003-04-05 04:32:16.000000000 -0800
@@ -25,11 +25,7 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/wait.h>
-#ifndef LINUX_ISAPNP_H
-#include <linux/isapnp.h>
-#define isapnp_card pci_bus
-#define isapnp_dev pci_dev
-#endif
+#include <linux/pnp.h>
 #include <sound/core.h>
 #define SNDRV_GET_ID
 #include <sound/initval.h>
@@ -87,159 +83,124 @@
 MODULE_PARM_SYNTAX(dma8, SNDRV_DMA8_DESC);
 
 struct snd_card_dt019x {
-#ifdef __ISAPNP__
-	struct isapnp_dev *dev;
-	struct isapnp_dev *devmpu;
-	struct isapnp_dev *devopl;
-#endif	/* __ISAPNP__ */
+	struct pnp_dev *dev;
+	struct pnp_dev *devmpu;
+	struct pnp_dev *devopl;
 };
 
-static snd_card_t *snd_dt019x_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
-
-#ifdef __ISAPNP__
-static struct isapnp_card *snd_dt019x_isapnp_cards[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PTR;
-static const struct isapnp_card_id *snd_dt019x_isapnp_id[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PTR;
-
-static struct isapnp_card_id snd_dt019x_pnpids[] __devinitdata = {
+static struct pnp_card_device_id snd_dt019x_pnpids[] __devinitdata = {
 	/* DT197A30 */
-	{
-		ISAPNP_CARD_ID('R','W','B',0x1688),
-		.devs = { ISAPNP_DEVICE_ID('@','@','@',0x0001),
-			ISAPNP_DEVICE_ID('@','X','@',0x0001),
-			ISAPNP_DEVICE_ID('@','H','@',0x0001) }
-	},
+	{ .id = "RWB1688", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" }, } },
 	/* DT0196 / ALS-007 */
-	{
-		ISAPNP_CARD_ID('A','L','S',0x0007),
-		.devs = { ISAPNP_DEVICE_ID('@','@','@',0x0001),
-			ISAPNP_DEVICE_ID('@','X','@',0x0001),
-			ISAPNP_DEVICE_ID('@','H','@',0x0001) }
-	},
-	{ ISAPNP_CARD_END, }
+	{ .id = "ALS0007", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" }, } },
+	{ .id = "",  }
 };
 
-ISAPNP_CARD_TABLE(snd_dt019x_pnpids);
+MODULE_DEVICE_TABLE(pnp_card, snd_dt019x_pnpids);
 
-#endif	/* __ISAPNP__ */
 
 #define DRIVER_NAME	"snd-card-dt019x"
 
 
-#ifdef __ISAPNP__
-static int __init snd_card_dt019x_isapnp(int dev, struct snd_card_dt019x *acard)
+static int __init snd_card_dt019x_isapnp(int dev, struct snd_card_dt019x *acard,
+							   struct pnp_card_link *card,
+							   const struct pnp_card_device_id *pid)
 {
-	const struct isapnp_card_id *id = snd_dt019x_isapnp_id[dev];
-	struct isapnp_card *card = snd_dt019x_isapnp_cards[dev];
-	struct isapnp_dev *pdev;
-
-	acard->dev = isapnp_find_dev(card, id->devs[0].vendor, id->devs[0].function, NULL);
-	if (acard->dev->active) {
-		acard->dev = NULL;
-		return -EBUSY;
-	}
-	acard->devmpu = isapnp_find_dev(card, id->devs[1].vendor, id->devs[1].function, NULL);
-	if (acard->devmpu->active) {
-		acard->dev = acard->devmpu = NULL;
-		return -EBUSY;
-	}
-	acard->devopl = isapnp_find_dev(card, id->devs[2].vendor, id->devs[2].function, NULL);
-	if (acard->devopl->active) {
-		acard->dev = acard->devmpu = acard->devopl = NULL;
-		return -EBUSY;
+	struct pnp_dev *pdev;
+	struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
+	int err;
+
+	if (!cfg)
+		return -ENOMEM;
+
+	acard->dev = pnp_request_card_device(card, pid->devs[0].id, NULL);
+	if (acard->dev == NULL) {
+		kfree (cfg);
+		return -ENODEV;
 	}
+	acard->devmpu = pnp_request_card_device(card, pid->devs[1].id, NULL);
+	acard->devopl = pnp_request_card_device(card, pid->devs[2].id, NULL);
 
 	pdev = acard->dev;
-	if (!pdev || pdev->prepare(pdev)<0)
-		return -EAGAIN;
+	pnp_init_resource_table(cfg);
 
 	if (port[dev] != SNDRV_AUTO_PORT)
-		isapnp_resource_change(&pdev->resource[0], port[dev], 16);
+		pnp_resource_change(&cfg->port_resource[0], port[dev], 16);
 	if (dma8[dev] != SNDRV_AUTO_DMA)
-		isapnp_resource_change(&pdev->dma_resource[0], dma8[dev],
+		pnp_resource_change(&cfg->dma_resource[0], dma8[dev],
 			1);
 	if (irq[dev] != SNDRV_AUTO_IRQ)
-		isapnp_resource_change(&pdev->irq_resource[0], irq[dev], 1);
+		pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
 
-	if (pdev->activate(pdev)<0) {
-		printk(KERN_ERR PFX "DT-019X AUDIO isapnp configure failure\n");
-		return -EBUSY;
-	}
-	port[dev] = pdev->resource[0].start;
-	dma8[dev] = pdev->dma_resource[0].start;
-	irq[dev] = pdev->irq_resource[0].start;
+	if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0)
+		printk(KERN_ERR PFX "DT-019X AUDIO the requested resources are invalid, using auto config\n");
+	err = pnp_activate_dev(pdev);
+	if (err < 0) {
+		printk(KERN_ERR PFX "DT-019X AUDIO pnp configure failure\n");
+		kfree(cfg);
+		return err;
+	}
+
+	port[dev] = pnp_port_start(pdev, 0);
+	dma8[dev] = pnp_dma(pdev, 0);
+	irq[dev] = pnp_irq(pdev, 0);
 	snd_printdd("dt019x: found audio interface: port=0x%lx, irq=0x%lx, dma=0x%lx\n",
 			port[dev],irq[dev],dma8[dev]);
 
 	pdev = acard->devmpu;
-	if (!pdev || pdev->prepare(pdev)<0) 
-		return 0;
-
-	if (mpu_port[dev] != SNDRV_AUTO_PORT)
-		isapnp_resource_change(&pdev->resource[0], mpu_port[dev],
-			2);
-	if (mpu_irq[dev] != SNDRV_AUTO_IRQ)
-		isapnp_resource_change(&pdev->irq_resource[0], mpu_irq[dev],
-			1);
 
-	if (pdev->activate(pdev)<0) {
-		printk(KERN_ERR PFX "DT-019X MPU-401 isapnp configure failure\n");
-		mpu_port[dev] = -1;
-		acard->devmpu = NULL;
-	} else {
-		mpu_port[dev] = pdev->resource[0].start;
-		mpu_irq[dev] = pdev->irq_resource[0].start;
+	if (pdev != NULL) {
+		pnp_init_resource_table(cfg);
+		if (mpu_port[dev] != SNDRV_AUTO_PORT)
+			pnp_resource_change(&cfg->port_resource[0], mpu_port[dev], 2);
+		if (mpu_irq[dev] != SNDRV_AUTO_IRQ)
+			pnp_resource_change(&cfg->irq_resource[0], mpu_irq[dev], 1);
+			if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0)
+			printk(KERN_ERR PFX "DT-019X MPU401 the requested resources are invalid, using auto config\n");
+			err = pnp_activate_dev(pdev);
+			if (err < 0)
+				goto __mpu_error;
+		mpu_port[dev] = pnp_port_start(pdev, 0);
+		mpu_irq[dev] = pnp_irq(pdev, 0);
 		snd_printdd("dt019x: found MPU-401: port=0x%lx, irq=0x%lx\n",
 			 	mpu_port[dev],mpu_irq[dev]);
+	} else {
+		__mpu_error:
+		if (pdev) {
+			pnp_release_card_device(pdev);
+			printk(KERN_ERR PFX "DT-019X MPU401 pnp configure failure, skipping\n");
+		}
+		acard->devmpu = NULL;
+		mpu_port[dev] = -1;
 	}
 
 	pdev = acard->devopl;
-	if (!pdev || pdev->prepare(pdev)<0)
-		return 0;
-
-	if (fm_port[dev] != SNDRV_AUTO_PORT)
-		isapnp_resource_change(&pdev->resource[0], fm_port[dev], 4);
-
-	if (pdev->activate(pdev)<0) {
-		printk(KERN_ERR PFX "DT-019X OPL3 isapnp configure failure\n");
-		fm_port[dev] = -1;
-		acard->devopl = NULL;
-	} else {
-		fm_port[dev] = pdev->resource[0].start;
+	if (pdev != NULL) {
+		pnp_init_resource_table(cfg);
+		if (fm_port[dev] != SNDRV_AUTO_PORT)
+			pnp_resource_change(&cfg->port_resource[0], fm_port[dev], 4);
+		if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0)
+			printk(KERN_ERR PFX "DT-019X OPL3 the requested resources are invalid, using auto config\n");
+		err = pnp_activate_dev(pdev);
+		if (err < 0)
+			goto __fm_error;
+		fm_port[dev] = pnp_port_start(pdev, 0);
 		snd_printdd("dt019x: found OPL3 synth: port=0x%lx\n",fm_port[dev]);
-	}
-
-	return 0;
-}
-
-static void snd_card_dt019x_deactivate(struct snd_card_dt019x *acard)
-{
-	if (acard->dev) {
-		acard->dev->deactivate(acard->dev);
-		acard->dev = NULL;
-	}
-	if (acard->devmpu) {
-		acard->devmpu->deactivate(acard->devmpu);
-		acard->devmpu = NULL;
-	}
-	if (acard->devopl) {
-		acard->devopl->deactivate(acard->devopl);
+	} else {
+		__fm_error:
+		if (pdev) {
+			pnp_release_card_device(pdev);
+			printk(KERN_ERR PFX "DT-019X OPL3 pnp configure failure, skipping\n");
+		}
 		acard->devopl = NULL;
+		fm_port[dev] = -1;
 	}
-}
-#endif	/* __ISAPNP__ */
 
-static void snd_card_dt019x_free(snd_card_t *card)
-{
-	struct snd_card_dt019x *acard = (struct snd_card_dt019x *)card->private_data;
-
-	if (acard != NULL) {
-#ifdef __ISAPNP__
-		snd_card_dt019x_deactivate(acard);
-#endif	/* __ISAPNP__ */
-	}
+	kfree(cfg);
+	return 0;
 }
 
-static int __init snd_card_dt019x_probe(int dev)
+static int __init snd_card_dt019x_probe(int dev, struct pnp_card_link *pcard, const struct pnp_card_device_id *pid)
 {
 	int error;
 	sb_t *chip;
@@ -251,18 +212,11 @@
 				 sizeof(struct snd_card_dt019x))) == NULL)
 		return -ENOMEM;
 	acard = (struct snd_card_dt019x *)card->private_data;
-	card->private_free = snd_card_dt019x_free;
 
-#ifdef __ISAPNP__
-	if ((error = snd_card_dt019x_isapnp(dev, acard))) {
+	if ((error = snd_card_dt019x_isapnp(dev, acard, pcard, pid))) {
 		snd_card_free(card);
 		return error;
 	}
-#else
-	printk(KERN_ERR PFX "you have to enable PnP support ...\n");
-	snd_card_free(card);
-	return -ENOSYS;
-#endif	/* __ISAPNP__ */
 
 	if ((error = snd_sbdsp_create(card, port[dev],
 				      irq[dev],
@@ -324,13 +278,12 @@
 		snd_card_free(card);
 		return error;
 	}
-	snd_dt019x_cards[dev] = card;
+	pnp_set_card_drvdata(pcard, card);
 	return 0;
 }
 
-#ifdef __ISAPNP__
-static int __init snd_dt019x_isapnp_detect(struct isapnp_card *card,
-					    const struct isapnp_card_id *id)
+static int __init snd_dt019x_pnp_probe(struct pnp_card_link *card,
+					    const struct pnp_card_device_id *pid)
 {
 	static int dev;
 	int res;
@@ -338,9 +291,7 @@
 	for ( ; dev < SNDRV_CARDS; dev++) {
 		if (!enable[dev])
 			continue;
-		snd_dt019x_isapnp_cards[dev] = card;
-		snd_dt019x_isapnp_id[dev] = id;
-		res = snd_card_dt019x_probe(dev);
+		res = snd_card_dt019x_probe(dev, card, pid);
 		if (res < 0)
 			return res;
 		dev++;
@@ -348,17 +299,28 @@
         }
         return -ENODEV;
 }
-#endif /* __ISAPNP__ */
+
+static void __devexit snd_dt019x_pnp_remove(struct pnp_card_link * pcard)
+{
+	snd_card_t *card = (snd_card_t *) pnp_get_card_drvdata(pcard);
+	snd_card_disconnect(card);
+	snd_card_free_in_thread(card);
+}
+
+static struct pnp_card_driver dt019x_pnpc_driver = {
+	.flags          = PNP_DRIVER_RES_DISABLE,
+	.name           = "dt019x",
+	.id_table       = snd_dt019x_pnpids,
+	.probe          = snd_dt019x_pnp_probe,
+	.remove         = __devexit_p(snd_dt019x_pnp_remove),
+};
 
 static int __init alsa_card_dt019x_init(void)
 {
 	int cards = 0;
 
-#ifdef __ISAPNP__
-	cards += isapnp_probe_cards(snd_dt019x_pnpids, snd_dt019x_isapnp_detect);
-#else
-	printk(KERN_ERR PFX "you have to enable ISA PnP support.\n");
-#endif
+	cards += pnp_register_card_driver(&dt019x_pnpc_driver);
+
 #ifdef MODULE
 	if (!cards)
 		printk(KERN_ERR "no DT-019X / ALS-007 based soundcards found\n");
@@ -368,10 +330,7 @@
 
 static void __exit alsa_card_dt019x_exit(void)
 {
-	int dev;
-
-	for (dev = 0; dev < SNDRV_CARDS; dev++)
-		snd_card_free(snd_dt019x_cards[dev]);
+	pnp_unregister_card_driver(&dt019x_pnpc_driver);
 }
 
 module_init(alsa_card_dt019x_init)
diff -urN linux-2.5.66-bk10/sound/isa/sb/es968.c linux-2.5.66-bk11/sound/isa/sb/es968.c
--- linux-2.5.66-bk10/sound/isa/sb/es968.c	2003-03-24 14:00:37.000000000 -0800
+++ linux-2.5.66-bk11/sound/isa/sb/es968.c	2003-04-05 04:32:16.000000000 -0800
@@ -69,7 +69,7 @@
 	struct pnp_dev *dev;
 };
 
-static struct pnp_card_id snd_es968_pnpids[] __devinitdata = {
+static struct pnp_card_device_id snd_es968_pnpids[] __devinitdata = {
 	{ .id = "ESS0968", .devs = { { "@@@0968" }, } },
 	{ .id = "", } /* end */
 };
@@ -92,10 +92,10 @@
 
 static int __devinit snd_card_es968_isapnp(int dev, struct snd_card_es968 *acard,
 					struct pnp_card_link *card,
-					const struct pnp_card_id *id)
+					const struct pnp_card_device_id *id)
 {
 	struct pnp_dev *pdev;
-	struct pnp_resource_table * cfg = kmalloc(GFP_ATOMIC, sizeof(struct pnp_resource_table));
+	struct pnp_resource_table *cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
 	int err;
 	if (!cfg)
 		return -ENOMEM;
@@ -133,7 +133,7 @@
 
 static int __init snd_card_es968_probe(int dev,
 					struct pnp_card_link *pcard,
-					const struct pnp_card_id *pid)
+					const struct pnp_card_device_id *pid)
 {
 	int error;
 	sb_t *chip;
@@ -188,7 +188,7 @@
 }
 
 static int __devinit snd_es968_pnp_detect(struct pnp_card_link *card,
-                                          const struct pnp_card_id *id)
+                                          const struct pnp_card_device_id *id)
 {
 	static int dev;
 	int res;
diff -urN linux-2.5.66-bk10/sound/isa/sb/sb16.c linux-2.5.66-bk11/sound/isa/sb/sb16.c
--- linux-2.5.66-bk10/sound/isa/sb/sb16.c	2003-03-24 14:01:16.000000000 -0800
+++ linux-2.5.66-bk11/sound/isa/sb/sb16.c	2003-04-05 04:32:16.000000000 -0800
@@ -23,11 +23,7 @@
 #include <asm/dma.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#ifndef LINUX_ISAPNP_H
-#include <linux/isapnp.h>
-#define isapnp_card pci_bus
-#define isapnp_dev pci_dev
-#endif
+#include <linux/pnp.h>
 #include <sound/core.h>
 #include <sound/sb.h>
 #include <sound/sb16_csp.h>
@@ -77,7 +73,7 @@
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
-#ifdef __ISAPNP__
+#ifdef CONFIG_PNP
 static int isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
 #endif
 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* 0x220,0x240,0x260,0x280 */
@@ -106,10 +102,10 @@
 MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
 MODULE_PARM_DESC(enable, "Enable SoundBlaster 16 soundcard.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-#ifdef __ISAPNP__
-MODULE_PARM(isapnp, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
-MODULE_PARM_DESC(isapnp, "ISA PnP detection for specified soundcard.");
-MODULE_PARM_SYNTAX(isapnp, SNDRV_ISAPNP_DESC);
+#ifdef CONFIG_PNP
+MODULE_PARM(pnp, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(pnp, "PnP detection for specified soundcard.");
+MODULE_PARM_SYNTAX(pnp, SNDRV_ISAPNP_DESC);
 #endif
 MODULE_PARM(port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
 MODULE_PARM_DESC(port, "Port # for SB16 driver.");
@@ -148,231 +144,211 @@
 MODULE_PARM_SYNTAX(seq_ports, SNDRV_ENABLED ",allows:{{0,8}},skill:advanced");
 #endif
 
-struct snd_sb16 {
+struct snd_card_sb16 {
 	struct resource *fm_res;	/* used to block FM i/o region for legacy cards */
-#ifdef __ISAPNP__
-	struct isapnp_dev *dev;
+#ifdef CONFIG_PNP
+	int dev_no;
+	struct pnp_dev *dev;
 #ifdef SNDRV_SBAWE_EMU8000
-	struct isapnp_dev *devwt;
+	struct pnp_dev *devwt;
 #endif
 #endif
 };
 
-static snd_card_t *snd_sb16_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
-
-#ifdef __ISAPNP__
-
-static struct isapnp_card *snd_sb16_isapnp_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
-static const struct isapnp_card_id *snd_sb16_isapnp_id[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
-
-#define ISAPNP_SB16(_va, _vb, _vc, _device, _audio) \
-	{ \
-		ISAPNP_CARD_ID(_va, _vb, _vc, _device), \
-		.devs = { ISAPNP_DEVICE_ID(_va, _vb, _vc, _audio), } \
-	}
-#define ISAPNP_SBAWE(_va, _vb, _vc, _device, _audio, _awe) \
-	{ \
-		ISAPNP_CARD_ID(_va, _vb, _vc, _device), \
-		.devs = { ISAPNP_DEVICE_ID(_va, _vb, _vc, _audio), \
-			 ISAPNP_DEVICE_ID(_va, _vb, _vc, _awe), } \
-	}
+static snd_card_t *snd_sb16_legacy[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
 
-static struct isapnp_card_id snd_sb16_pnpids[] __devinitdata = {
+static struct pnp_card_device_id snd_sb16_pnpids[] __devinitdata = {
 #ifndef SNDRV_SBAWE
 	/* Sound Blaster 16 PnP */
-	ISAPNP_SB16('C','T','L',0x0024,0x0031),
+	{ .id = "CTL0024", .devs = { { "CTL0031" } } },
 	/* Sound Blaster 16 PnP */
-	ISAPNP_SB16('C','T','L',0x0025,0x0031),
+	{ .id = "CTL0025", .devs = { { "CTL0031" } } },
 	/* Sound Blaster 16 PnP */
-	ISAPNP_SB16('C','T','L',0x0026,0x0031),
+	{ .id = "CTL0026", .devs = { { "CTL0031" } } },
 	/* Sound Blaster 16 PnP */
-	ISAPNP_SB16('C','T','L',0x0027,0x0031),
+	{ .id = "CTL0027", .devs = { { "CTL0031" } } },
 	/* Sound Blaster 16 PnP */
-	ISAPNP_SB16('C','T','L',0x0028,0x0031),
+	{ .id = "CTL0028", .devs = { { "CTL0031" } } },
 	/* Sound Blaster 16 PnP */
-	ISAPNP_SB16('C','T','L',0x0029,0x0031),
+	{ .id = "CTL0029", .devs = { { "CTL0031" } } },
 	/* Sound Blaster 16 PnP */
-	ISAPNP_SB16('C','T','L',0x002a,0x0031),
+	{ .id = "CTL002a", .devs = { { "CTL0031" } } },
 	/* Sound Blaster 16 PnP */
 	/* Note: This card has also a CTL0051:StereoEnhance device!!! */
-	ISAPNP_SB16('C','T','L',0x002b,0x0031),
+	{ .id = "CTL002b", .devs = { { "CTL0031" } } },
 	/* Sound Blaster 16 PnP */
-	ISAPNP_SB16('C','T','L',0x002c,0x0031),	
+	{ .id = "CTL002c", .devs = { { "CTL0031" } } },
 	/* Sound Blaster Vibra16S */
-	ISAPNP_SB16('C','T','L',0x0051,0x0001),
+	{ .id = "CTL0051", .devs = { { "CTL0001" } } },
 	/* Sound Blaster Vibra16C */
-	ISAPNP_SB16('C','T','L',0x0070,0x0001),
+	{ .id = "CTL0070", .devs = { { "CTL0001" } } },
 	/* Sound Blaster Vibra16CL - added by ctm@ardi.com */
-	ISAPNP_SB16('C','T','L',0x0080,0x0041),
+	{ .id = "CTL0080", .devs = { { "CTL0041" } } },
 	/* Sound Blaster 16 'value' PnP. It says model ct4130 on the pcb, */
 	/* but ct4131 on a sticker on the board.. */
-	ISAPNP_SB16('C','T','L',0x0086,0x0041),
+	{ .id = "CTL0086", .devs = { { "CTL0041" } } },
 	/* Sound Blaster Vibra16X */
-	ISAPNP_SB16('C','T','L',0x00f0,0x0043),
+	{ .id = "CTL00f0", .devs = { { "CTL0043" } } },
 #else  /* SNDRV_SBAWE defined */
 	/* Sound Blaster AWE 32 PnP */
-	ISAPNP_SBAWE('C','T','L',0x0035,0x0031,0x0021),
+	{ .id = "CTL0035", .devs = { { "CTL0031" }, { "CTL0021" } } },
 	/* Sound Blaster AWE 32 PnP */
-	ISAPNP_SBAWE('C','T','L',0x0039,0x0031,0x0021),
+	{ .id = "CTL0039", .devs = { { "CTL0031" }, { "CTL0021" } } },
 	/* Sound Blaster AWE 32 PnP */
-	ISAPNP_SBAWE('C','T','L',0x0042,0x0031,0x0021),
+	{ .id = "CTL0042", .devs = { { "CTL0031" }, { "CTL0021" } } },
 	/* Sound Blaster AWE 32 PnP */
-	ISAPNP_SBAWE('C','T','L',0x0043,0x0031,0x0021),
+	{ .id = "CTL0043", .devs = { { "CTL0031" }, { "CTL0021" } } },
 	/* Sound Blaster AWE 32 PnP */
 	/* Note: This card has also a CTL0051:StereoEnhance device!!! */
-	ISAPNP_SBAWE('C','T','L',0x0044,0x0031,0x0021),
+	{ .id = "CTL0044", .devs = { { "CTL0031" }, { "CTL0021" } } },
 	/* Sound Blaster AWE 32 PnP */
 	/* Note: This card has also a CTL0051:StereoEnhance device!!! */
-	ISAPNP_SBAWE('C','T','L',0x0045,0x0031,0x0021),
+	{ .id = "CTL0045", .devs = { { "CTL0031" }, { "CTL0021" } } },
 	/* Sound Blaster AWE 32 PnP */
-	ISAPNP_SBAWE('C','T','L',0x0046,0x0031,0x0021),
+	{ .id = "CTL0046", .devs = { { "CTL0031" }, { "CTL0021" } } },
 	/* Sound Blaster AWE 32 PnP */
-	ISAPNP_SBAWE('C','T','L',0x0047,0x0031,0x0021),
+	{ .id = "CTL0047", .devs = { { "CTL0031" }, { "CTL0021" } } },
 	/* Sound Blaster AWE 32 PnP */
-	ISAPNP_SBAWE('C','T','L',0x0048,0x0031,0x0021),
+	{ .id = "CTL0048", .devs = { { "CTL0031" }, { "CTL0021" } } },
 	/* Sound Blaster AWE 32 PnP */
-	ISAPNP_SBAWE('C','T','L',0x0054,0x0031,0x0021),
+	{ .id = "CTL0054", .devs = { { "CTL0031" }, { "CTL0021" } } },
 	/* Sound Blaster AWE 32 PnP */
-	ISAPNP_SBAWE('C','T','L',0x009a,0x0041,0x0021),
+	{ .id = "CTL009a", .devs = { { "CTL0041" }, { "CTL0021" } } },
 	/* Sound Blaster AWE 32 PnP */
-	ISAPNP_SBAWE('C','T','L',0x009c,0x0041,0x0021),
+	{ .id = "CTL009c", .devs = { { "CTL0041" }, { "CTL0021" } } },
 	/* Sound Blaster 32 PnP */
-	ISAPNP_SBAWE('C','T','L',0x009f,0x0041,0x0021),
+	{ .id = "CTL009f", .devs = { { "CTL0041" }, { "CTL0021" } } },
 	/* Sound Blaster AWE 64 PnP */
-	ISAPNP_SBAWE('C','T','L',0x009d,0x0042,0x0022),
+	{ .id = "CTL009d", .devs = { { "CTL0042" }, { "CTL0022" } } },
 	/* Sound Blaster AWE 64 PnP Gold */
-	ISAPNP_SBAWE('C','T','L',0x009e,0x0044,0x0023),
+	{ .id = "CTL009e", .devs = { { "CTL0044" }, { "CTL0023" } } },
 	/* Sound Blaster AWE 64 PnP Gold */
-	ISAPNP_SBAWE('C','T','L',0x00b2,0x0044,0x0023),
+	{ .id = "CTL00b2", .devs = { { "CTL0044" }, { "CTL0023" } } },
 	/* Sound Blaster AWE 64 PnP */
-	ISAPNP_SBAWE('C','T','L',0x00c1,0x0042,0x0022),
+	{ .id = "CTL00c1", .devs = { { "CTL0042" }, { "CTL0022" } } },
 	/* Sound Blaster AWE 64 PnP */
-	ISAPNP_SBAWE('C','T','L',0x00c3,0x0045,0x0022),
+	{ .id = "CTL00c3", .devs = { { "CTL0045" }, { "CTL0022" } } },
 	/* Sound Blaster AWE 64 PnP */
-	ISAPNP_SBAWE('C','T','L',0x00c5,0x0045,0x0022),
+	{ .id = "CTL00c5", .devs = { { "CTL0045" }, { "CTL0022" } } },
 	/* Sound Blaster AWE 64 PnP */
-	ISAPNP_SBAWE('C','T','L',0x00c7,0x0045,0x0022),
+	{ .id = "CTL00c7", .devs = { { "CTL0045" }, { "CTL0022" } } },
 	/* Sound Blaster AWE 64 PnP */
-	ISAPNP_SBAWE('C','T','L',0x00e4,0x0045,0x0022),
+	{ .id = "CTL00e4", .devs = { { "CTL0045" }, { "CTL0022" } } },
 	/* Sound Blaster AWE 64 PnP */
-	ISAPNP_SBAWE('C','T','L',0x00e9,0x0045,0x0022),
+	{ .id = "CTL00e9", .devs = { { "CTL0045" }, { "CTL0022" } } },
 	/* Sound Blaster 16 PnP (AWE) */
-	ISAPNP_SBAWE('C','T','L',0x00ed,0x0041,0x0070),
+	{ .id = "CTL00ed", .devs = { { "CTL0041" }, { "CTL0070" } } },
 	/* Generic entries */
-	ISAPNP_SBAWE('C','T','L',ISAPNP_ANY_ID,0x0031,0x0021),
-	ISAPNP_SBAWE('C','T','L',ISAPNP_ANY_ID,0x0041,0x0021),
-	ISAPNP_SBAWE('C','T','L',ISAPNP_ANY_ID,0x0042,0x0022),
-	ISAPNP_SBAWE('C','T','L',ISAPNP_ANY_ID,0x0044,0x0023),
-	ISAPNP_SBAWE('C','T','L',ISAPNP_ANY_ID,0x0045,0x0022),
+	{ .id = "CTLXXXX" , .devs = { { "CTL0031" }, { "CTL0021" } } },
+	{ .id = "CTLXXXX" , .devs = { { "CTL0041" }, { "CTL0021" } } },
+	{ .id = "CTLXXXX" , .devs = { { "CTL0042" }, { "CTL0022" } } },
+	{ .id = "CTLXXXX" , .devs = { { "CTL0044" }, { "CTL0023" } } },
+	{ .id = "CTLXXXX" , .devs = { { "CTL0045" }, { "CTL0022" } } },
 #endif /* SNDRV_SBAWE */
-	{ ISAPNP_CARD_END, }
+	{ .id = "", }
 };
 
-ISAPNP_CARD_TABLE(snd_sb16_pnpids);
+MODULE_DEVICE_TABLE(pnp_card, snd_sb16_pnpids);
 
-static int __init snd_sb16_isapnp(int dev, struct snd_sb16 *acard)
+#ifdef SNDRV_SBAWE_EMU8000
+#define DRIVER_NAME	"snd-card-sbawe"
+#else
+#define DRIVER_NAME	"snd-card-sb16"
+#endif
+
+static int __devinit snd_card_sb16_pnp(int dev, struct snd_card_sb16 *acard,
+				       struct pnp_card_link *card,
+				       const struct pnp_card_device_id *id)
 {
-	const struct isapnp_card_id *id = snd_sb16_isapnp_id[dev];
-	struct isapnp_card *card = snd_sb16_isapnp_cards[dev];
-	struct isapnp_dev *pdev;
-
-	acard->dev = isapnp_find_dev(card, id->devs[0].vendor, id->devs[0].function, NULL);
-	if (acard->dev->active) {
-		acard->dev = NULL;
-		return -EBUSY;
-	}
-#ifdef SNDRV_SBAWE_EMU8000
-	acard->devwt = isapnp_find_dev(card, id->devs[1].vendor, id->devs[1].function, NULL);
-	if (acard->devwt->active) {
-		acard->dev = acard->devwt = NULL;
-		return -EBUSY;
-	}
-#endif	
+	struct pnp_dev *pdev;
+	struct pnp_resource_table * cfg = kmalloc(GFP_ATOMIC, sizeof(struct pnp_resource_table));
+	int err;
+
+	if (!cfg) 
+		return -ENOMEM; 
+	acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
+	if (acard->dev == NULL) { 
+		kfree(cfg); 
+		return -ENODEV; 
+	} 
+#ifdef SNDRV_SBAWE_EMU8000
+	acard->devwt = pnp_request_card_device(card, id->devs[1].id, acard->dev);
+#endif
 	/* Audio initialization */
 	pdev = acard->dev;
-	if (pdev->prepare(pdev) < 0)
-		return -EAGAIN;
+
+	pnp_init_resource_table(cfg); 
+	 
+	/* override resources */ 
+
 	if (port[dev] != SNDRV_AUTO_PORT)
-		isapnp_resource_change(&pdev->resource[0], port[dev], 16);
+		pnp_resource_change(&cfg->port_resource[0], port[dev], 16);
 	if (mpu_port[dev] != SNDRV_AUTO_PORT)
-		isapnp_resource_change(&pdev->resource[1], mpu_port[dev], 2);
+		pnp_resource_change(&cfg->port_resource[1], mpu_port[dev], 2);
 	if (fm_port[dev] != SNDRV_AUTO_PORT)
-		isapnp_resource_change(&pdev->resource[2], fm_port[dev], 4);
+		pnp_resource_change(&cfg->port_resource[2], fm_port[dev], 4);
 	if (dma8[dev] != SNDRV_AUTO_DMA)
-		isapnp_resource_change(&pdev->dma_resource[0], dma8[dev], 1);
+		pnp_resource_change(&cfg->dma_resource[0], dma8[dev], 1);
 	if (dma16[dev] != SNDRV_AUTO_DMA)
-		isapnp_resource_change(&pdev->dma_resource[1], dma16[dev], 1);
+		pnp_resource_change(&cfg->dma_resource[1], dma16[dev], 1);
 	if (irq[dev] != SNDRV_AUTO_IRQ)
-		isapnp_resource_change(&pdev->irq_resource[0], irq[dev], 1);
-	if (pdev->activate(pdev) < 0) {
-		printk(KERN_ERR PFX "isapnp configure failure (out of resources?)\n");
-		return -EBUSY;
-	}
-	port[dev] = pdev->resource[0].start;
-	mpu_port[dev] = pdev->resource[1].start;
-	fm_port[dev] = pdev->resource[2].start;
-	dma8[dev] = pdev->dma_resource[0].start;
-	dma16[dev] = pdev->dma_resource[1].start;
-	irq[dev] = pdev->irq_resource[0].start;
-	snd_printdd("isapnp SB16: port=0x%lx, mpu port=0x%lx, fm port=0x%lx\n",
+		pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
+	if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0) 
+		printk(KERN_ERR PFX "AUDIO the requested resources are invalid, using auto config\n"); 
+	err = pnp_activate_dev(pdev); 
+	if (err < 0) { 
+		printk(KERN_ERR PFX "AUDIO pnp configure failure\n"); 
+		kfree(cfg);
+		return err; 
+	} 
+	port[dev] = pnp_port_start(pdev, 0);
+	mpu_port[dev] = pnp_port_start(pdev, 1);
+	fm_port[dev] = pnp_port_start(pdev, 2);
+	dma8[dev] = pnp_dma(pdev, 0);
+	dma16[dev] = pnp_dma(pdev, 1);
+	irq[dev] = pnp_irq(pdev, 0);
+	snd_printdd("pnp SB16: port=0x%lx, mpu port=0x%lx, fm port=0x%lx\n",
 			port[dev], mpu_port[dev], fm_port[dev]);
-	snd_printdd("isapnp SB16: dma1=%i, dma2=%i, irq=%i\n",
+	snd_printdd("pnp SB16: dma1=%i, dma2=%i, irq=%i\n",
 			dma8[dev], dma16[dev], irq[dev]);
 #ifdef SNDRV_SBAWE_EMU8000
 	/* WaveTable initialization */
 	pdev = acard->devwt;
-	if (pdev->prepare(pdev)<0) {
-		acard->dev->deactivate(acard->dev);
-		return -EAGAIN;
-	}
-	if (awe_port[dev] != SNDRV_AUTO_PORT) {
-		isapnp_resource_change(&pdev->resource[0], awe_port[dev], 4);
-		isapnp_resource_change(&pdev->resource[1], awe_port[dev] + 0x400, 4);
-		isapnp_resource_change(&pdev->resource[2], awe_port[dev] + 0x800, 4);
-	}
-	if (pdev->activate(pdev)<0) {
-		printk(KERN_ERR PFX "WaveTable isapnp configure failure (out of resources?)\n");
-		acard->dev->deactivate(acard->dev);		
-		return -EBUSY;
-	}
-	awe_port[dev] = pdev->resource[0].start;
-	snd_printdd("isapnp SB16: wavetable port=0x%lx\n", pdev->resource[0].start);
-#endif
-	return 0;
-}
-
-static void snd_sb16_deactivate(struct snd_sb16 *acard)
-{
-	if (acard->dev) {
-		acard->dev->deactivate(acard->dev);
-		acard->dev = NULL;
-	}
-#ifdef SNDRV_SBAWE_EMU8000
-	if (acard->devwt) {
-		acard->devwt->deactivate(acard->devwt);
+	if (pdev != NULL) {
+		pnp_init_resource_table(cfg); 
+	 
+		/* override resources */ 
+
+		if (awe_port[dev] != SNDRV_AUTO_PORT) {
+			pnp_resource_change(&cfg->port_resource[0], awe_port[dev], 4);
+			pnp_resource_change(&cfg->port_resource[1], awe_port[dev] + 0x400, 4);
+			pnp_resource_change(&cfg->port_resource[2], awe_port[dev] + 0x800, 4);
+		}
+		if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0) 
+			printk(KERN_ERR PFX "WaveTable the requested resources are invalid, using auto config\n"); 
+		err = pnp_activate_dev(pdev); 
+		if (err < 0) { 
+			goto __wt_error; 
+		} 
+		awe_port[dev] = pnp_port_start(pdev, 0);
+		snd_printdd("pnp SB16: wavetable port=0x%lx\n", pdev->resource[0].start);
+	} else {
+__wt_error:
+		if (pdev) {
+			pnp_release_card_device(pdev);
+			printk(KERN_ERR PFX "WaveTable pnp configure failure\n");
+		}
 		acard->devwt = NULL;
+		awe_port[dev] = -1;
 	}
 #endif
+	kfree(cfg);
+	return 0;
 }
 
-#endif /* __ISAPNP__ */
-
-static void snd_sb16_free(snd_card_t *card)
-{
-	struct snd_sb16 *acard = (struct snd_sb16 *)card->private_data;
-
-	if (acard == NULL)
-		return;
-	if (acard->fm_res) {
-		release_resource(acard->fm_res);
-		kfree_nocheck(acard->fm_res);
-	}
-#ifdef __ISAPNP__
-	snd_sb16_deactivate(acard);
-#endif
-}
-
-static int __init snd_sb16_probe(int dev)
+static int __init snd_sb16_probe(int dev,
+				 struct pnp_card_link *pcard,
+				 const struct pnp_card_device_id *pid)
 {
 	static int possible_irqs[] = {5, 9, 10, 7, -1};
 	static int possible_dmas8[] = {1, 3, 0, -1};
@@ -380,7 +356,7 @@
 	int xirq, xdma8, xdma16;
 	sb_t *chip;
 	snd_card_t *card;
-	struct snd_sb16 *acard;
+	struct snd_card_sb16 *acard;
 	opl3_t *opl3;
 	snd_hwdep_t *synth = NULL;
 #ifdef CONFIG_SND_SB16_CSP
@@ -390,22 +366,21 @@
 	int err;
 
 	card = snd_card_new(index[dev], id[dev], THIS_MODULE,
-			    sizeof(struct snd_sb16));
+			    sizeof(struct snd_card_sb16));
 	if (card == NULL)
 		return -ENOMEM;
-	acard = (struct snd_sb16 *) card->private_data;
-	card->private_free = snd_sb16_free;
-#ifdef __ISAPNP__
-	if (isapnp[dev] && snd_sb16_isapnp(dev, acard) < 0) {
-		snd_card_free(card);
-		return -EBUSY;
+	acard = (struct snd_card_sb16 *) card->private_data;
+	if (isapnp[dev]) {
+		if ((err = snd_card_sb16_pnp(dev, acard, pcard, pid))) {
+			snd_card_free(card);
+			return err;
+		}
 	}
-#endif
 
 	xirq = irq[dev];
 	xdma8 = dma8[dev];
 	xdma16 = dma16[dev];
-#ifdef __ISAPNP__
+#ifdef CONFIG_PNP
 	if (!isapnp[dev]) {
 #endif
 	if (xirq == SNDRV_AUTO_IRQ) {
@@ -437,7 +412,7 @@
 	/* non-PnP AWE port address is hardwired with base port address */
 	awe_port[dev] = port[dev] + 0x400;
 #endif
-#ifdef __ISAPNP__
+#ifdef CONFIG_PNP
 	}
 #endif
 
@@ -458,7 +433,7 @@
 		return -ENODEV;
 	}
 	chip->mpu_port = mpu_port[dev];
-#ifdef __ISAPNP__
+#ifdef CONFIG_PNP
 	if (!isapnp[dev] && (err = snd_sb16dsp_configure(chip)) < 0) {
 #else
 	if ((err = snd_sb16dsp_configure(chip)) < 0) {
@@ -554,7 +529,10 @@
 		snd_card_free(card);
 		return err;
 	}
-	snd_sb16_cards[dev] = card;
+	if (pcard)
+		pnp_set_card_drvdata(pcard, card);
+	else
+		snd_sb16_legacy[dev] = card;
 	return 0;
 }
 
@@ -566,12 +544,12 @@
 	for ( ; dev < SNDRV_CARDS; dev++) {
 		if (!enable[dev] || port[dev] != SNDRV_AUTO_PORT)
 			continue;
-#ifdef __ISAPNP__
+#ifdef CONFIG_PNP
 		if (isapnp[dev])
 			continue;
 #endif
 		port[dev] = xport;
-		res = snd_sb16_probe(dev);
+		res = snd_sb16_probe(dev, NULL, NULL);
 		if (res < 0)
 			port[dev] = SNDRV_AUTO_PORT;
 		return res;
@@ -579,10 +557,10 @@
 	return -ENODEV;
 }
 
-#ifdef __ISAPNP__
+#ifdef CONFIG_PNP
 
-static int __init snd_sb16_isapnp_detect(struct isapnp_card *card,
-					 const struct isapnp_card_id *id)
+static int __devinit snd_sb16_pnp_detect(struct pnp_card_link *card,
+					 const struct pnp_card_device_id *id)
 {
 	static int dev;
 	int res;
@@ -590,9 +568,7 @@
 	for ( ; dev < SNDRV_CARDS; dev++) {
 		if (!enable[dev] || !isapnp[dev])
 			continue;
-		snd_sb16_isapnp_cards[dev] = card;
-		snd_sb16_isapnp_id[dev] = id;
-		res = snd_sb16_probe(dev);
+		res = snd_sb16_probe(dev, card, id);
 		if (res < 0)
 			return res;
 		dev++;
@@ -602,7 +578,23 @@
 	return -ENODEV;
 }
 
-#endif /* __ISAPNP__ */
+#endif
+
+static void __devexit snd_sb16_pnp_remove(struct pnp_card_link * pcard)
+{
+	snd_card_t *card = (snd_card_t *) pnp_get_card_drvdata(pcard);
+
+	snd_card_disconnect(card);
+	snd_card_free_in_thread(card);
+}
+
+static struct pnp_card_driver sb16_pnpc_driver = {
+	.flags = PNP_DRIVER_RES_DISABLE,
+	.name = "sb16",
+	.id_table = snd_sb16_pnpids,
+	.probe = snd_sb16_pnp_detect,
+	.remove = __devexit_p(snd_sb16_pnp_remove),
+};
 
 static int __init alsa_card_sb16_init(void)
 {
@@ -613,23 +605,23 @@
 	for (dev = 0; dev < SNDRV_CARDS; dev++) {
 		if (!enable[dev] || port[dev] == SNDRV_AUTO_PORT)
 			continue;
-#ifdef __ISAPNP__
+#ifdef CONFIG_PNP
 		if (isapnp[dev])
 			continue;
 #endif
-		if (!snd_sb16_probe(dev)) {
+		if (!snd_sb16_probe(dev, NULL, NULL)) {
 			cards++;
 			continue;
 		}
 #ifdef MODULE
 		printk(KERN_ERR "Sound Blaster 16+ soundcard #%i not found at 0x%lx or device busy\n", dev, port[dev]);
-#endif			
+#endif
 	}
 	/* legacy auto configured cards */
 	cards += snd_legacy_auto_probe(possible_ports, snd_sb16_probe_legacy_port);
-#ifdef __ISAPNP__
-	/* ISA PnP cards at last */
-	cards += isapnp_probe_cards(snd_sb16_pnpids, snd_sb16_isapnp_detect);
+#ifdef CONFIG_PNP
+	/* PnP cards at last */
+	cards += pnp_register_card_driver(&sb16_pnpc_driver);
 #endif
 
 	if (!cards) {
@@ -650,8 +642,12 @@
 {
 	int dev;
 
+#ifdef CONFIG_PNP
+	/* PnP cards first */
+	pnp_unregister_card_driver(&sb16_pnpc_driver);
+#endif
 	for (dev = 0; dev < SNDRV_CARDS; dev++)
-		snd_card_free(snd_sb16_cards[dev]);
+		snd_card_free(snd_sb16_legacy[dev]);
 }
 
 module_init(alsa_card_sb16_init)
@@ -659,7 +655,7 @@
 
 #ifndef MODULE
 
-/* format is: snd-sb16=enable,index,id,isapnp,
+/* format is: snd-sb16=enable,index,id,pnp,
 		       port,mpu_port,fm_port,
 		       irq,dma8,dma16,
 		       mic_agc,csp,
@@ -694,7 +690,7 @@
 	       get_option(&str,&seq_ports[nr_dev]) == 2
 #endif
 	       );
-#ifdef __ISAPNP__
+#ifdef CONFIG_PNP
 	if (pnp != INT_MAX)
 		isapnp[nr_dev] = pnp;
 #endif
diff -urN linux-2.5.66-bk10/sound/oss/sb_card.c linux-2.5.66-bk11/sound/oss/sb_card.c
--- linux-2.5.66-bk10/sound/oss/sb_card.c	2003-03-24 14:00:54.000000000 -0800
+++ linux-2.5.66-bk11/sound/oss/sb_card.c	2003-04-05 04:32:16.000000000 -0800
@@ -224,7 +224,7 @@
 }
 
 /* Probe callback function for the PnP API */
-static int sb_pnp_probe(struct pnp_card_link *card, const struct pnp_card_id *card_id)
+static int sb_pnp_probe(struct pnp_card_link *card, const struct pnp_card_device_id *card_id)
 {
 	struct sb_card_config *scc;
 	struct sb_module_options sbmo = {0}; /* Default to 0 for PnP */
diff -urN linux-2.5.66-bk10/sound/oss/sb_card.h linux-2.5.66-bk11/sound/oss/sb_card.h
--- linux-2.5.66-bk10/sound/oss/sb_card.h	2003-03-24 14:00:42.000000000 -0800
+++ linux-2.5.66-bk11/sound/oss/sb_card.h	2003-04-05 04:32:16.000000000 -0800
@@ -23,7 +23,7 @@
  */
 
 /* Card PnP ID Table */
-static struct pnp_card_id sb_pnp_card_table[] = {
+static struct pnp_card_device_id sb_pnp_card_table[] = {
 	/* Sound Blaster 16 */
 	{.id = "CTL0024", .driver_data = 0, devs : { {.id="CTL0031"}, } },
 	/* Sound Blaster 16 */
