## Automatically generated incremental diff
## From:   linux-2.4.29-rc2
## To:     linux-2.4.29-rc3
## Robot:  $Id: make-incremental-diff,v 1.12 2004/01/06 07:19:36 hpa Exp $

diff -urN linux-2.4.29-rc2/Documentation/Changes linux-2.4.29-rc3/Documentation/Changes
--- linux-2.4.29-rc2/Documentation/Changes	2004-02-18 05:36:30.000000000 -0800
+++ linux-2.4.29-rc3/Documentation/Changes	2005-01-15 10:14:23.646066024 -0800
@@ -52,7 +52,7 @@
 o  Gnu make               3.77                    # make --version
 o  binutils               2.9.1.0.25              # ld -v
 o  util-linux             2.10o                   # fdformat --version
-o  modutils               2.4.2                   # insmod -V
+o  modutils               2.4.10                   # insmod -V
 o  e2fsprogs              1.25                    # tune2fs
 o  jfsutils               1.0.12                  # fsck.jfs -V
 o  reiserfsprogs          3.6.3                   # reiserfsck -V 2>&1|grep reiserfsprogs
@@ -159,8 +159,8 @@
 Upgrade to recent modutils to fix various outstanding bugs which are
 seen more frequently under 2.4.x, and to enable auto-loading of USB
 modules.  In addition, the layout of modules under
-/lib/modules/`uname -r`/ has been made more sane.  This change also
-requires that you upgrade to a recent modutils.
+/lib/modules/`uname -r`/ has been made more sane, and EXPORT_SYMBOL_GPL 
+also requires that you upgrade to a recent modutils.
 
 Mkinitrd
 --------
diff -urN linux-2.4.29-rc2/Documentation/Configure.help linux-2.4.29-rc3/Documentation/Configure.help
--- linux-2.4.29-rc2/Documentation/Configure.help	2005-01-15 10:14:19.811902374 -0800
+++ linux-2.4.29-rc3/Documentation/Configure.help	2005-01-15 10:14:23.834074049 -0800
@@ -3042,19 +3042,6 @@
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.  If unsure, say `N'.
 
-Local NAT support
-CONFIG_IP_NF_NAT_LOCAL
-  This option enables support for NAT of locally originated connections. 
-  Enable this if you need to use destination NAT on connections
-  originating from local processes on the nat box itself.
-
-  Please note that you will need a recent version (>= 1.2.6a)
-  of the iptables userspace program in order to use this feature.
-  See <http://www.iptables.org/> for download instructions.
-
-  If unsure, say 'N'.
-
-
 Full NAT (Network Address Translation)
 CONFIG_IP_NF_NAT
   The Full NAT option allows masquerading, port forwarding and other
diff -urN linux-2.4.29-rc2/Makefile linux-2.4.29-rc3/Makefile
--- linux-2.4.29-rc2/Makefile	2005-01-15 10:14:19.924907197 -0800
+++ linux-2.4.29-rc3/Makefile	2005-01-15 10:14:23.999081092 -0800
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 29
-EXTRAVERSION = -rc2
+EXTRAVERSION = -rc3
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.4.29-rc2/arch/mips/defconfig-bosporus linux-2.4.29-rc3/arch/mips/defconfig-bosporus
--- linux-2.4.29-rc2/arch/mips/defconfig-bosporus	2005-01-15 10:14:20.055912789 -0800
+++ linux-2.4.29-rc3/arch/mips/defconfig-bosporus	2005-01-15 10:14:24.063083824 -0800
@@ -341,7 +341,6 @@
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
-CONFIG_IP_NF_NAT_LOCAL=y
 CONFIG_IP_NF_NAT_SNMP_BASIC=m
 CONFIG_IP_NF_MANGLE=m
 # CONFIG_IP_NF_TARGET_TOS is not set
diff -urN linux-2.4.29-rc2/arch/mips/defconfig-mtx-1 linux-2.4.29-rc3/arch/mips/defconfig-mtx-1
--- linux-2.4.29-rc2/arch/mips/defconfig-mtx-1	2005-01-15 10:14:20.082913941 -0800
+++ linux-2.4.29-rc3/arch/mips/defconfig-mtx-1	2005-01-15 10:14:24.090084976 -0800
@@ -335,7 +335,6 @@
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
-# CONFIG_IP_NF_NAT_LOCAL is not set
 # CONFIG_IP_NF_NAT_SNMP_BASIC is not set
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
diff -urN linux-2.4.29-rc2/arch/mips64/defconfig linux-2.4.29-rc3/arch/mips64/defconfig
--- linux-2.4.29-rc2/arch/mips64/defconfig	2005-01-15 10:14:20.218919747 -0800
+++ linux-2.4.29-rc3/arch/mips64/defconfig	2005-01-15 10:14:24.193089373 -0800
@@ -265,7 +265,6 @@
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
 CONFIG_IP_NF_NAT_AMANDA=m
-CONFIG_IP_NF_NAT_LOCAL=y
 # CONFIG_IP_NF_NAT_SNMP_BASIC is not set
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
diff -urN linux-2.4.29-rc2/arch/mips64/defconfig-ip27 linux-2.4.29-rc3/arch/mips64/defconfig-ip27
--- linux-2.4.29-rc2/arch/mips64/defconfig-ip27	2005-01-15 10:14:20.223919960 -0800
+++ linux-2.4.29-rc3/arch/mips64/defconfig-ip27	2005-01-15 10:14:24.197089543 -0800
@@ -265,7 +265,6 @@
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
 CONFIG_IP_NF_NAT_AMANDA=m
-CONFIG_IP_NF_NAT_LOCAL=y
 # CONFIG_IP_NF_NAT_SNMP_BASIC is not set
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
diff -urN linux-2.4.29-rc2/arch/ppc/configs/apus_defconfig linux-2.4.29-rc3/arch/ppc/configs/apus_defconfig
--- linux-2.4.29-rc2/arch/ppc/configs/apus_defconfig	2004-02-18 05:36:30.000000000 -0800
+++ linux-2.4.29-rc3/arch/ppc/configs/apus_defconfig	2005-01-15 10:14:24.311094409 -0800
@@ -199,7 +199,6 @@
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
 CONFIG_IP_NF_NAT_AMANDA=m
-# CONFIG_IP_NF_NAT_LOCAL is not set
 CONFIG_IP_NF_NAT_SNMP_BASIC=m
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
diff -urN linux-2.4.29-rc2/arch/ppc/configs/briq_defconfig linux-2.4.29-rc3/arch/ppc/configs/briq_defconfig
--- linux-2.4.29-rc2/arch/ppc/configs/briq_defconfig	2004-02-18 05:36:30.000000000 -0800
+++ linux-2.4.29-rc3/arch/ppc/configs/briq_defconfig	2005-01-15 10:14:24.311094409 -0800
@@ -175,7 +175,6 @@
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
 CONFIG_IP_NF_NAT_AMANDA=m
-# CONFIG_IP_NF_NAT_LOCAL is not set
 CONFIG_IP_NF_NAT_SNMP_BASIC=m
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
diff -urN linux-2.4.29-rc2/arch/ppc/configs/common_defconfig linux-2.4.29-rc3/arch/ppc/configs/common_defconfig
--- linux-2.4.29-rc2/arch/ppc/configs/common_defconfig	2004-02-18 05:36:30.000000000 -0800
+++ linux-2.4.29-rc3/arch/ppc/configs/common_defconfig	2005-01-15 10:14:24.312094452 -0800
@@ -180,7 +180,6 @@
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
 CONFIG_IP_NF_NAT_AMANDA=m
-# CONFIG_IP_NF_NAT_LOCAL is not set
 CONFIG_IP_NF_NAT_SNMP_BASIC=m
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
diff -urN linux-2.4.29-rc2/arch/ppc/configs/ibmchrp_defconfig linux-2.4.29-rc3/arch/ppc/configs/ibmchrp_defconfig
--- linux-2.4.29-rc2/arch/ppc/configs/ibmchrp_defconfig	2004-02-18 05:36:30.000000000 -0800
+++ linux-2.4.29-rc3/arch/ppc/configs/ibmchrp_defconfig	2005-01-15 10:14:24.313094495 -0800
@@ -173,7 +173,6 @@
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
 CONFIG_IP_NF_NAT_AMANDA=m
-# CONFIG_IP_NF_NAT_LOCAL is not set
 CONFIG_IP_NF_NAT_SNMP_BASIC=m
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
diff -urN linux-2.4.29-rc2/arch/ppc/configs/pal4_defconfig linux-2.4.29-rc3/arch/ppc/configs/pal4_defconfig
--- linux-2.4.29-rc2/arch/ppc/configs/pal4_defconfig	2004-02-18 05:36:30.000000000 -0800
+++ linux-2.4.29-rc3/arch/ppc/configs/pal4_defconfig	2005-01-15 10:14:24.314094537 -0800
@@ -172,7 +172,6 @@
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
 CONFIG_IP_NF_NAT_AMANDA=m
-# CONFIG_IP_NF_NAT_LOCAL is not set
 CONFIG_IP_NF_NAT_SNMP_BASIC=m
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
diff -urN linux-2.4.29-rc2/arch/ppc/configs/pmac_defconfig linux-2.4.29-rc3/arch/ppc/configs/pmac_defconfig
--- linux-2.4.29-rc2/arch/ppc/configs/pmac_defconfig	2004-02-18 05:36:30.000000000 -0800
+++ linux-2.4.29-rc3/arch/ppc/configs/pmac_defconfig	2005-01-15 10:14:24.314094537 -0800
@@ -183,7 +183,6 @@
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
 CONFIG_IP_NF_NAT_AMANDA=m
-# CONFIG_IP_NF_NAT_LOCAL is not set
 CONFIG_IP_NF_NAT_SNMP_BASIC=m
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
diff -urN linux-2.4.29-rc2/arch/ppc/configs/pplus_defconfig linux-2.4.29-rc3/arch/ppc/configs/pplus_defconfig
--- linux-2.4.29-rc2/arch/ppc/configs/pplus_defconfig	2004-02-18 05:36:30.000000000 -0800
+++ linux-2.4.29-rc3/arch/ppc/configs/pplus_defconfig	2005-01-15 10:14:24.315094580 -0800
@@ -175,7 +175,6 @@
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
 CONFIG_IP_NF_NAT_AMANDA=m
-# CONFIG_IP_NF_NAT_LOCAL is not set
 CONFIG_IP_NF_NAT_SNMP_BASIC=m
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
diff -urN linux-2.4.29-rc2/arch/ppc/configs/prpmc750_defconfig linux-2.4.29-rc3/arch/ppc/configs/prpmc750_defconfig
--- linux-2.4.29-rc2/arch/ppc/configs/prpmc750_defconfig	2004-02-18 05:36:30.000000000 -0800
+++ linux-2.4.29-rc3/arch/ppc/configs/prpmc750_defconfig	2005-01-15 10:14:24.316094623 -0800
@@ -183,7 +183,6 @@
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
-# CONFIG_IP_NF_NAT_LOCAL is not set
 # CONFIG_IP_NF_NAT_SNMP_BASIC is not set
 CONFIG_IP_NF_NAT_FTP=m
 # CONFIG_IP_NF_MANGLE is not set
diff -urN linux-2.4.29-rc2/arch/ppc/defconfig linux-2.4.29-rc3/arch/ppc/defconfig
--- linux-2.4.29-rc2/arch/ppc/defconfig	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29-rc3/arch/ppc/defconfig	2005-01-15 10:14:24.319094751 -0800
@@ -180,7 +180,6 @@
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
 CONFIG_IP_NF_NAT_AMANDA=m
-# CONFIG_IP_NF_NAT_LOCAL is not set
 CONFIG_IP_NF_NAT_SNMP_BASIC=m
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
diff -urN linux-2.4.29-rc2/arch/s390/defconfig linux-2.4.29-rc3/arch/s390/defconfig
--- linux-2.4.29-rc2/arch/s390/defconfig	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29-rc3/arch/s390/defconfig	2005-01-15 10:14:24.330095220 -0800
@@ -199,7 +199,6 @@
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
-CONFIG_IP_NF_NAT_LOCAL=y
 # CONFIG_IP_NF_NAT_SNMP_BASIC is not set
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
diff -urN linux-2.4.29-rc2/arch/sparc64/defconfig linux-2.4.29-rc3/arch/sparc64/defconfig
--- linux-2.4.29-rc2/arch/sparc64/defconfig	2005-01-15 10:14:20.341924997 -0800
+++ linux-2.4.29-rc3/arch/sparc64/defconfig	2005-01-15 10:14:24.354096245 -0800
@@ -253,7 +253,6 @@
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
 CONFIG_IP_NF_NAT_AMANDA=m
-# CONFIG_IP_NF_NAT_LOCAL is not set
 CONFIG_IP_NF_NAT_SNMP_BASIC=m
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
diff -urN linux-2.4.29-rc2/drivers/char/tty_io.c linux-2.4.29-rc3/drivers/char/tty_io.c
--- linux-2.4.29-rc2/drivers/char/tty_io.c	2005-01-15 10:14:20.700940320 -0800
+++ linux-2.4.29-rc3/drivers/char/tty_io.c	2005-01-15 10:14:24.550104611 -0800
@@ -718,7 +718,12 @@
 	wake_up_interruptible(&tty->write_wait);
 }
 
-EXPORT_SYMBOL_GPL(tty_wakeup);
+/*
+ * tty_wakeup/tty_ldisc_flush are actually _GPL exports but we can't do 
+ * that in 2.4 for modutils compat reasons.
+ */
+EXPORT_SYMBOL(tty_wakeup);
+
 
 void tty_ldisc_flush(struct tty_struct *tty)
 {
@@ -730,7 +735,12 @@
 	}
 }
 
-EXPORT_SYMBOL_GPL(tty_ldisc_flush);
+
+/*
+ * tty_wakeup/tty_ldisc_flush are actually _GPL exports but we can't do 
+ * that in 2.4 for modutils compat reasons.
+ */
+EXPORT_SYMBOL(tty_ldisc_flush);
 
 void do_tty_hangup(void *data)
 {
diff -urN linux-2.4.29-rc2/drivers/net/tg3.c linux-2.4.29-rc3/drivers/net/tg3.c
--- linux-2.4.29-rc2/drivers/net/tg3.c	2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.29-rc3/drivers/net/tg3.c	2005-01-15 10:14:24.634108196 -0800
@@ -59,8 +59,8 @@
 
 #define DRV_MODULE_NAME		"tg3"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"3.14"
-#define DRV_MODULE_RELDATE	"November 15, 2004"
+#define DRV_MODULE_VERSION	"3.15"
+#define DRV_MODULE_RELDATE	"January 6, 2005"
 
 #define TG3_DEF_MAC_MODE	0
 #define TG3_DEF_RX_MODE		0
@@ -477,7 +477,8 @@
 static int tg3_readphy(struct tg3 *tp, int reg, u32 *val)
 {
 	u32 frame_val;
-	int loops, ret;
+	unsigned int loops;
+	int ret;
 
 	if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
 		tw32_f(MAC_MI_MODE,
@@ -485,7 +486,7 @@
 		udelay(80);
 	}
 
-	*val = 0xffffffff;
+	*val = 0x0;
 
 	frame_val  = ((PHY_ADDR << MI_COM_PHY_ADDR_SHIFT) &
 		      MI_COM_PHY_ADDR_MASK);
@@ -496,7 +497,7 @@
 	tw32_f(MAC_MI_COM, frame_val);
 
 	loops = PHY_BUSY_LOOPS;
-	while (loops-- > 0) {
+	while (loops != 0) {
 		udelay(10);
 		frame_val = tr32(MAC_MI_COM);
 
@@ -505,10 +506,11 @@
 			frame_val = tr32(MAC_MI_COM);
 			break;
 		}
+		loops -= 1;
 	}
 
 	ret = -EBUSY;
-	if (loops > 0) {
+	if (loops != 0) {
 		*val = frame_val & MI_COM_DATA_MASK;
 		ret = 0;
 	}
@@ -524,7 +526,8 @@
 static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
 {
 	u32 frame_val;
-	int loops, ret;
+	unsigned int loops;
+	int ret;
 
 	if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
 		tw32_f(MAC_MI_MODE,
@@ -542,7 +545,7 @@
 	tw32_f(MAC_MI_COM, frame_val);
 
 	loops = PHY_BUSY_LOOPS;
-	while (loops-- > 0) {
+	while (loops != 0) {
 		udelay(10);
 		frame_val = tr32(MAC_MI_COM);
 		if ((frame_val & MI_COM_BUSY) == 0) {
@@ -550,10 +553,11 @@
 			frame_val = tr32(MAC_MI_COM);
 			break;
 		}
+		loops -= 1;
 	}
 
 	ret = -EBUSY;
-	if (loops > 0)
+	if (loops != 0)
 		ret = 0;
 
 	if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
diff -urN linux-2.4.29-rc2/include/linux/if_arp.h linux-2.4.29-rc3/include/linux/if_arp.h
--- linux-2.4.29-rc2/include/linux/if_arp.h	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29-rc3/include/linux/if_arp.h	2005-01-15 10:14:25.286136026 -0800
@@ -40,6 +40,7 @@
 #define ARPHRD_METRICOM	23		/* Metricom STRIP (new IANA id)	*/
 #define	ARPHRD_IEEE1394	24		/* IEEE 1394 IPv4 - RFC 2734	*/
 #define ARPHRD_EUI64	27		/* EUI-64                       */
+#define ARPHRD_INFINIBAND	32		/* InfiniBand                   */
 
 /* Dummy types for non ARP hardware */
 #define ARPHRD_SLIP	256
diff -urN linux-2.4.29-rc2/include/linux/if_ether.h linux-2.4.29-rc3/include/linux/if_ether.h
--- linux-2.4.29-rc2/include/linux/if_ether.h	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.29-rc3/include/linux/if_ether.h	2005-01-15 10:14:25.286136026 -0800
@@ -61,6 +61,8 @@
 #define ETH_P_IPV6	0x86DD		/* IPv6 over bluebook		*/
 #define ETH_P_PPP_DISC	0x8863		/* PPPoE discovery messages     */
 #define ETH_P_PPP_SES	0x8864		/* PPPoE session messages	*/
+#define ETH_P_MPLS_UC	0x8847		/* MPLS Unicast traffic         */
+#define ETH_P_MPLS_MC	0x8848		/* MPLS Multicast traffic       */
 #define ETH_P_ATMMPOA	0x884c		/* MultiProtocol Over ATM	*/
 #define ETH_P_ATMFATE	0x8884		/* Frame-based ATM Transport
 					 * over Ethernet
diff -urN linux-2.4.29-rc2/include/linux/netfilter.h linux-2.4.29-rc3/include/linux/netfilter.h
--- linux-2.4.29-rc2/include/linux/netfilter.h	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29-rc3/include/linux/netfilter.h	2005-01-15 10:14:25.292136282 -0800
@@ -153,6 +153,7 @@
 extern inline struct arpt_target *
 arpt_find_target_lock(const char *name, int *error, struct semaphore *mutex);
 extern void (*ip_ct_attach)(struct sk_buff *, struct nf_ct_info *);
+extern void nf_ct_attach(struct sk_buff *, struct sk_buff *);
 
 #ifdef CONFIG_NETFILTER_DEBUG
 extern void nf_dump_skb(int pf, struct sk_buff *skb);
@@ -163,6 +164,7 @@
 
 #else /* !CONFIG_NETFILTER */
 #define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb)
+static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {}
 #endif /*CONFIG_NETFILTER*/
 
 /* From arch/i386/kernel/smp.c:
diff -urN linux-2.4.29-rc2/include/linux/netfilter_ipv4/ip_conntrack_core.h linux-2.4.29-rc3/include/linux/netfilter_ipv4/ip_conntrack_core.h
--- linux-2.4.29-rc2/include/linux/netfilter_ipv4/ip_conntrack_core.h	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.29-rc3/include/linux/netfilter_ipv4/ip_conntrack_core.h	2005-01-15 10:14:25.292136282 -0800
@@ -25,9 +25,9 @@
 extern struct ip_conntrack *icmp_error_track(struct sk_buff *skb,
 					     enum ip_conntrack_info *ctinfo,
 					     unsigned int hooknum);
-extern int get_tuple(const struct iphdr *iph, size_t len,
-		     struct ip_conntrack_tuple *tuple,
-		     struct ip_conntrack_protocol *protocol);
+extern int ip_ct_get_tuple(const struct iphdr *iph, size_t len,
+                           struct ip_conntrack_tuple *tuple,
+                           struct ip_conntrack_protocol *protocol);
 
 /* Find a connection corresponding to a tuple. */
 struct ip_conntrack_tuple_hash *
diff -urN linux-2.4.29-rc2/include/linux/netfilter_ipv4/ip_nat.h linux-2.4.29-rc3/include/linux/netfilter_ipv4/ip_nat.h
--- linux-2.4.29-rc2/include/linux/netfilter_ipv4/ip_nat.h	2004-04-14 06:05:40.000000000 -0700
+++ linux-2.4.29-rc3/include/linux/netfilter_ipv4/ip_nat.h	2005-01-15 10:14:25.293136325 -0800
@@ -11,13 +11,8 @@
 	IP_NAT_MANIP_DST
 };
 
-#ifndef CONFIG_IP_NF_NAT_LOCAL
-/* SRC manip occurs only on POST_ROUTING */
-#define HOOK2MANIP(hooknum) ((hooknum) != NF_IP_POST_ROUTING)
-#else
 /* SRC manip occurs POST_ROUTING or LOCAL_IN */
 #define HOOK2MANIP(hooknum) ((hooknum) != NF_IP_POST_ROUTING && (hooknum) != NF_IP_LOCAL_IN)
-#endif
 
 /* 2.3.19 (I hope) will define this in linux/netfilter_ipv4.h. */
 #ifndef SO_ORIGINAL_DST
diff -urN linux-2.4.29-rc2/include/linux/sctp.h linux-2.4.29-rc3/include/linux/sctp.h
--- linux-2.4.29-rc2/include/linux/sctp.h	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29-rc3/include/linux/sctp.h	2005-01-15 10:14:25.298136539 -0800
@@ -364,7 +364,7 @@
  */
 typedef struct sctp_abort_chunk {
         sctp_chunkhdr_t uh;
-} __attribute__((packed)) sctp_abort_chunkt_t;
+} __attribute__((packed)) sctp_abort_chunk_t;
 
 
 /* For the graceful shutdown we must carry the tag (in common header)
diff -urN linux-2.4.29-rc2/include/net/inet_ecn.h linux-2.4.29-rc3/include/net/inet_ecn.h
--- linux-2.4.29-rc2/include/net/inet_ecn.h	2001-10-30 15:08:12.000000000 -0800
+++ linux-2.4.29-rc3/include/net/inet_ecn.h	2005-01-15 10:14:25.305136837 -0800
@@ -1,6 +1,14 @@
 #ifndef _INET_ECN_H_
 #define _INET_ECN_H_
 
+enum {
+	INET_ECN_NOT_ECT = 0,
+	INET_ECN_ECT_1 = 1,
+	INET_ECN_ECT_0 = 2,
+	INET_ECN_CE = 3,
+	INET_ECN_MASK = 3,
+};
+
 static inline int INET_ECN_is_ce(__u8 dsfield)
 {
 	return (dsfield&3) == 3;
diff -urN linux-2.4.29-rc2/include/net/ip.h linux-2.4.29-rc3/include/net/ip.h
--- linux-2.4.29-rc2/include/net/ip.h	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29-rc3/include/net/ip.h	2005-01-15 10:14:25.305136837 -0800
@@ -102,7 +102,8 @@
 				      int getfrag (const void *,
 						   char *,
 						   unsigned int,
-						   unsigned int),
+						   unsigned int,
+						   struct sk_buff *),
 				      const void *frag,
 				      unsigned length,
 				      struct ipcm_cookie *ipc,
diff -urN linux-2.4.29-rc2/include/net/ip_vs.h linux-2.4.29-rc3/include/net/ip_vs.h
--- linux-2.4.29-rc2/include/net/ip_vs.h	2005-01-15 10:14:21.231962985 -0800
+++ linux-2.4.29-rc3/include/net/ip_vs.h	2005-01-15 10:14:25.306136880 -0800
@@ -97,6 +97,7 @@
 	int             state;          /* sync daemon state */
 	char            mcast_ifn[IP_VS_IFNAME_MAXLEN];
 					/* multicast interface name */
+	int		syncid;
 
 	/* virtual service options */
 	u_int16_t	protocol;
@@ -213,8 +214,9 @@
 
 /* The argument to IP_VS_SO_GET_DAEMON */
 struct ip_vs_daemon_user {
-	int	state;				/* sync daemon state */
-	char	mcast_ifn[IP_VS_IFNAME_MAXLEN];	/* multicast interface name */
+	int	state;					/* sync daemon state */
+	char	mcast_master_ifn[IP_VS_IFNAME_MAXLEN];	/* mcast master interface name */
+	char	mcast_backup_ifn[IP_VS_IFNAME_MAXLEN];	/* mcast backup interface name */
 };
 
 
@@ -726,9 +728,10 @@
  *      (from ip_vs_sync.c)
  */
 extern volatile int ip_vs_sync_state;
-extern char ip_vs_mcast_ifn[IP_VS_IFNAME_MAXLEN];
-extern int start_sync_thread(int state, char *mcast_ifn);
-extern int stop_sync_thread(void);
+extern char ip_vs_mcast_master_ifn[IP_VS_IFNAME_MAXLEN];
+extern char ip_vs_mcast_backup_ifn[IP_VS_IFNAME_MAXLEN];
+extern int start_sync_thread(int state, char *mcast_ifn, __u8 syncid);
+extern int stop_sync_thread(int state);
 extern void ip_vs_sync_conn(struct ip_vs_conn *cp);
 
 
diff -urN linux-2.4.29-rc2/include/net/sctp/command.h linux-2.4.29-rc3/include/net/sctp/command.h
--- linux-2.4.29-rc2/include/net/sctp/command.h	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29-rc3/include/net/sctp/command.h	2005-01-15 10:14:25.307136923 -0800
@@ -189,11 +189,6 @@
 } sctp_cmd_seq_t;
 
 
-/* Create a new sctp_command_sequence.
- * Return NULL if creating a new sequence fails.
- */
-sctp_cmd_seq_t *sctp_new_cmd_seq(int gfp);
-
 /* Initialize a block of memory as a command sequence.
  * Return 0 if the initialization fails.
  */
@@ -207,18 +202,10 @@
  */
 int sctp_add_cmd(sctp_cmd_seq_t *seq, sctp_verb_t verb, sctp_arg_t obj);
 
-/* Rewind an sctp_cmd_seq_t to iterate from the start.
- * Return 0 if the rewind fails.
- */
-int sctp_rewind_sequence(sctp_cmd_seq_t *seq);
-
 /* Return the next command structure in an sctp_cmd_seq.
  * Return NULL at the end of the sequence.
  */
 sctp_cmd_t *sctp_next_cmd(sctp_cmd_seq_t *seq);
 
-/* Dispose of a command sequence.  */
-void sctp_free_cmd_seq(sctp_cmd_seq_t *seq);
-
 #endif /* __net_sctp_command_h__ */
 
diff -urN linux-2.4.29-rc2/include/net/sctp/compat.h linux-2.4.29-rc3/include/net/sctp/compat.h
--- linux-2.4.29-rc2/include/net/sctp/compat.h	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29-rc3/include/net/sctp/compat.h	2005-01-15 10:14:25.307136923 -0800
@@ -64,37 +64,6 @@
 #define __unsafe(x)
 #define dst_pmtu(x) ((x)->pmtu)
 
-#define sk_family family
-#define sk_state state
-#define sk_type type
-#define sk_socket socket
-#define sk_prot prot
-#define sk_rcvbuf rcvbuf
-#define sk_sndbuf sndbuf
-#define sk_ack_backlog ack_backlog
-#define sk_max_ack_backlog max_ack_backlog
-#define sk_write_space write_space
-#define sk_use_write_queue use_write_queue
-#define sk_err err
-#define sk_err_soft err_soft
-#define sk_error_report error_report
-#define sk_error_queue error_queue
-#define sk_shutdown shutdown
-#define sk_state_change state_change
-#define sk_receive_queue receive_queue
-#define sk_data_ready data_ready
-#define sk_no_check no_check
-#define sk_reuse reuse
-#define sk_destruct destruct
-#define sk_zapped zapped
-#define sk_protocol protocol
-#define sk_backlog_rcv backlog_rcv
-#define sk_allocation allocation
-#define sk_lingertime lingertime
-#define sk_sleep sleep
-#define sk_wmem_queued wmem_queued
-#define sk_bound_dev_if bound_dev_if
-
 /*
  * find last bit set.
  */
diff -urN linux-2.4.29-rc2/include/net/sctp/constants.h linux-2.4.29-rc3/include/net/sctp/constants.h
--- linux-2.4.29-rc2/include/net/sctp/constants.h	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29-rc3/include/net/sctp/constants.h	2005-01-15 10:14:25.308136965 -0800
@@ -105,9 +105,10 @@
 
 typedef enum {
 	SCTP_EVENT_NO_PENDING_TSN = 0,
+	SCTP_EVENT_ICMP_PROTO_UNREACH,
 } sctp_event_other_t;
 
-#define SCTP_EVENT_OTHER_MAX		SCTP_EVENT_NO_PENDING_TSN
+#define SCTP_EVENT_OTHER_MAX		SCTP_EVENT_ICMP_PROTO_UNREACH
 #define SCTP_NUM_OTHER_TYPES		(SCTP_EVENT_OTHER_MAX + 1)
 
 /* These are primitive requests from the ULP.  */
@@ -155,10 +156,6 @@
 		       		- (unsigned long)(c->chunk_hdr)\
 				- sizeof(sctp_data_chunk_t)))
 
-/* This is a table of printable names of sctp_param_t's.  */
-extern const char *sctp_param_tbl[];
-
-
 #define SCTP_MAX_ERROR_CAUSE  SCTP_ERROR_NONEXIST_IP
 #define SCTP_NUM_ERROR_CAUSE  10
 
@@ -179,6 +176,7 @@
 	SCTP_IERROR_IGNORE_TSN,
 	SCTP_IERROR_NO_DATA,
 	SCTP_IERROR_BAD_STREAM,
+	SCTP_IERROR_BAD_PORTS,
 
 } sctp_ierror_t;
 
diff -urN linux-2.4.29-rc2/include/net/sctp/sctp.h linux-2.4.29-rc3/include/net/sctp/sctp.h
--- linux-2.4.29-rc2/include/net/sctp/sctp.h	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29-rc3/include/net/sctp/sctp.h	2005-01-15 10:14:25.309137008 -0800
@@ -166,17 +166,9 @@
 int sctp_rcv(struct sk_buff *skb);
 void sctp_v4_err(struct sk_buff *skb, u32 info);
 void sctp_hash_established(struct sctp_association *);
-void __sctp_hash_established(struct sctp_association *);
 void sctp_unhash_established(struct sctp_association *);
-void __sctp_unhash_established(struct sctp_association *);
 void sctp_hash_endpoint(struct sctp_endpoint *);
-void __sctp_hash_endpoint(struct sctp_endpoint *);
 void sctp_unhash_endpoint(struct sctp_endpoint *);
-void __sctp_unhash_endpoint(struct sctp_endpoint *);
-struct sctp_association *__sctp_lookup_association(
-	const union sctp_addr *,
-	const union sctp_addr *,
-	struct sctp_transport **);
 struct sock *sctp_err_lookup(int family, struct sk_buff *,
 			     struct sctphdr *, struct sctp_endpoint **,
 			     struct sctp_association **,
@@ -185,6 +177,10 @@
 			    struct sctp_association *);
 void sctp_icmp_frag_needed(struct sock *, struct sctp_association *,
 			   struct sctp_transport *t, __u32 pmtu);
+void sctp_icmp_proto_unreachable(struct sock *sk,
+				 struct sctp_endpoint *ep,
+				 struct sctp_association *asoc,
+				 struct sctp_transport *t);
 
 /*
  *  Section:  Macros, externs, and inlines
@@ -332,8 +328,6 @@
 
 int sctp_v6_init(void);
 void sctp_v6_exit(void);
-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) */
 
@@ -477,7 +471,8 @@
 #define _sctp_walk_params(pos, chunk, end, member)\
 for (pos.v = chunk->member;\
      pos.v <= (void *)chunk + end - sizeof(sctp_paramhdr_t) &&\
-     pos.v <= (void *)chunk + end - WORD_ROUND(ntohs(pos.p->length)); \
+     pos.v <= (void *)chunk + end - WORD_ROUND(ntohs(pos.p->length)) &&\
+     ntohs(pos.p->length) >= sizeof(sctp_paramhdr_t);\
      pos.v += WORD_ROUND(ntohs(pos.p->length)))
 
 #define sctp_walk_errors(err, chunk_hdr)\
@@ -487,10 +482,9 @@
 for (err = (sctp_errhdr_t *)((void *)chunk_hdr + \
 	    sizeof(sctp_chunkhdr_t));\
      (void *)err <= (void *)chunk_hdr + end - sizeof(sctp_errhdr_t) &&\
-     (void *)err <= (void *)chunk_hdr + end - \
-		    WORD_ROUND(ntohs(err->length));\
-     err = (sctp_errhdr_t *)((void *)err + \
-	    WORD_ROUND(ntohs(err->length))))
+     (void *)err <= (void *)chunk_hdr + end - WORD_ROUND(ntohs(err->length)) &&\
+     ntohs(err->length) >= sizeof(sctp_errhdr_t); \
+     err = (sctp_errhdr_t *)((void *)err + WORD_ROUND(ntohs(err->length))))
 
 #define sctp_walk_fwdtsn(pos, chunk)\
 _sctp_walk_fwdtsn((pos), (chunk), ntohs((chunk)->chunk_hdr->length) - sizeof(struct sctp_fwdtsn_chunk))
@@ -622,7 +616,7 @@
 #define sctp_sstate(sk, state) __sctp_sstate((sk), (SCTP_SS_##state))
 int static inline __sctp_sstate(const struct sock *sk, sctp_sock_state_t state)
 {
-	return sk->sk_state == state;
+	return sk->state == state;
 }
 
 /* Map v4-mapped v6 address back to v4 address */
diff -urN linux-2.4.29-rc2/include/net/sctp/sm.h linux-2.4.29-rc3/include/net/sctp/sm.h
--- linux-2.4.29-rc2/include/net/sctp/sm.h	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29-rc3/include/net/sctp/sm.h	2005-01-15 10:14:25.310137051 -0800
@@ -128,9 +128,9 @@
 sctp_state_fn_t sctp_sf_do_ecn_cwr;
 sctp_state_fn_t sctp_sf_do_ecne;
 sctp_state_fn_t sctp_sf_ootb;
-sctp_state_fn_t sctp_sf_shut_8_4_5;
 sctp_state_fn_t sctp_sf_pdiscard;
 sctp_state_fn_t sctp_sf_violation;
+sctp_state_fn_t sctp_sf_violation_chunklen;
 sctp_state_fn_t sctp_sf_discard_chunk;
 sctp_state_fn_t sctp_sf_do_5_2_1_siminit;
 sctp_state_fn_t sctp_sf_do_5_2_2_dupinit;
@@ -138,7 +138,6 @@
 sctp_state_fn_t sctp_sf_unk_chunk;
 sctp_state_fn_t sctp_sf_do_8_5_1_E_sa;
 sctp_state_fn_t sctp_sf_cookie_echoed_err;
-sctp_state_fn_t sctp_sf_do_5_2_6_stale;
 sctp_state_fn_t sctp_sf_do_asconf;
 sctp_state_fn_t sctp_sf_do_asconf_ack;
 sctp_state_fn_t sctp_sf_do_9_2_reshutack;
@@ -167,6 +166,7 @@
 sctp_state_fn_t sctp_sf_do_9_2_start_shutdown;
 sctp_state_fn_t sctp_sf_do_9_2_shutdown_ack;
 sctp_state_fn_t sctp_sf_ignore_other;
+sctp_state_fn_t sctp_sf_cookie_wait_icmp_abort;
 
 /* Prototypes for timeout event state functions.  */
 sctp_state_fn_t sctp_sf_do_6_3_3_rtx;
@@ -200,19 +200,10 @@
 struct sctp_chunk *sctp_make_cwr(const struct sctp_association *,
 				 const __u32 lowest_tsn,
 				 const struct sctp_chunk *);
-struct sctp_chunk *sctp_make_datafrag(struct sctp_association *,
-				 const struct sctp_sndrcvinfo *sinfo,
-				 int len, const __u8 *data,
-				 __u8 flags, __u16 ssn);
 struct sctp_chunk * sctp_make_datafrag_empty(struct sctp_association *,
 					const struct sctp_sndrcvinfo *sinfo,
 					int len, const __u8 flags,
 					__u16 ssn);
-struct sctp_chunk *sctp_make_data(struct sctp_association *,
-			     const struct sctp_sndrcvinfo *sinfo,
-			     int len, const __u8 *data);
-struct sctp_chunk *sctp_make_data_empty(struct sctp_association *,
-				   const struct sctp_sndrcvinfo *, int len);
 struct sctp_chunk *sctp_make_ecne(const struct sctp_association *,
 				  const __u32);
 struct sctp_chunk *sctp_make_sack(const struct sctp_association *);
@@ -232,6 +223,10 @@
 struct sctp_chunk *sctp_make_abort_user(const struct sctp_association *,
 				   const struct sctp_chunk *,
 				   const struct msghdr *);
+struct sctp_chunk *sctp_make_abort_violation(const struct sctp_association *,
+				   const struct sctp_chunk *,
+				   const __u8 *,
+				   const size_t );
 struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *,
 				  const struct sctp_transport *,
 				  const void *payload,
@@ -246,17 +241,12 @@
 				 const void *payload,
 				 size_t paylen);
 
-struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc,
-				    union sctp_addr *addr,
-				    int vparam_len);
 struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *,
 					      union sctp_addr *,
 					      struct sockaddr *,
 					      int, __u16);
 struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc,
 					     union sctp_addr *addr);
-struct sctp_chunk *sctp_make_asconf_ack(const struct sctp_association *asoc,
-					__u32 serial, int vparam_len);
 struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
 				       struct sctp_chunk *asconf);
 int sctp_process_asconf_ack(struct sctp_association *asoc,
@@ -268,6 +258,8 @@
 void sctp_chunk_assign_tsn(struct sctp_chunk *);
 void sctp_chunk_assign_ssn(struct sctp_chunk *);
 
+void sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands, __u16 error);
+
 /* Prototypes for statetable processing. */
 
 int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype,
@@ -277,71 +269,26 @@
                void *event_arg,
                int gfp);
 
-int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype,
-		      sctp_state_t state,
-                      struct sctp_endpoint *,
-                      struct sctp_association *asoc,
-                      void *event_arg,
-                      sctp_disposition_t status,
-		      sctp_cmd_seq_t *commands,
-                      int gfp);
-
 /* 2nd level prototypes */
-int sctp_cmd_interpreter(sctp_event_t, sctp_subtype_t, sctp_state_t,
-			 struct sctp_endpoint *, struct sctp_association *,
-			 void *event_arg, sctp_disposition_t,
-			 sctp_cmd_seq_t *retval, int gfp);
-
-
-int sctp_gen_sack(struct sctp_association *, int force, sctp_cmd_seq_t *);
 void sctp_generate_t3_rtx_event(unsigned long peer);
 void sctp_generate_heartbeat_event(unsigned long peer);
 
-sctp_sackhdr_t *sctp_sm_pull_sack(struct sctp_chunk *);
-struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *,
-				       const struct sctp_association *,
-				       struct sctp_chunk *chunk,
-				       const void *payload,
-				       size_t paylen);
-struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *,
-				      const struct sctp_chunk *);
 void sctp_ootb_pkt_free(struct sctp_packet *);
 
-struct sctp_cookie_param *
-sctp_pack_cookie(const struct sctp_endpoint *, const struct sctp_association *,
-		 const struct sctp_chunk *, int *cookie_len,
-		 const __u8 *, int addrs_len);
 struct sctp_association *sctp_unpack_cookie(const struct sctp_endpoint *,
 				       const struct sctp_association *,
 				       struct sctp_chunk *, int gfp, int *err,
 				       struct sctp_chunk **err_chk_p);
 int sctp_addip_addr_config(struct sctp_association *, sctp_param_t,
 			   struct sockaddr_storage*, int);
-void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep,
-				const struct sctp_association *asoc,
-				const struct sctp_chunk *chunk,
-				sctp_cmd_seq_t *commands,
-				struct sctp_chunk *err_chunk);
-int sctp_eat_data(const struct sctp_association *asoc,
-		  struct sctp_chunk *chunk,
-		  sctp_cmd_seq_t *commands);
 
 /* 3rd level prototypes */
 __u32 sctp_generate_tag(const struct sctp_endpoint *);
 __u32 sctp_generate_tsn(const struct sctp_endpoint *);
 
 /* Extern declarations for major data structures.  */
-const sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t, sctp_state_t);
-extern const sctp_sm_table_entry_t
-primitive_event_table[SCTP_NUM_PRIMITIVE_TYPES][SCTP_STATE_NUM_STATES];
-extern const sctp_sm_table_entry_t
-other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STATES];
-extern const sctp_sm_table_entry_t
-timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM_STATES];
 extern sctp_timer_event_t *sctp_timer_events[SCTP_NUM_TIMEOUT_TYPES];
 
-/* These are some handy utility macros... */
-
 
 /* Get the size of a DATA chunk payload. */
 static inline __u16 sctp_data_size(struct sctp_chunk *chunk)
diff -urN linux-2.4.29-rc2/include/net/sctp/structs.h linux-2.4.29-rc3/include/net/sctp/structs.h
--- linux-2.4.29-rc2/include/net/sctp/structs.h	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29-rc3/include/net/sctp/structs.h	2005-01-15 10:14:25.312137136 -0800
@@ -322,10 +322,19 @@
 	/* This holds the originating address of the INIT packet.  */
 	union sctp_addr peer_addr;
 
+	/* IG Section 2.35.3 
+	 * Include the source port of the INIT-ACK
+	 */
+	__u16		my_port;
+
 	__u8 prsctp_capable;
 
+	/* Padding for future use */
+	__u8 padding;  		
+
 	__u32 adaption_ind;	
 
+
 	/* This is a shim for my peer's INIT packet, followed by
 	 * a copy of the raw address list of the association.
 	 * The length of the raw address list is saved in the
@@ -406,7 +415,6 @@
 	int malloced;
 };
 
-struct sctp_ssnmap *sctp_ssnmap_init(struct sctp_ssnmap *, __u16, __u16);
 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);
@@ -538,12 +546,9 @@
 struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *,
 					    struct sctp_sndrcvinfo *,
 					    struct msghdr *, int len);
-struct sctp_datamsg *sctp_datamsg_new(int gfp);
 void sctp_datamsg_put(struct sctp_datamsg *);
-void sctp_datamsg_hold(struct sctp_datamsg *);
 void sctp_datamsg_free(struct sctp_datamsg *);
 void sctp_datamsg_track(struct sctp_chunk *);
-void sctp_datamsg_assign(struct sctp_datamsg *, struct sctp_chunk *);
 void sctp_chunk_fail(struct sctp_chunk *, int error);
 int sctp_chunk_abandoned(struct sctp_chunk *);
 
@@ -651,8 +656,6 @@
 void sctp_chunk_put(struct sctp_chunk *);
 int sctp_user_addto_chunk(struct sctp_chunk *chunk, int off, int len,
 			  struct iovec *data);
-struct sctp_chunk *sctp_make_chunk(const struct sctp_association *, __u8 type,
-				   __u8 flags, int size);
 void sctp_chunk_free(struct sctp_chunk *);
 void  *sctp_addto_chunk(struct sctp_chunk *, int len, const void *data);
 struct sctp_chunk *sctp_chunkify(struct sk_buff *,
@@ -853,12 +856,6 @@
 	/* Error count : The current error count for this destination.	*/
 	unsigned short error_count;
 
-	/* Error       : Current error threshold for this destination
-	 * Threshold   : i.e. what value marks the destination down if
-	 *	       : errorCount reaches this value.
-	 */
-	unsigned short error_threshold;
-
 	/* This is the max_retrans value for the transport and will
 	 * be initialized to proto.max_retrans.path.  This can be changed
 	 * using SCTP_SET_PEER_ADDR_PARAMS socket option.
@@ -922,15 +919,12 @@
 };
 
 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 *,
 			      struct sctp_association *);
 void sctp_transport_route(struct sctp_transport *, union sctp_addr *,
 			  struct sctp_opt *);
 void sctp_transport_pmtu(struct sctp_transport *);
 void sctp_transport_free(struct sctp_transport *);
-void sctp_transport_destroy(struct sctp_transport *);
 void sctp_transport_reset_timers(struct sctp_transport *);
 void sctp_transport_hold(struct sctp_transport *);
 void sctp_transport_put(struct sctp_transport *);
@@ -961,7 +955,6 @@
 	int malloced;	     /* Is this structure kfree()able?	*/
 };
 
-struct sctp_inq *sctp_inq_new(void);
 void sctp_inq_init(struct sctp_inq *);
 void sctp_inq_free(struct sctp_inq *);
 void sctp_inq_push(struct sctp_inq *, struct sctp_chunk *packet);
@@ -1029,7 +1022,6 @@
 	char malloced;
 };
 
-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*);
@@ -1070,7 +1062,6 @@
 	int malloced;	     /* Are we kfree()able?  */
 };
 
-struct sctp_bind_addr *sctp_bind_addr_new(int gfp_mask);
 void sctp_bind_addr_init(struct sctp_bind_addr *, __u16 port);
 void sctp_bind_addr_free(struct sctp_bind_addr *);
 int sctp_bind_addr_copy(struct sctp_bind_addr *dest,
@@ -1220,8 +1211,6 @@
 
 /* These are function signatures for manipulating endpoints.  */
 struct sctp_endpoint *sctp_endpoint_new(struct sock *, int);
-struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *,
-					 struct sock *, int gfp);
 void sctp_endpoint_free(struct sctp_endpoint *);
 void sctp_endpoint_put(struct sctp_endpoint *);
 void sctp_endpoint_hold(struct sctp_endpoint *);
@@ -1243,8 +1232,6 @@
 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 struct sctp_endpoint *);
 __u32 sctp_generate_tsn(const struct sctp_endpoint *);
 
@@ -1693,10 +1680,6 @@
 struct sctp_association *
 sctp_association_new(const struct sctp_endpoint *, const struct sock *,
 		     sctp_scope_t scope, int gfp);
-struct sctp_association *
-sctp_association_init(struct sctp_association *, const struct sctp_endpoint *,
-		      const struct sock *, sctp_scope_t scope,
-		      int gfp);
 void sctp_association_free(struct sctp_association *);
 void sctp_association_put(struct sctp_association *);
 void sctp_association_hold(struct sctp_association *);
@@ -1725,7 +1708,6 @@
 		       struct sctp_association *new);
 
 __u32 sctp_association_get_next_tsn(struct sctp_association *);
-__u32 sctp_association_get_tsn_block(struct sctp_association *, int);
 
 void sctp_assoc_sync_pmtu(struct sctp_association *);
 void sctp_assoc_rwnd_increase(struct sctp_association *, unsigned);
@@ -1739,7 +1721,6 @@
 int sctp_cmp_addr_exact(const union sctp_addr *ss1,
 			const union sctp_addr *ss2);
 struct sctp_chunk *sctp_get_ecne_prepend(struct sctp_association *asoc);
-struct sctp_chunk *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.4.29-rc2/include/net/sctp/tsnmap.h linux-2.4.29-rc3/include/net/sctp/tsnmap.h
--- linux-2.4.29-rc2/include/net/sctp/tsnmap.h	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29-rc3/include/net/sctp/tsnmap.h	2005-01-15 10:14:25.312137136 -0800
@@ -120,12 +120,6 @@
 	__u32 start;
 };
 
-/* Create a new tsnmap.  */
-struct sctp_tsnmap *sctp_tsnmap_new(__u16 len, __u32 init_tsn, int gfp);
-
-/* Dispose of a tsnmap.  */
-void sctp_tsnmap_free(struct sctp_tsnmap *);
-
 /* This macro assists in creation of external storage for variable length
  * internal buffers.  We double allocate so the overflow map works.
  */
@@ -210,14 +204,4 @@
 /* Is there a gap in the TSN map? */
 int sctp_tsnmap_has_gap(const struct sctp_tsnmap *);
 
-/* Initialize a gap ack block interator from user-provided memory.  */
-void sctp_tsnmap_iter_init(const struct sctp_tsnmap *,
-			   struct sctp_tsnmap_iter *);
-
-/* Get the next gap ack blocks.  We return 0 if there are no more
- * gap ack blocks.
- */
-int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *,
-	struct sctp_tsnmap_iter *,__u16 *start, __u16 *end);
-
 #endif /* __sctp_tsnmap_h__ */
diff -urN linux-2.4.29-rc2/include/net/sctp/ulpevent.h linux-2.4.29-rc3/include/net/sctp/ulpevent.h
--- linux-2.4.29-rc2/include/net/sctp/ulpevent.h	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29-rc3/include/net/sctp/ulpevent.h	2005-01-15 10:14:25.313137179 -0800
@@ -77,8 +77,6 @@
 	return (struct sctp_ulpevent *)skb->cb;
 }
 
-struct sctp_ulpevent *sctp_ulpevent_new(int size, int flags, int gfp);
-void sctp_ulpevent_init(struct sctp_ulpevent *, int flags);
 void sctp_ulpevent_free(struct sctp_ulpevent *);
 int sctp_ulpevent_is_notification(const struct sctp_ulpevent *);
 void sctp_queue_purge_ulpevents(struct sk_buff_head *list);
diff -urN linux-2.4.29-rc2/include/net/sctp/ulpqueue.h linux-2.4.29-rc3/include/net/sctp/ulpqueue.h
--- linux-2.4.29-rc2/include/net/sctp/ulpqueue.h	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29-rc3/include/net/sctp/ulpqueue.h	2005-01-15 10:14:25.313137179 -0800
@@ -57,7 +57,6 @@
 };
 
 /* Prototypes. */
-struct sctp_ulpq *sctp_ulpq_new(struct sctp_association *asoc, int gfp);
 struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *,
 				 struct sctp_association *);
 void sctp_ulpq_free(struct sctp_ulpq *);
diff -urN linux-2.4.29-rc2/net/core/neighbour.c linux-2.4.29-rc3/net/core/neighbour.c
--- linux-2.4.29-rc2/net/core/neighbour.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29-rc3/net/core/neighbour.c	2005-01-15 10:14:25.326137734 -0800
@@ -427,11 +427,12 @@
 
 	n->confirmed = jiffies - (n->parms->base_reachable_time<<1);
 
-	hash_val = tbl->hash(pkey, dev) & tbl->hash_mask;
-
 	write_lock_bh(&tbl->lock);
 	if (atomic_read(&tbl->entries) > (tbl->hash_mask + 1))
 		neigh_hash_grow(tbl, (tbl->hash_mask + 1) << 1);
+
+	hash_val = tbl->hash(pkey, dev) & tbl->hash_mask;
+
 	for (n1 = tbl->hash_buckets[hash_val]; n1; n1 = n1->next) {
 		if (dev == n1->dev &&
 		    memcmp(n1->primary_key, pkey, key_len) == 0) {
diff -urN linux-2.4.29-rc2/net/core/netfilter.c linux-2.4.29-rc3/net/core/netfilter.c
--- linux-2.4.29-rc2/net/core/netfilter.c	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.29-rc3/net/core/netfilter.c	2005-01-15 10:14:25.327137776 -0800
@@ -622,12 +622,21 @@
 }
 #endif /*CONFIG_INET*/
 
-/* This does not belong here, but ipt_REJECT needs it if connection
-   tracking in use: without this, connection may not be in hash table,
-   and hence manufactured ICMP or RST packets will not be associated
-   with it. */
+/* This does not belong here, but locally generated errors need it if connection
+   tracking in use: without this, connection may not be in hash table, and hence
+   manufactured ICMP or RST packets will not be associated with it. */
 void (*ip_ct_attach)(struct sk_buff *, struct nf_ct_info *);
 
+void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb)
+{
+	void (*attach)(struct sk_buff *, struct nf_ct_info *);
+
+	if (skb->nfct && (attach = ip_ct_attach) != NULL) {
+		mb(); /* Just to be sure: must be read before executing this */
+		attach(new, skb->nfct);
+	}
+}
+
 void __init netfilter_init(void)
 {
 	int i, h;
diff -urN linux-2.4.29-rc2/net/ipv4/icmp.c linux-2.4.29-rc3/net/ipv4/icmp.c
--- linux-2.4.29-rc2/net/ipv4/icmp.c	2004-04-14 06:05:41.000000000 -0700
+++ linux-2.4.29-rc3/net/ipv4/icmp.c	2005-01-15 10:14:25.330137904 -0800
@@ -281,12 +281,16 @@
  *	Checksum each fragment, and on the first include the headers and final checksum.
  */
  
-static int icmp_glue_bits(const void *p, char *to, unsigned int offset, unsigned int fraglen)
+static int icmp_glue_bits(const void *p, char *to, unsigned int offset,
+                          unsigned int fraglen, struct sk_buff *skb)
 {
 	struct icmp_bxm *icmp_param = (struct icmp_bxm *)p;
 	struct icmphdr *icmph;
 	unsigned int csum;
 
+	if (icmp_pointers[icmp_param->data.icmph.type].error)
+		nf_ct_attach(skb, icmp_param->skb);
+
 	if (offset) {
 		icmp_param->csum=skb_copy_and_csum_bits(icmp_param->skb,
 							icmp_param->offset+(offset-icmp_param->head_len), 
diff -urN linux-2.4.29-rc2/net/ipv4/ip_output.c linux-2.4.29-rc3/net/ipv4/ip_output.c
--- linux-2.4.29-rc2/net/ipv4/ip_output.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29-rc3/net/ipv4/ip_output.c	2005-01-15 10:14:25.333138032 -0800
@@ -438,7 +438,8 @@
 		  int getfrag (const void *,
 			       char *,
 			       unsigned int,	
-			       unsigned int),
+			       unsigned int,
+			       struct sk_buff *),
 		  const void *frag,
 		  unsigned length,
 		  struct ipcm_cookie *ipc,
@@ -607,7 +608,7 @@
 		 *	User data callback
 		 */
 
-		if (getfrag(frag, data, offset, fraglen-fragheaderlen)) {
+		if (getfrag(frag, data, offset, fraglen-fragheaderlen, skb)) {
 			err = -EFAULT;
 			kfree_skb(skb);
 			goto error;
@@ -647,7 +648,8 @@
 		  int getfrag (const void *,
 			       char *,
 			       unsigned int,	
-			       unsigned int),
+			       unsigned int,
+			       struct sk_buff *),
 		  const void *frag,
 		  unsigned length,
 		  struct ipcm_cookie *ipc,
@@ -721,10 +723,10 @@
 		iph->daddr=rt->rt_dst;
 		iph->check=0;
 		iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
-		err = getfrag(frag, ((char *)iph)+iph->ihl*4,0, length-iph->ihl*4);
+		err = getfrag(frag, ((char *)iph)+iph->ihl*4,0, length-iph->ihl*4, skb);
 	}
 	else
-		err = getfrag(frag, (void *)iph, 0, length);
+		err = getfrag(frag, (void *)iph, 0, length, skb);
 
 	if (err)
 		goto error_fault;
@@ -921,7 +923,7 @@
  *	Fetch data from kernel space and fill in checksum if needed.
  */
 static int ip_reply_glue_bits(const void *dptr, char *to, unsigned int offset, 
-			      unsigned int fraglen)
+			      unsigned int fraglen, struct sk_buff *skb)
 {
         struct ip_reply_arg *dp = (struct ip_reply_arg*)dptr;
 	u16 *pktp = (u16 *)to;
diff -urN linux-2.4.29-rc2/net/ipv4/ipvs/ip_vs_core.c linux-2.4.29-rc3/net/ipv4/ipvs/ip_vs_core.c
--- linux-2.4.29-rc2/net/ipv4/ipvs/ip_vs_core.c	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.29-rc3/net/ipv4/ipvs/ip_vs_core.c	2005-01-15 10:14:25.336138161 -0800
@@ -1131,7 +1131,7 @@
 	/* increase its packet counter and check if it is needed
 	   to be synchronized */
 	atomic_inc(&cp->in_pkts);
-	if (ip_vs_sync_state == IP_VS_STATE_MASTER &&
+	if (ip_vs_sync_state & IP_VS_STATE_MASTER &&
 	    (cp->protocol != IPPROTO_TCP ||
 	     cp->state == IP_VS_S_ESTABLISHED) &&
 	    (atomic_read(&cp->in_pkts) % 50 == sysctl_ip_vs_sync_threshold))
diff -urN linux-2.4.29-rc2/net/ipv4/ipvs/ip_vs_ctl.c linux-2.4.29-rc3/net/ipv4/ipvs/ip_vs_ctl.c
--- linux-2.4.29-rc2/net/ipv4/ipvs/ip_vs_ctl.c	2005-01-15 10:14:21.249963754 -0800
+++ linux-2.4.29-rc3/net/ipv4/ipvs/ip_vs_ctl.c	2005-01-15 10:14:25.337138203 -0800
@@ -1731,10 +1731,11 @@
 		ret = ip_vs_set_timeouts(urule);
 		goto out_unlock;
 	} else if (cmd == IP_VS_SO_SET_STARTDAEMON) {
-		ret = start_sync_thread(urule->state, urule->mcast_ifn);
+		ret = start_sync_thread(urule->state, urule->mcast_ifn,
+					urule->syncid);
 		goto out_unlock;
 	} else if (cmd == IP_VS_SO_SET_STOPDAEMON) {
-		ret = stop_sync_thread();
+		ret = stop_sync_thread(urule->state);
 		goto out_unlock;
 	} else if (cmd == IP_VS_SO_SET_ZERO) {
 		/* if no service address is set, zero counters in all */
@@ -2082,7 +2083,10 @@
 			goto out;
 		}
 		u.state = ip_vs_sync_state;
-		strcpy(u.mcast_ifn, ip_vs_mcast_ifn);
+		if (ip_vs_sync_state & IP_VS_STATE_MASTER)
+			strcpy(u.mcast_master_ifn, ip_vs_mcast_master_ifn);
+		if (ip_vs_sync_state & IP_VS_STATE_BACKUP)
+			strcpy(u.mcast_backup_ifn, ip_vs_mcast_backup_ifn);
 		if (copy_to_user(user, &u, sizeof(u)) != 0)
 			ret = -EFAULT;
 	}
diff -urN linux-2.4.29-rc2/net/ipv4/ipvs/ip_vs_sync.c linux-2.4.29-rc3/net/ipv4/ipvs/ip_vs_sync.c
--- linux-2.4.29-rc2/net/ipv4/ipvs/ip_vs_sync.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29-rc3/net/ipv4/ipvs/ip_vs_sync.c	2005-01-15 10:14:25.339138289 -0800
@@ -13,6 +13,9 @@
  *              through multicast
  *
  * Changes:
+ *	Alexandre Cassen        :       Added master & backup support at a time.
+ *	Alexandre Cassen        :       Added SyncID support for incoming sync
+ *					messages filtering.
  *	Justin Ossevoort	:	Fix endian problem on sync message size.
  */
 
@@ -74,7 +77,7 @@
        0                   1                   2                   3
        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-      |  Count Conns  |   Reserved    |            Size               |
+      |  Count Conns  |    Sync ID    |            Size               |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                                                               |
       |                    IPVS Sync Connection (1)                   |
@@ -86,11 +89,16 @@
       |                                                               |
       |                    IPVS Sync Connection (n)                   |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+   Count Conns : Number of IPVS sync Connection entries.
+   Sync ID     : IPVS sync group we belong to.
+   Size        : Size of packet.
+
 */
 #define SYNC_MESG_MAX_SIZE      (24*50+4)
 struct ip_vs_sync_mesg {
 	__u8                    nr_conns;
-	__u8                    reserved;
+	__u8                    syncid;
 	__u16                   size;
 
 	/* ip_vs_sync_conn entries start here */
@@ -116,6 +124,18 @@
 static struct ip_vs_sync_buff   *curr_sb = NULL;
 static spinlock_t curr_sb_lock = SPIN_LOCK_UNLOCKED;
 
+/* ipvs sync daemon state */
+volatile int ip_vs_sync_state = IP_VS_STATE_NONE;
+volatile int ip_vs_master_syncid = 0;
+volatile int ip_vs_backup_syncid = 0;
+
+/* multicast interface name */
+char ip_vs_mcast_master_ifn[IP_VS_IFNAME_MAXLEN];
+char ip_vs_mcast_backup_ifn[IP_VS_IFNAME_MAXLEN];
+
+/* multicast addr */
+static struct sockaddr_in mcast_addr;
+
 static inline void sb_queue_tail(struct ip_vs_sync_buff *sb)
 {
 	spin_lock(&ip_vs_sync_lock);
@@ -153,6 +173,7 @@
 		return NULL;
 	}
 	sb->mesg->nr_conns = 0;
+	sb->mesg->syncid = ip_vs_master_syncid;
 	sb->mesg->size = 4;
 	sb->head = (unsigned char *)sb->mesg + 4;
 	sb->end = (unsigned char *)sb->mesg + SYNC_MESG_MAX_SIZE;
@@ -265,6 +286,13 @@
 		return;
 	}
 
+	/* SyncID sanity check */
+	if (ip_vs_backup_syncid != 0 && m->syncid != ip_vs_backup_syncid) {
+		IP_VS_DBG(7, "Ignoring incoming msg with syncid = %d\n",
+			  m->syncid);
+		return;
+	}
+
 	p = (char *)buffer + sizeof(struct ip_vs_sync_mesg);
 	for (i=0; i<m->nr_conns; i++) {
 		s = (struct ip_vs_sync_conn *)p;
@@ -308,16 +336,6 @@
 }
 
 
-/* ipvs sync daemon state */
-volatile int ip_vs_sync_state = IP_VS_STATE_NONE;
-
-/* multicast interface name */
-char ip_vs_mcast_ifn[IP_VS_IFNAME_MAXLEN];
-
-/* multicast addr */
-static struct sockaddr_in mcast_addr;
-
-
 /*
  *      Setup loopback of outgoing multicasts on a sending socket
  */
@@ -429,7 +447,7 @@
 		return NULL;
 	}
 
-	if (set_mcast_if(sock->sk, ip_vs_mcast_ifn) < 0) {
+	if (set_mcast_if(sock->sk, ip_vs_mcast_master_ifn) < 0) {
 		IP_VS_ERR("Error setting outbound mcast interface\n");
 		goto error;
 	}
@@ -437,7 +455,7 @@
 	set_mcast_loop(sock->sk, 0);
 	set_mcast_ttl(sock->sk, 1);
 
-	if (bind_mcastif_addr(sock, ip_vs_mcast_ifn) < 0) {
+	if (bind_mcastif_addr(sock, ip_vs_mcast_master_ifn) < 0) {
 		IP_VS_ERR("Error binding address of the mcast interface\n");
 		goto error;
 	}
@@ -483,7 +501,7 @@
 	/* join the multicast group */
 	if (join_mcast_group(sock->sk,
 			     (struct in_addr*)&mcast_addr.sin_addr,
-			     ip_vs_mcast_ifn) < 0) {
+			     ip_vs_mcast_backup_ifn) < 0) {
 		IP_VS_ERR("Error joining to the multicast group\n");
 		goto error;
 	}
@@ -571,10 +589,12 @@
 
 
 static DECLARE_WAIT_QUEUE_HEAD(sync_wait);
-static pid_t sync_pid = 0;
+static pid_t sync_master_pid = 0;
+static pid_t sync_backup_pid = 0;
 
 static DECLARE_WAIT_QUEUE_HEAD(stop_sync_wait);
-static int stop_sync = 0;
+static int stop_master_sync = 0;
+static int stop_backup_sync = 0;
 
 static void sync_master_loop(void)
 {
@@ -586,6 +606,10 @@
 	if (!sock)
 		return;
 
+	IP_VS_INFO("sync thread started: state = MASTER, mcast_ifn = %s, "
+		   "syncid = %d\n",
+		   ip_vs_mcast_master_ifn, ip_vs_master_syncid);
+
 	for (;;) {
 		while ((sb=sb_dequeue())) {
 			ip_vs_send_sync_msg(sock, sb->mesg);
@@ -598,7 +622,7 @@
 			ip_vs_sync_buff_release(sb);
 		}
 
-		if (stop_sync)
+		if (stop_master_sync)
 			break;
 
 		__set_current_state(TASK_INTERRUPTIBLE);
@@ -637,6 +661,10 @@
 	if (!sock)
 		goto out;
 
+	IP_VS_INFO("sync thread started: state = BACKUP, mcast_ifn = %s, "
+		   "syncid = %d\n",
+		   ip_vs_mcast_backup_ifn, ip_vs_backup_syncid);
+
 	for (;;) {
 		/* do you have data now? */
 		while (!skb_queue_empty(&(sock->sk->receive_queue))) {
@@ -652,7 +680,7 @@
 			local_bh_enable();
 		}
 
-		if (stop_sync)
+		if (stop_backup_sync)
 			break;
 
 		__set_current_state(TASK_INTERRUPTIBLE);
@@ -667,12 +695,31 @@
 	kfree(buf);
 }
 
+static void sync_pid_set(int sync_state, pid_t sync_pid)
+{
+	if (sync_state == IP_VS_STATE_MASTER)
+		sync_master_pid = sync_pid;
+	else if (sync_state == IP_VS_STATE_BACKUP)
+		sync_backup_pid = sync_pid;
+}
+
+static void sync_stop_set(int sync_state, int set)
+{
+	if (sync_state == IP_VS_STATE_MASTER)
+		stop_master_sync = set;
+	else if (sync_state == IP_VS_STATE_BACKUP)
+		stop_backup_sync = set;
+	else {
+		stop_master_sync = set;
+		stop_backup_sync = set;
+	}
+}
 
 static int sync_thread(void *startup)
 {
 	DECLARE_WAITQUEUE(wait, current);
 	mm_segment_t oldmm;
-	int state;
+	int state = IP_VS_STATE_NONE;
 
 	MOD_INC_USE_COUNT;
 	daemonize();
@@ -680,12 +727,15 @@
 	oldmm = get_fs();
 	set_fs(KERNEL_DS);
 
-	if (ip_vs_sync_state == IP_VS_STATE_MASTER)
+	if (ip_vs_sync_state & IP_VS_STATE_MASTER && !sync_master_pid) {
+		state = IP_VS_STATE_MASTER;
 		sprintf(current->comm, "ipvs_syncmaster");
-	else if (ip_vs_sync_state == IP_VS_STATE_BACKUP)
+	} else if (ip_vs_sync_state & IP_VS_STATE_BACKUP) {
+		state = IP_VS_STATE_BACKUP;
 		sprintf(current->comm, "ipvs_syncbackup");
-	else IP_VS_BUG();
+	} else IP_VS_BUG();
 
+	/* Block all signals */
 	spin_lock_irq(&current->sigmask_lock);
 	siginitsetinv(&current->blocked, 0);
 	recalc_sigpending(current);
@@ -698,9 +748,7 @@
 
 	add_wait_queue(&sync_wait, &wait);
 
-	state = ip_vs_sync_state;
-	sync_pid = current->pid;
-	IP_VS_INFO("sync thread started.\n");
+	sync_pid_set(state, current->pid);
 	complete((struct completion *)startup);
 
 	/* processing master/backup loop here */
@@ -713,13 +761,13 @@
 	remove_wait_queue(&sync_wait, &wait);
 
 	/* thread exits */
-	sync_pid = 0;
+	sync_pid_set(state, 0);
 	IP_VS_INFO("sync thread stopped!\n");
 
 	set_fs(oldmm);
 	MOD_DEC_USE_COUNT;
 
-	stop_sync = 0;
+	sync_stop_set(state, 0);
 	wake_up(&stop_sync_wait);
 
 	return 0;
@@ -745,20 +793,27 @@
 }
 
 
-int start_sync_thread(int state, char *mcast_ifn)
+int start_sync_thread(int state, char *mcast_ifn, __u8 syncid)
 {
 	DECLARE_COMPLETION(startup);
 	pid_t pid;
 
-	if (sync_pid)
+	if ((state == IP_VS_STATE_MASTER && sync_master_pid) ||
+	    (state == IP_VS_STATE_BACKUP && sync_backup_pid))
 		return -EEXIST;
 
 	IP_VS_DBG(7, "%s: pid %d\n", __FUNCTION__, current->pid);
 	IP_VS_DBG(7, "Each ip_vs_sync_conn entry need %d bytes\n",
 		  sizeof(struct ip_vs_sync_conn));
 
-	ip_vs_sync_state = state;
-	strcpy(ip_vs_mcast_ifn, mcast_ifn);
+	ip_vs_sync_state |= state;
+	if (state == IP_VS_STATE_MASTER) {
+		strcpy(ip_vs_mcast_master_ifn, mcast_ifn);
+		ip_vs_master_syncid = syncid;
+	} else {
+		strcpy(ip_vs_mcast_backup_ifn, mcast_ifn);
+		ip_vs_backup_syncid = syncid;
+	}
 
   repeat:
 	if ((pid = kernel_thread(fork_sync_thread, &startup, 0)) < 0) {
@@ -775,20 +830,22 @@
 }
 
 
-int stop_sync_thread(void)
+int stop_sync_thread(int state)
 {
 	DECLARE_WAITQUEUE(wait, current);
 
-	if (!sync_pid)
+	if ((state == IP_VS_STATE_MASTER && !sync_master_pid) ||
+	    (state == IP_VS_STATE_BACKUP && !sync_backup_pid))
 		return -ESRCH;
 
 	IP_VS_DBG(7, "%s: pid %d\n", __FUNCTION__, current->pid);
-	IP_VS_INFO("stopping sync thread %d ...\n", sync_pid);
+	IP_VS_INFO("stopping sync thread %d ...\n",
+		   (state == IP_VS_STATE_MASTER) ? sync_master_pid : sync_backup_pid);
 
 	__set_current_state(TASK_UNINTERRUPTIBLE);
 	add_wait_queue(&stop_sync_wait, &wait);
-	ip_vs_sync_state = IP_VS_STATE_NONE;
-	stop_sync = 1;
+	sync_stop_set(state, 1);
+	ip_vs_sync_state -= state;
 	wake_up(&sync_wait);
 	schedule();
 	__set_current_state(TASK_RUNNING);
@@ -797,7 +854,8 @@
 	/* Note: no need to reap the sync thread, because its parent
 	   process is the init process */
 
-	if (stop_sync)
+	if ((state == IP_VS_STATE_MASTER && stop_master_sync) ||
+	    (state == IP_VS_STATE_BACKUP && stop_backup_sync))
 		IP_VS_BUG();
 
 	return 0;
diff -urN linux-2.4.29-rc2/net/ipv4/netfilter/Config.in linux-2.4.29-rc3/net/ipv4/netfilter/Config.in
--- linux-2.4.29-rc2/net/ipv4/netfilter/Config.in	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.29-rc3/net/ipv4/netfilter/Config.in	2005-01-15 10:14:25.340138331 -0800
@@ -66,7 +66,6 @@
           define_tristate CONFIG_IP_NF_NAT_AMANDA $CONFIG_IP_NF_NAT
         fi
       fi
-      bool '    NAT of local connections (READ HELP)' CONFIG_IP_NF_NAT_LOCAL
       if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
         dep_tristate '    Basic SNMP-ALG support (EXPERIMENTAL)' CONFIG_IP_NF_NAT_SNMP_BASIC $CONFIG_IP_NF_NAT
       fi
diff -urN linux-2.4.29-rc2/net/ipv4/netfilter/ip_conntrack_core.c linux-2.4.29-rc3/net/ipv4/netfilter/ip_conntrack_core.c
--- linux-2.4.29-rc2/net/ipv4/netfilter/ip_conntrack_core.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29-rc3/net/ipv4/netfilter/ip_conntrack_core.c	2005-01-15 10:14:25.341138374 -0800
@@ -122,9 +122,9 @@
 }
 
 inline int
-get_tuple(const struct iphdr *iph, size_t len,
-	  struct ip_conntrack_tuple *tuple,
-	  struct ip_conntrack_protocol *protocol)
+ip_ct_get_tuple(const struct iphdr *iph, size_t len,
+                struct ip_conntrack_tuple *tuple,
+                struct ip_conntrack_protocol *protocol)
 {
 	int ret;
 
@@ -546,7 +546,7 @@
 	innerproto = ip_ct_find_proto(inner->protocol);
 	/* Are they talking about one of our connections? */
 	if (inner->ihl * 4 + 8 > datalen
-	    || !get_tuple(inner, datalen, &origtuple, innerproto)) {
+	    || !ip_ct_get_tuple(inner, datalen, &origtuple, innerproto)) {
 		DEBUGP("icmp_error: ! get_tuple p=%u (%u*4+%u dlen=%u)\n",
 		       inner->protocol, inner->ihl, 8,
 		       datalen);
@@ -757,7 +757,7 @@
 
 	IP_NF_ASSERT((skb->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
 
-	if (!get_tuple(skb->nh.iph, skb->len, &tuple, proto))
+	if (!ip_ct_get_tuple(skb->nh.iph, skb->len, &tuple, proto))
 		return NULL;
 
 	/* look for tuple match */
diff -urN linux-2.4.29-rc2/net/ipv4/netfilter/ip_conntrack_standalone.c linux-2.4.29-rc3/net/ipv4/netfilter/ip_conntrack_standalone.c
--- linux-2.4.29-rc2/net/ipv4/netfilter/ip_conntrack_standalone.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29-rc3/net/ipv4/netfilter/ip_conntrack_standalone.c	2005-01-15 10:14:25.341138374 -0800
@@ -468,6 +468,7 @@
 EXPORT_SYMBOL(ip_conntrack_protocol_register);
 EXPORT_SYMBOL(ip_conntrack_protocol_unregister);
 EXPORT_SYMBOL(invert_tuplepr);
+EXPORT_SYMBOL(ip_ct_get_tuple);
 EXPORT_SYMBOL(ip_conntrack_alter_reply);
 EXPORT_SYMBOL(ip_conntrack_destroyed);
 EXPORT_SYMBOL(ip_conntrack_get);
diff -urN linux-2.4.29-rc2/net/ipv4/netfilter/ip_fw_compat_masq.c linux-2.4.29-rc3/net/ipv4/netfilter/ip_fw_compat_masq.c
--- linux-2.4.29-rc2/net/ipv4/netfilter/ip_fw_compat_masq.c	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29-rc3/net/ipv4/netfilter/ip_fw_compat_masq.c	2005-01-15 10:14:25.342138417 -0800
@@ -157,7 +157,7 @@
 	case IPPROTO_UDP:
 		IP_NF_ASSERT(((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
 
-		if (!get_tuple(iph, (*pskb)->len, &tuple, protocol)) {
+		if (!ip_ct_get_tuple(iph, (*pskb)->len, &tuple, protocol)) {
 			if (net_ratelimit())
 				printk("ip_fw_compat_masq: Can't get tuple\n");
 			return NF_ACCEPT;
diff -urN linux-2.4.29-rc2/net/ipv4/netfilter/ip_nat_core.c linux-2.4.29-rc3/net/ipv4/netfilter/ip_nat_core.c
--- linux-2.4.29-rc2/net/ipv4/netfilter/ip_nat_core.c	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29-rc3/net/ipv4/netfilter/ip_nat_core.c	2005-01-15 10:14:25.343138459 -0800
@@ -198,7 +198,6 @@
 		return NULL;
 }
 
-#ifdef CONFIG_IP_NF_NAT_LOCAL
 /* If it's really a local destination manip, it may need to do a
    source manip too. */
 static int
@@ -217,7 +216,6 @@
 	ip_rt_put(rt);
 	return 1;
 }
-#endif
 
 /* Simple way to iterate through all. */
 static inline int fake_cmp(const struct ip_nat_hash *i,
@@ -317,7 +315,6 @@
 			 * do_extra_mangle last time. */
 			*other_ipp = saved_ip;
 
-#ifdef CONFIG_IP_NF_NAT_LOCAL
 			if (hooknum == NF_IP_LOCAL_OUT
 			    && *var_ipp != orig_dstip
 			    && !do_extra_mangle(*var_ipp, other_ipp)) {
@@ -328,7 +325,6 @@
 				 * anyway. */
 				continue;
 			}
-#endif
 
 			/* Count how many others map onto this. */
 			score = count_maps(tuple->src.ip, tuple->dst.ip,
@@ -372,13 +368,11 @@
 		else {
 			/* Only do extra mangle when required (breaks
                            socket binding) */
-#ifdef CONFIG_IP_NF_NAT_LOCAL
 			if (tuple->dst.ip != mr->range[0].min_ip
 			    && hooknum == NF_IP_LOCAL_OUT
 			    && !do_extra_mangle(mr->range[0].min_ip,
 						&tuple->src.ip))
 				return NULL;
-#endif
 			tuple->dst.ip = mr->range[0].min_ip;
 		}
 	}
@@ -501,10 +495,8 @@
 static unsigned int opposite_hook[NF_IP_NUMHOOKS]
 = { [NF_IP_PRE_ROUTING] = NF_IP_POST_ROUTING,
     [NF_IP_POST_ROUTING] = NF_IP_PRE_ROUTING,
-#ifdef CONFIG_IP_NF_NAT_LOCAL
     [NF_IP_LOCAL_OUT] = NF_IP_LOCAL_IN,
     [NF_IP_LOCAL_IN] = NF_IP_LOCAL_OUT,
-#endif
 };
 
 unsigned int
@@ -868,6 +860,23 @@
 	/* not reached */
 }
 
+static inline int tuple_src_equal_dst(const struct ip_conntrack_tuple *t1,
+                                      const struct ip_conntrack_tuple *t2)
+{
+	if (t1->dst.protonum != t2->dst.protonum || t1->src.ip != t2->dst.ip)
+		return 0;
+	if (t1->dst.protonum != IPPROTO_ICMP)
+		return t1->src.u.all == t2->dst.u.all;
+	else {
+		struct ip_conntrack_tuple inv;
+
+		/* ICMP tuples are asymetric */
+		invert_tuplepr(&inv, t1);
+		return inv.src.u.all == t2->src.u.all &&
+		       inv.dst.u.all == t2->dst.u.all;
+	}
+}
+
 unsigned int
 icmp_reply_translation(struct sk_buff *skb,
 		       struct ip_conntrack *conntrack,
@@ -880,6 +889,7 @@
 	size_t datalen = skb->len - ((void *)inner - (void *)iph);
 	unsigned int i;
 	struct ip_nat_info *info = &conntrack->nat.info;
+	struct ip_conntrack_tuple *cttuple, innertuple;
 
 	IP_NF_ASSERT(skb->len >= iph->ihl*4 + sizeof(struct icmphdr));
 	/* Must be RELATED */
@@ -914,6 +924,11 @@
 	   such addresses are not too uncommon, as Alan Cox points
 	   out) */
 
+	if (!ip_ct_get_tuple(inner, datalen, &innertuple,
+	                     ip_ct_find_proto(inner->protocol)))
+		return 0;
+	cttuple = &conntrack->tuplehash[dir].tuple;
+
 	READ_LOCK(&ip_nat_lock);
 	for (i = 0; i < info->num_manips; i++) {
 		DEBUGP("icmp_reply: manip %u dir %s hook %u\n",
@@ -923,35 +938,49 @@
 		if (info->manips[i].direction != dir)
 			continue;
 
-		/* Mapping the inner packet is just like a normal
-		   packet, except it was never src/dst reversed, so
-		   where we would normally apply a dst manip, we apply
-		   a src, and vice versa. */
-		if (info->manips[i].hooknum == hooknum) {
-			DEBUGP("icmp_reply: inner %s -> %u.%u.%u.%u %u\n",
-			       info->manips[i].maniptype == IP_NAT_MANIP_SRC
-			       ? "DST" : "SRC",
-			       NIPQUAD(info->manips[i].manip.ip),
-			       ntohs(info->manips[i].manip.u.udp.port));
-			manip_pkt(inner->protocol, inner,
-				  skb->len - ((void *)inner - (void *)iph),
-				  &info->manips[i].manip,
-				  !info->manips[i].maniptype,
-				  &skb->nfcache);
-			/* Outer packet needs to have IP header NATed like
-	                   it's a reply. */
-
-			/* Use mapping to map outer packet: 0 give no
-                           per-proto mapping */
-			DEBUGP("icmp_reply: outer %s -> %u.%u.%u.%u\n",
-			       info->manips[i].maniptype == IP_NAT_MANIP_SRC
-			       ? "SRC" : "DST",
-			       NIPQUAD(info->manips[i].manip.ip));
-			manip_pkt(0, iph, skb->len,
-				  &info->manips[i].manip,
-				  info->manips[i].maniptype,
-				  &skb->nfcache);
+		/* Mapping the inner packet is just like a normal packet, except
+		 * it was never src/dst reversed, so where we would normally
+		 * apply a dst manip, we apply a src, and vice versa. */
+
+		/* Only true for forwarded packets, locally generated packets
+		 * never hit PRE_ROUTING, we need to apply their PRE_ROUTING
+		 * manips in LOCAL_OUT. */
+		if (hooknum == NF_IP_LOCAL_OUT &&
+		    info->manips[i].hooknum == NF_IP_PRE_ROUTING)
+			hooknum = info->manips[i].hooknum;
+
+		if (info->manips[i].hooknum != hooknum)
+			continue;
+
+		/* ICMP errors may be generated locally for packets that
+		 * don't have all NAT manips applied yet. Verify manips
+		 * have been applied before reversing them */
+		if (info->manips[i].maniptype == IP_NAT_MANIP_SRC) {
+			if (!tuple_src_equal_dst(cttuple, &innertuple))
+				continue;
+		} else {
+			if (!tuple_src_equal_dst(&innertuple, cttuple))
+				continue;
 		}
+
+		DEBUGP("icmp_reply: inner %s -> %u.%u.%u.%u %u\n",
+		       info->manips[i].maniptype == IP_NAT_MANIP_SRC
+		       ? "DST" : "SRC", NIPQUAD(info->manips[i].manip.ip),
+		       ntohs(info->manips[i].manip.u.udp.port));
+		manip_pkt(inner->protocol, inner,
+			  skb->len - ((void *)inner - (void *)iph),
+			  &info->manips[i].manip, !info->manips[i].maniptype,
+			  &skb->nfcache);
+		/* Outer packet needs to have IP header NATed like
+                   it's a reply. */
+
+		/* Use mapping to map outer packet: 0 give no
+                          per-proto mapping */
+		DEBUGP("icmp_reply: outer %s -> %u.%u.%u.%u\n",
+		       info->manips[i].maniptype == IP_NAT_MANIP_SRC
+		       ? "SRC" : "DST", NIPQUAD(info->manips[i].manip.ip));
+		manip_pkt(0, iph, skb->len, &info->manips[i].manip,
+			  info->manips[i].maniptype, &skb->nfcache);
 	}
 	READ_UNLOCK(&ip_nat_lock);
 
diff -urN linux-2.4.29-rc2/net/ipv4/netfilter/ip_nat_rule.c linux-2.4.29-rc3/net/ipv4/netfilter/ip_nat_rule.c
--- linux-2.4.29-rc2/net/ipv4/netfilter/ip_nat_rule.c	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29-rc3/net/ipv4/netfilter/ip_nat_rule.c	2005-01-15 10:14:25.344138502 -0800
@@ -138,12 +138,8 @@
 	struct ip_conntrack *ct;
 	enum ip_conntrack_info ctinfo;
 
-#ifdef CONFIG_IP_NF_NAT_LOCAL
 	IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING
 		     || hooknum == NF_IP_LOCAL_OUT);
-#else
-	IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING);
-#endif
 
 	ct = ip_conntrack_get(*pskb, &ctinfo);
 
@@ -221,13 +217,6 @@
 		return 0;
 	}
 	
-#ifndef CONFIG_IP_NF_NAT_LOCAL
-	if (hook_mask & (1 << NF_IP_LOCAL_OUT)) {
-		DEBUGP("DNAT: CONFIG_IP_NF_NAT_LOCAL not enabled\n");
-		return 0;
-	}
-#endif
-
 	return 1;
 }
 
diff -urN linux-2.4.29-rc2/net/ipv4/netfilter/ip_nat_standalone.c linux-2.4.29-rc3/net/ipv4/netfilter/ip_nat_standalone.c
--- linux-2.4.29-rc2/net/ipv4/netfilter/ip_nat_standalone.c	2004-04-14 06:05:41.000000000 -0700
+++ linux-2.4.29-rc3/net/ipv4/netfilter/ip_nat_standalone.c	2005-01-15 10:14:25.345138545 -0800
@@ -114,16 +114,7 @@
 		WRITE_LOCK(&ip_nat_lock);
 		/* Seen it before?  This can happen for loopback, retrans,
 		   or local packets.. */
-		if (!(info->initialized & (1 << maniptype))
-#ifndef CONFIG_IP_NF_NAT_LOCAL
-		    /* If this session has already been confirmed we must not
-		     * touch it again even if there is no mapping set up.
-		     * Can only happen on local->local traffic with
-		     * CONFIG_IP_NF_NAT_LOCAL disabled.
-		     */
-		    && !(ct->status & IPS_CONFIRMED)
-#endif
-		    ) {
+		if (!(info->initialized & (1 << maniptype))) {
 			unsigned int ret;
 
 			if (ct->master
@@ -132,15 +123,14 @@
 				ret = call_expect(master_ct(ct), pskb, 
 						  hooknum, ct, info);
 			} else {
-#ifdef CONFIG_IP_NF_NAT_LOCAL
 				/* LOCAL_IN hook doesn't have a chain!  */
 				if (hooknum == NF_IP_LOCAL_IN)
 					ret = alloc_null_binding(ct, info,
 								 hooknum);
 				else
-#endif
-				ret = ip_nat_rule_find(pskb, hooknum, in, out,
-						       ct, info);
+					ret = ip_nat_rule_find(pskb, hooknum,
+					                       in, out,
+					                       ct, info);
 			}
 
 			if (ret != NF_ACCEPT) {
@@ -166,6 +156,29 @@
 }
 
 static unsigned int
+ip_nat_in(unsigned int hooknum,
+          struct sk_buff **pskb,
+          const struct net_device *in,
+          const struct net_device *out,
+          int (*okfn)(struct sk_buff *))
+{
+	u_int32_t saddr, daddr;
+	unsigned int ret;
+
+	saddr = (*pskb)->nh.iph->saddr;
+	daddr = (*pskb)->nh.iph->daddr;
+
+	ret = ip_nat_fn(hooknum, pskb, in, out, okfn);
+	if (ret != NF_DROP && ret != NF_STOLEN
+	    && ((*pskb)->nh.iph->saddr != saddr
+	        || (*pskb)->nh.iph->daddr != daddr)) {
+		dst_release((*pskb)->dst);
+		(*pskb)->dst = NULL;
+	}
+	return ret;
+}
+
+static unsigned int
 ip_nat_out(unsigned int hooknum,
 	   struct sk_buff **pskb,
 	   const struct net_device *in,
@@ -197,7 +210,6 @@
 	return ip_nat_fn(hooknum, pskb, in, out, okfn);
 }
 
-#ifdef CONFIG_IP_NF_NAT_LOCAL
 static unsigned int
 ip_nat_local_fn(unsigned int hooknum,
 		struct sk_buff **pskb,
@@ -223,25 +235,21 @@
 		return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP;
 	return ret;
 }
-#endif
 
 /* We must be after connection tracking and before packet filtering. */
 
 /* Before packet filtering, change destination */
 static struct nf_hook_ops ip_nat_in_ops
-= { { NULL, NULL }, ip_nat_fn, PF_INET, NF_IP_PRE_ROUTING, NF_IP_PRI_NAT_DST };
+= { { NULL, NULL }, ip_nat_in, PF_INET, NF_IP_PRE_ROUTING, NF_IP_PRI_NAT_DST };
 /* After packet filtering, change source */
 static struct nf_hook_ops ip_nat_out_ops
 = { { NULL, NULL }, ip_nat_out, PF_INET, NF_IP_POST_ROUTING, NF_IP_PRI_NAT_SRC};
-
-#ifdef CONFIG_IP_NF_NAT_LOCAL
 /* Before packet filtering, change destination */
 static struct nf_hook_ops ip_nat_local_out_ops
 = { { NULL, NULL }, ip_nat_local_fn, PF_INET, NF_IP_LOCAL_OUT, NF_IP_PRI_NAT_DST };
 /* After packet filtering, change source for reply packets of LOCAL_OUT DNAT */
 static struct nf_hook_ops ip_nat_local_in_ops
 = { { NULL, NULL }, ip_nat_fn, PF_INET, NF_IP_LOCAL_IN, NF_IP_PRI_NAT_SRC };
-#endif
 
 /* Protocol registration. */
 int ip_nat_protocol_register(struct ip_nat_protocol *proto)
@@ -306,7 +314,6 @@
 		printk("ip_nat_init: can't register out hook.\n");
 		goto cleanup_inops;
 	}
-#ifdef CONFIG_IP_NF_NAT_LOCAL
 	ret = nf_register_hook(&ip_nat_local_out_ops);
 	if (ret < 0) {
 		printk("ip_nat_init: can't register local out hook.\n");
@@ -317,16 +324,13 @@
 		printk("ip_nat_init: can't register local in hook.\n");
 		goto cleanup_localoutops;
 	}
-#endif
 	return ret;
 
  cleanup:
-#ifdef CONFIG_IP_NF_NAT_LOCAL
 	nf_unregister_hook(&ip_nat_local_in_ops);
  cleanup_localoutops:
 	nf_unregister_hook(&ip_nat_local_out_ops);
  cleanup_outops:
-#endif
 	nf_unregister_hook(&ip_nat_out_ops);
  cleanup_inops:
 	nf_unregister_hook(&ip_nat_in_ops);
diff -urN linux-2.4.29-rc2/net/ipv4/netfilter/ip_tables.c linux-2.4.29-rc3/net/ipv4/netfilter/ip_tables.c
--- linux-2.4.29-rc2/net/ipv4/netfilter/ip_tables.c	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29-rc3/net/ipv4/netfilter/ip_tables.c	2005-01-15 10:14:25.346138587 -0800
@@ -1274,7 +1274,7 @@
 			       sizeof(info.underflow));
 			info.num_entries = t->private->number;
 			info.size = t->private->size;
-			strcpy(info.name, name);
+			memcpy(info.name, name, sizeof(info.name));
 
 			if (copy_to_user(user, &info, *len) != 0)
 				ret = -EFAULT;
diff -urN linux-2.4.29-rc2/net/ipv4/netfilter/ipt_MASQUERADE.c linux-2.4.29-rc3/net/ipv4/netfilter/ipt_MASQUERADE.c
--- linux-2.4.29-rc2/net/ipv4/netfilter/ipt_MASQUERADE.c	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29-rc3/net/ipv4/netfilter/ipt_MASQUERADE.c	2005-01-15 10:14:25.346138587 -0800
@@ -125,35 +125,58 @@
 }
 
 static inline int
-device_cmp(const struct ip_conntrack *i, void *_ina)
+device_cmp(const struct ip_conntrack *i, void *ifindex)
 {
-	int ret = 0;
-	struct in_ifaddr *ina = _ina;
+	int ret;
 
 	READ_LOCK(&masq_lock);
-	/* If it's masquerading out this interface with a different address,
-	 * or we don't know the new address of this interface. */
-	if (i->nat.masq_index == ina->ifa_dev->dev->ifindex
-	    && i->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip != ina->ifa_address)
-		ret = 1;
+	ret = (i->nat.masq_index == (int)(long)ifindex);
 	READ_UNLOCK(&masq_lock);
 
 	return ret;
 }
 
+static int masq_device_event(struct notifier_block *this,
+			     unsigned long event,
+			     void *ptr)
+{
+	struct net_device *dev = ptr;
+
+	if (event == NETDEV_DOWN) {
+		/* Device was downed.  Search entire table for
+		   conntracks which were associated with that device,
+		   and forget them. */
+		IP_NF_ASSERT(dev->ifindex != 0);
+ 
+		ip_ct_selective_cleanup(device_cmp, (void *)(long)dev->ifindex);
+	}
+
+	return NOTIFY_DONE;
+}
+
+
 static int masq_inet_event(struct notifier_block *this,
 			   unsigned long event,
 			   void *ptr)
 {
-	/* For some configurations, interfaces often come back with
-	 * the same address.  If not, clean up old conntrack
-	 * entries. */
-	if (event == NETDEV_UP)
-		ip_ct_selective_cleanup(device_cmp, ptr);
+	struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev;
+
+	if (event == NETDEV_DOWN) {
+		/* IP address was deleted.  Search entire table for
+		   conntracks which were associated with that device,
+		   and forget them. */
+		IP_NF_ASSERT(dev->ifindex != 0);
+
+		ip_ct_selective_cleanup(device_cmp, (void *)(long)dev->ifindex);
+	}
 
 	return NOTIFY_DONE;
 }
 
+static struct notifier_block masq_dev_notifier = {
+	.notifier_call  = masq_device_event,
+};
+
 static struct notifier_block masq_inet_notifier = {
 	.notifier_call = masq_inet_event
 };
@@ -168,9 +191,12 @@
 
 	ret = ipt_register_target(&masquerade);
 
-	if (ret == 0)
+	if (ret == 0) {
+		/* Register for device down reports */
+		register_netdevice_notifier(&masq_dev_notifier);
 		/* Register IP address change reports */
 		register_inetaddr_notifier(&masq_inet_notifier);
+	}
 
 	return ret;
 }
@@ -178,6 +204,7 @@
 static void __exit fini(void)
 {
 	ipt_unregister_target(&masquerade);
+	unregister_netdevice_notifier(&masq_dev_notifier);
 	unregister_inetaddr_notifier(&masq_inet_notifier);	
 }
 
diff -urN linux-2.4.29-rc2/net/ipv4/netfilter/ipt_REJECT.c linux-2.4.29-rc3/net/ipv4/netfilter/ipt_REJECT.c
--- linux-2.4.29-rc2/net/ipv4/netfilter/ipt_REJECT.c	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29-rc3/net/ipv4/netfilter/ipt_REJECT.c	2005-01-15 10:14:25.347138630 -0800
@@ -22,18 +22,6 @@
 #define DEBUGP(format, args...)
 #endif
 
-/* If the original packet is part of a connection, but the connection
-   is not confirmed, our manufactured reply will not be associated
-   with it, so we need to do this manually. */
-static void connection_attach(struct sk_buff *new_skb, struct nf_ct_info *nfct)
-{
-	void (*attach)(struct sk_buff *, struct nf_ct_info *);
-
-	/* Avoid module unload race with ip_ct_attach being NULLed out */
-	if (nfct && (attach = ip_ct_attach) != NULL)
-		attach(new_skb, nfct);
-}
-
 static inline struct rtable *route_reverse(struct sk_buff *skb, int hook)
 {
 	struct iphdr *iph = skb->nh.iph;
@@ -187,7 +175,7 @@
 	if (nskb->len > nskb->dst->pmtu)
 		goto free_nskb;
 
-	connection_attach(nskb, oldskb->nfct);
+	nf_ct_attach(nskb, oldskb);
 
 	NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
 		ip_finish_output);
@@ -323,7 +311,7 @@
 	icmph->checksum = ip_compute_csum((unsigned char *)icmph,
 					  length - sizeof(struct iphdr));
 
-	connection_attach(nskb, skb_in->nfct);
+	nf_ct_attach(nskb, skb_in);
 
 	NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
 		ip_finish_output);
diff -urN linux-2.4.29-rc2/net/ipv4/raw.c linux-2.4.29-rc3/net/ipv4/raw.c
--- linux-2.4.29-rc2/net/ipv4/raw.c	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.29-rc3/net/ipv4/raw.c	2005-01-15 10:14:25.348138673 -0800
@@ -266,7 +266,7 @@
  */
   
 static int raw_getfrag(const void *p, char *to, unsigned int offset,
-			unsigned int fraglen)
+		       unsigned int fraglen, struct sk_buff *skb)
 {
 	struct rawfakehdr *rfh = (struct rawfakehdr *) p;
 	return memcpy_fromiovecend(to, rfh->iov, offset, fraglen);
@@ -277,7 +277,7 @@
  */
  
 static int raw_getrawfrag(const void *p, char *to, unsigned int offset,
-				unsigned int fraglen)
+				unsigned int fraglen, struct sk_buff *skb)
 {
 	struct rawfakehdr *rfh = (struct rawfakehdr *) p;
 
diff -urN linux-2.4.29-rc2/net/ipv4/udp.c linux-2.4.29-rc3/net/ipv4/udp.c
--- linux-2.4.29-rc2/net/ipv4/udp.c	2005-01-15 10:14:21.253963924 -0800
+++ linux-2.4.29-rc3/net/ipv4/udp.c	2005-01-15 10:14:25.352138843 -0800
@@ -389,7 +389,8 @@
  *	Copy and checksum a UDP packet from user space into a buffer.
  */
  
-static int udp_getfrag(const void *p, char * to, unsigned int offset, unsigned int fraglen) 
+static int udp_getfrag(const void *p, char * to, unsigned int offset,
+                       unsigned int fraglen, struct sk_buff *skb)
 {
 	struct udpfakehdr *ufh = (struct udpfakehdr *)p;
 	if (offset==0) {
@@ -416,7 +417,8 @@
  *	Copy a UDP packet from user space into a buffer without checksumming.
  */
  
-static int udp_getfrag_nosum(const void *p, char * to, unsigned int offset, unsigned int fraglen) 
+static int udp_getfrag_nosum(const void *p, char * to, unsigned int offset,
+                             unsigned int fraglen, struct sk_buff *skb) 
 {
 	struct udpfakehdr *ufh = (struct udpfakehdr *)p;
 
diff -urN linux-2.4.29-rc2/net/ipv6/netfilter/ip6_tables.c linux-2.4.29-rc3/net/ipv6/netfilter/ip6_tables.c
--- linux-2.4.29-rc2/net/ipv6/netfilter/ip6_tables.c	2004-08-07 16:26:07.000000000 -0700
+++ linux-2.4.29-rc3/net/ipv6/netfilter/ip6_tables.c	2005-01-15 10:14:25.357139057 -0800
@@ -149,14 +149,15 @@
 /* Returns whether matches rule or not. */
 static inline int
 ip6_packet_match(const struct sk_buff *skb,
-		 const struct ipv6hdr *ipv6,
 		 const char *indev,
 		 const char *outdev,
 		 const struct ip6t_ip6 *ip6info,
-		 int isfrag)
+		 unsigned int *protoff,
+		 int *fragoff)
 {
 	size_t i;
 	unsigned long ret;
+	const struct ipv6hdr *ipv6 = skb->nh.ipv6h;
 
 #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))
 
@@ -210,6 +211,7 @@
 		struct ipv6_opt_hdr *hdrptr;
 		u_int16_t ptr;		/* Header offset in skb */
 		u_int16_t hdrlen;	/* Header */
+		u_int16_t foff = 0;
 
 		ptr = IPV6_HDR_LEN;
 
@@ -229,6 +231,16 @@
 
 			/* Size calculation */
 	                if (currenthdr == IPPROTO_FRAGMENT) {
+				unsigned int foff_off;
+
+				foff_off = ptr + offsetof(struct frag_hdr,
+							  frag_off);
+				if (skb->len - foff_off < sizeof(foff))
+					return 0;
+
+				foff = ntohs(*(u_int16_t *)(skb->data
+							    + foff_off))
+				       & ~0x7;
 	                        hdrlen = 8;
 	                } else if (currenthdr == IPPROTO_AH)
 	                        hdrlen = (hdrptr->hdrlen+2)<<2;
@@ -240,8 +252,16 @@
 			/* ptr is too large */
 	                if ( ptr > skb->len ) 
 				return 0;
+			if (foff) {
+				if (ip6t_ext_hdr(currenthdr))
+					return 0;
+				break;
+			}
 		}
 
+		*protoff = ptr;
+		*fragoff = foff;
+
 		/* currenthdr contains the protocol header */
 
 		dprintf("Packet protocol %hi ?= %s%hi.\n",
@@ -329,10 +349,8 @@
 	      void *userdata)
 {
 	static const char nulldevname[IFNAMSIZ] = { 0 };
-	u_int16_t offset = 0;
-	struct ipv6hdr *ipv6;
-	void *protohdr;
-	u_int16_t datalen;
+	int offset = 0;
+	unsigned int protoff = 0;
 	int hotdrop = 0;
 	/* Initializing verdict to NF_DROP keeps gcc happy. */
 	unsigned int verdict = NF_DROP;
@@ -341,9 +359,6 @@
 	struct ip6t_entry *e, *back;
 
 	/* Initialization */
-	ipv6 = (*pskb)->nh.ipv6h;
-	protohdr = (u_int32_t *)((char *)ipv6 + IPV6_HDR_LEN);
-	datalen = (*pskb)->len - IPV6_HDR_LEN;
 	indev = in ? in->name : nulldevname;
 	outdev = out ? out->name : nulldevname;
 
@@ -381,17 +396,20 @@
 		IP_NF_ASSERT(e);
 		IP_NF_ASSERT(back);
 		(*pskb)->nfcache |= e->nfcache;
-		if (ip6_packet_match(*pskb, ipv6, indev, outdev, 
-			&e->ipv6, offset)) {
+		if (ip6_packet_match(*pskb, indev, outdev, &e->ipv6,
+				     &protoff, &offset)) {
 			struct ip6t_entry_target *t;
 
 			if (IP6T_MATCH_ITERATE(e, do_match,
 					       *pskb, in, out,
-					       offset, protohdr,
-					       datalen, &hotdrop) != 0)
+					       offset,
+					       (void *)((*pskb)->data
+							+ protoff),
+					       (*pskb)->len - protoff,
+					       &hotdrop) != 0)
 				goto no_match;
 
-			ADD_COUNTER(e->counters, ntohs(ipv6->payload_len) + IPV6_HDR_LEN, 1);
+			ADD_COUNTER(e->counters, ntohs((*pskb)->nh.ipv6h->payload_len) + IPV6_HDR_LEN, 1);
 
 			t = ip6t_get_target(e);
 			IP_NF_ASSERT(t->u.kernel.target);
@@ -447,11 +465,6 @@
 				((struct ip6t_entry *)table_base)->comefrom
 					= 0x57acc001;
 #endif
-				/* Target might have changed stuff. */
-				ipv6 = (*pskb)->nh.ipv6h;
-				protohdr = (u_int32_t *)((void *)ipv6 + IPV6_HDR_LEN);
-				datalen = (*pskb)->len - IPV6_HDR_LEN;
-
 				if (verdict == IP6T_CONTINUE)
 					e = (void *)e + e->next_offset;
 				else
@@ -1343,7 +1356,7 @@
 			       sizeof(info.underflow));
 			info.num_entries = t->private->number;
 			info.size = t->private->size;
-			strcpy(info.name, name);
+			memcpy(info.name, name, sizeof(info.name));
 
 			if (copy_to_user(user, &info, *len) != 0)
 				ret = -EFAULT;
@@ -1567,10 +1580,8 @@
 	  u_int16_t datalen,
 	  int *hotdrop)
 {
-	const struct tcphdr *tcp;
+	const struct tcphdr *tcp = hdr;
 	const struct ip6t_tcp *tcpinfo = matchinfo;
-	int tcpoff;
-	u8 nexthdr = skb->nh.ipv6h->nexthdr;
 
 	/* To quote Alan:
 
@@ -1591,24 +1602,6 @@
 		return 0;
 	}
 
-	tcpoff = (u8*)(skb->nh.ipv6h + 1) - skb->data;
-	tcpoff = ipv6_skip_exthdr(skb, tcpoff, &nexthdr, skb->len - tcpoff);
-	if (tcpoff < 0 || tcpoff > skb->len) {
-		duprintf("tcp_match: cannot skip exthdr. Dropping.\n");
-		*hotdrop = 1;
-		return 0;
-	} else if (nexthdr == IPPROTO_FRAGMENT)
-		return 0;
-	else if (nexthdr != IPPROTO_TCP ||
-		 skb->len - tcpoff < sizeof(struct tcphdr)) {
-		/* cannot be occured */
-		duprintf("tcp_match: cannot get TCP header. Dropping.\n");
-		*hotdrop = 1;
-		return 0;
-	}
-
-	tcp = (struct tcphdr *)(skb->data + tcpoff);
-
 	/* FIXME: Try tcp doff >> packet len against various stacks --RR */
 
 #define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg))
@@ -1659,10 +1652,8 @@
 	  u_int16_t datalen,
 	  int *hotdrop)
 {
-	const struct udphdr *udp;
+	const struct udphdr *udp = hdr;
 	const struct ip6t_udp *udpinfo = matchinfo;
-	int udpoff;
-	u8 nexthdr = skb->nh.ipv6h->nexthdr;
 
 	if (offset == 0 && datalen < sizeof(struct udphdr)) {
 		/* We've been asked to examine this packet, and we
@@ -1672,23 +1663,6 @@
 		return 0;
 	}
 
-	udpoff = (u8*)(skb->nh.ipv6h + 1) - skb->data;
-	udpoff = ipv6_skip_exthdr(skb, udpoff, &nexthdr, skb->len - udpoff);
-	if (udpoff < 0 || udpoff > skb->len) {
-		duprintf("udp_match: cannot skip exthdr. Dropping.\n");
-		*hotdrop = 1;
-		return 0;
-	} else if (nexthdr == IPPROTO_FRAGMENT)
-		return 0;
-	else if (nexthdr != IPPROTO_UDP ||
-		 skb->len - udpoff < sizeof(struct udphdr)) {
-		duprintf("udp_match: cannot get UDP header. Dropping.\n");
-		*hotdrop = 1;
-		return 0;
-	}
-
-	udp = (struct udphdr *)(skb->data + udpoff);
-
 	/* Must not be a fragment. */
 	return !offset
 		&& port_match(udpinfo->spts[0], udpinfo->spts[1],
diff -urN linux-2.4.29-rc2/net/ipv6/netfilter/ip6t_LOG.c linux-2.4.29-rc3/net/ipv6/netfilter/ip6t_LOG.c
--- linux-2.4.29-rc2/net/ipv6/netfilter/ip6t_LOG.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29-rc3/net/ipv6/netfilter/ip6t_LOG.c	2005-01-15 10:14:25.358139100 -0800
@@ -35,54 +35,40 @@
 	ntohs((addr).s6_addr16[6]), \
 	ntohs((addr).s6_addr16[7])
 
-struct esphdr {
-	__u32   spi;
-}; /* FIXME evil kludge */
-        
-/* Use lock to serialize, so printks don't overlap */
-static spinlock_t log_lock = SPIN_LOCK_UNLOCKED;
+/* FIXME evil kludge */
 
-/* takes in current header and pointer to the header */
-/* if another header exists, sets hdrptr to the next header
-   and returns the new header value, else returns 0 */
-static u_int8_t ip6_nexthdr(u_int8_t currenthdr, u_int8_t **hdrptr)
-{
-	u_int8_t hdrlen, nexthdr = 0;
+struct ahhdr {
+	__u8  nexthdr;
+	__u8  hdrlen;
+	__u16 reserved;
+	__u32 spi;
+	__u32 seq_no;
+};
 
-	switch(currenthdr){
-		case IPPROTO_AH:
-		/* whoever decided to do the length of AUTH for ipv6
-		in 32bit units unlike other headers should be beaten...
-		repeatedly...with a large stick...no, an even LARGER
-		stick...no, you're still not thinking big enough */
-			nexthdr = **hdrptr;
-			hdrlen = (*hdrptr)[1] * 4 + 8;
-			*hdrptr = *hdrptr + hdrlen;
-			break;
-		/*stupid rfc2402 */
-		case IPPROTO_DSTOPTS:
-		case IPPROTO_ROUTING:
-		case IPPROTO_HOPOPTS:
-			nexthdr = **hdrptr;
-			hdrlen = (*hdrptr)[1] * 8 + 8;
-			*hdrptr = *hdrptr + hdrlen;
-			break;
-		case IPPROTO_FRAGMENT:
-			nexthdr = **hdrptr;
-			*hdrptr = *hdrptr + 8;
-			break;
-	}	
-	return nexthdr;
+struct esphdr {
+	__u32 spi;
+	__u32 seq_no;
+};
 
-}
+/* Use lock to serialize, so printks don't overlap */
+static spinlock_t log_lock = SPIN_LOCK_UNLOCKED;
 
 /* One level of recursion won't kill us */
 static void dump_packet(const struct ip6t_log_info *info,
-			struct ipv6hdr *ipv6h, int recurse)
+			const struct sk_buff *skb, unsigned int ip6hoff,
+			int recurse)
 {
-	u_int8_t currenthdr = ipv6h->nexthdr;
-	u_int8_t *hdrptr;
+	u_int8_t currenthdr;
 	int fragment;
+	struct ipv6hdr *ipv6h;
+	unsigned int ptr;
+	unsigned int hdrlen = 0;
+
+	if (skb->len - ip6hoff < sizeof(*ipv6h)) {
+		printk("TRUNCATED");
+		return;
+	}
+	ipv6h = (struct ipv6hdr *)(skb->data + ip6hoff);
 
 	/* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000" */
 	printk("SRC=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ipv6h->saddr));
@@ -96,60 +82,131 @@
 	       (ntohl(*(u_int32_t *)ipv6h) & 0x000fffff));
 
 	fragment = 0;
-	hdrptr = (u_int8_t *)(ipv6h + 1);
-	while (currenthdr) {
-		if ((currenthdr == IPPROTO_TCP) ||
-		    (currenthdr == IPPROTO_UDP) ||
-		    (currenthdr == IPPROTO_ICMPV6))
-			break;
+	ptr = ip6hoff + sizeof(struct ipv6hdr);
+	currenthdr = ipv6h->nexthdr;
+	while (currenthdr != NEXTHDR_NONE && ip6t_ext_hdr(currenthdr)) {
+		struct ipv6_opt_hdr *hdr;
+
+		if (skb->len - ptr < sizeof(*hdr)) {
+			printk("TRUNCATED");
+			return;
+		}
+		hdr = (struct ipv6_opt_hdr *)(skb->data + ptr);
+
 		/* Max length: 48 "OPT (...) " */
-		printk("OPT ( ");
+		if (info->logflags & IP6T_LOG_IPOPT)
+			printk("OPT ( ");
+
 		switch (currenthdr) {
 		case IPPROTO_FRAGMENT: {
-			struct frag_hdr *fhdr = (struct frag_hdr *)hdrptr;
+			struct frag_hdr *fhdr;
 
-			/* Max length: 11 "FRAG:65535 " */
-			printk("FRAG:%u ", ntohs(fhdr->frag_off) & 0xFFF8);
+			printk("FRAG:");
+			if (skb->len - ptr < sizeof(*fhdr)) {
+				printk("TRUNCATED ");
+				return;
+			}
+			fhdr = (struct frag_hdr *)(skb->data + ptr);
+
+			/* Max length: 6 "65535 " */
+			printk("%u ", ntohs(fhdr->frag_off) & 0xFFF8);
 
 			/* Max length: 11 "INCOMPLETE " */
 			if (fhdr->frag_off & htons(0x0001))
 				printk("INCOMPLETE ");
 
-			printk("ID:%08x ", fhdr->identification);
+			printk("ID:%08x ", ntohl(fhdr->identification));
 
 			if (ntohs(fhdr->frag_off) & 0xFFF8)
 				fragment = 1;
 
+			hdrlen = 8;
+
 			break;
 		}
 		case IPPROTO_DSTOPTS:
 		case IPPROTO_ROUTING:
 		case IPPROTO_HOPOPTS:
+			if (fragment) {
+				if (info->logflags & IP6T_LOG_IPOPT)
+					printk(")");
+				return;
+			}
+			hdrlen = ipv6_optlen(hdr);
 			break;
 		/* Max Length */
 		case IPPROTO_AH:
+			if (info->logflags & IP6T_LOG_IPOPT) {
+				struct ahhdr *ah;
+
+				/* Max length: 3 "AH " */
+				printk("AH ");
+
+				if (fragment) {
+					printk(")");
+					return;
+				}
+
+				if (skb->len - ptr < sizeof(*ah)) {
+					/*
+					 * Max length: 26 "INCOMPLETE [65535 	
+					 *  bytes] )"
+					 */
+					printk("INCOMPLETE [%u bytes] )",
+					       skb->len - ptr);
+					return;
+				}
+				ah = (struct ahhdr *)(skb->data + ptr);
+
+				/* Length: 15 "SPI=0xF1234567 */
+				printk("SPI=0x%x ", ntohl(ah->spi));
+
+			}
+
+			hdrlen = (hdr->hdrlen+2)<<2;
+			break;
 		case IPPROTO_ESP:
 			if (info->logflags & IP6T_LOG_IPOPT) {
-				struct esphdr *esph = (struct esphdr *)hdrptr;
-				int esp = (currenthdr == IPPROTO_ESP);
+				struct esphdr *esph;
 
 				/* Max length: 4 "ESP " */
-				printk("%s ",esp ? "ESP" : "AH");
+				printk("ESP ");
+
+				if (fragment) {
+					printk(")");
+					return;
+				}
+
+				/*
+				 * Max length: 26 "INCOMPLETE [65535 bytes] )"
+				 */
+				if (skb->len - ptr < sizeof(*esph)) {
+					printk("INCOMPLETE [%u bytes] )",
+					       skb->len - ptr);
+					return;
+				}
+				esph = (struct esphdr *)(skb->data + ptr);
+
+				/* Length: 16 "SPI=0xF1234567 )" */
+				printk("SPI=0x%x )", ntohl(esph->spi) );
 
-				/* Length: 15 "SPI=0xF1234567 " */
-				printk("SPI=0x%x ", ntohl(esph->spi) );
-				break;
 			}
+			return;
 		default:
-			break;
+			/* Max length: 20 "Unknown Ext Hdr 255" */
+			printk("Unknown Ext Hdr %u", currenthdr);
+			return;
 		}
-		printk(") ");
-		currenthdr = ip6_nexthdr(currenthdr, &hdrptr);
+		if (info->logflags & IP6T_LOG_IPOPT)
+			printk(") ");
+
+		currenthdr = hdr->nexthdr;
+		ptr += hdrlen;
 	}
 
 	switch (currenthdr) {
 	case IPPROTO_TCP: {
-		struct tcphdr *tcph = (struct tcphdr *)hdrptr;
+		struct tcphdr *tcph;
 
 		/* Max length: 10 "PROTO=TCP " */
 		printk("PROTO=TCP ");
@@ -157,6 +214,13 @@
 		if (fragment)
 			break;
 
+		/* Max length: 25 "INCOMPLETE [65535 bytes] " */
+		if (skb->len - ptr < sizeof(*tcph)) {
+			printk("INCOMPLETE [%u bytes] ", skb->len - ptr);
+			return;
+		}
+		tcph = (struct tcphdr *)(skb->data + ptr);
+
 		/* Max length: 20 "SPT=65535 DPT=65535 " */
 		printk("SPT=%u DPT=%u ",
 		       ntohs(tcph->source), ntohs(tcph->dest));
@@ -166,7 +230,7 @@
 			       ntohl(tcph->seq), ntohl(tcph->ack_seq));
 		/* Max length: 13 "WINDOW=65535 " */
 		printk("WINDOW=%u ", ntohs(tcph->window));
-		/* Max length: 9 "RES=0x3F " */
+		/* Max length: 9 "RES=0x3C " */
 		printk("RES=0x%02x ", (u_int8_t)(ntohl(tcp_flag_word(tcph) & TCP_RESERVED_BITS) >> 22));
 		/* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */
 		if (tcph->cwr)
@@ -189,19 +253,29 @@
 		printk("URGP=%u ", ntohs(tcph->urg_ptr));
 
 		if ((info->logflags & IP6T_LOG_TCPOPT)
-		    && tcph->doff * 4 != sizeof(struct tcphdr)) {
+		    && tcph->doff * 4 > sizeof(struct tcphdr)) {
+			u_int8_t *op;
 			unsigned int i;
+			unsigned int optsize = tcph->doff * 4
+					       - sizeof(struct tcphdr);
+
+			if (skb->len - ptr - sizeof(struct tcphdr) < optsize) {
+				printk("OPT (TRUNCATED)");
+				return;
+			}
+			op = (u_int8_t *)(skb->data + ptr
+					  + sizeof(struct tcphdr));
 
 			/* Max length: 127 "OPT (" 15*4*2chars ") " */
 			printk("OPT (");
-			for (i =sizeof(struct tcphdr); i < tcph->doff * 4; i++)
-				printk("%02X", ((u_int8_t *)tcph)[i]);
+			for (i =0; i < optsize; i++)
+				printk("%02X", op[i]);
 			printk(") ");
 		}
 		break;
 	}
 	case IPPROTO_UDP: {
-		struct udphdr *udph = (struct udphdr *)hdrptr;
+		struct udphdr *udph;
 
 		/* Max length: 10 "PROTO=UDP " */
 		printk("PROTO=UDP ");
@@ -209,6 +283,13 @@
 		if (fragment)
 			break;
 
+		/* Max length: 25 "INCOMPLETE [65535 bytes] " */
+		if (skb->len - ptr < sizeof(*udph)) {
+			printk("INCOMPLETE [%u bytes] ", skb->len - ptr);
+			return;
+		}
+		udph = (struct udphdr *)(skb->data + ptr);
+
 		/* Max length: 20 "SPT=65535 DPT=65535 " */
 		printk("SPT=%u DPT=%u LEN=%u ",
 		       ntohs(udph->source), ntohs(udph->dest),
@@ -216,7 +297,7 @@
 		break;
 	}
 	case IPPROTO_ICMPV6: {
-		struct icmp6hdr *icmp6h = (struct icmp6hdr *)hdrptr;
+		struct icmp6hdr *icmp6h;
 
 		/* Max length: 13 "PROTO=ICMPv6 " */
 		printk("PROTO=ICMPv6 ");
@@ -224,6 +305,13 @@
 		if (fragment)
 			break;
 
+		/* Max length: 25 "INCOMPLETE [65535 bytes] " */
+		if (skb->len - ptr < sizeof(*icmp6h)) {
+			printk("INCOMPLETE [%u bytes] ", skb->len - ptr);
+			return;
+		}
+		icmp6h = (struct icmp6hdr *)(skb->data + ptr);
+
 		/* Max length: 18 "TYPE=255 CODE=255 " */
 		printk("TYPE=%u CODE=%u ", icmp6h->icmp6_type, icmp6h->icmp6_code);
 
@@ -250,7 +338,8 @@
 			/* Max length: 3+maxlen */
 			if (recurse) {
 				printk("[");
-				dump_packet(info, (struct ipv6hdr *)(icmp6h + 1), 0);
+				dump_packet(info, skb, ptr + sizeof(*icmp6h),
+					    0);
 				printk("] ");
 			}
 
@@ -260,7 +349,7 @@
 		}
 		break;
 	}
-	/* Max length: 10 "PROTO 255 " */
+	/* Max length: 10 "PROTO=255 " */
 	default:
 		printk("PROTO=%u ", currenthdr);
 	}
@@ -326,7 +415,8 @@
 			printk(" ");
 	}
 
-	dump_packet(loginfo, ipv6h, 1);
+	dump_packet(loginfo, (*pskb), (u8*)(*pskb)->nh.ipv6h - (*pskb)->data,
+		    1);
 	printk("\n");
 	spin_unlock_bh(&log_lock);
 
diff -urN linux-2.4.29-rc2/net/ipv6/netfilter/ip6t_dst.c linux-2.4.29-rc3/net/ipv6/netfilter/ip6t_dst.c
--- linux-2.4.29-rc2/net/ipv6/netfilter/ip6t_dst.c	2003-06-13 07:51:39.000000000 -0700
+++ linux-2.4.29-rc3/net/ipv6/netfilter/ip6t_dst.c	2005-01-15 10:14:25.359139142 -0800
@@ -11,8 +11,6 @@
 #include <linux/netfilter_ipv6/ip6_tables.h>
 #include <linux/netfilter_ipv6/ip6t_opts.h>
 
-#define LOW(n)		(n & 0x00FF)
-
 #define HOPBYHOP	0
 
 EXPORT_NO_SYMBOLS;
@@ -40,8 +38,8 @@
  *  	0	-> invariant
  *  	1	-> can change the routing
  *  (Type & 0x1F) Type
- *      0	-> PAD0 (only 1 byte!)
- *      1	-> PAD1 LENGTH info (total length = length + 2)
+ *      0	-> Pad1 (only 1 byte!)
+ *      1	-> PadN LENGTH info (total length = length + 2)
  *      C0 | 2	-> JUMBO 4 x x x x ( xxxx > 64k )
  *      5	-> RTALERT 2 x x
  */
@@ -64,7 +62,8 @@
        unsigned int ptr;
        unsigned int hdrlen = 0;
        unsigned int ret = 0;
-       u_int16_t *optdesc = NULL;
+       u8 *opttype = NULL;
+       unsigned int optlen;
        
        /* type of the 1st exthdr */
        nexthdr = skb->nh.ipv6h->nexthdr;
@@ -91,7 +90,7 @@
                      break;
               }
 
-              hdr=(void *)(skb->data)+ptr;
+	      hdr = (void *)(skb->data + ptr);
 
               /* Calculate the header length */
                 if (nexthdr == NEXTHDR_FRAGMENT) {
@@ -153,7 +152,7 @@
        		return 0;
        }
 
-       optsh=(void *)(skb->data)+ptr;
+       optsh = (void *)(skb->data + ptr);
 
        DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, optsh->hdrlen);
 
@@ -169,7 +168,6 @@
                            ((optinfo->hdrlen == hdrlen) ^
                            !!(optinfo->invflags & IP6T_OPTS_INV_LEN)));
 
-       temp = len = 0;
        ptr += 2;
        hdrlen -= 2;
        if ( !(optinfo->flags & IP6T_OPTS_OPTS) ){
@@ -180,48 +178,52 @@
 		DEBUGP("Strict ");
 		DEBUGP("#%d ",optinfo->optsnr);
 		for(temp=0; temp<optinfo->optsnr; temp++){
-			optdesc = (void *)(skb->data)+ptr;
+			/* type field exists ? */
+			if (ptr > skb->len - 1 || hdrlen < 1)
+				break;
+			opttype = (void *)(skb->data + ptr);
+
 			/* Type check */
-			if ( (unsigned char)*optdesc != 
-				(optinfo->opts[temp] & 0xFF00)>>8 ){
+			if (*opttype != (optinfo->opts[temp] & 0xFF00)>>8){
 				DEBUGP("Tbad %02X %02X\n",
-						(unsigned char)*optdesc,
-						(optinfo->opts[temp] &
-						 0xFF00)>>8);
+				       *opttype,
+				       (optinfo->opts[temp] & 0xFF00)>>8);
 				return 0;
 			} else {
 				DEBUGP("Tok ");
 			}
 			/* Length check */
-			if (((optinfo->opts[temp] & 0x00FF) != 0xFF) &&
-				(unsigned char)*optdesc != 0){
-				if ( ntohs((u16)*optdesc) != 
-						optinfo->opts[temp] ){
-					DEBUGP("Lbad %02X %04X %04X\n",
-							(unsigned char)*optdesc,
-							ntohs((u16)*optdesc),
-							optinfo->opts[temp]);
+			if (*opttype) {
+				u16 spec_len;
+
+				/* length field exists ? */
+				if (ptr > skb->len - 2 || hdrlen < 2)
+					break;
+				optlen = *((u8 *)(skb->data + ptr + 1));
+				spec_len = optinfo->opts[temp] & 0x00FF;
+
+				if (spec_len != 0x00FF && spec_len != optlen) {
+					DEBUGP("Lbad %02X %04X\n", optlen,
+					       spec_len);
 					return 0;
-				} else {
-					DEBUGP("Lok ");
 				}
-			}
-			/* Step to the next */
-			if ((unsigned char)*optdesc == 0){
-				DEBUGP("PAD0 \n");
-				ptr++;
-				hdrlen--;
+				DEBUGP("Lok ");
+				optlen += 2;
 			} else {
-				ptr += LOW(ntohs(*optdesc));
-				hdrlen -= LOW(ntohs(*optdesc));
-				DEBUGP("len%04X \n", 
-					LOW(ntohs(*optdesc)));
+				DEBUGP("Pad1\n");
+				optlen = 1;
 			}
-			if (ptr > skb->len || ( !hdrlen && 
-				(temp != optinfo->optsnr - 1))) {
+
+			/* Step to the next */
+			DEBUGP("len%04X \n", optlen);
+
+			if ((ptr > skb->len - optlen || hdrlen < optlen) &&
+			    (temp < optinfo->optsnr - 1)) {
 				DEBUGP("new pointer is too large! \n");
 				break;
 			}
+			ptr += optlen;
+			hdrlen -= optlen;
 		}
 		if (temp == optinfo->optsnr)
 			return ret;
diff -urN linux-2.4.29-rc2/net/ipv6/netfilter/ip6t_esp.c linux-2.4.29-rc3/net/ipv6/netfilter/ip6t_esp.c
--- linux-2.4.29-rc2/net/ipv6/netfilter/ip6t_esp.c	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.29-rc3/net/ipv6/netfilter/ip6t_esp.c	2005-01-15 10:14:25.360139185 -0800
@@ -22,6 +22,7 @@
 
 struct esphdr {
 	__u32   spi;
+	__u32   seq_no;
 };
 
 /* Returns 1 if the spi is matched by the range, 0 otherwise */
diff -urN linux-2.4.29-rc2/net/ipv6/netfilter/ip6t_eui64.c linux-2.4.29-rc3/net/ipv6/netfilter/ip6t_eui64.c
--- linux-2.4.29-rc2/net/ipv6/netfilter/ip6t_eui64.c	2002-11-28 15:53:15.000000000 -0800
+++ linux-2.4.29-rc3/net/ipv6/netfilter/ip6t_eui64.c	2005-01-15 10:14:25.360139185 -0800
@@ -58,7 +58,7 @@
 {
 	if (hook_mask
 	    & ~((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_IN) |
-		(1 << NF_IP6_PRE_ROUTING) )) {
+		(1 << NF_IP6_FORWARD))) {
 		printk("ip6t_eui64: only valid for PRE_ROUTING, LOCAL_IN or FORWARD.\n");
 		return 0;
 	}
diff -urN linux-2.4.29-rc2/net/ipv6/netfilter/ip6t_frag.c linux-2.4.29-rc3/net/ipv6/netfilter/ip6t_frag.c
--- linux-2.4.29-rc2/net/ipv6/netfilter/ip6t_frag.c	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.29-rc3/net/ipv6/netfilter/ip6t_frag.c	2005-01-15 10:14:25.361139228 -0800
@@ -6,8 +6,6 @@
 #include <net/checksum.h>
 #include <net/ipv6.h>
 
-#include <asm/byteorder.h>
-
 #include <linux/netfilter_ipv6/ip6_tables.h>
 #include <linux/netfilter_ipv6/ip6t_frag.h>
 
@@ -22,28 +20,7 @@
 #define DEBUGP(format, args...)
 #endif
 
-#if 0
-#if     BYTE_ORDER == BIG_ENDIAN
-#define IP6F_OFF_MASK       0xfff8  /* mask out offset from _offlg */
-#define IP6F_RESERVED_MASK  0x0006  /* reserved bits in ip6f_offlg */
-#define IP6F_MORE_FRAG      0x0001  /* more-fragments flag */
-#else   /* BYTE_ORDER == LITTLE_ENDIAN */
-#define IP6F_OFF_MASK       0xf8ff  /* mask out offset from _offlg */
-#define IP6F_RESERVED_MASK  0x0600  /* reserved bits in ip6f_offlg */
-#define IP6F_MORE_FRAG      0x0100  /* more-fragments flag */
-#endif
-#endif
-
-#define IP6F_OFF_MASK       0xf8ff  /* mask out offset from _offlg */
-#define IP6F_RESERVED_MASK  0x0600  /* reserved bits in ip6f_offlg */
-#define IP6F_MORE_FRAG      0x0100  /* more-fragments flag */
-
-struct fraghdr {
-       __u8    nexthdr;
-       __u8    hdrlen;
-       __u16   info;
-       __u32   id;
-};
+#define IP6_MF	0x0001
 
 /* Returns 1 if the id is matched by the range, 0 otherwise */
 static inline int
@@ -67,7 +44,7 @@
       u_int16_t datalen,
       int *hotdrop)
 {
-       struct fraghdr *frag = NULL;
+       struct frag_hdr *frag = NULL;
        const struct ip6t_frag *fraginfo = matchinfo;
        unsigned int temp;
        int len;
@@ -100,7 +77,7 @@
                      break;
               }
 
-              hdr=(struct ipv6_opt_hdr *)skb->data+ptr;
+              hdr=(struct ipv6_opt_hdr *)(skb->data+ptr);
 
               /* Calculate the header length */
                 if (nexthdr == NEXTHDR_FRAGMENT) {
@@ -143,59 +120,62 @@
        /* FRAG header not found */
        if ( temp != MASK_FRAGMENT ) return 0;
 
-       if (len < (int)sizeof(struct fraghdr)){
+       if (len < sizeof(struct frag_hdr)){
 	       *hotdrop = 1;
        		return 0;
        }
 
-       frag = (struct fraghdr *) (skb->data + ptr);
+       frag = (struct frag_hdr *) (skb->data + ptr);
 
-       DEBUGP("IPv6 FRAG LEN %u %u ", hdrlen, frag->hdrlen);
-       DEBUGP("INFO %04X ", frag->info);
-       DEBUGP("OFFSET %04X ", frag->info & IP6F_OFF_MASK);
-       DEBUGP("RES %04X ", frag->info & IP6F_RESERVED_MASK);
-       DEBUGP("MF %04X ", frag->info & IP6F_MORE_FRAG);
-       DEBUGP("ID %u %08X\n", ntohl(frag->id), ntohl(frag->id));
+       DEBUGP("INFO %04X ", frag->frag_off);
+       DEBUGP("OFFSET %04X ", ntohs(frag->frag_off) & ~0x7);
+       DEBUGP("RES %02X %04X", frag->reserved, ntohs(frag->frag_off) & 0x6);
+       DEBUGP("MF %04X ", frag->frag_off & htons(IP6_MF));
+       DEBUGP("ID %u %08X\n", ntohl(frag->identification),
+	      ntohl(frag->identification));
 
        DEBUGP("IPv6 FRAG id %02X ",
        		(id_match(fraginfo->ids[0], fraginfo->ids[1],
-                           ntohl(frag->id),
+                           ntohl(frag->identification),
                            !!(fraginfo->invflags & IP6T_FRAG_INV_IDS))));
-       DEBUGP("len %02X %04X %02X ",
-       		fraginfo->hdrlen, hdrlen,
-       		(!fraginfo->hdrlen ||
-                           (fraginfo->hdrlen == hdrlen) ^
-                           !!(fraginfo->invflags & IP6T_FRAG_INV_LEN)));
-       DEBUGP("res %02X %02X %02X ", 
-       		(fraginfo->flags & IP6T_FRAG_RES), frag->info & IP6F_RESERVED_MASK,
-       		!((fraginfo->flags & IP6T_FRAG_RES) && (frag->info & IP6F_RESERVED_MASK)));
+       DEBUGP("res %02X %02X%04X %02X ", 
+       		(fraginfo->flags & IP6T_FRAG_RES), frag->reserved,
+		ntohs(frag->frag_off) & 0x6,
+       		!((fraginfo->flags & IP6T_FRAG_RES)
+			&& (frag->reserved || (ntohs(frag->frag_off) & 0x6))));
        DEBUGP("first %02X %02X %02X ", 
-       		(fraginfo->flags & IP6T_FRAG_FST), frag->info & IP6F_OFF_MASK,
-       		!((fraginfo->flags & IP6T_FRAG_FST) && (frag->info & IP6F_OFF_MASK)));
+       		(fraginfo->flags & IP6T_FRAG_FST),
+		ntohs(frag->frag_off) & ~0x7,
+       		!((fraginfo->flags & IP6T_FRAG_FST)
+			&& (ntohs(frag->frag_off) & ~0x7)));
        DEBUGP("mf %02X %02X %02X ", 
-       		(fraginfo->flags & IP6T_FRAG_MF), frag->info & IP6F_MORE_FRAG,
-       		!((fraginfo->flags & IP6T_FRAG_MF) && !((frag->info & IP6F_MORE_FRAG))));
+       		(fraginfo->flags & IP6T_FRAG_MF),
+		ntohs(frag->frag_off) & IP6_MF,
+       		!((fraginfo->flags & IP6T_FRAG_MF)
+			&& !((ntohs(frag->frag_off) & IP6_MF))));
        DEBUGP("last %02X %02X %02X\n", 
-       		(fraginfo->flags & IP6T_FRAG_NMF), frag->info & IP6F_MORE_FRAG,
-       		!((fraginfo->flags & IP6T_FRAG_NMF) && (frag->info & IP6F_MORE_FRAG)));
+       		(fraginfo->flags & IP6T_FRAG_NMF),
+		ntohs(frag->frag_off) & IP6_MF,
+       		!((fraginfo->flags & IP6T_FRAG_NMF)
+			&& (ntohs(frag->frag_off) & IP6_MF)));
 
        return (frag != NULL)
        		&&
        		(id_match(fraginfo->ids[0], fraginfo->ids[1],
-                           ntohl(frag->id),
+			  ntohl(frag->identification),
                            !!(fraginfo->invflags & IP6T_FRAG_INV_IDS)))
 		&&
-	      	(!fraginfo->hdrlen ||
-                           (fraginfo->hdrlen == hdrlen) ^
-                           !!(fraginfo->invflags & IP6T_FRAG_INV_LEN))
-		&&
-		!((fraginfo->flags & IP6T_FRAG_RES) && (frag->info & IP6F_RESERVED_MASK))
+		!((fraginfo->flags & IP6T_FRAG_RES)
+			&& (frag->reserved || (ntohs(frag->frag_off) & 0x6)))
 		&&
-		!((fraginfo->flags & IP6T_FRAG_FST) && (frag->info & IP6F_OFF_MASK))
+		!((fraginfo->flags & IP6T_FRAG_FST)
+			&& (ntohs(frag->frag_off) & ~0x7))
 		&&
-		!((fraginfo->flags & IP6T_FRAG_MF) && !((frag->info & IP6F_MORE_FRAG)))
+		!((fraginfo->flags & IP6T_FRAG_MF)
+			&& !(ntohs(frag->frag_off) & IP6_MF))
 		&&
-		!((fraginfo->flags & IP6T_FRAG_NMF) && (frag->info & IP6F_MORE_FRAG));
+		!((fraginfo->flags & IP6T_FRAG_NMF)
+			&& (ntohs(frag->frag_off) & IP6_MF));
 }
 
 /* Called when user tries to insert an entry of this type. */
diff -urN linux-2.4.29-rc2/net/ipv6/netfilter/ip6t_hbh.c linux-2.4.29-rc3/net/ipv6/netfilter/ip6t_hbh.c
--- linux-2.4.29-rc2/net/ipv6/netfilter/ip6t_hbh.c	2003-06-13 07:51:39.000000000 -0700
+++ linux-2.4.29-rc3/net/ipv6/netfilter/ip6t_hbh.c	2005-01-15 10:14:25.362139270 -0800
@@ -11,8 +11,6 @@
 #include <linux/netfilter_ipv6/ip6_tables.h>
 #include <linux/netfilter_ipv6/ip6t_opts.h>
 
-#define LOW(n)		(n & 0x00FF)
-
 #define HOPBYHOP	1
 
 EXPORT_NO_SYMBOLS;
@@ -40,8 +38,8 @@
  *  	0	-> invariant
  *  	1	-> can change the routing
  *  (Type & 0x1F) Type
- *      0	-> PAD0 (only 1 byte!)
- *      1	-> PAD1 LENGTH info (total length = length + 2)
+ *      0	-> Pad1 (only 1 byte!)
+ *      1	-> PadN LENGTH info (total length = length + 2)
  *      C0 | 2	-> JUMBO 4 x x x x ( xxxx > 64k )
  *      5	-> RTALERT 2 x x
  */
@@ -64,7 +62,8 @@
        unsigned int ptr;
        unsigned int hdrlen = 0;
        unsigned int ret = 0;
-       u_int16_t *optdesc = NULL;
+       u8 *opttype = NULL;
+       unsigned int optlen;
        
        /* type of the 1st exthdr */
        nexthdr = skb->nh.ipv6h->nexthdr;
@@ -91,7 +90,7 @@
                      break;
               }
 
-              hdr=(void *)(skb->data)+ptr;
+	      hdr = (void *)(skb->data + ptr);
 
               /* Calculate the header length */
                 if (nexthdr == NEXTHDR_FRAGMENT) {
@@ -153,7 +152,7 @@
        		return 0;
        }
 
-       optsh=(void *)(skb->data)+ptr;
+       optsh = (void *)(skb->data + ptr);
 
        DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, optsh->hdrlen);
 
@@ -169,7 +168,6 @@
                            ((optinfo->hdrlen == hdrlen) ^
                            !!(optinfo->invflags & IP6T_OPTS_INV_LEN)));
 
-       temp = len = 0;
        ptr += 2;
        hdrlen -= 2;
        if ( !(optinfo->flags & IP6T_OPTS_OPTS) ){
@@ -180,48 +178,52 @@
 		DEBUGP("Strict ");
 		DEBUGP("#%d ",optinfo->optsnr);
 		for(temp=0; temp<optinfo->optsnr; temp++){
-			optdesc = (void *)(skb->data)+ptr;
+			/* type field exists ? */
+			if (ptr > skb->len - 1 || hdrlen < 1)
+				break;
+			opttype = (void *)(skb->data + ptr);
+
 			/* Type check */
-			if ( (unsigned char)*optdesc != 
-				(optinfo->opts[temp] & 0xFF00)>>8 ){
+			if (*opttype != (optinfo->opts[temp] & 0xFF00)>>8){
 				DEBUGP("Tbad %02X %02X\n",
-						(unsigned char)*optdesc,
-						(optinfo->opts[temp] &
-						 0xFF00)>>8);
+				       *opttype,
+				       (optinfo->opts[temp] & 0xFF00)>>8);
 				return 0;
 			} else {
 				DEBUGP("Tok ");
 			}
 			/* Length check */
-			if (((optinfo->opts[temp] & 0x00FF) != 0xFF) &&
-				(unsigned char)*optdesc != 0){
-				if ( ntohs((u16)*optdesc) != 
-						optinfo->opts[temp] ){
-					DEBUGP("Lbad %02X %04X %04X\n",
-							(unsigned char)*optdesc,
-							ntohs((u16)*optdesc),
-							optinfo->opts[temp]);
+			if (*opttype) {
+				u16 spec_len;
+
+				/* length field exists ? */
+				if (ptr > skb->len - 2 || hdrlen < 2)
+					break;
+				optlen = *((u8 *)(skb->data + ptr + 1));
+				spec_len = optinfo->opts[temp] & 0x00FF;
+
+				if (spec_len != 0x00FF && spec_len != optlen) {
+					DEBUGP("Lbad %02X %04X\n", optlen,
+					       spec_len);
 					return 0;
-				} else {
-					DEBUGP("Lok ");
 				}
-			}
-			/* Step to the next */
-			if ((unsigned char)*optdesc == 0){
-				DEBUGP("PAD0 \n");
-				ptr++;
-				hdrlen--;
+				DEBUGP("Lok ");
+				optlen += 2;
 			} else {
-				ptr += LOW(ntohs(*optdesc));
-				hdrlen -= LOW(ntohs(*optdesc));
-				DEBUGP("len%04X \n", 
-					LOW(ntohs(*optdesc)));
+				DEBUGP("Pad1\n");
+				optlen = 1;
 			}
-			if (ptr > skb->len || ( !hdrlen && 
-				(temp != optinfo->optsnr - 1))) {
+
+			/* Step to the next */
+			DEBUGP("len%04X \n", optlen);
+
+			if ((ptr > skb->len - optlen || hdrlen < optlen) &&
+			    (temp < optinfo->optsnr - 1)) {
 				DEBUGP("new pointer is too large! \n");
 				break;
 			}
+			ptr += optlen;
+			hdrlen -= optlen;
 		}
 		if (temp == optinfo->optsnr)
 			return ret;
diff -urN linux-2.4.29-rc2/net/ipv6/netfilter/ip6t_ipv6header.c linux-2.4.29-rc3/net/ipv6/netfilter/ip6t_ipv6header.c
--- linux-2.4.29-rc2/net/ipv6/netfilter/ip6t_ipv6header.c	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.29-rc3/net/ipv6/netfilter/ip6t_ipv6header.c	2005-01-15 10:14:25.362139270 -0800
@@ -63,7 +63,7 @@
 			break;
 		}
 
-		hdr=(struct ipv6_opt_hdr *)skb->data+ptr;
+		hdr=(struct ipv6_opt_hdr *)(skb->data+ptr);
 
 		/* Calculate the header length */
                 if (nexthdr == NEXTHDR_FRAGMENT) {
@@ -107,10 +107,14 @@
 		temp |= MASK_PROTO;
 
 	if (info->modeflag)
-		return (!( (temp & info->matchflags)
-			^ info->matchflags) ^ info->invflags);
-	else
-		return (!( temp ^ info->matchflags) ^ info->invflags);
+		return !((temp ^ info->matchflags ^ info->invflags)
+			 & info->matchflags);
+	else {
+		if (info->invflags)
+			return temp != info->matchflags;
+		else
+			return temp == info->matchflags;
+	}
 }
 
 static int
@@ -120,11 +124,17 @@
 		      unsigned int matchsize,
 		      unsigned int hook_mask)
 {
+	const struct ip6t_ipv6header_info *info = matchinfo;
+
 	/* Check for obvious errors */
 	/* This match is valid in all hooks! */
-	if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_ipv6header_info))) {
+	if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_ipv6header_info)))
+		return 0;
+
+	/* invflags is 0 or 0xff in hard mode */
+	if ((!info->modeflag) && info->invflags != 0x00
+			      && info->invflags != 0xFF)
 		return 0;
-	}
 
 	return 1;
 }
diff -urN linux-2.4.29-rc2/net/ipv6/netfilter/ip6t_multiport.c linux-2.4.29-rc3/net/ipv6/netfilter/ip6t_multiport.c
--- linux-2.4.29-rc2/net/ipv6/netfilter/ip6t_multiport.c	2001-10-30 15:08:12.000000000 -0800
+++ linux-2.4.29-rc3/net/ipv6/netfilter/ip6t_multiport.c	2005-01-15 10:14:25.363139313 -0800
@@ -74,9 +74,12 @@
 {
 	const struct ip6t_multiport *multiinfo = matchinfo;
 
+	if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_multiport)))
+		return 0;
+
 	/* Must specify proto == TCP/UDP, no unknown flags or bad count */
 	return (ip->proto == IPPROTO_TCP || ip->proto == IPPROTO_UDP)
-		&& !(ip->flags & IP6T_INV_PROTO)
+		&& !(ip->invflags & IP6T_INV_PROTO)
 		&& matchsize == IP6T_ALIGN(sizeof(struct ip6t_multiport))
 		&& (multiinfo->flags == IP6T_MULTIPORT_SOURCE
 		    || multiinfo->flags == IP6T_MULTIPORT_DESTINATION
diff -urN linux-2.4.29-rc2/net/ipv6/netfilter/ip6t_rt.c linux-2.4.29-rc3/net/ipv6/netfilter/ip6t_rt.c
--- linux-2.4.29-rc2/net/ipv6/netfilter/ip6t_rt.c	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.29-rc3/net/ipv6/netfilter/ip6t_rt.c	2005-01-15 10:14:25.363139313 -0800
@@ -78,7 +78,7 @@
                      break;
               }
 
-              hdr=(struct ipv6_opt_hdr *)skb->data+ptr;
+              hdr=(struct ipv6_opt_hdr *)(skb->data+ptr);
 
               /* Calculate the header length */
                 if (nexthdr == NEXTHDR_FRAGMENT) {
@@ -135,11 +135,11 @@
 
        DEBUGP("IPv6 RT LEN %u %u ", hdrlen, route->hdrlen);
        DEBUGP("TYPE %04X ", route->type);
-       DEBUGP("SGS_LEFT %u %08X\n", ntohl(route->segments_left), ntohl(route->segments_left));
+       DEBUGP("SGS_LEFT %u %02X\n", route->segments_left, route->segments_left);
 
        DEBUGP("IPv6 RT segsleft %02X ",
        		(segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
-                           ntohl(route->segments_left),
+                           route->segments_left,
                            !!(rtinfo->invflags & IP6T_RT_INV_SGS))));
        DEBUGP("type %02X %02X %02X ",
        		rtinfo->rt_type, route->type, 
@@ -158,7 +158,7 @@
        ret = (route != NULL)
        		&&
        		(segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
-                           ntohl(route->segments_left),
+                           route->segments_left,
                            !!(rtinfo->invflags & IP6T_RT_INV_SGS)))
 		&&
 	      	(!(rtinfo->flags & IP6T_RT_LEN) ||
diff -urN linux-2.4.29-rc2/net/ipv6/sit.c linux-2.4.29-rc3/net/ipv6/sit.c
--- linux-2.4.29-rc2/net/ipv6/sit.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29-rc3/net/ipv6/sit.c	2005-01-15 10:14:25.364139356 -0800
@@ -139,10 +139,10 @@
 {
 	struct ip_tunnel **tp = ipip6_bucket(t);
 
-	write_lock_bh(&ipip6_lock);
 	t->next = *tp;
-	write_unlock_bh(&ipip6_lock);
+	write_lock_bh(&ipip6_lock);
 	*tp = t;
+	write_unlock_bh(&ipip6_lock);
 }
 
 struct ip_tunnel * ipip6_tunnel_locate(struct ip_tunnel_parm *parms, int create)
diff -urN linux-2.4.29-rc2/net/netsyms.c linux-2.4.29-rc3/net/netsyms.c
--- linux-2.4.29-rc2/net/netsyms.c	2005-01-15 10:14:21.259964180 -0800
+++ linux-2.4.29-rc3/net/netsyms.c	2005-01-15 10:14:25.368139526 -0800
@@ -607,6 +607,7 @@
 EXPORT_SYMBOL(nf_setsockopt);
 EXPORT_SYMBOL(nf_getsockopt);
 EXPORT_SYMBOL(ip_ct_attach);
+EXPORT_SYMBOL(nf_ct_attach);
 #ifdef CONFIG_INET
 #include <linux/netfilter_ipv4.h>
 EXPORT_SYMBOL(ip_route_me_harder);
diff -urN linux-2.4.29-rc2/net/sched/sch_dsmark.c linux-2.4.29-rc3/net/sched/sch_dsmark.c
--- linux-2.4.29-rc2/net/sched/sch_dsmark.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29-rc3/net/sched/sch_dsmark.c	2005-01-15 10:14:25.370139612 -0800
@@ -13,6 +13,7 @@
 #include <linux/rtnetlink.h>
 #include <net/pkt_sched.h>
 #include <net/dsfield.h>
+#include <net/inet_ecn.h>
 #include <asm/byteorder.h>
 
 
@@ -196,10 +197,12 @@
 	if (p->set_tc_index) {
 		switch (skb->protocol) {
 			case __constant_htons(ETH_P_IP):
-				skb->tc_index = ipv4_get_dsfield(skb->nh.iph);
+				skb->tc_index = ipv4_get_dsfield(skb->nh.iph)
+					& ~INET_ECN_MASK;
 				break;
 			case __constant_htons(ETH_P_IPV6):
-				skb->tc_index = ipv6_get_dsfield(skb->nh.ipv6h);
+				skb->tc_index = ipv6_get_dsfield(skb->nh.ipv6h)
+					& ~INET_ECN_MASK;
 				break;
 			default:
 				skb->tc_index = 0;
diff -urN linux-2.4.29-rc2/net/sctp/associola.c linux-2.4.29-rc3/net/sctp/associola.c
--- linux-2.4.29-rc2/net/sctp/associola.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29-rc3/net/sctp/associola.c	2005-01-15 10:14:25.372139697 -0800
@@ -66,33 +66,8 @@
 
 /* 1st Level Abstractions. */
 
-/* Allocate and initialize a new association */
-struct sctp_association *sctp_association_new(const struct sctp_endpoint *ep,
-					 const struct sock *sk,
-					 sctp_scope_t scope, int gfp)
-{
-	struct sctp_association *asoc;
-
-	asoc = t_new(struct sctp_association, gfp);
-	if (!asoc)
-		goto fail;
-
-	if (!sctp_association_init(asoc, ep, sk, scope, gfp))
-		goto fail_init;
-
-	asoc->base.malloced = 1;
-	SCTP_DBG_OBJCNT_INC(assoc);
-
-	return asoc;
-
-fail_init:
-	kfree(asoc);
-fail:
-	return NULL;
-}
-
 /* Initialize a new association from provided memory. */
-struct sctp_association *sctp_association_init(struct sctp_association *asoc,
+static struct sctp_association *sctp_association_init(struct sctp_association *asoc,
 					  const struct sctp_endpoint *ep,
 					  const struct sock *sk,
 					  sctp_scope_t scope,
@@ -182,10 +157,10 @@
 	 * RFC 6 - A SCTP receiver MUST be able to receive a minimum of
 	 * 1500 bytes in one SCTP packet.
 	 */
-	if (sk->sk_rcvbuf < SCTP_DEFAULT_MINWINDOW)
+	if (sk->rcvbuf < SCTP_DEFAULT_MINWINDOW)
 		asoc->rwnd = SCTP_DEFAULT_MINWINDOW;
 	else
-		asoc->rwnd = sk->sk_rcvbuf;
+		asoc->rwnd = sk->rcvbuf;
 
 	asoc->a_rwnd = asoc->rwnd;
 
@@ -204,6 +179,7 @@
 	asoc->c.peer_vtag = 0;
 	asoc->c.my_ttag   = 0;
 	asoc->c.peer_ttag = 0;
+	asoc->c.my_port = ep->base.bind_addr.port;
 
 	asoc->c.initial_tsn = sctp_generate_tsn(ep);
 
@@ -296,6 +272,31 @@
 	return NULL;
 }
 
+/* Allocate and initialize a new association */
+struct sctp_association *sctp_association_new(const struct sctp_endpoint *ep,
+					 const struct sock *sk,
+					 sctp_scope_t scope, int gfp)
+{
+	struct sctp_association *asoc;
+
+	asoc = t_new(struct sctp_association, gfp);
+	if (!asoc)
+		goto fail;
+
+	if (!sctp_association_init(asoc, ep, sk, scope, gfp))
+		goto fail_init;
+
+	asoc->base.malloced = 1;
+	SCTP_DBG_OBJCNT_INC(assoc);
+
+	return asoc;
+
+fail_init:
+	kfree(asoc);
+fail:
+	return NULL;
+}
+
 /* Free this association if possible.  There may still be users, so
  * the actual deallocation may be delayed.
  */
@@ -310,7 +311,7 @@
 
 	/* Decrement the backlog value for a TCP-style listening socket. */
 	if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))
-		sk->sk_ack_backlog--;
+		sk->ack_backlog--;
 
 	/* Mark as dead, so other users can know this structure is
 	 * going away.
@@ -496,7 +497,6 @@
 
 	peer->partial_bytes_acked = 0;
 	peer->flight_size = 0;
-	peer->error_threshold = peer->max_retrans;
 
 	/* By default, enable heartbeat for peer address. */
 	peer->hb_allowed = 1;
@@ -507,7 +507,7 @@
 	peer->hb_interval = SCTP_MSECS_TO_JIFFIES(sp->paddrparam.spp_hbinterval);
 
 	/* Set the path max_retrans.  */
-	peer->max_retrans = asoc->max_retrans;
+	peer->max_retrans = sp->paddrparam.spp_pathmaxrxt;
 
 	/* Set the transport's RTO.initial value */
 	peer->rto = asoc->rto_initial;
@@ -710,18 +710,6 @@
 	return retval;
 }
 
-/* Allocate 'num' TSNs by incrementing the association's TSN by num. */
-__u32 sctp_association_get_tsn_block(struct sctp_association *asoc, int num)
-{
-	__u32 retval = asoc->next_tsn;
-
-	asoc->next_tsn += num;
-	asoc->unack_data += num;
-
-	return retval;
-}
-
-
 /* Compare two addresses to see if they match.  Wildcard addresses
  * only match themselves.
  */
@@ -756,14 +744,6 @@
 	return chunk;
 }
 
-/* Use this function for the packet prepend callback when no ECNE
- * packet is desired (e.g. some packets don't like to be bundled).
- */
-struct sctp_chunk *sctp_get_no_prepend(struct sctp_association *asoc)
-{
-	return NULL;
-}
-
 /*
  * Find which transport this TSN was sent on.
  */
@@ -877,7 +857,8 @@
 	struct sctp_chunk *chunk;
 	struct sock *sk;
 	struct sctp_inq *inqueue;
-	int state, subtype;
+	int state;
+	sctp_subtype_t subtype;
 	int error = 0;
 
 	/* The association should be held so we should be safe. */
@@ -887,7 +868,7 @@
 	inqueue = &asoc->base.inqueue;
 	while (NULL != (chunk = sctp_inq_pop(inqueue))) {
 		state = asoc->state;
-		subtype = chunk->chunk_hdr->type;
+		subtype = SCTP_ST_CHUNK(chunk->chunk_hdr->type);
 
 		/* Remember where the last DATA chunk came from so we
 		 * know where to send the SACK.
@@ -901,7 +882,7 @@
 			chunk->transport->last_time_heard = jiffies;
 
 		/* Run through the state machine. */
-		error = sctp_do_sm(SCTP_EVENT_T_CHUNK, SCTP_ST_CHUNK(subtype),
+		error = sctp_do_sm(SCTP_EVENT_T_CHUNK, subtype,
 				   state, ep, asoc, chunk, GFP_ATOMIC);
 
 		/* Check to see if the association is freed in response to
@@ -930,7 +911,7 @@
 
 	/* Decrement the backlog value for a TCP-style socket. */
 	if (sctp_style(oldsk, TCP))
-		oldsk->sk_ack_backlog--;
+		oldsk->ack_backlog--;
 
 	/* Release references to the old endpoint and the sock.  */
 	sctp_endpoint_put(assoc->ep);
@@ -1112,7 +1093,7 @@
 	case SCTP_STATE_SHUTDOWN_SENT:
 		if ((asoc->rwnd > asoc->a_rwnd) &&
 		    ((asoc->rwnd - asoc->a_rwnd) >=
-		     min_t(__u32, (asoc->base.sk->sk_rcvbuf >> 1), asoc->pmtu)))
+		     min_t(__u32, (asoc->base.sk->rcvbuf >> 1), asoc->pmtu)))
 			return 1;
 		break;
 	default:
@@ -1195,7 +1176,7 @@
 	 * the endpoint.
 	 */
 	scope = sctp_scope(&asoc->peer.active_path->ipaddr);
-	flags = (PF_INET6 == asoc->base.sk->sk_family) ? SCTP_ADDR6_ALLOWED : 0;
+	flags = (PF_INET6 == asoc->base.sk->family) ? SCTP_ADDR6_ALLOWED : 0;
 	if (asoc->peer.ipv4_address)
 		flags |= SCTP_ADDR4_PEERSUPP;
 	if (asoc->peer.ipv6_address)
diff -urN linux-2.4.29-rc2/net/sctp/bind_addr.c linux-2.4.29-rc3/net/sctp/bind_addr.c
--- linux-2.4.29-rc2/net/sctp/bind_addr.c	2004-04-14 06:05:41.000000000 -0700
+++ linux-2.4.29-rc3/net/sctp/bind_addr.c	2005-01-15 10:14:25.373139740 -0800
@@ -104,23 +104,6 @@
 	return error;
 }
 
-/* Create a new SCTP_bind_addr from nothing.  */
-struct sctp_bind_addr *sctp_bind_addr_new(int gfp)
-{
-	struct sctp_bind_addr *retval;
-
-	retval = t_new(struct sctp_bind_addr, gfp);
-	if (!retval)
-		goto nomem;
-
-	sctp_bind_addr_init(retval, 0);
-	retval->malloced = 1;
-	SCTP_DBG_OBJCNT_INC(bind_addr);
-
-nomem:
-	return retval;
-}
-
 /* Initialize the SCTP_bind_addr structure for either an endpoint or
  * an association.
  */
diff -urN linux-2.4.29-rc2/net/sctp/chunk.c linux-2.4.29-rc3/net/sctp/chunk.c
--- linux-2.4.29-rc2/net/sctp/chunk.c	2004-08-07 16:26:07.000000000 -0700
+++ linux-2.4.29-rc3/net/sctp/chunk.c	2005-01-15 10:14:25.373139740 -0800
@@ -51,7 +51,7 @@
  */
 
 /* Initialize datamsg from memory. */
-void sctp_datamsg_init(struct sctp_datamsg *msg)
+static void sctp_datamsg_init(struct sctp_datamsg *msg)
 {
 	atomic_set(&msg->refcnt, 1);
 	msg->send_failed = 0;
@@ -62,7 +62,7 @@
 }
 
 /* Allocate and initialize datamsg. */
-struct sctp_datamsg *sctp_datamsg_new(int gfp)
+SCTP_STATIC struct sctp_datamsg *sctp_datamsg_new(int gfp)
 {
 	struct sctp_datamsg *msg;
 	msg = kmalloc(sizeof(struct sctp_datamsg), gfp);
@@ -124,7 +124,7 @@
 }
 
 /* Hold a reference. */
-void sctp_datamsg_hold(struct sctp_datamsg *msg)
+static void sctp_datamsg_hold(struct sctp_datamsg *msg)
 {
 	atomic_inc(&msg->refcnt);
 }
@@ -151,7 +151,7 @@
 }
 
 /* Assign a chunk to this datamsg. */
-void sctp_datamsg_assign(struct sctp_datamsg *msg, struct sctp_chunk *chunk)
+static void sctp_datamsg_assign(struct sctp_datamsg *msg, struct sctp_chunk *chunk)
 {
 	sctp_datamsg_hold(msg);
 	chunk->msg = msg;
diff -urN linux-2.4.29-rc2/net/sctp/command.c linux-2.4.29-rc3/net/sctp/command.c
--- linux-2.4.29-rc2/net/sctp/command.c	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.29-rc3/net/sctp/command.c	2005-01-15 10:14:25.374139783 -0800
@@ -42,17 +42,6 @@
 #include <net/sctp/sctp.h>
 #include <net/sctp/sm.h>
 
-/* Create a new sctp_command_sequence.  */
-sctp_cmd_seq_t *sctp_new_cmd_seq(int gfp)
-{
-	sctp_cmd_seq_t *retval = t_new(sctp_cmd_seq_t, gfp);
-
-	if (retval)
-		sctp_init_cmd_seq(retval);
-
-	return retval;
-}
-
 /* Initialize a block of memory as a command sequence. */
 int sctp_init_cmd_seq(sctp_cmd_seq_t *seq)
 {
@@ -77,13 +66,6 @@
 	return 0;
 }
 
-/* Rewind an sctp_cmd_seq_t to iterate from the start.  */
-int sctp_rewind_sequence(sctp_cmd_seq_t *seq)
-{
-	seq->next_cmd = 0;
-	return 1;		/* We always succeed. */
-}
-
 /* Return the next command structure in a sctp_cmd_seq.
  * Returns NULL at the end of the sequence.
  */
@@ -97,8 +79,3 @@
 	return retval;
 }
 
-/* Dispose of a command sequence.  */
-void sctp_free_cmd_seq(sctp_cmd_seq_t *seq)
-{
-	kfree(seq);
-}
diff -urN linux-2.4.29-rc2/net/sctp/debug.c linux-2.4.29-rc3/net/sctp/debug.c
--- linux-2.4.29-rc2/net/sctp/debug.c	2004-08-07 16:26:07.000000000 -0700
+++ linux-2.4.29-rc3/net/sctp/debug.c	2005-01-15 10:14:25.374139783 -0800
@@ -98,23 +98,6 @@
 	return "unknown chunk";
 }
 
-/* These are printable form of variable-length parameters. */
-const char *sctp_param_tbl[SCTP_PARAM_ECN_CAPABLE + 1] = {
-	"",
-	"PARAM_HEARTBEAT_INFO",
-	"",
-	"",
-	"",
-	"PARAM_IPV4_ADDRESS",
-	"PARAM_IPV6_ADDRESS",
-	"PARAM_STATE_COOKIE",
-	"PARAM_UNRECOGNIZED_PARAMETERS",
-	"PARAM_COOKIE_PRESERVATIVE",
-	"",
-	"PARAM_HOST_NAME_ADDRESS",
-	"PARAM_SUPPORTED_ADDRESS_TYPES",
-};
-
 /* These are printable forms of the states.  */
 const char *sctp_state_tbl[SCTP_STATE_NUM_STATES] = {
 	"STATE_EMPTY",
@@ -171,6 +154,7 @@
 
 static const char *sctp_other_tbl[] = {
 	"NO_PENDING_TSN",
+        "ICMP_PROTO_UNREACH",
 };
 
 /* Lookup "other" debug name. */
@@ -178,7 +162,7 @@
 {
 	if (id.other < 0)
 		return "illegal 'other' event";
-	if (id.other < SCTP_EVENT_OTHER_MAX)
+	if (id.other <= SCTP_EVENT_OTHER_MAX)
 		return sctp_other_tbl[id.other];
 	return "unknown 'other' event";
 }
diff -urN linux-2.4.29-rc2/net/sctp/endpointola.c linux-2.4.29-rc3/net/sctp/endpointola.c
--- linux-2.4.29-rc2/net/sctp/endpointola.c	2004-04-14 06:05:41.000000000 -0700
+++ linux-2.4.29-rc3/net/sctp/endpointola.c	2005-01-15 10:14:25.375139825 -0800
@@ -63,34 +63,11 @@
 /* Forward declarations for internal helpers. */
 static void sctp_endpoint_bh_rcv(struct sctp_endpoint *ep);
 
-/* Create a sctp_endpoint with all that boring stuff initialized.
- * Returns NULL if there isn't enough memory.
- */
-struct sctp_endpoint *sctp_endpoint_new(struct sock *sk, int gfp)
-{
-	struct sctp_endpoint *ep;
-
-	/* Build a local endpoint. */
-	ep = t_new(struct sctp_endpoint, gfp);
-	if (!ep)
-		goto fail;
-	if (!sctp_endpoint_init(ep, sk, gfp))
-		goto fail_init;
-	ep->base.malloced = 1;
-	SCTP_DBG_OBJCNT_INC(ep);
-	return ep;
-
-fail_init:
-	kfree(ep);
-fail:
-	return NULL;
-}
-
 /*
  * Initialize the base fields of the endpoint structure.
  */
-struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
-					 struct sock *sk, int gfp)
+static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
+						struct sock *sk, int gfp)
 {
 	struct sctp_opt *sp = sctp_sk(sk);
 	memset(ep, 0, sizeof(struct sctp_endpoint));
@@ -148,8 +125,8 @@
 		sp->autoclose * HZ;
 
 	/* Use SCTP specific send buffer space queues.  */
-	sk->sk_write_space = sctp_write_space;
-	sk->sk_use_write_queue = 1;
+	sk->write_space = sctp_write_space;
+	sk->use_write_queue = 1;
 
 	/* Initialize the secret key used with cookie. */
 	get_random_bytes(&ep->secret_key[0], SCTP_SECRET_SIZE);
@@ -160,6 +137,29 @@
 	return ep;
 }
 
+/* Create a sctp_endpoint with all that boring stuff initialized.
+ * Returns NULL if there isn't enough memory.
+ */
+struct sctp_endpoint *sctp_endpoint_new(struct sock *sk, int gfp)
+{
+	struct sctp_endpoint *ep;
+
+	/* Build a local endpoint. */
+	ep = t_new(struct sctp_endpoint, gfp);
+	if (!ep)
+		goto fail;
+	if (!sctp_endpoint_init(ep, sk, gfp))
+		goto fail_init;
+	ep->base.malloced = 1;
+	SCTP_DBG_OBJCNT_INC(ep);
+	return ep;
+
+fail_init:
+	kfree(ep);
+fail:
+	return NULL;
+}
+
 /* Add an association to an endpoint.  */
 void sctp_endpoint_add_asoc(struct sctp_endpoint *ep,
 			    struct sctp_association *asoc)
@@ -171,7 +171,7 @@
 
 	/* Increment the backlog value for a TCP-style listening socket. */
 	if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))
-		sk->sk_ack_backlog++;
+		sk->ack_backlog++;
 }
 
 /* Free the endpoint structure.  Delay cleanup until
@@ -184,11 +184,11 @@
 }
 
 /* Final destructor for endpoint.  */
-void sctp_endpoint_destroy(struct sctp_endpoint *ep)
+static void sctp_endpoint_destroy(struct sctp_endpoint *ep)
 {
 	SCTP_ASSERT(ep->base.dead, "Endpoint is not dead", return);
 
-	ep->base.sk->sk_state = SCTP_SS_CLOSED;
+	ep->base.sk->state = SCTP_SS_CLOSED;
 
 	/* Unlink this endpoint, so we can't find it again! */
 	sctp_unhash_endpoint(ep);
@@ -257,7 +257,7 @@
  * We do a linear search of the associations for this endpoint.
  * We return the matching transport address too.
  */
-struct sctp_association *__sctp_endpoint_lookup_assoc(
+static struct sctp_association *__sctp_endpoint_lookup_assoc(
 	const struct sctp_endpoint *ep,
 	const union sctp_addr *paddr,
 	struct sctp_transport **transport)
@@ -345,7 +345,7 @@
 	sk = ep->base.sk;
 
 	while (NULL != (chunk = sctp_inq_pop(inqueue))) {
-		subtype.chunk = chunk->chunk_hdr->type;
+		subtype = SCTP_ST_CHUNK(chunk->chunk_hdr->type);
 
 		/* We might have grown an association since last we
 		 * looked, so try again.
diff -urN linux-2.4.29-rc2/net/sctp/input.c linux-2.4.29-rc3/net/sctp/input.c
--- linux-2.4.29-rc2/net/sctp/input.c	2004-04-14 06:05:41.000000000 -0700
+++ linux-2.4.29-rc3/net/sctp/input.c	2005-01-15 10:14:25.376139868 -0800
@@ -63,11 +63,15 @@
 
 /* Forward declarations for internal helpers. */
 static int sctp_rcv_ootb(struct sk_buff *);
-struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb,
+static struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb,
 				      const union sctp_addr *laddr,
 				      const union sctp_addr *paddr,
 				      struct sctp_transport **transportp);
-struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr);
+static struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr);
+static struct sctp_association *__sctp_lookup_association(
+					const union sctp_addr *local,
+					const union sctp_addr *peer,
+					struct sctp_transport **pt);
 
 
 /* Calculate the SCTP checksum of an SCTP packet.  */
@@ -130,6 +134,10 @@
 
 	skb_pull(skb, sizeof(struct sctphdr));
 
+	/* Make sure we at least have chunk headers worth of data left. */
+	if (skb->len < sizeof(struct sctp_chunkhdr))
+		goto discard_it;
+
 	family = ipver2af(skb->nh.iph->version);
 	af = sctp_get_af_specific(family);
 	if (unlikely(!af))
@@ -278,6 +286,31 @@
 	}
 }
 
+/*
+ * SCTP Implementer's Guide, 2.37 ICMP handling procedures
+ *
+ * ICMP8) If the ICMP code is a "Unrecognized next header type encountered"
+ *        or a "Protocol Unreachable" treat this message as an abort
+ *        with the T bit set.
+ *
+ * This function sends an event to the state machine, which will abort the
+ * association.
+ *
+ */
+void sctp_icmp_proto_unreachable(struct sock *sk,
+                           struct sctp_endpoint *ep,
+                           struct sctp_association *asoc,
+                           struct sctp_transport *t)
+{
+	SCTP_DEBUG_PRINTK("%s\n",  __FUNCTION__);
+
+	sctp_do_sm(SCTP_EVENT_T_OTHER,
+		   SCTP_ST_OTHER(SCTP_EVENT_ICMP_PROTO_UNREACH),
+		   asoc->state, asoc->ep, asoc, NULL,
+		   GFP_ATOMIC);
+
+}
+
 /* Common lookup code for icmp/icmpv6 error handler. */
 struct sock *sctp_err_lookup(int family, struct sk_buff *skb,
 			     struct sctphdr *sctphdr,
@@ -320,11 +353,12 @@
 	}
 
 	if (asoc) {
+		sk = asoc->base.sk;
+
 		if (ntohl(sctphdr->vtag) != asoc->c.peer_vtag) {
 			ICMP_INC_STATS_BH(IcmpInErrors);
 			goto out;
 		}
-		sk = asoc->base.sk;
 	} else
 		sk = ep->base.sk;
 
@@ -426,7 +460,13 @@
 			sctp_icmp_frag_needed(sk, asoc, transport, info);
 			goto out_unlock;
 		}
-
+		else {
+			if (ICMP_PROT_UNREACH == code) {
+				sctp_icmp_proto_unreachable(sk, ep, asoc,
+							    transport);
+				goto out_unlock;
+			}
+		}
 		err = icmp_err_convert[code].errno;
 		break;
 	case ICMP_TIME_EXCEEDED:
@@ -444,10 +484,10 @@
 
 	inet = inet_sk(sk);
 	if (!sock_owned_by_user(sk) && inet->recverr) {
-		sk->sk_err = err;
-		sk->sk_error_report(sk);
+		sk->err = err;
+		sk->error_report(sk);
 	} else {  /* Only an error on timeout */
-		sk->sk_err_soft = err;
+		sk->err_soft = err;
 	}
 
 out_unlock:
@@ -473,10 +513,10 @@
 	sctp_errhdr_t *err;
 
 	ch = (sctp_chunkhdr_t *) skb->data;
+	ch_end = ((__u8 *) ch) + WORD_ROUND(ntohs(ch->length));
 
 	/* Scan through all the chunks in the packet.  */
-	do {
-		ch_end = ((__u8 *) ch) + WORD_ROUND(ntohs(ch->length));
+	while (ch_end > (__u8 *)ch && ch_end < skb->tail) {
 
 		/* RFC 8.4, 2) If the OOTB packet contains an ABORT chunk, the
 		 * receiver MUST silently discard the OOTB packet and take no
@@ -507,7 +547,8 @@
 		}
 
 		ch = (sctp_chunkhdr_t *) ch_end;
-	} while (ch_end < skb->tail);
+	        ch_end = ((__u8 *) ch) + WORD_ROUND(ntohs(ch->length));
+	}
 
 	return 0;
 
@@ -516,7 +557,7 @@
 }
 
 /* Insert endpoint into the hash table.  */
-void __sctp_hash_endpoint(struct sctp_endpoint *ep)
+static void __sctp_hash_endpoint(struct sctp_endpoint *ep)
 {
 	struct sctp_ep_common **epp;
 	struct sctp_ep_common *epb;
@@ -546,7 +587,7 @@
 }
 
 /* Remove endpoint from the hash table.  */
-void __sctp_unhash_endpoint(struct sctp_endpoint *ep)
+static void __sctp_unhash_endpoint(struct sctp_endpoint *ep)
 {
 	struct sctp_hashbucket *head;
 	struct sctp_ep_common *epb;
@@ -578,7 +619,7 @@
 }
 
 /* Look up an endpoint. */
-struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr)
+static struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr)
 {
 	struct sctp_hashbucket *head;
 	struct sctp_ep_common *epb;
@@ -604,16 +645,8 @@
 	return ep;
 }
 
-/* Add an association to the hash. Local BH-safe. */
-void sctp_hash_established(struct sctp_association *asoc)
-{
-	sctp_local_bh_disable();
-	__sctp_hash_established(asoc);
-	sctp_local_bh_enable();
-}
-
 /* Insert association into the hash table.  */
-void __sctp_hash_established(struct sctp_association *asoc)
+static void __sctp_hash_established(struct sctp_association *asoc)
 {
 	struct sctp_ep_common **epp;
 	struct sctp_ep_common *epb;
@@ -636,16 +669,16 @@
 	sctp_write_unlock(&head->lock);
 }
 
-/* Remove association from the hash table.  Local BH-safe. */
-void sctp_unhash_established(struct sctp_association *asoc)
+/* Add an association to the hash. Local BH-safe. */
+void sctp_hash_established(struct sctp_association *asoc)
 {
 	sctp_local_bh_disable();
-	__sctp_unhash_established(asoc);
+	__sctp_hash_established(asoc);
 	sctp_local_bh_enable();
 }
 
 /* Remove association from the hash table.  */
-void __sctp_unhash_established(struct sctp_association *asoc)
+static void __sctp_unhash_established(struct sctp_association *asoc)
 {
 	struct sctp_hashbucket *head;
 	struct sctp_ep_common *epb;
@@ -669,8 +702,16 @@
 	sctp_write_unlock(&head->lock);
 }
 
+/* Remove association from the hash table.  Local BH-safe. */
+void sctp_unhash_established(struct sctp_association *asoc)
+{
+	sctp_local_bh_disable();
+	__sctp_unhash_established(asoc);
+	sctp_local_bh_enable();
+}
+
 /* Look up an association. */
-struct sctp_association *__sctp_lookup_association(
+static struct sctp_association *__sctp_lookup_association(
 					const union sctp_addr *local,
 					const union sctp_addr *peer,
 					struct sctp_transport **pt)
@@ -707,8 +748,9 @@
 }
 
 /* Look up an association. BH-safe. */
+SCTP_STATIC
 struct sctp_association *sctp_lookup_association(const union sctp_addr *laddr,
-					    const union sctp_addr *paddr,
+						 const union sctp_addr *paddr,
 					    struct sctp_transport **transportp)
 {
 	struct sctp_association *asoc;
@@ -778,6 +820,14 @@
 		return NULL;
 	}
 
+	/* The code below will attempt to walk the chunk and extract
+	 * parameter information.  Before we do that, we need to verify
+	 * that the chunk length doesn't cause overflow.  Otherwise, we'll
+	 * walk off the end.
+	 */
+	if (WORD_ROUND(ntohs(ch->length)) > skb->len)
+		return NULL;
+
 	/*
 	 * This code will NOT touch anything inside the chunk--it is
 	 * strictly READ-ONLY.
@@ -815,7 +865,7 @@
 }
 
 /* Lookup an association for an inbound skb. */
-struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb,
+static struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb,
 				      const union sctp_addr *paddr,
 				      const union sctp_addr *laddr,
 				      struct sctp_transport **transportp)
diff -urN linux-2.4.29-rc2/net/sctp/inqueue.c linux-2.4.29-rc3/net/sctp/inqueue.c
--- linux-2.4.29-rc2/net/sctp/inqueue.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29-rc3/net/sctp/inqueue.c	2005-01-15 10:14:25.377139911 -0800
@@ -62,19 +62,6 @@
 	queue->malloced = 0;
 }
 
-/* Create an initialized sctp_inq.  */
-struct sctp_inq *sctp_inq_new(void)
-{
-	struct sctp_inq *retval;
-
-	retval = t_new(struct sctp_inq, GFP_ATOMIC);
-	if (retval) {
-		sctp_inq_init(retval);
-		retval->malloced = 1;
-	}
-        return retval;
-}
-
 /* Release the memory associated with an SCTP inqueue.  */
 void sctp_inq_free(struct sctp_inq *queue)
 {
@@ -160,14 +147,36 @@
 	}
 
         chunk->chunk_hdr = ch;
-        chunk->chunk_end = ((__u8 *) ch)
-		+ WORD_ROUND(ntohs(ch->length));
+        chunk->chunk_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length));
+	/* In the unlikely case of an IP reassembly, the skb could be
+	 * non-linear. If so, update chunk_end so that it doesn't go past
+	 * the skb->tail.
+	 */
+	if (unlikely(skb_is_nonlinear(chunk->skb))) {
+		if (chunk->chunk_end > chunk->skb->tail)
+			chunk->chunk_end = chunk->skb->tail;
+	}
 	skb_pull(chunk->skb, sizeof(sctp_chunkhdr_t));
 	chunk->subh.v = NULL; /* Subheader is no longer valid.  */
 
 	if (chunk->chunk_end < chunk->skb->tail) {
 		/* This is not a singleton */
 		chunk->singleton = 0;
+	} else if (chunk->chunk_end > chunk->skb->tail) {
+                /* RFC 2960, Section 6.10  Bundling
+		 *
+		 * Partial chunks MUST NOT be placed in an SCTP packet.
+		 * If the receiver detects a partial chunk, it MUST drop
+		 * the chunk.  
+		 *
+		 * Since the end of the chunk is past the end of our buffer
+		 * (which contains the whole packet, we can freely discard
+		 * the whole packet.
+		 */
+		sctp_chunk_free(chunk);
+		chunk = queue->in_progress = NULL;
+
+		return NULL;
 	} else {
 		/* We are at the end of the packet, so mark the chunk
 		 * in case we need to send a SACK.
diff -urN linux-2.4.29-rc2/net/sctp/ipv6.c linux-2.4.29-rc3/net/sctp/ipv6.c
--- linux-2.4.29-rc2/net/sctp/ipv6.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29-rc3/net/sctp/ipv6.c	2005-01-15 10:14:25.378139953 -0800
@@ -95,8 +95,8 @@
 	ntohs((addr)->s6_addr16[7])
 
 /* ICMP error handler. */
-void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
-		 int type, int code, int offset, __u32 info)
+SCTP_STATIC void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+			     int type, int code, int offset, __u32 info)
 {
 	struct inet6_dev *idev;
 	struct ipv6hdr *iph = (struct ipv6hdr *)skb->data;
@@ -133,6 +133,12 @@
 	case ICMPV6_PKT_TOOBIG:
 		sctp_icmp_frag_needed(sk, asoc, transport, ntohl(info));
 		goto out_unlock;
+	case ICMPV6_PARAMPROB:
+		if (ICMPV6_UNK_NEXTHDR == code) {
+			sctp_icmp_proto_unreachable(sk, ep, asoc, transport);
+			goto out_unlock;
+		}
+		break;
 	default:
 		break;
 	}
@@ -140,10 +146,10 @@
 	np = inet6_sk(sk);
 	icmpv6_err_convert(type, code, &err);
 	if (!sock_owned_by_user(sk) && np->recverr) {
-		sk->sk_err = err;
-		sk->sk_error_report(sk);
+		sk->err = err;
+		sk->error_report(sk);
 	} else {  /* Only an error on timeout */
-		sk->sk_err_soft = err;
+		sk->err_soft = err;
 	}
 
 out_unlock:
@@ -163,7 +169,7 @@
 
 	memset(&fl, 0, sizeof(fl));
 
-	fl.proto = sk->sk_protocol;
+	fl.proto = sk->protocol;
 
 	/* Fill in the dest address from the route entry passed with the skb
 	 * and the source address from the transport.
@@ -176,7 +182,7 @@
 	if (ipv6_addr_type(fl.fl6_src) & IPV6_ADDR_LINKLOCAL)
 		fl.oif = transport->saddr.v6.sin6_scope_id;
 	else
-		fl.oif = sk->sk_bound_dev_if;
+		fl.oif = sk->bound_dev_if;
 	fl.uli_u.ports.sport = sk->sport;
 	fl.uli_u.ports.dport = transport->ipaddr.v6.sin6_port;
 
@@ -199,9 +205,9 @@
 /* Returns the dst cache entry for the given source and destination ip
  * addresses.
  */
-struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc,
-				  union sctp_addr *daddr,
-				  union sctp_addr *saddr)
+static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc,
+					 union sctp_addr *daddr,
+					 union sctp_addr *saddr)
 {
 	struct dst_entry *dst;
 	struct flowi fl;
@@ -262,8 +268,10 @@
 /* Fills in the source address(saddr) based on the destination address(daddr)
  * and asoc's bind address list.
  */
-void sctp_v6_get_saddr(struct sctp_association *asoc, struct dst_entry *dst,
-		       union sctp_addr *daddr, union sctp_addr *saddr)
+static void sctp_v6_get_saddr(struct sctp_association *asoc,
+			      struct dst_entry *dst,
+			      union sctp_addr *daddr,
+			      union sctp_addr *saddr)
 {
 	struct sctp_bind_addr *bp;
 	rwlock_t *addr_lock;
@@ -588,8 +596,8 @@
 }
 
 /* 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)
+static struct sock *sctp_v6_create_accept_sk(struct sock *sk,
+					     struct sctp_association *asoc)
 {
 	struct sock *newsk;
 	struct inet_opt *newinet;
@@ -602,18 +610,18 @@
 	sock_init_data(NULL, newsk);
 	sk_set_owner(newsk, THIS_MODULE);
 
-	newsk->sk_type = SOCK_STREAM;
+	newsk->type = SOCK_STREAM;
 
-	newsk->sk_prot = sk->sk_prot;
-	newsk->sk_no_check = sk->sk_no_check;
-	newsk->sk_reuse = sk->sk_reuse;
-
-	newsk->sk_destruct = inet_sock_destruct;
-	newsk->sk_zapped = 0;
-	newsk->sk_family = PF_INET6;
-	newsk->sk_protocol = IPPROTO_SCTP;
-	newsk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;
-	newsk->sk_shutdown = sk->sk_shutdown;
+	newsk->prot = sk->prot;
+	newsk->no_check = sk->no_check;
+	newsk->reuse = sk->reuse;
+
+	newsk->destruct = inet_sock_destruct;
+	newsk->zapped = 0;
+	newsk->family = PF_INET6;
+	newsk->protocol = IPPROTO_SCTP;
+	newsk->backlog_rcv = sk->prot->backlog_rcv;
+	newsk->shutdown = sk->shutdown;
 
 	newinet = inet_sk(newsk);
 	newnp = inet6_sk(newsk);
@@ -648,7 +656,7 @@
 	atomic_inc(&inet_sock_nr);
 #endif
 
-	if (newsk->sk_prot->init(newsk)) {
+	if (newsk->prot->init(newsk)) {
 		inet_sock_release(newsk);
 		newsk = NULL;
 	}
@@ -823,8 +831,8 @@
 			 */
 
 			if (addr->v6.sin6_scope_id)
-				sk->sk_bound_dev_if = addr->v6.sin6_scope_id;
-			if (!sk->sk_bound_dev_if)
+				sk->bound_dev_if = addr->v6.sin6_scope_id;
+			if (!sk->bound_dev_if)
 				return 0;
 		}
 		af = opt->pf->af;
@@ -853,8 +861,8 @@
 			 */
 
 			if (addr->v6.sin6_scope_id)
-				sk->sk_bound_dev_if = addr->v6.sin6_scope_id;
-			if (!sk->sk_bound_dev_if)
+				sk->bound_dev_if = addr->v6.sin6_scope_id;
+			if (!sk->bound_dev_if)
 				return 0;
 		}
 		af = opt->pf->af;
diff -urN linux-2.4.29-rc2/net/sctp/objcnt.c linux-2.4.29-rc3/net/sctp/objcnt.c
--- linux-2.4.29-rc2/net/sctp/objcnt.c	2004-08-07 16:26:07.000000000 -0700
+++ linux-2.4.29-rc3/net/sctp/objcnt.c	2005-01-15 10:14:25.379139996 -0800
@@ -61,7 +61,7 @@
 /* An array to make it easy to pretty print the debug information
  * to the proc fs.
  */
-sctp_dbg_objcnt_entry_t sctp_dbg_objcnt[] = {
+static sctp_dbg_objcnt_entry_t sctp_dbg_objcnt[] = {
 	SCTP_DBG_OBJCNT_ENTRY(sock),
 	SCTP_DBG_OBJCNT_ENTRY(ep),
 	SCTP_DBG_OBJCNT_ENTRY(assoc),
diff -urN linux-2.4.29-rc2/net/sctp/output.c linux-2.4.29-rc3/net/sctp/output.c
--- linux-2.4.29-rc2/net/sctp/output.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29-rc3/net/sctp/output.c	2005-01-15 10:14:25.379139996 -0800
@@ -161,7 +161,7 @@
 		if (!packet->has_cookie_echo) {
 			error = sctp_packet_transmit(packet);
 			if (error < 0)
-				chunk->skb->sk->sk_err = -error;
+				chunk->skb->sk->err = -error;
 
 			/* If we have an empty packet, then we can NOT ever
 			 * return PMTU_FULL.
diff -urN linux-2.4.29-rc2/net/sctp/outqueue.c linux-2.4.29-rc3/net/sctp/outqueue.c
--- linux-2.4.29-rc2/net/sctp/outqueue.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29-rc3/net/sctp/outqueue.c	2005-01-15 10:14:25.381140081 -0800
@@ -200,19 +200,6 @@
 	return 0;
 }
 
-/* Generate a new outqueue.  */
-struct sctp_outq *sctp_outq_new(struct sctp_association *asoc)
-{
-	struct sctp_outq *q;
-
-	q = t_new(struct sctp_outq, GFP_KERNEL);
-	if (q) {
-		sctp_outq_init(asoc, q);
-		q->malloced = 1;
-	}
-	return q;
-}
-
 /* Initialize an existing sctp_outq.  This does the boring stuff.
  * You still need to define handlers if you really want to DO
  * something with this structure...
@@ -372,7 +359,7 @@
 /* Insert a chunk into the sorted list based on the TSNs.  The retransmit list
  * and the abandoned list are in ascending order.
  */
-void sctp_insert_list(struct list_head *head, struct list_head *new)
+static void sctp_insert_list(struct list_head *head, struct list_head *new)
 {
 	struct list_head *pos;
 	struct sctp_chunk *nchunk, *lchunk;
@@ -510,7 +497,7 @@
 	error = sctp_outq_flush(q, /* rtx_timeout */ 1);
 
 	if (error)
-		q->asoc->base.sk->sk_err = -error;
+		q->asoc->base.sk->err = -error;
 }
 
 /*
diff -urN linux-2.4.29-rc2/net/sctp/proc.c linux-2.4.29-rc3/net/sctp/proc.c
--- linux-2.4.29-rc2/net/sctp/proc.c	2004-04-14 06:05:41.000000000 -0700
+++ linux-2.4.29-rc3/net/sctp/proc.c	2005-01-15 10:14:25.381140081 -0800
@@ -177,7 +177,7 @@
 			ep = sctp_ep(epb);
 			sk = epb->sk;
 			seq_printf(seq, "%8p %8p %-3d %-3d %-4d %-5d ", ep, sk,
-				   sctp_sk(sk)->type, sk->sk_state, hash,
+				   sctp_sk(sk)->type, sk->state, hash,
 				   epb->bind_addr.port);
 			sctp_seq_dump_local_addrs(seq, epb);
 			seq_printf(seq, "\n");
@@ -240,7 +240,7 @@
 			sk = epb->sk;
 			seq_printf(seq,
 				   "%8p %8p %-3d %-3d %-2d %-4d %-5d %-5d ",
-				   assoc, sk, sctp_sk(sk)->type, sk->sk_state,
+				   assoc, sk, sctp_sk(sk)->type, sk->state,
 				   assoc->state, hash, epb->bind_addr.port,
 				   assoc->peer.port);
 			sctp_seq_dump_local_addrs(seq, epb);
diff -urN linux-2.4.29-rc2/net/sctp/protocol.c linux-2.4.29-rc3/net/sctp/protocol.c
--- linux-2.4.29-rc2/net/sctp/protocol.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29-rc3/net/sctp/protocol.c	2005-01-15 10:14:25.383140167 -0800
@@ -93,7 +93,7 @@
 }
 
 /* Set up the proc fs entry for the SCTP protocol. */
-__init int sctp_proc_init(void)
+static __init int sctp_proc_init(void)
 {
 	if (!proc_net_sctp) {
 		struct proc_dir_entry *ent;
@@ -122,7 +122,7 @@
  * Note: Do not make this __exit as it is used in the init error
  * path.
  */
-void sctp_proc_exit(void)
+static void sctp_proc_exit(void)
 {
 	sctp_snmp_proc_exit();
 	sctp_eps_proc_exit();
@@ -428,9 +428,9 @@
  * addresses. If an association is passed, trys to get a dst entry with a
  * source address that matches an address in the bind address list.
  */
-struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
-				  union sctp_addr *daddr,
-				  union sctp_addr *saddr)
+static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
+					 union sctp_addr *daddr,
+					 union sctp_addr *saddr)
 {
 	struct rtable *rt;
 	struct rt_key key;
@@ -520,10 +520,10 @@
 /* For v4, the source address is cached in the route entry(dst). So no need
  * to cache it separately and hence this is an empty routine.
  */
-void sctp_v4_get_saddr(struct sctp_association *asoc,
-		       struct dst_entry *dst,
-		       union sctp_addr *daddr,
-		       union sctp_addr *saddr)
+static void sctp_v4_get_saddr(struct sctp_association *asoc,
+			      struct dst_entry *dst,
+			      union sctp_addr *daddr,
+			      union sctp_addr *saddr)
 {
 	struct rtable *rt = (struct rtable *)dst;
 
@@ -547,8 +547,8 @@
 }
 
 /* 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)
+static struct sock *sctp_v4_create_accept_sk(struct sock *sk,
+					     struct sctp_association *asoc)
 {
 	struct sock *newsk;
 	struct inet_opt *inet = inet_sk(sk);
@@ -561,18 +561,18 @@
 	sock_init_data(NULL, newsk);
 	sk_set_owner(newsk, THIS_MODULE);
 
-	newsk->sk_type = SOCK_STREAM;
+	newsk->type = SOCK_STREAM;
 
-	newsk->sk_prot = sk->sk_prot;
-	newsk->sk_no_check = sk->sk_no_check;
-	newsk->sk_reuse = sk->sk_reuse;
-	newsk->sk_shutdown = sk->sk_shutdown;
-
-	newsk->sk_destruct = inet_sock_destruct;
-	newsk->sk_zapped = 0;
-	newsk->sk_family = PF_INET;
-	newsk->sk_protocol = IPPROTO_SCTP;
-	newsk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;
+	newsk->prot = sk->prot;
+	newsk->no_check = sk->no_check;
+	newsk->reuse = sk->reuse;
+	newsk->shutdown = sk->shutdown;
+
+	newsk->destruct = inet_sock_destruct;
+	newsk->zapped = 0;
+	newsk->family = PF_INET;
+	newsk->protocol = IPPROTO_SCTP;
+	newsk->backlog_rcv = sk->prot->backlog_rcv;
 
 	newinet = inet_sk(newsk);
 
@@ -597,7 +597,7 @@
 	atomic_inc(&inet_sock_nr);
 #endif
 
-	if (newsk->sk_prot->init(newsk)) {
+	if (newsk->prot->init(newsk)) {
 		inet_sock_release(newsk);
 		newsk = NULL;
 	}
@@ -638,7 +638,7 @@
  * Initialize the control inode/socket with a control endpoint data
  * structure.  This endpoint is reserved exclusively for the OOTB processing.
  */
-int sctp_ctl_sock_init(void)
+static int sctp_ctl_sock_init(void)
 {
 	int err;
 	sa_family_t family;
@@ -655,7 +655,7 @@
 		       "SCTP: Failed to create the SCTP control socket.\n");
 		return err;
 	}
-	sctp_ctl_socket->sk->sk_allocation = GFP_ATOMIC;
+	sctp_ctl_socket->sk->allocation = GFP_ATOMIC;
 	inet_sk(sctp_ctl_socket->sk)->ttl = MAXTTL;
 
 	return 0;
@@ -807,7 +807,7 @@
 	return ip_queue_xmit(skb, ipfragok);
 }
 
-struct sctp_af sctp_ipv4_specific;
+static struct sctp_af sctp_ipv4_specific;
 
 static struct sctp_pf sctp_pf_inet = {
 	.event_msgname = sctp_inet_event_msgname,
@@ -828,7 +828,7 @@
 };
 
 /* Socket operations.  */
-struct proto_ops inet_seqpacket_ops = {
+static struct proto_ops inet_seqpacket_ops = {
 	.family      = PF_INET,
 	.release     = inet_release,       /* Needs to be wrapped... */
 	.bind        = inet_bind,
@@ -877,7 +877,7 @@
 };
 
 /* IPv4 address related functions.  */
-struct sctp_af sctp_ipv4_specific = {
+static struct sctp_af sctp_ipv4_specific = {
 	.sctp_xmit      = sctp_v4_xmit,
 	.setsockopt     = ip_setsockopt,
 	.getsockopt     = ip_getsockopt,
@@ -948,7 +948,7 @@
 }
 
 /* Initialize the universe into something sensible.  */
-__init int sctp_init(void)
+SCTP_STATIC __init int sctp_init(void)
 {
 	int i;
 	int status = 0;
@@ -1161,7 +1161,7 @@
 }
 
 /* Exit handler for the SCTP protocol.  */
-__exit void sctp_exit(void)
+SCTP_STATIC __exit void sctp_exit(void)
 {
 	/* BUG.  This should probably do something useful like clean
 	 * up all the remaining associations and all that memory.
diff -urN linux-2.4.29-rc2/net/sctp/sm_make_chunk.c linux-2.4.29-rc3/net/sctp/sm_make_chunk.c
--- linux-2.4.29-rc2/net/sctp/sm_make_chunk.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29-rc3/net/sctp/sm_make_chunk.c	2005-01-15 10:14:25.385140252 -0800
@@ -67,6 +67,19 @@
 
 extern kmem_cache_t *sctp_chunk_cachep;
 
+SCTP_STATIC
+struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc,
+				   __u8 type, __u8 flags, int paylen);
+static sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
+					const struct sctp_association *asoc,
+					const struct sctp_chunk *init_chunk,
+					int *cookie_len,
+					const __u8 *raw_addrs, int addrs_len);
+static int sctp_process_param(struct sctp_association *asoc,
+			      union sctp_params param,
+			      const union sctp_addr *peer_addr,
+			      int gfp);
+
 /* What was the inbound interface for this chunk? */
 int sctp_chunk_iif(const struct sctp_chunk *chunk)
 {
@@ -559,52 +572,6 @@
 	return retval;
 }
 
-/* Make a DATA chunk for the given association.  Populate the data
- * payload.
- */
-struct sctp_chunk *sctp_make_datafrag(struct sctp_association *asoc,
-				 const struct sctp_sndrcvinfo *sinfo,
-				 int data_len, const __u8 *data,
-				 __u8 flags, __u16 ssn)
-{
-	struct sctp_chunk *retval;
-
-	retval = sctp_make_datafrag_empty(asoc, sinfo, data_len, flags, ssn);
-	if (retval)
-		sctp_addto_chunk(retval, data_len, data);
-
-	return retval;
-}
-
-/* Make a DATA chunk for the given association to ride on stream id
- * 'stream', with a payload id of 'payload', and a body of 'data'.
- */
-struct sctp_chunk *sctp_make_data(struct sctp_association *asoc,
-			     const struct sctp_sndrcvinfo *sinfo,
-			     int data_len, const __u8 *data)
-{
-	struct sctp_chunk *retval = NULL;
-
-	retval = sctp_make_data_empty(asoc, sinfo, data_len);
-	if (retval)
-		sctp_addto_chunk(retval, data_len, data);
-        return retval;
-}
-
-/* Make a DATA chunk for the given association to ride on stream id
- * 'stream', with a payload id of 'payload', and a body big enough to
- * hold 'data_len' octets of data.  We use this version when we need
- * to build the message AFTER allocating memory.
- */
-struct sctp_chunk *sctp_make_data_empty(struct sctp_association *asoc,
-				   const struct sctp_sndrcvinfo *sinfo,
-				   int data_len)
-{
-	__u8 flags = SCTP_DATA_NOT_FRAG;
-
-	return sctp_make_datafrag_empty(asoc, sinfo, data_len, flags, 0);
-}
-
 /* Create a selective ackowledgement (SACK) for the given
  * association.  This reports on which TSN's we've seen to date,
  * including duplicates and gaps.
@@ -881,6 +848,31 @@
 	return retval;
 }
 
+/* Make an ABORT chunk with a PROTOCOL VIOLATION cause code. */ 
+struct sctp_chunk *sctp_make_abort_violation(
+	const struct sctp_association *asoc,
+	const struct sctp_chunk *chunk,
+	const __u8   *payload,
+	const size_t paylen)
+{
+	struct sctp_chunk  *retval;
+	struct sctp_paramhdr phdr;
+
+	retval = sctp_make_abort(asoc, chunk, sizeof(sctp_errhdr_t) + paylen
+					+ sizeof(sctp_chunkhdr_t));
+	if (!retval)
+		goto end;
+
+	sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION, payload, paylen);
+
+	phdr.type = htons(chunk->chunk_hdr->type);
+	phdr.length = chunk->chunk_hdr->length;
+	sctp_addto_chunk(retval, sizeof(sctp_paramhdr_t), &phdr);
+
+end:
+	return retval;
+}
+
 /* Make a HEARTBEAT chunk.  */
 struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc,
 				  const struct sctp_transport *transport,
@@ -933,7 +925,7 @@
 /* Create an Operation Error chunk with the specified space reserved.
  * This routine can be used for containing multiple causes in the chunk.
  */
-struct sctp_chunk *sctp_make_op_error_space(
+static struct sctp_chunk *sctp_make_op_error_space(
 	const struct sctp_association *asoc,
 	const struct sctp_chunk *chunk,
 	size_t size)
@@ -1034,7 +1026,6 @@
 	SCTP_DBG_OBJCNT_INC(chunk);
 	atomic_set(&retval->refcnt, 1);
 
-
 nodata:
 	return retval;
 }
@@ -1062,6 +1053,7 @@
 /* Create a new chunk, setting the type and flags headers from the
  * arguments, reserving enough space for a 'paylen' byte payload.
  */
+SCTP_STATIC
 struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc,
 				   __u8 type, __u8 flags, int paylen)
 {
@@ -1261,7 +1253,7 @@
 /* Build a cookie representing asoc.
  * This INCLUDES the param header needed to put the cookie in the INIT ACK.
  */
-sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
+static sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
 				      const struct sctp_association *asoc,
 				      const struct sctp_chunk *init_chunk,
 				      int *cookie_len,
@@ -1409,6 +1401,24 @@
 	}
 
 no_hmac:
+	/* IG Section 2.35.2:
+	 *  3) Compare the port numbers and the verification tag contained
+	 *     within the COOKIE ECHO chunk to the actual port numbers and the
+	 *     verification tag within the SCTP common header of the received
+	 *     packet. If these values do not match the packet MUST be silently
+	 *     discarded,
+	 */
+	if (ntohl(chunk->sctp_hdr->vtag) != bear_cookie->my_vtag) {
+		*error = -SCTP_IERROR_BAD_TAG;
+		goto fail;
+	}
+
+	if (ntohs(chunk->sctp_hdr->source) != bear_cookie->peer_addr.v4.sin_port ||
+	    ntohs(chunk->sctp_hdr->dest) != bear_cookie->my_port) {
+		*error = -SCTP_IERROR_BAD_PORTS;
+		goto fail;
+	}
+
 	/* Check to see if the cookie is stale.  If there is already
 	 * an association, there is no need to check cookie's expiration
 	 * for init collision case of lost COOKIE ACK.
@@ -1547,6 +1557,30 @@
 	return 0;
 }
 
+static int sctp_process_inv_paramlength(const struct sctp_association *asoc,
+					struct sctp_paramhdr *param,
+					const struct sctp_chunk *chunk,
+					struct sctp_chunk **errp)
+{
+	char		error[] = "The following parameter had invalid length:";
+	size_t		payload_len = WORD_ROUND(sizeof(error)) + 
+						sizeof(sctp_paramhdr_t);
+
+
+	/* Create an error chunk and fill it in with our payload. */
+	if (!*errp)
+		*errp = sctp_make_op_error_space(asoc, chunk, payload_len);
+
+	if (*errp) {
+		sctp_init_cause(*errp, SCTP_ERROR_PROTO_VIOLATION, error,
+				sizeof(error));
+		sctp_addto_chunk(*errp, sizeof(sctp_paramhdr_t), param);
+	}
+
+	return 0;
+}
+
+
 /* Do not attempt to handle the HOST_NAME parm.  However, do
  * send back an indicator to the peer.
  */
@@ -1725,6 +1759,18 @@
 
 	} /* for (loop through all parameters) */
 
+	/* There is a possibility that a parameter length was bad and
+	 * in that case we would have stoped walking the parameters.
+	 * The current param.p would point at the bad one.
+	 * Current consensus on the mailing list is to generate a PROTOCOL
+	 * VIOLATION error.  We build the ERROR chunk here and let the normal
+	 * error handling code build and send the packet.
+	 */
+	if (param.v < (void*)chunk->chunk_end - sizeof(sctp_paramhdr_t)) {
+		sctp_process_inv_paramlength(asoc, param.p, chunk, errp);
+		return 0;
+	}
+
 	/* The only missing mandatory param possible today is
 	 * the state cookie for an INIT-ACK chunk.
 	 */
@@ -1896,8 +1942,10 @@
  * work we do.  In particular, we should not build transport
  * structures for the addresses.
  */
-int sctp_process_param(struct sctp_association *asoc, union sctp_params param,
-		       const union sctp_addr *peer_addr, int gfp)
+static int sctp_process_param(struct sctp_association *asoc,
+			      union sctp_params param,
+			      const union sctp_addr *peer_addr,
+			      int gfp)
 {
 	union sctp_addr addr;
 	int i;
@@ -1913,7 +1961,7 @@
 	 */
 	switch (param.p->type) {
 	case SCTP_PARAM_IPV6_ADDRESS:
-		if (PF_INET6 != asoc->base.sk->sk_family)
+		if (PF_INET6 != asoc->base.sk->family)
 			break;
 		/* Fall through. */
 	case SCTP_PARAM_IPV4_ADDRESS:
@@ -2062,8 +2110,9 @@
  *
  * Address Parameter and other parameter will not be wrapped in this function 
  */
-struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc,
-				    union sctp_addr *addr, int vparam_len)
+static struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc,
+					   union sctp_addr *addr,
+					   int vparam_len)
 {
 	sctp_addiphdr_t asconf;
 	struct sctp_chunk *retval;
@@ -2232,8 +2281,8 @@
  *
  * Create an ASCONF_ACK chunk with enough space for the parameter responses. 
  */
-struct sctp_chunk *sctp_make_asconf_ack(const struct sctp_association *asoc,
-					__u32 serial, int vparam_len)
+static struct sctp_chunk *sctp_make_asconf_ack(const struct sctp_association *asoc,
+					       __u32 serial, int vparam_len)
 {
 	sctp_addiphdr_t		asconf;
 	struct sctp_chunk	*retval;
diff -urN linux-2.4.29-rc2/net/sctp/sm_sideeffect.c linux-2.4.29-rc3/net/sctp/sm_sideeffect.c
--- linux-2.4.29-rc2/net/sctp/sm_sideeffect.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29-rc3/net/sctp/sm_sideeffect.c	2005-01-15 10:14:25.387140337 -0800
@@ -55,6 +55,24 @@
 #include <net/sctp/sctp.h>
 #include <net/sctp/sm.h>
 
+static int sctp_cmd_interpreter(sctp_event_t event_type,
+				sctp_subtype_t subtype,
+				sctp_state_t state,
+				struct sctp_endpoint *ep,
+				struct sctp_association *asoc,
+				void *event_arg,
+			 	sctp_disposition_t status,
+				sctp_cmd_seq_t *commands,
+				int gfp);
+static int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype,
+			     sctp_state_t state,
+			     struct sctp_endpoint *ep,
+			     struct sctp_association *asoc,
+			     void *event_arg,
+			     sctp_disposition_t status,
+			     sctp_cmd_seq_t *commands,
+			     int gfp);
+
 /********************************************************************
  * Helper functions
  ********************************************************************/
@@ -134,8 +152,8 @@
 }
 
 /* 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)
+static int sctp_gen_sack(struct sctp_association *asoc, int force,
+			 sctp_cmd_seq_t *commands)
 {
 	__u32 ctsn, max_tsn_seen;
 	struct sctp_chunk *sack;
@@ -229,7 +247,7 @@
 			   transport, GFP_ATOMIC);
 
 	if (error)
-		asoc->base.sk->sk_err = -error;
+		asoc->base.sk->err = -error;
 
 out_unlock:
 	sctp_bh_unlock_sock(asoc->base.sk);
@@ -269,38 +287,38 @@
 			   (void *)timeout_type, GFP_ATOMIC);
 
 	if (error)
-		asoc->base.sk->sk_err = -error;
+		asoc->base.sk->err = -error;
 
 out_unlock:
 	sctp_bh_unlock_sock(asoc->base.sk);
 	sctp_association_put(asoc);
 }
 
-void sctp_generate_t1_cookie_event(unsigned long data)
+static void sctp_generate_t1_cookie_event(unsigned long data)
 {
 	struct sctp_association *asoc = (struct sctp_association *) data;
 	sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T1_COOKIE);
 }
 
-void sctp_generate_t1_init_event(unsigned long data)
+static void sctp_generate_t1_init_event(unsigned long data)
 {
 	struct sctp_association *asoc = (struct sctp_association *) data;
 	sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T1_INIT);
 }
 
-void sctp_generate_t2_shutdown_event(unsigned long data)
+static void sctp_generate_t2_shutdown_event(unsigned long data)
 {
 	struct sctp_association *asoc = (struct sctp_association *) data;
 	sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T2_SHUTDOWN);
 }
 
-void sctp_generate_t4_rto_event(unsigned long data)
+static void sctp_generate_t4_rto_event(unsigned long data)
 {
 	struct sctp_association *asoc = (struct sctp_association *) data;
 	sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T4_RTO);
 }
 
-void sctp_generate_t5_shutdown_guard_event(unsigned long data)
+static void sctp_generate_t5_shutdown_guard_event(unsigned long data)
 {
         struct sctp_association *asoc = (struct sctp_association *)data;
         sctp_generate_timeout_event(asoc,
@@ -308,7 +326,7 @@
 
 } /* sctp_generate_t5_shutdown_guard_event() */
 
-void sctp_generate_autoclose_event(unsigned long data)
+static void sctp_generate_autoclose_event(unsigned long data)
 {
 	struct sctp_association *asoc = (struct sctp_association *) data;
 	sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_AUTOCLOSE);
@@ -345,7 +363,7 @@
 			   transport, GFP_ATOMIC);
 
          if (error)
-		 asoc->base.sk->sk_err = -error;
+		 asoc->base.sk->err = -error;
 
 out_unlock:
 	sctp_bh_unlock_sock(asoc->base.sk);
@@ -353,7 +371,7 @@
 }
 
 /* Inject a SACK Timeout event into the state machine.  */
-void sctp_generate_sack_event(unsigned long data)
+static void sctp_generate_sack_event(unsigned long data)
 {
 	struct sctp_association *asoc = (struct sctp_association *) data;
 	sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_SACK);
@@ -397,7 +415,7 @@
 	asoc->overall_error_count++;
 
 	if (transport->active &&
-	    (transport->error_count++ >= transport->error_threshold)) {
+	    (transport->error_count++ >= transport->max_retrans)) {
 		SCTP_DEBUG_PRINTK("transport_strike: transport "
 				  "IP:%d.%d.%d.%d failed.\n",
 				  NIPQUAD(transport->ipaddr.v4.sin_addr));
@@ -460,9 +478,9 @@
 	sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
 			SCTP_STATE(SCTP_STATE_CLOSED));
 
-	/* Set sk_err to ECONNRESET on a 1-1 style socket. */
+	/* Set sk->err to ECONNRESET on a 1-1 style socket. */
 	if (!sctp_style(asoc->base.sk, UDP))
-		asoc->base.sk->sk_err = ECONNRESET; 
+		asoc->base.sk->err = ECONNRESET; 
 
 	/* SEND_FAILED sent later when cleaning up the association. */
 	asoc->outqueue.error = error;
@@ -648,16 +666,16 @@
 	asoc->state = state;
 
 	if (sctp_style(sk, TCP)) {
-		/* Change the sk->sk_state of a TCP-style socket that has 
+		/* Change the sk->state of a TCP-style socket that has 
 		 * sucessfully completed a connect() call.
 		 */
 		if (sctp_state(asoc, ESTABLISHED) && sctp_sstate(sk, CLOSED))
-			sk->sk_state = SCTP_SS_ESTABLISHED;
+			sk->state = SCTP_SS_ESTABLISHED;
 
 		/* Set the RCV_SHUTDOWN flag when a SHUTDOWN is received. */
 		if (sctp_state(asoc, SHUTDOWN_RECEIVED) &&
 		    sctp_sstate(sk, ESTABLISHED))
-			sk->sk_shutdown |= RCV_SHUTDOWN;
+			sk->shutdown |= RCV_SHUTDOWN;
 	}
 
 	if (sctp_state(asoc, ESTABLISHED) ||
@@ -676,7 +694,7 @@
 		 * notifications.
 		 */
 		if (!sctp_style(sk, UDP))
-			sk->sk_state_change(sk);
+			sk->state_change(sk);
 	}
 }
 
@@ -691,7 +709,7 @@
 	 * can pick it up later.
 	 */ 
 	if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING) &&
-	    (!asoc->temp) && (sk->sk_shutdown != SHUTDOWN_MASK))
+	    (!asoc->temp) && (sk->shutdown != SHUTDOWN_MASK))
 		return;
 
 	sctp_unhash_established(asoc);
@@ -857,14 +875,14 @@
 /*****************************************************************
  * 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,
-		      struct sctp_endpoint *ep,
-		      struct sctp_association *asoc,
-		      void *event_arg,
-		      sctp_disposition_t status,
-		      sctp_cmd_seq_t *commands,
-		      int gfp)
+static int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype,
+			     sctp_state_t state,
+			     struct sctp_endpoint *ep,
+			     struct sctp_association *asoc,
+			     void *event_arg,
+			     sctp_disposition_t status,
+			     sctp_cmd_seq_t *commands,
+			     int gfp)
 {
 	int error;
 
@@ -944,11 +962,15 @@
  ********************************************************************/
 
 /* This is the side-effect interpreter.  */
-int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
-			 sctp_state_t state, struct sctp_endpoint *ep,
-			 struct sctp_association *asoc, void *event_arg,
-			 sctp_disposition_t status, sctp_cmd_seq_t *commands,
-			 int gfp)
+static int sctp_cmd_interpreter(sctp_event_t event_type,
+				sctp_subtype_t subtype,
+				sctp_state_t state,
+				struct sctp_endpoint *ep,
+				struct sctp_association *asoc,
+				void *event_arg,
+			 	sctp_disposition_t status,
+				sctp_cmd_seq_t *commands,
+				int gfp)
 {
 	int error = 0;
 	int force;
diff -urN linux-2.4.29-rc2/net/sctp/sm_statefuns.c linux-2.4.29-rc3/net/sctp/sm_statefuns.c
--- linux-2.4.29-rc2/net/sctp/sm_statefuns.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29-rc3/net/sctp/sm_statefuns.c	2005-01-15 10:14:25.392140551 -0800
@@ -65,6 +65,53 @@
 #include <net/sctp/sm.h>
 #include <net/sctp/structs.h>
 
+static struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *ep,
+				  const struct sctp_association *asoc,
+				  struct sctp_chunk *chunk,
+				  const void *payload,
+				  size_t paylen);
+static int sctp_eat_data(const struct sctp_association *asoc,
+			 struct sctp_chunk *chunk,
+			 sctp_cmd_seq_t *commands);
+static struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *asoc,
+					     const struct sctp_chunk *chunk);
+static void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep,
+				       const struct sctp_association *asoc,
+				       const struct sctp_chunk *chunk,
+				       sctp_cmd_seq_t *commands,
+				       struct sctp_chunk *err_chunk);
+static sctp_disposition_t sctp_sf_do_5_2_6_stale(const struct sctp_endpoint *ep,
+						 const struct sctp_association *asoc,
+						 const sctp_subtype_t type,
+						 void *arg,
+						 sctp_cmd_seq_t *commands);
+static sctp_disposition_t sctp_sf_shut_8_4_5(const struct sctp_endpoint *ep,
+					     const struct sctp_association *asoc,
+					     const sctp_subtype_t type,
+					     void *arg,
+					     sctp_cmd_seq_t *commands);
+static struct sctp_sackhdr *sctp_sm_pull_sack(struct sctp_chunk *chunk);
+
+
+/* Small helper function that checks if the chunk length
+ * is of the appropriate length.  The 'required_length' argument
+ * is set to be the size of a specific chunk we are testing.
+ * Return Values:  1 = Valid length
+ * 		   0 = Invalid length
+ *
+ */
+static inline int
+sctp_chunk_length_valid(struct sctp_chunk *chunk,
+			   __u16 required_length)
+{
+	__u16 chunk_length = ntohs(chunk->chunk_hdr->length);
+
+	if (unlikely(chunk_length < required_length))
+		return 0;
+
+	return 1;
+}
+
 /**********************************************************
  * These are the state functions for handling chunk events.
  **********************************************************/
@@ -199,9 +246,14 @@
 	/* 6.10 Bundling
 	 * An endpoint MUST NOT bundle INIT, INIT ACK or
 	 * SHUTDOWN COMPLETE with any other chunks.
+	 * 
+	 * IG Section 2.11.2
+	 * Furthermore, we require that the receiver of an INIT chunk MUST
+	 * enforce these rules by silently discarding an arriving packet
+	 * with an INIT chunk that is bundled with other chunks.
 	 */
 	if (!chunk->singleton)
-		return SCTP_DISPOSITION_VIOLATION;
+		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
 	/* If the packet is an OOTB packet which is temporarily on the
 	 * control endpoint, respond with an ABORT.
@@ -216,7 +268,7 @@
 	 */
 	if (!sctp_sstate(sk, LISTENING) ||
 	    (sctp_style(sk, TCP) &&
-	     (sk->sk_ack_backlog >= sk->sk_max_ack_backlog)))
+	     (sk->ack_backlog >= sk->max_ack_backlog)))
 		return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
 
 	/* 3.1 A packet containing an INIT chunk MUST have a zero Verification
@@ -225,6 +277,14 @@
 	if (chunk->sctp_hdr->vtag != 0)
 		return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
 
+	/* Make sure that the INIT chunk has a valid length.
+	 * Normally, this would cause an ABORT with a Protocol Violation
+	 * error, but since we don't have an association, we'll
+	 * just discard the packet.
+	 */
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_init_chunk_t)))
+		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+
 	/* Verify the INIT chunk before processing it. */
 	err_chunk = NULL;
 	if (!sctp_verify_init(asoc, chunk->chunk_hdr->type,
@@ -376,6 +436,13 @@
 	struct sctp_packet *packet;
 	sctp_disposition_t ret;
 
+	if (!sctp_vtag_verify(chunk, asoc))
+		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+
+	/* Make sure that the INIT-ACK chunk has a valid length */
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_initack_chunk_t)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
 	/* 6.10 Bundling
 	 * An endpoint MUST NOT bundle INIT, INIT ACK or
 	 * SHUTDOWN COMPLETE with any other chunks.
@@ -383,9 +450,6 @@
 	if (!chunk->singleton)
 		return SCTP_DISPOSITION_VIOLATION;
 
-	if (!sctp_vtag_verify(chunk, asoc))
-		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
-
 	/* Grab the INIT header.  */
 	chunk->subh.init_hdr = (sctp_inithdr_t *) chunk->skb->data;
 
@@ -542,6 +606,14 @@
 	if (ep == sctp_sk((sctp_get_ctl_sock()))->ep)
 		return sctp_sf_ootb(ep, asoc, type, arg, commands);
 
+	/* Make sure that the COOKIE_ECHO chunk has a valid length.
+	 * In this case, we check that we have enough for at least a
+	 * chunk header.  More detailed verification is done
+	 * in sctp_unpack_cookie().
+	 */
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
+		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+
 	/* "Decode" the chunk.  We have no optional parameters so we
 	 * are in good shape.
 	 */
@@ -687,6 +759,13 @@
 	if (!sctp_vtag_verify(chunk, asoc))
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+	/* Verify that the chunk length for the COOKIE-ACK is OK.
+	 * If we don't do this, any bundled chunks may be junked.
+	 */
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
+
 	/* Reset init error count upon receipt of COOKIE-ACK,
 	 * to avoid problems with the managemement of this
 	 * counter in stale cookie situations when a transition back
@@ -748,11 +827,11 @@
 }
 
 /* Generate and sendout a heartbeat packet.  */
-sctp_disposition_t sctp_sf_heartbeat(const struct sctp_endpoint *ep,
-				     const struct sctp_association *asoc,
-				     const sctp_subtype_t type,
-				     void *arg,
-				     sctp_cmd_seq_t *commands)
+static sctp_disposition_t sctp_sf_heartbeat(const struct sctp_endpoint *ep,
+					    const struct sctp_association *asoc,
+					    const sctp_subtype_t type,
+					    void *arg,
+					    sctp_cmd_seq_t *commands)
 {
 	struct sctp_transport *transport = (struct sctp_transport *) arg;
 	struct sctp_chunk *reply;
@@ -859,6 +938,11 @@
 	if (!sctp_vtag_verify(chunk, asoc))
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+	/* Make sure that the HEARTBEAT chunk has a valid length. */
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_heartbeat_chunk_t)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
+
 	/* 8.3 The receiver of the HEARTBEAT should immediately
 	 * respond with a HEARTBEAT ACK that contains the Heartbeat
 	 * Information field copied from the received HEARTBEAT chunk.
@@ -922,6 +1006,11 @@
 	if (!sctp_vtag_verify(chunk, asoc))
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+	/* Make sure that the HEARTBEAT-ACK chunk has a valid length.  */
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_heartbeat_chunk_t)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
+
 	hbinfo = (sctp_sender_hb_info_t *) chunk->skb->data;
 	from_addr = hbinfo->daddr;
 	link = sctp_assoc_lookup_paddr(asoc, &from_addr);
@@ -1165,9 +1254,14 @@
 	/* 6.10 Bundling
 	 * An endpoint MUST NOT bundle INIT, INIT ACK or
 	 * SHUTDOWN COMPLETE with any other chunks.
+	 *
+	 * IG Section 2.11.2
+	 * Furthermore, we require that the receiver of an INIT chunk MUST
+	 * enforce these rules by silently discarding an arriving packet
+	 * with an INIT chunk that is bundled with other chunks.
 	 */
 	if (!chunk->singleton)
-		return SCTP_DISPOSITION_VIOLATION;
+		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
 	/* 3.1 A packet containing an INIT chunk MUST have a zero Verification
 	 * Tag. 
@@ -1175,6 +1269,13 @@
 	if (chunk->sctp_hdr->vtag != 0)
 		return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
 
+	/* Make sure that the INIT chunk has a valid length.
+	 * In this case, we generate a protocol violation since we have
+	 * an association established.
+	 */
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_init_chunk_t)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
 	/* Grab the INIT header.  */
 	chunk->subh.init_hdr = (sctp_inithdr_t *) chunk->skb->data;
 
@@ -1718,6 +1819,15 @@
 	char action;
 	struct sctp_chunk *err_chk_p;
 
+	/* Make sure that the chunk has a valid length from the protocol
+	 * perspective.  In this case check to make sure we have at least
+	 * enough for the chunk header.  Cookie length verification is
+	 * done later.
+	 */
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
+
 	/* "Decode" the chunk.  We have no optional parameters so we
 	 * are in good shape.
 	 */
@@ -1815,6 +1925,19 @@
 	if (!sctp_vtag_verify_either(chunk, asoc))
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+	/* Make sure that the ABORT chunk has a valid length.
+	 * Since this is an ABORT chunk, we have to discard it
+	 * because of the following text:
+	 * RFC 2960, Section 3.3.7
+	 *    If an endpoint receives an ABORT with a format error or for an
+	 *    association that doesn't exist, it MUST silently discard it.
+	 * Becasue the length is "invalid", we can't really discard just
+	 * as we do not know its true length.  So, to be safe, discard the
+	 * packet.
+	 */
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_abort_chunk_t)))
+		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+
 	/* Stop the T5-shutdown guard timer.  */
 	sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
 			SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD));
@@ -1838,6 +1961,19 @@
 	if (!sctp_vtag_verify_either(chunk, asoc))
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+	/* Make sure that the ABORT chunk has a valid length.
+	 * Since this is an ABORT chunk, we have to discard it
+	 * because of the following text:
+	 * RFC 2960, Section 3.3.7
+	 *    If an endpoint receives an ABORT with a format error or for an
+	 *    association that doesn't exist, it MUST silently discard it.
+	 * Becasue the length is "invalid", we can't really discard just
+	 * as we do not know its true length.  So, to be safe, discard the
+	 * packet.
+	 */
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_abort_chunk_t)))
+		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+
 	/* Stop the T2-shutdown timer. */
 	sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
 			SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN));
@@ -1890,6 +2026,16 @@
 	struct sctp_chunk *chunk = arg;
 	sctp_errhdr_t *err;
 
+	if (!sctp_vtag_verify(chunk, asoc))
+		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+
+	/* Make sure that the ERROR chunk has a valid length.
+	 * The parameter walking depends on this as well.
+	 */
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_operr_chunk_t)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
+
 	/* Process the error here */
 	/* FUTURE FIXME:  When PR-SCTP related and other optional
 	 * parms are emitted, this will have to change to handle multiple
@@ -1900,6 +2046,12 @@
 			return sctp_sf_do_5_2_6_stale(ep, asoc, type, 
 							arg, commands);
 	}
+
+	/* It is possible to have malformed error causes, and that
+	 * will cause us to end the walk early.  However, since
+	 * we are discarding the packet, there should be no adverse
+	 * affects.
+	 */
 	return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 }
 
@@ -1928,11 +2080,11 @@
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_do_5_2_6_stale(const struct sctp_endpoint *ep,
-					  const struct sctp_association *asoc,
-					  const sctp_subtype_t type,
-					  void *arg,
-					  sctp_cmd_seq_t *commands)
+static sctp_disposition_t sctp_sf_do_5_2_6_stale(const struct sctp_endpoint *ep,
+						 const struct sctp_association *asoc,
+						 const sctp_subtype_t type,
+						 void *arg,
+						 sctp_cmd_seq_t *commands)
 {
 	struct sctp_chunk *chunk = arg;
 	time_t stale;
@@ -2064,12 +2216,24 @@
 	if (!sctp_vtag_verify_either(chunk, asoc))
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
-	/* Check that chunk header looks valid.  */
+	/* Make sure that the ABORT chunk has a valid length.
+	 * Since this is an ABORT chunk, we have to discard it
+	 * because of the following text:
+	 * RFC 2960, Section 3.3.7
+	 *    If an endpoint receives an ABORT with a format error or for an
+	 *    association that doesn't exist, it MUST silently discard it.
+	 * Becasue the length is "invalid", we can't really discard just
+	 * as we do not know its true length.  So, to be safe, discard the
+	 * packet.
+	 */
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_abort_chunk_t)))
+		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+
+	/* See if we have an error cause code in the chunk.  */
 	len = ntohs(chunk->chunk_hdr->length);
 	if (len >= 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_U32(error));
 	SCTP_INC_STATS(SctpAborteds);
@@ -2096,27 +2260,44 @@
 	if (!sctp_vtag_verify_either(chunk, asoc))
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
-	sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
-			SCTP_STATE(SCTP_STATE_CLOSED));
-	SCTP_INC_STATS(SctpAborteds);
-	sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
-			SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
+	/* Make sure that the ABORT chunk has a valid length.
+	 * Since this is an ABORT chunk, we have to discard it
+	 * because of the following text:
+	 * RFC 2960, Section 3.3.7
+	 *    If an endpoint receives an ABORT with a format error or for an
+	 *    association that doesn't exist, it MUST silently discard it.
+	 * Becasue the length is "invalid", we can't really discard just
+	 * as we do not know its true length.  So, to be safe, discard the
+	 * packet.
+	 */
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_abort_chunk_t)))
+		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
-	/* Check that chunk header looks valid.  */
+	/* See if we have an error cause code in the chunk.  */
 	len = ntohs(chunk->chunk_hdr->length);
 	if (len >= 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_U32(error));
+	sctp_stop_t1_and_abort(commands, error);
 
 	return SCTP_DISPOSITION_ABORT;
 }
 
 /*
+ * Process an incoming ICMP as an ABORT.  (COOKIE-WAIT state)
+ */
+sctp_disposition_t sctp_sf_cookie_wait_icmp_abort(const struct sctp_endpoint *ep,
+					const struct sctp_association *asoc,
+					const sctp_subtype_t type,
+					void *arg,
+					sctp_cmd_seq_t *commands)
+{
+	sctp_stop_t1_and_abort(commands, SCTP_ERROR_NO_ERROR);
+	return SCTP_DISPOSITION_ABORT;
+}
+
+/*
  * Process an ABORT.  (COOKIE-ECHOED state)
- *
- * See sctp_sf_do_9_1_abort() above.
  */
 sctp_disposition_t sctp_sf_cookie_echoed_abort(const struct sctp_endpoint *ep,
 					       const struct sctp_association *asoc,
@@ -2131,6 +2312,23 @@
 }
 
 /*
+ * Stop T1 timer and abort association with "INIT failed".
+ *
+ * This is common code called by several sctp_sf_*_abort() functions above.
+ */
+void sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands, __u16 error)
+{
+	sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
+			SCTP_STATE(SCTP_STATE_CLOSED));
+	SCTP_INC_STATS(SctpAborteds);
+	sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
+			SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
+	/* CMD_INIT_FAILED will DELETE_TCB. */
+	sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
+			SCTP_U32(error));
+}
+
+/*
  * sctp_sf_do_9_2_shut
  *
  * Section: 9.2
@@ -2174,14 +2372,20 @@
 	sctp_disposition_t disposition;
 	struct sctp_ulpevent *ev;
 
+	if (!sctp_vtag_verify(chunk, asoc))
+		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+
+	/* Make sure that the SHUTDOWN chunk has a valid length. */
+	if (!sctp_chunk_length_valid(chunk,
+				      sizeof(struct sctp_shutdown_chunk_t)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
+
 	/* Convert the elaborate header.  */
 	sdh = (sctp_shutdownhdr_t *)chunk->skb->data;
 	skb_pull(chunk->skb, sizeof(sctp_shutdownhdr_t));
 	chunk->subh.shutdown_hdr = sdh;
 
-	if (!sctp_vtag_verify(chunk, asoc))
-		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
-
 	/* Upon the reception of the SHUTDOWN, the peer endpoint shall
 	 *  - enter the SHUTDOWN-RECEIVED state,
 	 *  - stop accepting new data from its SCTP user
@@ -2238,6 +2442,10 @@
 	struct sctp_chunk *chunk = (struct sctp_chunk *) arg;
 	struct sctp_chunk *reply;
 
+	/* Since we are not going to really process this INIT, there
+	 * is no point in verifying chunk boundries.  Just generate
+	 * the SHUTDOWN ACK.
+	 */
 	reply = sctp_make_shutdown_ack(asoc, chunk);
 	if (NULL == reply)
 		goto nomem;
@@ -2295,6 +2503,10 @@
 	if (!sctp_vtag_verify(chunk, asoc))
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_ecne_chunk_t)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
+		
 	cwr = (sctp_cwrhdr_t *) chunk->skb->data;
 	skb_pull(chunk->skb, sizeof(sctp_cwrhdr_t));
 
@@ -2345,6 +2557,10 @@
 	if (!sctp_vtag_verify(chunk, asoc))
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_ecne_chunk_t)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
+
 	ecne = (sctp_ecnehdr_t *) chunk->skb->data;
 	skb_pull(chunk->skb, sizeof(sctp_ecnehdr_t));
 
@@ -2400,6 +2616,10 @@
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
         }
 
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_data_chunk_t)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
+
 	error = sctp_eat_data(asoc, chunk, commands );
 	switch (error) {
 	case SCTP_IERROR_NO_ERROR:
@@ -2518,6 +2738,10 @@
 	}
 
 
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_data_chunk_t)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
+
 	error = sctp_eat_data(asoc, chunk, commands );
 	switch (error) {
 	case SCTP_IERROR_NO_ERROR:
@@ -2599,6 +2823,11 @@
 	if (!sctp_vtag_verify(chunk, asoc))
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+	/* Make sure that the SACK chunk has a valid length. */
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_sack_chunk_t)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
+
 	/* Pull the SACK chunk from the data buffer */
 	sackh = sctp_sm_pull_sack(chunk);
 	/* Was this a bogus SACK? */
@@ -2701,6 +2930,14 @@
 	struct sctp_chunk *chunk = arg;
 	struct sctp_ulpevent *ev;
 
+	if (!sctp_vtag_verify(chunk, asoc))
+		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+
+	/* Make sure that the ERROR chunk has a valid length. */
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_operr_chunk_t)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
+
 	while (chunk->chunk_end > chunk->skb->data) {
 		ev = sctp_ulpevent_make_remote_error(asoc, chunk, 0,
 						     GFP_ATOMIC);
@@ -2745,6 +2982,11 @@
 	if (!sctp_vtag_verify(chunk, asoc))
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+	/* Make sure that the SHUTDOWN_ACK chunk has a valid length. */
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
+
 	/* 10.2 H) SHUTDOWN COMPLETE notification
 	 *
 	 * When SCTP completes the shutdown procedures (section 9.2) this
@@ -2819,11 +3061,23 @@
 
 	ch = (sctp_chunkhdr_t *) chunk->chunk_hdr;
 	do {
+		/* Break out if chunk length is less then minimal. */
+		if (ntohs(ch->length) < sizeof(sctp_chunkhdr_t))
+			break;
+
 		ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length));
 
 		if (SCTP_CID_SHUTDOWN_ACK == ch->type)
 			ootb_shut_ack = 1;
 
+		/* RFC 2960, Section 3.3.7
+		 *   Moreover, under any circumstances, an endpoint that
+		 *   receives an ABORT  MUST NOT respond to that ABORT by
+		 *   sending an ABORT of its own.
+		 */
+		if (SCTP_CID_ABORT == ch->type)
+			return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+			
 		ch = (sctp_chunkhdr_t *) ch_end;
 	} while (ch_end < skb->tail);
 
@@ -2854,11 +3108,11 @@
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_shut_8_4_5(const struct sctp_endpoint *ep,
-				      const struct sctp_association *asoc,
-				      const sctp_subtype_t type,
-				      void *arg,
-				      sctp_cmd_seq_t *commands)
+static sctp_disposition_t sctp_sf_shut_8_4_5(const struct sctp_endpoint *ep,
+					     const struct sctp_association *asoc,
+					     const sctp_subtype_t type,
+					     void *arg,
+					     sctp_cmd_seq_t *commands)
 {
 	struct sctp_packet *packet = NULL;
 	struct sctp_chunk *chunk = arg;
@@ -2886,6 +3140,12 @@
 
 		SCTP_INC_STATS(SctpOutCtrlChunks);
 
+		/* If the chunk length is invalid, we don't want to process
+		 * the reset of the packet.
+		 */
+		if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
+			return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+
 		return SCTP_DISPOSITION_CONSUME;
 	}
 
@@ -2928,6 +3188,17 @@
 	sctp_addiphdr_t		*hdr;
 	__u32			serial;
 
+	if (!sctp_vtag_verify(chunk, asoc)) {
+		sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG,
+				SCTP_NULL());
+		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+	}
+
+	/* Make sure that the ASCONF ADDIP chunk has a valid length.  */
+	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_addip_chunk_t)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
+
 	hdr = (sctp_addiphdr_t *)chunk->skb->data;
 	serial = ntohl(hdr->serial);
 
@@ -2948,7 +3219,8 @@
 		/* ADDIP 4.2 C3) If the value found in the serial number is
 		 * equal to the value stored in the 'Peer-Serial-Number'
 		 * IMPLEMENTATION NOTE: As an optimization a receiver may wish
-		 * to save the last ASCONF-ACK for some predetermined period of 		 * time and instead of re-processing the ASCONF (with the same
+		 * to save the last ASCONF-ACK for some predetermined period of
+		 * time and instead of re-processing the ASCONF (with the same
 		 * serial number) it may just re-transmit the ASCONF-ACK.
 		 */
 		if (asoc->addip_last_asconf_ack)
@@ -2987,6 +3259,17 @@
 	sctp_addiphdr_t		*addip_hdr;
 	__u32			sent_serial, rcvd_serial;
 
+	if (!sctp_vtag_verify(asconf_ack, asoc)) {
+		sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG,
+				SCTP_NULL());
+		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+	}
+
+	/* Make sure that the ADDIP chunk has a valid length.  */
+	if (!sctp_chunk_length_valid(asconf_ack, sizeof(sctp_addip_chunk_t)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
+
 	addip_hdr = (sctp_addiphdr_t *)asconf_ack->skb->data;
 	rcvd_serial = ntohl(addip_hdr->serial);
 
@@ -3085,6 +3368,11 @@
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 	}
 
+	/* Make sure that the FORWARD_TSN chunk has valid length.  */
+	if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_fwdtsn_chunk)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
+
 	fwdtsn_hdr = (struct sctp_fwdtsn_hdr *)chunk->skb->data;
 	chunk->subh.fwdtsn_hdr = fwdtsn_hdr;
 	len = ntohs(chunk->chunk_hdr->length);
@@ -3143,6 +3431,11 @@
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 	}
 
+	/* Make sure that the FORWARD_TSN chunk has a valid length.  */
+	if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_fwdtsn_chunk)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
+
 	fwdtsn_hdr = (struct sctp_fwdtsn_hdr *)chunk->skb->data;
 	chunk->subh.fwdtsn_hdr = fwdtsn_hdr;
 	len = ntohs(chunk->chunk_hdr->length);
@@ -3217,6 +3510,14 @@
 	if (!sctp_vtag_verify(unk_chunk, asoc))
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+	/* Make sure that the chunk has a valid length.
+	 * Since we don't know the chunk type, we use a general
+	 * chunkhdr structure to make a comparison.
+	 */
+	if (!sctp_chunk_length_valid(unk_chunk, sizeof(sctp_chunkhdr_t)))
+		return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+						  commands);
+
 	switch (type.chunk & SCTP_CID_ACTION_MASK) {
 	case SCTP_CID_ACTION_DISCARD:
 		/* Discard the packet.  */
@@ -3339,6 +3640,66 @@
 	return SCTP_DISPOSITION_VIOLATION;
 }
 
+
+/*
+ * Handle a protocol violation when the chunk length is invalid.
+ * "Invalid" length is identified as smaller then the minimal length a
+ * given chunk can be.  For example, a SACK chunk has invalid length
+ * if it's length is set to be smaller then the size of sctp_sack_chunk_t.
+ *
+ * We inform the other end by sending an ABORT with a Protocol Violation
+ * error code. 
+ *
+ * Section: Not specified
+ * Verification Tag:  Nothing to do
+ * Inputs
+ * (endpoint, asoc, chunk)
+ *
+ * Outputs
+ * (reply_msg, msg_up, counters)
+ *
+ * Generate an  ABORT chunk and terminate the association.
+ */
+sctp_disposition_t sctp_sf_violation_chunklen(const struct sctp_endpoint *ep,
+				     const struct sctp_association *asoc,
+				     const sctp_subtype_t type,
+				     void *arg,
+				     sctp_cmd_seq_t *commands)
+{
+	struct sctp_chunk *chunk =  arg;
+	struct sctp_chunk *abort = NULL;
+	char 		   err_str[]="The following chunk had invalid length:";
+
+	/* Make the abort chunk. */
+	abort = sctp_make_abort_violation(asoc, chunk, err_str,
+					  sizeof(err_str));
+	if (!abort)
+		goto nomem;
+
+	sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
+	SCTP_INC_STATS(SctpOutCtrlChunks);
+
+	if (asoc->state <= SCTP_STATE_COOKIE_ECHOED) {
+		sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
+				SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
+		sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
+				SCTP_U32(SCTP_ERROR_PROTO_VIOLATION));
+	} else {
+		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
+				SCTP_U32(SCTP_ERROR_PROTO_VIOLATION));
+		SCTP_DEC_STATS(SctpCurrEstab);
+	}
+
+	sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET, SCTP_NULL());
+
+	SCTP_INC_STATS(SctpAborteds);
+	
+	return SCTP_DISPOSITION_ABORT;
+
+nomem:
+	return SCTP_DISPOSITION_NOMEM;
+}
+
 /***************************************************************************
  * These are the state functions for handling primitive (Section 10) events.
  ***************************************************************************/
@@ -4051,6 +4412,23 @@
 	struct sctp_chunk *chunk = (struct sctp_chunk *) arg;
 	struct sctp_chunk *reply;
 
+	/* There are 2 ways of getting here:
+	 *    1) called in response to a SHUTDOWN chunk
+	 *    2) called when SCTP_EVENT_NO_PENDING_TSN event is issued.
+	 *
+	 * For the case (2), the arg parameter is set to NULL.  We need
+	 * to check that we have a chunk before accessing it's fields.
+	 */
+	if (chunk) {
+		if (!sctp_vtag_verify(chunk, asoc))
+			return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+
+		/* Make sure that the SHUTDOWN chunk has a valid length. */
+		if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_shutdown_chunk_t)))
+			return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+							  commands);
+	}
+
 	/* If it has no more outstanding DATA chunks, the SHUTDOWN receiver
 	 * shall send a SHUTDOWN ACK ...
 	 */
@@ -4538,7 +4916,7 @@
  ********************************************************************/
 
 /* Pull the SACK chunk based on the SACK header. */
-struct sctp_sackhdr *sctp_sm_pull_sack(struct sctp_chunk *chunk)
+static struct sctp_sackhdr *sctp_sm_pull_sack(struct sctp_chunk *chunk)
 {
 	struct sctp_sackhdr *sack;
 	unsigned int len;
@@ -4565,7 +4943,7 @@
 /* Create an ABORT packet to be sent as a response, with the specified
  * error causes.
  */
-struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *ep,
+static struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *ep,
 				  const struct sctp_association *asoc,
 				  struct sctp_chunk *chunk,
 				  const void *payload,
@@ -4601,8 +4979,8 @@
 }
 
 /* Allocate a packet for responding in the OOTB conditions.  */
-struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *asoc,
-				 const struct sctp_chunk *chunk)
+static struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *asoc,
+					     const struct sctp_chunk *chunk)
 {
 	struct sctp_packet *packet;
 	struct sctp_transport *transport;
@@ -4665,11 +5043,11 @@
 }
 
 /* Send a stale cookie error when a invalid COOKIE ECHO chunk is found  */
-void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep,
-				const struct sctp_association *asoc,
-				const struct sctp_chunk *chunk,
-				sctp_cmd_seq_t *commands,
-				struct sctp_chunk *err_chunk)
+static void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep,
+				       const struct sctp_association *asoc,
+				       const struct sctp_chunk *chunk,
+				       sctp_cmd_seq_t *commands,
+				       struct sctp_chunk *err_chunk)
 {
 	struct sctp_packet *packet;
 
@@ -4695,9 +5073,9 @@
 
 
 /* Process a data chunk */
-int sctp_eat_data(const struct sctp_association *asoc,
-		  struct sctp_chunk *chunk,
-		  sctp_cmd_seq_t *commands)
+static int sctp_eat_data(const struct sctp_association *asoc,
+			 struct sctp_chunk *chunk,
+			 sctp_cmd_seq_t *commands)
 {
 	sctp_datahdr_t *data_hdr;
 	struct sctp_chunk *err;
diff -urN linux-2.4.29-rc2/net/sctp/sm_statetable.c linux-2.4.29-rc3/net/sctp/sm_statetable.c
--- linux-2.4.29-rc2/net/sctp/sm_statetable.c	2004-08-07 16:26:07.000000000 -0700
+++ linux-2.4.29-rc3/net/sctp/sm_statetable.c	2005-01-15 10:14:25.394140636 -0800
@@ -50,6 +50,17 @@
 #include <net/sctp/sctp.h>
 #include <net/sctp/sm.h>
 
+static const sctp_sm_table_entry_t
+primitive_event_table[SCTP_NUM_PRIMITIVE_TYPES][SCTP_STATE_NUM_STATES];
+static const sctp_sm_table_entry_t
+other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STATES];
+static const sctp_sm_table_entry_t
+timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM_STATES];
+
+static const sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t cid,
+							    sctp_state_t state);
+
+
 static const sctp_sm_table_entry_t bug = {
 	.fn = sctp_sf_bug,
 	.name = "sctp_sf_bug"
@@ -419,7 +430,7 @@
  *
  * For base protocol (RFC 2960).
  */
-const sctp_sm_table_entry_t chunk_event_table[SCTP_NUM_BASE_CHUNK_TYPES][SCTP_STATE_NUM_STATES] = {
+static const sctp_sm_table_entry_t chunk_event_table[SCTP_NUM_BASE_CHUNK_TYPES][SCTP_STATE_NUM_STATES] = {
 	TYPE_SCTP_DATA,
 	TYPE_SCTP_INIT,
 	TYPE_SCTP_INIT_ACK,
@@ -482,7 +493,7 @@
 /* The primary index for this table is the chunk type.
  * The secondary index for this table is the state.
  */
-const sctp_sm_table_entry_t addip_chunk_event_table[SCTP_NUM_ADDIP_CHUNK_TYPES][SCTP_STATE_NUM_STATES] = {
+static const sctp_sm_table_entry_t addip_chunk_event_table[SCTP_NUM_ADDIP_CHUNK_TYPES][SCTP_STATE_NUM_STATES] = {
 	TYPE_SCTP_ASCONF,
 	TYPE_SCTP_ASCONF_ACK,
 }; /*state_fn_t addip_chunk_event_table[][] */
@@ -511,7 +522,7 @@
 /* The primary index for this table is the chunk type.
  * The secondary index for this table is the state.
  */
-const sctp_sm_table_entry_t prsctp_chunk_event_table[SCTP_NUM_PRSCTP_CHUNK_TYPES][SCTP_STATE_NUM_STATES] = {
+static const sctp_sm_table_entry_t prsctp_chunk_event_table[SCTP_NUM_PRSCTP_CHUNK_TYPES][SCTP_STATE_NUM_STATES] = {
 	TYPE_SCTP_FWD_TSN,
 }; /*state_fn_t prsctp_chunk_event_table[][] */
 
@@ -684,7 +695,7 @@
 /* The primary index for this table is the primitive type.
  * The secondary index for this table is the state.
  */
-const sctp_sm_table_entry_t primitive_event_table[SCTP_NUM_PRIMITIVE_TYPES][SCTP_STATE_NUM_STATES] = {
+static const sctp_sm_table_entry_t primitive_event_table[SCTP_NUM_PRIMITIVE_TYPES][SCTP_STATE_NUM_STATES] = {
 	TYPE_SCTP_PRIMITIVE_ASSOCIATE,
 	TYPE_SCTP_PRIMITIVE_SHUTDOWN,
 	TYPE_SCTP_PRIMITIVE_ABORT,
@@ -716,8 +727,31 @@
 	{.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
 }
 
-const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STATES] = {
+#define TYPE_SCTP_OTHER_ICMP_PROTO_UNREACH  { \
+	/* SCTP_STATE_EMPTY */ \
+	{.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
+	/* SCTP_STATE_CLOSED */ \
+	{.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
+	/* SCTP_STATE_COOKIE_WAIT */ \
+	{.fn = sctp_sf_cookie_wait_icmp_abort, \
+	 .name = "sctp_sf_cookie_wait_icmp_abort"}, \
+	/* SCTP_STATE_COOKIE_ECHOED */ \
+	{.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
+	/* SCTP_STATE_ESTABLISHED */ \
+	{.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
+	/* SCTP_STATE_SHUTDOWN_PENDING */ \
+	{.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
+	/* SCTP_STATE_SHUTDOWN_SENT */ \
+	{.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
+	/* SCTP_STATE_SHUTDOWN_RECEIVED */ \
+	{.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
+	/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
+	{.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
+}
+
+static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STATES] = {
 	TYPE_SCTP_OTHER_NO_PENDING_TSN,
+	TYPE_SCTP_OTHER_ICMP_PROTO_UNREACH,
 };
 
 #define TYPE_SCTP_EVENT_TIMEOUT_NONE { \
@@ -931,7 +965,7 @@
 	{.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
 }
 
-const sctp_sm_table_entry_t timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM_STATES] = {
+static const sctp_sm_table_entry_t timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM_STATES] = {
 	TYPE_SCTP_EVENT_TIMEOUT_NONE,
 	TYPE_SCTP_EVENT_TIMEOUT_T1_COOKIE,
 	TYPE_SCTP_EVENT_TIMEOUT_T1_INIT,
@@ -944,8 +978,8 @@
 	TYPE_SCTP_EVENT_TIMEOUT_AUTOCLOSE,
 };
 
-const sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t cid, 
-						     sctp_state_t state)
+static const sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t cid, 
+							    sctp_state_t state)
 {
 	if (state > SCTP_STATE_MAX)
 		return &bug;
diff -urN linux-2.4.29-rc2/net/sctp/socket.c linux-2.4.29-rc3/net/sctp/socket.c
--- linux-2.4.29-rc2/net/sctp/socket.c	2005-01-15 10:14:21.264964394 -0800
+++ linux-2.4.29-rc3/net/sctp/socket.c	2005-01-15 10:14:25.399140850 -0800
@@ -116,7 +116,7 @@
 	struct sock *sk = asoc->base.sk;
 	int amt = 0;
 
-	amt = sk->sk_sndbuf - asoc->sndbuf_used;
+	amt = sk->sndbuf - asoc->sndbuf_used;
 	if (amt < 0)
 		amt = 0;
 	return amt;
@@ -144,7 +144,7 @@
 	*((struct sctp_chunk **)(chunk->skb->cb)) = chunk;
 
 	asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk);
-	sk->sk_wmem_queued += SCTP_DATA_SNDSIZE(chunk);
+	sk->wmem_queued += SCTP_DATA_SNDSIZE(chunk);
 }
 
 /* Verify that this is a valid address. */
@@ -203,7 +203,7 @@
  * id are specified, the associations matching the address and the id should be
  * the same.
  */
-struct sctp_transport *sctp_addr_id2transport(struct sock *sk,
+static struct sctp_transport *sctp_addr_id2transport(struct sock *sk,
 					      struct sockaddr_storage *addr,
 					      sctp_assoc_t id)
 {
@@ -224,7 +224,7 @@
 	if (id_asoc && (id_asoc != addr_asoc))
 		return NULL;
 
-	sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk),
+	sctp_get_pf_specific(sk->family)->addr_v4map(sctp_sk(sk),
 						(union sctp_addr *)addr);
 
 	return transport;
@@ -240,7 +240,7 @@
  *             sockaddr_in6 [RFC 2553]),
  *   addr_len - the size of the address structure.
  */
-int sctp_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+SCTP_STATIC int sctp_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 {
 	int retval = 0;
 
@@ -338,8 +338,8 @@
 	}
 
 	/* Refresh ephemeral port.  */
-	if (!snum)
-		snum = sk->num;
+	if (!bp->port)
+		bp->port = sk->num;
 
 	/* Add the address to the bind address list.  */
 	sctp_local_bh_disable();
@@ -349,8 +349,6 @@
 	addr->v4.sin_port = ntohs(addr->v4.sin_port);
 	ret = sctp_add_bind_addr(bp, addr, GFP_ATOMIC);
 	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();
 
@@ -612,7 +610,7 @@
 		}
 
 		/* FIXME - There is probably a need to check if sk->sk_saddr and
-		 * sk->sk_rcv_addr are currently set to one of the addresses to
+		 * sk->rcv_addr are currently set to one of the addresses to
 		 * be removed. This is something which needs to be looked into
 		 * when we are fixing the outstanding issues with multi-homing
 		 * socket routing and failover schemes. Refer to comments in
@@ -951,7 +949,7 @@
 	SCTP_DEBUG_PRINTK("sctp_close(sk: 0x%p, timeout:%ld)\n", sk, timeout);
 
 	sctp_lock_sock(sk);
-	sk->sk_shutdown = SHUTDOWN_MASK;
+	sk->shutdown = SHUTDOWN_MASK;
 
 	ep = sctp_sk(sk)->ep;
 
@@ -969,7 +967,7 @@
 				sctp_unhash_established(asoc);
 				sctp_association_free(asoc);
 
-			} else if (sk->linger && !sk->sk_lingertime)
+			} else if (sk->linger && !sk->lingertime)
 				sctp_primitive_ABORT(asoc, NULL);
 			else
 				sctp_primitive_SHUTDOWN(asoc, NULL);
@@ -978,7 +976,7 @@
 	}
 
 	/* Clean up any skbs sitting on the receive queue.  */
-	sctp_queue_purge_ulpevents(&sk->sk_receive_queue);
+	sctp_queue_purge_ulpevents(&sk->receive_queue);
 	sctp_queue_purge_ulpevents(&sctp_sk(sk)->pd_lobby);
 
 	/* On a TCP-style socket, block for at most linger_time if set. */
@@ -1314,7 +1312,7 @@
 	/* API 7.1.7, the sndbuf size per association bounds the
 	 * maximum size of data that can be sent in a single send call.
 	 */
-	if (msg_len > sk->sk_sndbuf) {
+	if (msg_len > sk->sndbuf) {
 		err = -EMSGSIZE;
 		goto out_free;
 	}
@@ -1551,7 +1549,7 @@
 		if (flags & MSG_PEEK)
 			goto out_free;
 		sctp_skb_pull(skb, copied);
-		skb_queue_head(&sk->sk_receive_queue, skb);
+		skb_queue_head(&sk->receive_queue, skb);
 
 		/* When only partial message is copied to the user, increase
 		 * rwnd by that amount. If all the data in the skb is read,
@@ -1704,10 +1702,13 @@
 	/* update default value for endpoint (all future associations) */
 	if (!params.spp_assoc_id && 
 	    sctp_is_any(( union sctp_addr *)&params.spp_address)) {
-		if (params.spp_hbinterval)
+		/* Manual heartbeat on an endpoint is invalid. */
+		if (0xffffffff == params.spp_hbinterval)
+			return -EINVAL;
+		else if (params.spp_hbinterval)
 			sctp_sk(sk)->paddrparam.spp_hbinterval =
 						params.spp_hbinterval;
-		if (sctp_max_retrans_path)
+		if (params.spp_pathmaxrxt)
 			sctp_sk(sk)->paddrparam.spp_pathmaxrxt =
 						params.spp_pathmaxrxt;
 		return 0;
@@ -1749,7 +1750,8 @@
 	/* spp_pathmaxrxt contains the maximum number of retransmissions
 	 * before this address shall be considered unreachable.
 	 */
-	trans->error_threshold = params.spp_pathmaxrxt;
+	if (params.spp_pathmaxrxt)
+		trans->max_retrans = params.spp_pathmaxrxt;
 
 	return 0;
 }
@@ -2355,7 +2357,7 @@
 	af = sctp_get_af_specific(to.sa.sa_family);
 	af->to_sk_daddr(&to, sk);
 
-	timeo = sock_sndtimeo(sk, sk->sk_socket->file->f_flags & O_NONBLOCK);
+	timeo = sock_sndtimeo(sk, sk->socket->file->f_flags & O_NONBLOCK);
 	err = sctp_wait_for_connect(asoc, &timeo);
 
 out_unlock:
@@ -2401,7 +2403,7 @@
 		goto out;
 	}
 
-	timeo = sock_rcvtimeo(sk, sk->sk_socket->file->f_flags & O_NONBLOCK);
+	timeo = sock_rcvtimeo(sk, sk->socket->file->f_flags & O_NONBLOCK);
 
 	error = sctp_wait_for_accept(sk, timeo);
 	if (error)
@@ -2449,7 +2451,7 @@
 	sp = sctp_sk(sk);
 
 	/* Initialize the SCTP per socket area.  */
-	switch (sk->sk_type) {
+	switch (sk->type) {
 	case SOCK_SEQPACKET:
 		sp->type = SCTP_SOCKET_UDP;
 		break;
@@ -2529,7 +2531,7 @@
 
 	sp->adaption_ind = 0;
 
-	sp->pf = sctp_get_pf_specific(sk->sk_family);
+	sp->pf = sctp_get_pf_specific(sk->family);
 
 	/* Control variables for partial data delivery. */
 	sp->pd_mode           = 0;
@@ -2646,7 +2648,7 @@
 	memcpy(&status.sstat_primary.spinfo_address,
 	       &(transport->ipaddr), sizeof(union sctp_addr));
 	/* Map ipv4 address into v4-mapped-on-v6 address.  */
-	sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk),
+	sctp_get_pf_specific(sk->family)->addr_v4map(sctp_sk(sk),
 		(union sctp_addr *)&status.sstat_primary.spinfo_address);
 	status.sstat_primary.spinfo_state = transport->active;
 	status.sstat_primary.spinfo_cwnd = transport->cwnd;
@@ -2800,7 +2802,7 @@
 		return -EINVAL;
 
 	/* Create a new socket.  */
-	err = sock_create(sk->sk_family, SOCK_SEQPACKET, IPPROTO_SCTP, &sock);
+	err = sock_create(sk->family, SOCK_SEQPACKET, IPPROTO_SCTP, &sock);
 	if (err < 0)
 		return err;
 
@@ -2926,7 +2928,7 @@
 	/* spp_pathmaxrxt contains the maximum number of retransmissions
 	 * before this address shall be considered unreachable.
 	 */
-	params.spp_pathmaxrxt = trans->error_threshold;
+	params.spp_pathmaxrxt = trans->max_retrans;
 
 done:
 	if (copy_to_user(optval, &params, len))
@@ -3014,8 +3016,8 @@
 	list_for_each(pos, &asoc->peer.transport_addr_list) {
 		from = list_entry(pos, struct sctp_transport, transports);
 		memcpy(&temp, &from->ipaddr, sizeof(temp));
-		sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
-		addrlen = sctp_get_af_specific(sk->sk_family)->sockaddr_len;
+		sctp_get_pf_specific(sk->family)->addr_v4map(sp, &temp);
+		addrlen = sctp_get_af_specific(sk->family)->sockaddr_len;
 		temp.v4.sin_port = htons(temp.v4.sin_port);
 		if (copy_to_user(to, &temp, addrlen))
 			return -EFAULT;
@@ -3037,6 +3039,9 @@
 	struct sctp_bind_addr *bp;
 	struct sctp_association *asoc;
 	struct list_head *pos;
+	struct sctp_sockaddr_entry *addr;
+	rwlock_t *addr_lock;
+	unsigned long flags;
 	int cnt = 0;
 
 	if (len != sizeof(sctp_assoc_t))
@@ -3053,33 +3058,103 @@
 	 */
 	if (0 == id) {
 		bp = &sctp_sk(sk)->ep->base.bind_addr;
+		addr_lock = &sctp_sk(sk)->ep->base.addr_lock;
 	} else {
 		asoc = sctp_id2assoc(sk, id);
 		if (!asoc)
 			return -EINVAL;
 		bp = &asoc->base.bind_addr;
+		addr_lock = &asoc->base.addr_lock;
 	}
 
+	sctp_read_lock(addr_lock);
+
+	/* If the endpoint is bound to 0.0.0.0 or ::0, count the valid
+	 * addresses from the global local address list.
+	 */
+	if (sctp_list_single_entry(&bp->address_list)) {
+		addr = list_entry(bp->address_list.next,
+				  struct sctp_sockaddr_entry, list);
+		if (sctp_is_any(&addr->a)) {
+			sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags);
+			list_for_each(pos, &sctp_local_addr_list) {
+				addr = list_entry(pos,
+						  struct sctp_sockaddr_entry,
+						  list);
+				if ((PF_INET == sk->family) &&
+				    (AF_INET6 == addr->a.sa.sa_family))
+					continue;
+				cnt++;
+			}
+			sctp_spin_unlock_irqrestore(&sctp_local_addr_lock,
+						    flags);
+		} else {
+			cnt = 1;
+		}
+		goto done;
+        }
+
 	list_for_each(pos, &bp->address_list) {
 		cnt ++;
 	}
 
+done:
+	sctp_read_unlock(addr_lock);
+	return cnt;
+}
+
+/* Helper function that copies local addresses to user and returns the number
+ * of addresses copied.
+ */
+static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port, int max_addrs,
+				    void __user *to)
+{
+	struct list_head *pos;
+	struct sctp_sockaddr_entry *addr;
+	unsigned long flags;
+	union sctp_addr temp;
+	int cnt = 0;
+	int addrlen;
+
+	sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags);
+	list_for_each(pos, &sctp_local_addr_list) {
+		addr = list_entry(pos, struct sctp_sockaddr_entry, list);
+		if ((PF_INET == sk->family) &&
+		    (AF_INET6 == addr->a.sa.sa_family))
+			continue;
+		memcpy(&temp, &addr->a, sizeof(temp));
+		sctp_get_pf_specific(sk->family)->addr_v4map(sctp_sk(sk),
+								&temp);
+		addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;		temp.v4.sin_port = htons(port);
+		if (copy_to_user(to, &temp, addrlen)) {
+			sctp_spin_unlock_irqrestore(&sctp_local_addr_lock,
+						    flags);
+			return -EFAULT;
+		}
+		to += addrlen;
+		cnt ++;
+		if (cnt >= max_addrs) break;
+	}
+	sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags);
+
 	return cnt;
 }
 
 static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
-					char *optval, int *optlen)
+				       char *optval, int *optlen)
 {
 	struct sctp_bind_addr *bp;
 	struct sctp_association *asoc;
 	struct list_head *pos;
 	int cnt = 0;
 	struct sctp_getaddrs getaddrs;
-	struct sctp_sockaddr_entry *from;
+	struct sctp_sockaddr_entry *addr;
 	void *to;
 	union sctp_addr temp;
 	struct sctp_opt *sp = sctp_sk(sk);
 	int addrlen;
+	rwlock_t *addr_lock;
+	int err = 0;
 
 	if (len != sizeof(struct sctp_getaddrs))
 		return -EINVAL;
@@ -3096,33 +3171,59 @@
 	 */
 	if (0 == getaddrs.assoc_id) {
 		bp = &sctp_sk(sk)->ep->base.bind_addr;
+		addr_lock = &sctp_sk(sk)->ep->base.addr_lock;
 	} else {
 		asoc = sctp_id2assoc(sk, getaddrs.assoc_id);
 		if (!asoc)
 			return -EINVAL;
 		bp = &asoc->base.bind_addr;
+		addr_lock = &asoc->base.addr_lock;
 	}
 
 	to = (void *)getaddrs.addrs;
+
+	sctp_read_lock(addr_lock);
+
+	/* If the endpoint is bound to 0.0.0.0 or ::0, get the valid
+	 * addresses from the global local address list.
+	 */
+	if (sctp_list_single_entry(&bp->address_list)) {
+		addr = list_entry(bp->address_list.next,
+				  struct sctp_sockaddr_entry, list);
+		if (sctp_is_any(&addr->a)) {
+			cnt = sctp_copy_laddrs_to_user(sk, bp->port,
+						       getaddrs.addr_num, to);
+			if (cnt < 0) {
+				err = cnt;
+				goto unlock;
+			}
+			goto copy_getaddrs;
+		}
+	}
+
 	list_for_each(pos, &bp->address_list) {
-		from = list_entry(pos,
-				struct sctp_sockaddr_entry,
-				list);
-		memcpy(&temp, &from->a, sizeof(temp));
-		sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
+		addr = list_entry(pos, struct sctp_sockaddr_entry, list);
+		memcpy(&temp, &addr->a, sizeof(temp));
+		sctp_get_pf_specific(sk->family)->addr_v4map(sp, &temp);
 		addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
 		temp.v4.sin_port = htons(temp.v4.sin_port);
-		if (copy_to_user(to, &temp, addrlen))
-			return -EFAULT;
+		if (copy_to_user(to, &temp, addrlen)) {
+			err = -EFAULT;
+			goto unlock;
+		}
 		to += addrlen;
 		cnt ++;
 		if (cnt >= getaddrs.addr_num) break;
 	}
+
+copy_getaddrs:
 	getaddrs.addr_num = cnt;
 	if (copy_to_user(optval, &getaddrs, sizeof(struct sctp_getaddrs)))
-		return -EFAULT;
+		err = -EFAULT;
 
-	return 0;
+unlock:
+	sctp_read_unlock(addr_lock);
+	return err;
 }
 
 /* 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR)
@@ -3158,7 +3259,7 @@
 	asoc->peer.primary_path->ipaddr.v4.sin_port =
 		ntohs(asoc->peer.primary_path->ipaddr.v4.sin_port);
 
-	sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp,
+	sctp_get_pf_specific(sk->family)->addr_v4map(sp,
 			(union sctp_addr *)&prim.ssp_addr);
 
 	if (copy_to_user(optval, &prim, sizeof(struct sctp_prim)))
@@ -3662,12 +3763,12 @@
 		 * used by other socket (pp->sk != NULL); that other
 		 * socket is going to be sk2.
 		 */
-		int sk_reuse = sk->sk_reuse;
+		int reuse = sk->reuse;
 		struct sock *sk2 = pp->sk;
 
 		SCTP_DEBUG_PRINTK("sctp_get_port() found a "
 				  "possible match\n");
-		if (pp->fastreuse != 0 && sk->sk_reuse != 0)
+		if (pp->fastreuse != 0 && sk->reuse != 0)
 			goto success;
 
 		/* Run through the list of sockets bound to the port
@@ -3684,7 +3785,7 @@
 			struct sctp_endpoint *ep2;
 			ep2 = sctp_sk(sk2)->ep;
 
-			if (sk_reuse && sk2->sk_reuse)
+			if (reuse && sk2->reuse)
 				continue;
 
 			if (sctp_bind_addr_match(&ep2->base.bind_addr, addr,
@@ -3708,12 +3809,12 @@
 		goto fail_unlock;
 
 	/* In either case (hit or miss), make sure fastreuse is 1 only
-	 * if sk->sk_reuse is too (that is, if the caller requested
+	 * if sk->reuse is too (that is, if the caller requested
 	 * SO_REUSEADDR on this socket -sk-).
 	 */
 	if (!pp->sk)
-		pp->fastreuse = sk->sk_reuse ? 1 : 0;
-	else if (pp->fastreuse && sk->sk_reuse == 0)
+		pp->fastreuse = sk->reuse ? 1 : 0;
+	else if (pp->fastreuse && sk->reuse == 0)
 		pp->fastreuse = 0;
 
 	/* We are set, so fill up all the data in the hash table
@@ -3785,7 +3886,7 @@
 			return 0;
 		
 		sctp_unhash_endpoint(ep);
-		sk->sk_state = SCTP_SS_CLOSED;
+		sk->state = SCTP_SS_CLOSED;
 	}
 
 	/* Return if we are already listening. */
@@ -3806,7 +3907,7 @@
 		if (sctp_autobind(sk))
 			return -EAGAIN;
 	}
-	sk->sk_state = SCTP_SS_LISTENING;
+	sk->state = SCTP_SS_LISTENING;
 	sctp_hash_endpoint(ep);
 	return 0;
 }
@@ -3828,7 +3929,7 @@
 			return 0;
 		
 		sctp_unhash_endpoint(ep);
-		sk->sk_state = SCTP_SS_CLOSED;
+		sk->state = SCTP_SS_CLOSED;
 	}
 
 	if (sctp_sstate(sk, LISTENING))
@@ -3848,8 +3949,8 @@
 		if (sctp_autobind(sk))
 			return -EAGAIN;
 	}
-	sk->sk_state = SCTP_SS_LISTENING;
-	sk->sk_max_ack_backlog = backlog;
+	sk->state = SCTP_SS_LISTENING;
+	sk->max_ack_backlog = backlog;
 	sctp_hash_endpoint(ep);
 	return 0;
 }
@@ -3923,7 +4024,7 @@
 	struct sctp_opt *sp = sctp_sk(sk);
 	unsigned int mask;
 
-	poll_wait(file, sk->sk_sleep, wait);
+	poll_wait(file, sk->sleep, wait);
 
 	/* A TCP-style listening socket becomes readable when the accept queue
 	 * is not empty.
@@ -3935,14 +4036,14 @@
 	mask = 0;
 
 	/* Is there any exceptional events?  */
-	if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
+	if (sk->err || !skb_queue_empty(&sk->error_queue))
 		mask |= POLLERR;
-	if (sk->sk_shutdown == SHUTDOWN_MASK)
+	if (sk->shutdown == SHUTDOWN_MASK)
 		mask |= POLLHUP;
 
 	/* Is it readable?  Reconsider this code with TCP-style support.  */
-	if (!skb_queue_empty(&sk->sk_receive_queue) ||
-	    (sk->sk_shutdown & RCV_SHUTDOWN))
+	if (!skb_queue_empty(&sk->receive_queue) ||
+	    (sk->shutdown & RCV_SHUTDOWN))
 		mask |= POLLIN | POLLRDNORM;
 
 	/* The association is either gone or not ready.  */
@@ -3953,7 +4054,7 @@
 	if (sctp_writeable(sk)) {
 		mask |= POLLOUT | POLLWRNORM;
 	} else {
-		set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
+		set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
 		/*
 		 * Since the socket is not locked, the buffer
 		 * might be made available after the writeable check and
@@ -4162,7 +4263,7 @@
 	int error;
 	DECLARE_WAITQUEUE(wait, current);
 
-	add_wait_queue_exclusive(sk->sk_sleep, &wait);
+	add_wait_queue_exclusive(sk->sleep, &wait);
 	__set_current_state(TASK_INTERRUPTIBLE);
 
 	/* Socket errors? */
@@ -4170,11 +4271,11 @@
 	if (error)
 		goto out;
 
-	if (!skb_queue_empty(&sk->sk_receive_queue))
+	if (!skb_queue_empty(&sk->receive_queue))
 		goto ready;
 
 	/* Socket shut down?  */
-	if (sk->sk_shutdown & RCV_SHUTDOWN)
+	if (sk->shutdown & RCV_SHUTDOWN)
 		goto out;
 
 	/* Sequenced packets can come disconnected.  If so we report the
@@ -4200,7 +4301,7 @@
 	sctp_lock_sock(sk);
 
 ready:
-	remove_wait_queue(sk->sk_sleep, &wait);
+	remove_wait_queue(sk->sleep, &wait);
 	__set_current_state(TASK_RUNNING);
 	return 0;
 
@@ -4208,7 +4309,7 @@
 	error = sock_intr_errno(*timeo_p);
 
 out:
-	remove_wait_queue(sk->sk_sleep, &wait);
+	remove_wait_queue(sk->sleep, &wait);
 	__set_current_state(TASK_RUNNING);
 	*err = error;
 	return error;
@@ -4225,7 +4326,7 @@
 	struct sk_buff *skb;
 	long timeo;
 
-	/* Caller is allowed not to check sk->sk_err before calling.  */
+	/* Caller is allowed not to check sk->err before calling.  */
 	error = sock_error(sk);
 	if (error)
 		goto no_packet;
@@ -4246,21 +4347,21 @@
 		if (flags & MSG_PEEK) {
 			unsigned long cpu_flags;
 
-			sctp_spin_lock_irqsave(&sk->sk_receive_queue.lock,
+			sctp_spin_lock_irqsave(&sk->receive_queue.lock,
 					       cpu_flags);
-			skb = skb_peek(&sk->sk_receive_queue);
+			skb = skb_peek(&sk->receive_queue);
 			if (skb)
 				atomic_inc(&skb->users);
-			sctp_spin_unlock_irqrestore(&sk->sk_receive_queue.lock,
+			sctp_spin_unlock_irqrestore(&sk->receive_queue.lock,
 						    cpu_flags);
 		} else {
-			skb = skb_dequeue(&sk->sk_receive_queue);
+			skb = skb_dequeue(&sk->receive_queue);
 		}
 
 		if (skb)
 			return skb;
 
-		if (sk->sk_shutdown & RCV_SHUTDOWN)
+		if (sk->shutdown & RCV_SHUTDOWN)
 			break;
 
 		/* User doesn't want to wait.  */
@@ -4280,22 +4381,22 @@
 static void __sctp_write_space(struct sctp_association *asoc)
 {
 	struct sock *sk = asoc->base.sk;
-	struct socket *sock = sk->sk_socket;
+	struct socket *sock = sk->socket;
 
 	if ((sctp_wspace(asoc) > 0) && sock) {
 		if (waitqueue_active(&asoc->wait))
 			wake_up_interruptible(&asoc->wait);
 
 		if (sctp_writeable(sk)) {
-			if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
-				wake_up_interruptible(sk->sk_sleep);
+			if (sk->sleep && waitqueue_active(sk->sleep))
+				wake_up_interruptible(sk->sleep);
 
 			/* Note that we try to include the Async I/O support
 			 * here by modeling from the current TCP/UDP code.
 			 * We have not tested with it yet.
 			 */
 			if (sock->fasync_list &&
-			    !(sk->sk_shutdown & SEND_SHUTDOWN))
+			    !(sk->shutdown & SEND_SHUTDOWN))
 				sock_wake_async(sock, 2, POLL_OUT);
 		}
 	}
@@ -4316,7 +4417,7 @@
 	asoc = chunk->asoc;
 	sk = asoc->base.sk;
 	asoc->sndbuf_used -= SCTP_DATA_SNDSIZE(chunk);
-	sk->sk_wmem_queued -= SCTP_DATA_SNDSIZE(chunk);
+	sk->wmem_queued -= SCTP_DATA_SNDSIZE(chunk);
 	__sctp_write_space(asoc);
 
 	sctp_association_put(asoc);
@@ -4345,7 +4446,7 @@
 		__set_current_state(TASK_INTERRUPTIBLE);
 		if (!*timeo_p)
 			goto do_nonblock;
-		if (sk->sk_err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING ||
+		if (sk->err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING ||
 		    asoc->base.dead)
 			goto do_error;
 		if (signal_pending(current))
@@ -4413,7 +4514,7 @@
 {
 	int amt = 0;
 
-	amt = sk->sk_sndbuf - sk->sk_wmem_queued;
+	amt = sk->sndbuf - sk->wmem_queued;
 	if (amt < 0)
 		amt = 0;
 	return amt;
@@ -4440,9 +4541,9 @@
 		__set_current_state(TASK_INTERRUPTIBLE);
 		if (!*timeo_p)
 			goto do_nonblock;
-		if (sk->sk_shutdown & RCV_SHUTDOWN)
+		if (sk->shutdown & RCV_SHUTDOWN)
 			break;
-		if (sk->sk_err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING ||
+		if (sk->err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING ||
 		    asoc->base.dead)
 			goto do_error;
 		if (signal_pending(current))
@@ -4495,7 +4596,7 @@
 
 	ep = sctp_sk(sk)->ep;
 
-	add_wait_queue_exclusive(sk->sk_sleep, &wait);
+	add_wait_queue_exclusive(sk->sleep, &wait);
 
 	for (;;) {
 		__set_current_state(TASK_INTERRUPTIBLE);
@@ -4522,7 +4623,7 @@
 			break;
 	}
 
-	remove_wait_queue(sk->sk_sleep, &wait);
+	remove_wait_queue(sk->sleep, &wait);
 	__set_current_state(TASK_RUNNING);	
 
 	return err;
@@ -4532,7 +4633,7 @@
 {
 	DECLARE_WAITQUEUE(wait, current);
 
-	add_wait_queue_exclusive(sk->sk_sleep, &wait);
+	add_wait_queue_exclusive(sk->sleep, &wait);
 
 	do {
 		__set_current_state(TASK_INTERRUPTIBLE);
@@ -4543,7 +4644,7 @@
 		sctp_lock_sock(sk);
 	} while (!signal_pending(current) && timeout);
 
-	remove_wait_queue(sk->sk_sleep, &wait);
+	remove_wait_queue(sk->sleep, &wait);
 	__set_current_state(TASK_RUNNING);	
 }
 
@@ -4563,8 +4664,8 @@
 	/* Migrate socket buffer sizes and all the socket level options to the
 	 * new socket.
 	 */
-	newsk->sk_sndbuf = oldsk->sk_sndbuf;
-	newsk->sk_rcvbuf = oldsk->sk_rcvbuf;
+	newsk->sndbuf = oldsk->sndbuf;
+	newsk->rcvbuf = oldsk->rcvbuf;
 	/* Brute force copy old sctp opt. */
 	memcpy(newsp, oldsp, sizeof(struct sctp_opt));
 
@@ -4579,11 +4680,11 @@
 	/* Move any messages in the old socket's receive queue that are for the
 	 * peeled off association to the new socket's receive queue.
 	 */
-	sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) {
+	sctp_skb_for_each(skb, &oldsk->receive_queue, tmp) {
 		event = sctp_skb2event(skb);
 		if (event->asoc == assoc) {
 			__skb_unlink(skb, skb->list);
-			__skb_queue_tail(&newsk->sk_receive_queue, skb);
+			__skb_queue_tail(&newsk->receive_queue, skb);
 		}
 	}
 
@@ -4603,7 +4704,7 @@
 		if (assoc->ulpq.pd_mode) {
 			queue = &newsp->pd_lobby;
 		} else
-			queue = &newsk->sk_receive_queue;
+			queue = &newsk->receive_queue;
 
 		/* Walk through the pd_lobby, looking for skbs that
 		 * need moved to the new socket.
@@ -4637,9 +4738,9 @@
 	 * is called, set RCV_SHUTDOWN flag.
 	 */
 	if (sctp_state(assoc, CLOSED) && sctp_style(newsk, TCP))
-		newsk->sk_shutdown |= RCV_SHUTDOWN;
+		newsk->shutdown |= RCV_SHUTDOWN;
 
-	newsk->sk_state = SCTP_SS_ESTABLISHED;
+	newsk->state = SCTP_SS_ESTABLISHED;
 }
 
 /* This proto struct describes the ULP interface for SCTP.  */
diff -urN linux-2.4.29-rc2/net/sctp/ssnmap.c linux-2.4.29-rc3/net/sctp/ssnmap.c
--- linux-2.4.29-rc2/net/sctp/ssnmap.c	2004-04-14 06:05:41.000000000 -0700
+++ linux-2.4.29-rc3/net/sctp/ssnmap.c	2005-01-15 10:14:25.400140892 -0800
@@ -42,6 +42,9 @@
 
 #define MAX_KMALLOC_SIZE	131072
 
+static struct sctp_ssnmap *sctp_ssnmap_init(struct sctp_ssnmap *map, __u16 in,
+					    __u16 out);
+
 /* Storage size needed for map includes 2 headers and then the
  * specific needs of in or out streams.
  */
@@ -87,8 +90,8 @@
 
 
 /* Initialize a block of memory as a ssnmap.  */
-struct sctp_ssnmap *sctp_ssnmap_init(struct sctp_ssnmap *map, __u16 in,
-				     __u16 out)
+static struct sctp_ssnmap *sctp_ssnmap_init(struct sctp_ssnmap *map, __u16 in,
+					    __u16 out)
 {
 	memset(map, 0x00, sctp_ssnmap_size(in, out));
 
diff -urN linux-2.4.29-rc2/net/sctp/transport.c linux-2.4.29-rc3/net/sctp/transport.c
--- linux-2.4.29-rc2/net/sctp/transport.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29-rc3/net/sctp/transport.c	2005-01-15 10:14:25.400140892 -0800
@@ -54,34 +54,10 @@
 
 /* 1st Level Abstractions.  */
 
-/* Allocate and initialize a new transport.  */
-struct sctp_transport *sctp_transport_new(const union sctp_addr *addr, int gfp)
-{
-        struct sctp_transport *transport;
-
-        transport = t_new(struct sctp_transport, gfp);
-	if (!transport)
-		goto fail;
-
-	if (!sctp_transport_init(transport, addr, gfp))
-		goto fail_init;
-
-	transport->malloced = 1;
-	SCTP_DBG_OBJCNT_INC(transport);
-
-	return transport;
-
-fail_init:
-	kfree(transport);
-
-fail:
-	return NULL;
-}
-
 /* Initialize a new transport from provided memory.  */
-struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
-					   const union sctp_addr *addr,
-					   int gfp)
+static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
+						  const union sctp_addr *addr,
+						  int gfp)
 {
 	/* Copy in the address.  */
 	peer->ipaddr = *addr;
@@ -112,7 +88,6 @@
 
 	/* Initialize the default path max_retrans.  */
 	peer->max_retrans = sctp_max_retrans_path;
-	peer->error_threshold = 0;
 	peer->error_count = 0;
 
 	INIT_LIST_HEAD(&peer->transmitted);
@@ -144,6 +119,30 @@
 	return peer;
 }
 
+/* Allocate and initialize a new transport.  */
+struct sctp_transport *sctp_transport_new(const union sctp_addr *addr, int gfp)
+{
+        struct sctp_transport *transport;
+
+        transport = t_new(struct sctp_transport, gfp);
+	if (!transport)
+		goto fail;
+
+	if (!sctp_transport_init(transport, addr, gfp))
+		goto fail_init;
+
+	transport->malloced = 1;
+	SCTP_DBG_OBJCNT_INC(transport);
+
+	return transport;
+
+fail_init:
+	kfree(transport);
+
+fail:
+	return NULL;
+}
+
 /* This transport is no longer needed.  Free up if possible, or
  * delay until it last reference count.
  */
@@ -155,13 +154,23 @@
 	if (del_timer(&transport->hb_timer))
 		sctp_transport_put(transport);
 
+	/* Delete the T3_rtx timer if it's active.
+	 * There is no point in not doing this now and letting
+	 * structure hang around in memory since we know
+	 * the tranport is going away.
+	 */
+	if (timer_pending(&transport->T3_rtx_timer) &&
+	    del_timer(&transport->T3_rtx_timer))
+		sctp_transport_put(transport);
+
+
 	sctp_transport_put(transport);
 }
 
 /* Destroy the transport data structure.
  * Assumes there are no more users of this structure.
  */
-void sctp_transport_destroy(struct sctp_transport *transport)
+static void sctp_transport_destroy(struct sctp_transport *transport)
 {
 	SCTP_ASSERT(transport->dead, "Transport is not dead", return);
 
diff -urN linux-2.4.29-rc2/net/sctp/tsnmap.c linux-2.4.29-rc3/net/sctp/tsnmap.c
--- linux-2.4.29-rc2/net/sctp/tsnmap.c	2004-08-07 16:26:07.000000000 -0700
+++ linux-2.4.29-rc3/net/sctp/tsnmap.c	2005-01-15 10:14:25.401140935 -0800
@@ -52,29 +52,6 @@
 				     int *started, __u16 *start,
 				     int *ended, __u16 *end);
 
-/* Create a new sctp_tsnmap.
- * Allocate room to store at least 'len' contiguous TSNs.
- */
-struct sctp_tsnmap *sctp_tsnmap_new(__u16 len, __u32 initial_tsn, int gfp)
-{
-	struct sctp_tsnmap *retval;
-
-	retval = kmalloc(sizeof(struct sctp_tsnmap) +
-			 sctp_tsnmap_storage_size(len), gfp);
-	if (!retval)
-		goto fail;
-
-	if (!sctp_tsnmap_init(retval, len, initial_tsn))
-		goto fail_map;
-	retval->malloced = 1;
-	return retval;
-
-fail_map:
-	kfree(retval);
-fail:
-	return NULL;
-}
-
 /* Initialize a block of memory as a tsnmap.  */
 struct sctp_tsnmap *sctp_tsnmap_init(struct sctp_tsnmap *map, __u16 len,
 				     __u32 initial_tsn)
@@ -168,16 +145,9 @@
 }
 
 
-/* Dispose of a tsnmap.  */
-void sctp_tsnmap_free(struct sctp_tsnmap *map)
-{
-	if (map->malloced)
-		kfree(map);
-}
-
 /* Initialize a Gap Ack Block iterator from memory being provided.  */
-void sctp_tsnmap_iter_init(const struct sctp_tsnmap *map,
-			   struct sctp_tsnmap_iter *iter)
+SCTP_STATIC void sctp_tsnmap_iter_init(const struct sctp_tsnmap *map,
+				       struct sctp_tsnmap_iter *iter)
 {
 	/* Only start looking one past the Cumulative TSN Ack Point.  */
 	iter->start = map->cumulative_tsn_ack_point + 1;
@@ -186,8 +156,9 @@
 /* Get the next Gap Ack Blocks. Returns 0 if there was not another block
  * to get.
  */
-int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *map,
-	struct sctp_tsnmap_iter *iter, __u16 *start, __u16 *end)
+SCTP_STATIC int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *map,
+					 struct sctp_tsnmap_iter *iter,
+					 __u16 *start, __u16 *end)
 {
 	int started, ended;
 	__u16 _start, _end, offset;
diff -urN linux-2.4.29-rc2/net/sctp/ulpevent.c linux-2.4.29-rc3/net/sctp/ulpevent.c
--- linux-2.4.29-rc2/net/sctp/ulpevent.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29-rc3/net/sctp/ulpevent.c	2005-01-15 10:14:25.402140978 -0800
@@ -65,8 +65,16 @@
  */
 }
 
+/* Initialize an ULP event from an given skb.  */
+SCTP_STATIC void sctp_ulpevent_init(struct sctp_ulpevent *event, int msg_flags)
+{
+	memset(event, 0, sizeof(struct sctp_ulpevent));
+	event->msg_flags = msg_flags;
+}
+
 /* Create a new sctp_ulpevent.  */
-struct sctp_ulpevent *sctp_ulpevent_new(int size, int msg_flags, int gfp)
+SCTP_STATIC struct sctp_ulpevent *sctp_ulpevent_new(int size, int msg_flags,
+						    int gfp)
 {
 	struct sctp_ulpevent *event;
 	struct sk_buff *skb;
@@ -84,13 +92,6 @@
 	return NULL;
 }
 
-/* Initialize an ULP event from an given skb.  */
-void sctp_ulpevent_init(struct sctp_ulpevent *event, int msg_flags)
-{
-	memset(event, 0, sizeof(struct sctp_ulpevent));
-	event->msg_flags = msg_flags;
-}
-
 /* Is this a MSG_NOTIFICATION?  */
 int sctp_ulpevent_is_notification(const struct sctp_ulpevent *event)
 {
@@ -322,7 +323,7 @@
 	memcpy(&spc->spc_aaddr, aaddr, sizeof(struct sockaddr_storage));
 
 	/* Map ipv4 address into v4-mapped-on-v6 address.  */
-	sctp_get_pf_specific(asoc->base.sk->sk_family)->addr_v4map(
+	sctp_get_pf_specific(asoc->base.sk->family)->addr_v4map(
 					sctp_sk(asoc->base.sk),
 					(union sctp_addr *)&spc->spc_aaddr);
 
diff -urN linux-2.4.29-rc2/net/sctp/ulpqueue.c linux-2.4.29-rc3/net/sctp/ulpqueue.c
--- linux-2.4.29-rc2/net/sctp/ulpqueue.c	2004-11-17 03:54:22.000000000 -0800
+++ linux-2.4.29-rc3/net/sctp/ulpqueue.c	2005-01-15 10:14:25.403141020 -0800
@@ -56,25 +56,6 @@
 
 /* 1st Level Abstractions */
 
-/* Create a new ULP queue.  */
-struct sctp_ulpq *sctp_ulpq_new(struct sctp_association *asoc, int gfp)
-{
-	struct sctp_ulpq *ulpq;
-
-	ulpq = kmalloc(sizeof(struct sctp_ulpq), gfp);
-	if (!ulpq)
-		goto fail;
-	if (!sctp_ulpq_init(ulpq, asoc))
-		goto fail_init;
-	ulpq->malloced = 1;
-	return ulpq;
-
-fail_init:
-	kfree(ulpq);
-fail:
-	return NULL;
-}
-
 /* Initialize a ULP queue from a block of memory.  */
 struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *ulpq,
 				 struct sctp_association *asoc)
@@ -92,7 +73,7 @@
 
 
 /* Flush the reassembly and ordering queues.  */
-void sctp_ulpq_flush(struct sctp_ulpq *ulpq)
+static void sctp_ulpq_flush(struct sctp_ulpq *ulpq)
 {
 	struct sk_buff *skb;
 	struct sctp_ulpevent *event;
@@ -163,7 +144,7 @@
 	sp->pd_mode = 0;
 	if (!skb_queue_empty(&sp->pd_lobby)) {
 		struct list_head *list;
-		sctp_skb_list_tail(&sp->pd_lobby, &sk->sk_receive_queue);
+		sctp_skb_list_tail(&sp->pd_lobby, &sk->receive_queue);
 		list = (struct list_head *)&sctp_sk(sk)->pd_lobby;
 		INIT_LIST_HEAD(list);
 		return 1;
@@ -189,7 +170,7 @@
 	/* If the socket is just going to throw this away, do not
 	 * even try to deliver it.
 	 */
-	if (sk->dead || (sk->sk_shutdown & RCV_SHUTDOWN))
+	if (sk->dead || (sk->shutdown & RCV_SHUTDOWN))
 		goto out_free;
 
 	/* Check if the user wishes to receive this event.  */
@@ -202,13 +183,13 @@
 	 */
 
 	if (!sctp_sk(sk)->pd_mode) {
-		queue = &sk->sk_receive_queue;
+		queue = &sk->receive_queue;
 	} else if (ulpq->pd_mode) {
 		if (event->msg_flags & MSG_NOTIFICATION)
 		       	queue = &sctp_sk(sk)->pd_lobby;
 		else {
 			clear_pd = event->msg_flags & MSG_EOR;
-			queue = &sk->sk_receive_queue;
+			queue = &sk->receive_queue;
 		}
 	} else
 		queue = &sctp_sk(sk)->pd_lobby;
@@ -229,8 +210,8 @@
 	if (clear_pd)
 		sctp_ulpq_clear_pd(ulpq);
 
-	if (queue == &sk->sk_receive_queue)
-		sk->sk_data_ready(sk, 0);
+	if (queue == &sk->receive_queue)
+		sk->data_ready(sk, 0);
 	return 1;
 
 out_free:
@@ -837,7 +818,7 @@
 
 	freed = 0;
 
-	if (skb_queue_empty(&asoc->base.sk->sk_receive_queue)) {
+	if (skb_queue_empty(&asoc->base.sk->receive_queue)) {
 		freed = sctp_ulpq_renege_order(ulpq, needed);
 		if (freed < needed) {
 			freed += sctp_ulpq_renege_frags(ulpq, needed - freed);
@@ -876,9 +857,9 @@
 					      SCTP_PARTIAL_DELIVERY_ABORTED,
 					      gfp);
 	if (ev)
-		__skb_queue_tail(&sk->sk_receive_queue, sctp_event2skb(ev));
+		__skb_queue_tail(&sk->receive_queue, sctp_event2skb(ev));
 
 	/* If there is data waiting, send it up the socket now. */
 	if (sctp_ulpq_clear_pd(ulpq) || ev)
-		sk->sk_data_ready(sk, 0);
+		sk->data_ready(sk, 0);
 }
