[netfilter-cvslog] r3551 - in branches/netfilter-ha/linux-2.6: ct_sync patches

hidden at netfilter.org hidden at netfilter.org
Mon Jan 3 00:13:27 CET 2005


Author: hidden at netfilter.org
Date: 2005-01-03 00:13:27 +0100 (Mon, 03 Jan 2005)
New Revision: 3551

Added:
   branches/netfilter-ha/linux-2.6/patches/conntrack_alloc.patch
   branches/netfilter-ha/linux-2.6/patches/conntrack_hash_manip.patch
   branches/netfilter-ha/linux-2.6/patches/ct_notifier_pkt.patch
   branches/netfilter-ha/linux-2.6/patches/export_ip_conntrack_clean_from_lists.patch
   branches/netfilter-ha/linux-2.6/patches/export_ip_nat_lock_and_hash.patch
Removed:
   branches/netfilter-ha/linux-2.6/ct_sync/Makefile
   branches/netfilter-ha/linux-2.6/ct_sync/ct_sync_main.h
   branches/netfilter-ha/linux-2.6/patches/export_ct_id.patch
   branches/netfilter-ha/linux-2.6/patches/export_hash_conntrack.patch
   branches/netfilter-ha/linux-2.6/patches/export_ip_nat_hash.patch
   branches/netfilter-ha/linux-2.6/patches/export_ip_nat_lock.patch
   branches/netfilter-ha/linux-2.6/patches/kgdb-1.9.patch
   branches/netfilter-ha/linux-2.6/patches/nfnetlink-ctnetlink.patch
   branches/netfilter-ha/linux-2.6/patches/proc_net_stat.patch
   branches/netfilter-ha/linux-2.6/patches/raw.patch
   branches/netfilter-ha/linux-2.6/patches/seq_file-seq_start_token.patch
Modified:
   branches/netfilter-ha/linux-2.6/ct_sync/ct_sync.h
   branches/netfilter-ha/linux-2.6/ct_sync/ct_sync_main.c
   branches/netfilter-ha/linux-2.6/ct_sync/ct_sync_proto.c
   branches/netfilter-ha/linux-2.6/ct_sync/ct_sync_proto.h
   branches/netfilter-ha/linux-2.6/ct_sync/ct_sync_sock.c
   branches/netfilter-ha/linux-2.6/patches/connmark.patch
   branches/netfilter-ha/linux-2.6/patches/ct_sync_config_and_makefile.patch
   branches/netfilter-ha/linux-2.6/patches/export_ip_conntrack_find.patch
   branches/netfilter-ha/linux-2.6/patches/export_ip_conntrack_helpers.patch
   branches/netfilter-ha/linux-2.6/patches/export_ip_nat_helpers.patch
   branches/netfilter-ha/linux-2.6/patches/pf_packet.patch
   branches/netfilter-ha/linux-2.6/patches/pf_packet_remove_warning.patch
   branches/netfilter-ha/linux-2.6/patches/series
Log:
Initial port of the netfilter-ha code to Linux 2.6, along with some
enhancements and cleanups.

hidden at sch.bme.hu--2005-public/netfilter-ha--mainline--1.0--patch-3

  * ct_sync/ct_sync_proto.c (cts_proto_request_recovery): use a variable
    instead of that ugly constant value
  * ct_sync/ct_sync_main.c: export cts_proto_recovery_threshold through
    sysctl

hidden at sch.bme.hu--2005-public/netfilter-ha--mainline--1.0--patch-2

  * ct_sync/ct_sync_proto.c (cts_proto_initsync_follows): add missing
    fourth argument to csb_hdr_fill() which was removed by accident

hidden at sch.bme.hu--2005-public/netfilter-ha--mainline--1.0--patch-1

  * ct_sync/ct_sync_proto.c (cts_proto_request_recovery): set active flag
    before touching other recovery parameters

hidden at sch.bme.hu--2004-public/netfilter-ha--mainline--1.0--patch-4

  * ct_sync/ct_sync_proto.c (cts_proto_init): removed group ID and state
    parameters, use transition_callback() instead of became_slave()
  * ct_sync/ct_sync_main.c (ct_sync_state_transition): new transition
    callback, called on every protocol state transition
  * ct_sync/ct_sync_main.c (_send_empty_initsync): use specified flags for
    sending
  * ct_sync/ct_sync_main.c (ct_sync_initsync_thread_main): send empty update
    message with the new CTS_UPD_F_INITSYNC_DONE flag after completing the
    initsync run
  * ct_sync/ct_sync_main.c: more sysctl controllable parameters (maxage,
    send_burst, recv_burst)

hidden at sch.bme.hu--2004-public/netfilter-ha--mainline--1.0--patch-3

  * ct_sync/ct_sync_proto.c: removed cts_proto_recv_running()
  * ct_sync/ct_sync.h: added some comments, removed lots of includes,
    removed ct_thread_startup structure
  * ct_sync/*.{c,h}: a bit more consistent indentation

hidden at sch.bme.hu--2004-public/netfilter-ha--mainline--1.0--patch-2

  * ct_sync/ct_sync_main.c: use kthread_ helper functions
    instead of own startup code
  * ct_sync/ct_sync_main.h: removed, was junk anyway
  * ct_sync/ct_sync_main.c, ct_sync/ct_sync_proto.c, ct_syncct_sync_sock.c:
    removed remnants of the CVS ID

hidden at sch.bme.hu--2004-public/netfilter-ha--mainline--1.0--patch-1

  * ct_sync/ct_sync_main.c(notrack_hook): when assigning conntrack to the skb,
    initialize nfctinfo to IP_CT_NEW



Deleted: branches/netfilter-ha/linux-2.6/ct_sync/Makefile
===================================================================
--- branches/netfilter-ha/linux-2.6/ct_sync/Makefile	2005-01-02 22:40:48 UTC (rev 3550)
+++ branches/netfilter-ha/linux-2.6/ct_sync/Makefile	2005-01-02 23:13:27 UTC (rev 3551)
@@ -1,35 +0,0 @@
-# set to your kernel tree
-KERNEL  = /usr/src/linux-ctsync
-
-# get the Linux architecture. Needed to find proper include file for CFLAGS
-ARCH=$(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
-# set default flags to compile module
-#CFLAGS = -DARCH=um -DCTSYNC_DEBUG -D__KERNEL__ -DMODULE -I$(KERNEL)/include -I$(KERNEL)/arch/um/include -I$(KERNEL)/arch/um/kernel/tt/include -I$(KERNEL)/arch/um/kernel/skas/include
-CFLAGS = -DCTSYNC_DEBUG -D__KERNEL__ -DMODULE -I$(KERNEL)/include 
-CFLAGS+= -Wall -Wstrict-prototypes -g -fomit-frame-pointer -fno-strict-aliasing
-
-CT_SYNC_MOD	= ct_sync.o
-CT_SYNC_OBJS	= ct_sync_main.o ct_sync_sock.o ct_sync_proto.o
-
-all:    $(CT_SYNC_MOD)
-
-# get configuration of kernel
-include $(KERNEL)/.config
-# modify CFLAGS with architecture specific flags
-include $(KERNEL)/arch/${ARCH}/Makefile
-
-# enable the module versions, if configured in kernel source tree
-ifdef CONFIG_MODVERSIONS
-CFLAGS+= -DMODVERSIONS -include $(KERNEL)/include/linux/modversions.h
-endif
-# enable SMP, if configured in kernel source tree
-ifdef CONFIG_SMP
-CFLAGS+= -D__SMP__
-endif
-
-$(CT_SYNC_MOD): $(CT_SYNC_OBJS)
-	$(LD) -r $^ -o $@
-
-clean:
-	rm -f *.o
-

Modified: branches/netfilter-ha/linux-2.6/ct_sync/ct_sync.h
===================================================================
--- branches/netfilter-ha/linux-2.6/ct_sync/ct_sync.h	2005-01-02 22:40:48 UTC (rev 3550)
+++ branches/netfilter-ha/linux-2.6/ct_sync/ct_sync.h	2005-01-02 23:13:27 UTC (rev 3551)
@@ -8,40 +8,17 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
- * $Id$
- *
  */
 #ifndef _CT_SYNC_H
 #define _CT_SYNC_H
 
-#if 0
-#include <linux/config.h>
-#include <linux/version.h>
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/tqueue.h>
-#include <linux/wait.h>
-
-#include <asm/semaphore.h>
-#include <linux/if_ether.h>
-#endif
-
 #include <linux/list.h>
 #include <linux/types.h>
 #include <linux/if_ether.h>
 #include <linux/netfilter_ipv4/ip_conntrack.h>
 
-#if 0
-#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
-#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
-#include <linux/netfilter_ipv4/ip_conntrack_core.h>
-#include <linux/netfilter_ipv4/ip_nat.h>
-#include <linux/netfilter_ipv4/ip_nat_helper.h>
-#endif
+#define CTSYNC_DEBUG 8
 
-#define CTSYNC_DEBUG 0
-
 /* debugging macros */
 #if (CTSYNC_DEBUG > 0)
 #define CT_SYNC_DEBUG(x, args...) printk (KERN_DEBUG "ct_sync: %s " x, __FUNCTION__ , ## args)
@@ -80,21 +57,21 @@
 {
 	__u8		version;		/* version number */
 	__u8		pkttype;		/* type of packet: sync/NACK */
-	__u8		node_id;		/* id of the sender node */
+	__u8		__reserved1;		/* id of the sender node */
 	__u8		count;			/* number of msgs in packet */
 	__u16		pktseq;			/* packet sequence number */
 	__u16		minseq;			/* min seqno master has */
 	__u8		flags;			/* flags: 1 == recover */
-	__u8		__reserved;		/* placeholder :) */
-	__u16		__reserved2;		/* placeholder :) */
+	__u8		__reserved2;		/* placeholder :) */
+	__u16		__reserved3;		/* placeholder :) */
 };
 
 /* packet types */
 enum ct_sync_pkttype_t
 {
 	CT_SYNC_PKT_UNKNOWN 		= 0x00,	/* not defined, illegal */
-	CT_SYNC_PKT_MASTER_ANNOUNCE	= 0x01,
-	CT_SYNC_PKT_SLAVE_INITSYNC	= 0x02,
+	CT_SYNC_PKT_MASTER_ANNOUNCE	= 0x01, /* master announcement (carrying seqno) */
+	CT_SYNC_PKT_SLAVE_INITSYNC	= 0x02, /* slave requests a full re-sync */
 	CT_SYNC_PKT_SYNC		= 0x03,	/* normal sync packet */
 	CT_SYNC_PKT_NACK		= 0x04,	/* negative ack packet */
 	CT_SYNC_PKT_INITSYNC_FOLLOWS	= 0x05,	/* a full re-sync follows */
@@ -102,17 +79,17 @@
 
 enum ct_sync_pkt_flag_t
 {
-	CT_SYNC_PKT_F_RECOVER 		= 0x01,
+	CT_SYNC_PKT_F_RECOVER 		= 0x01, /* recovery packet */
 };
 
-/* CT_SYNC_PKT_MASTER_ANNOUNCE */
+/* CT_SYNC_PKT_MASTER_ANNOUNCE payload */
 struct ct_sync_master_announce
 {
 	__u32	upsince;			/* master up since */
 	__u8	flags;				/* flags */
 };
 
-/* CT_SYNC_PKT_SLAVE_INITSYNC */
+/* CT_SYNC_PKT_SLAVE_INITSYNC payload */
 struct ct_sync_slave_initsync
 {
 	__u32	master;
@@ -146,7 +123,7 @@
 	CT_SYNC_MSG_DELETE	= 0x02,	/* delete conntrack entry */
 };
 
-/* CT_SYNC_PKT_SYNC: ressources */
+/* CT_SYNC_PKT_SYNC: resources */
 enum ct_sync_resource_t
 {
 	CT_SYNC_RES_CONNTRACK	= 0x01,
@@ -157,6 +134,7 @@
 {
 	CTS_UPD_F_NEW 		= 0x01,	/* creates new conntrack */
 	CTS_UPD_F_INITSYNC	= 0x02,	/* part of initial sync */
+	CTS_UPD_F_INITSYNC_DONE	= 0x04, /* sent after an initsync session is complete */
 };
 
 /* linearized conntrack data */
@@ -210,13 +188,6 @@
 
 #ifdef __KERNEL__
 
-/* thread startup structure */
-struct ct_thread_startup
-{
-	struct completion *completion;	/* signalling init of new thread */
-	int (*function)(void *);	/* function to run in the new thread */
-};
-
 /* statistics */
 struct ct_sync_st
 {
@@ -250,16 +221,14 @@
 	unsigned long slave2master;	/* slave->master transitions */
 	unsigned long master2slave;	/* master->slave transitions */
 	unsigned long master2slave_auto;
-	
-	unsigned long initsyncs;	/* master: started initsyncs */
 
+	unsigned long initsyncs;	/* master: started initsyncs */
 };
 
-extern struct ct_sync_stat ct_sync_stats[NR_CPUS];
+DECLARE_PER_CPU(struct ct_sync_stat, ct_sync_stats);
 
-#define CTS_STAT_INC(field)	(ct_sync_stats[smp_processor_id()].field++)
+#define CTS_STAT_INC(field)	(__get_cpu_var(ct_sync_stats).field++)
 
 #endif /* _KERNEL_ */
 
 #endif
-

Modified: branches/netfilter-ha/linux-2.6/ct_sync/ct_sync_main.c
===================================================================
--- branches/netfilter-ha/linux-2.6/ct_sync/ct_sync_main.c	2005-01-02 22:40:48 UTC (rev 3550)
+++ branches/netfilter-ha/linux-2.6/ct_sync/ct_sync_main.c	2005-01-02 23:13:27 UTC (rev 3551)
@@ -1,7 +1,7 @@
 /*
  * Connection tracking state replication for Netfilter
  *
- * (C) 2002-2003, KOVACS Krisztian <hidden at sch.bme.hu>
+ * (C) 2002-2004, KOVACS Krisztian <hidden at sch.bme.hu>
  * (C) 2003-2004, Harald Welte <laforge at netfilter.org>
  * (C) 2004, BalaBit IT Ltd. <www.balabit.com>
  *
@@ -9,8 +9,6 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
- * $Id$
- *
  */
 
 #define __KERNEL_SYSCALLS__
@@ -18,6 +16,7 @@
 #include <linux/config.h>
 #include <linux/version.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/sched.h>
@@ -30,12 +29,14 @@
 #include <linux/notifier.h>
 #include <linux/sysctl.h>
 #include <linux/seq_file.h>
+#include <linux/percpu.h>
+#include <linux/kthread.h>
 #include <net/sock.h>
 
 #include <linux/netdevice.h>
 #include <linux/netlink.h>
-#include <linux/netfilter_ipv4.h>
 #include <linux/netfilter_packet.h>
+#include <linux/netfilter_ipv4.h>
 #include <linux/netfilter_ipv4/ip_conntrack.h>
 #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
 #include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
@@ -50,7 +51,7 @@
 #include <linux/netfilter_ipv4/ct_sync.h>
 #include <linux/netfilter_ipv4/ct_sync_proto.h>
 
-#define DEBUGP	printk
+#define DEBUGP printk
 
 #if (CTSYNC_DEBUG > 0)
 #define CT_SYNC_DUMP_TUPLE(x) DUMP_TUPLE(x)
@@ -62,7 +63,7 @@
 #define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_conntrack_lock)
 #include <linux/netfilter_ipv4/listhelp.h>
 
-#define CT_SYNC_VERSION	"0.18"
+#define CT_SYNC_VERSION	"0.19"
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("KOVACS Krisztian <hidden at sch.bme.hu>, Harald Welte <laforge at netfilter.org>");
@@ -70,37 +71,21 @@
 
 /* module parameters */
 static char *syncdev = "";
-static int state = -1;
-static int id = -1;
+module_param(syncdev, charp, 0000);
 static int l2drop = 0;
+module_param(l2drop, int, 0000);
 static int cmarkbit = sizeof(unsigned long) * 8 - 1;
+module_param(cmarkbit, int, 0000);
 
-MODULE_PARM(syncdev, "s");
-MODULE_PARM_DESC(syncdev, "Interface used for sync messages");
-MODULE_PARM(state, "i");
-MODULE_PARM_DESC(state, "Initial state: 0=slave 1=master");
-MODULE_PARM(id, "i");
-MODULE_PARM_DESC(id, "unique Node ID (0..255) of local node");
-MODULE_PARM(l2drop, "i");
-MODULE_PARM_DESC(l2drop, "drop all packets at layer 2 if slave");
-MODULE_PARM(cmarkbit, "i");
-MODULE_PARM_DESC(cmarkbit, "bit in the connection mark to use as sync mark");
-
-/* used to stop ct_sync threads */
+/* thread wait queue heads */
 static DECLARE_WAIT_QUEUE_HEAD(ct_sync_rcv_wait);
-static DECLARE_WAIT_QUEUE_HEAD(stop_ct_rcv_thread_wait);
-static atomic_t stop_ct_rcv_thread = ATOMIC_INIT(0);
 
 static DECLARE_WAIT_QUEUE_HEAD(ct_sync_send_wait);
-static DECLARE_WAIT_QUEUE_HEAD(stop_ct_send_thread_wait);
-static atomic_t stop_ct_send_thread = ATOMIC_INIT(0);
 
 static atomic_t ct_sync_initsync_active = ATOMIC_INIT(0);
 static DECLARE_WAIT_QUEUE_HEAD(ct_sync_initsync_wait);
-static DECLARE_WAIT_QUEUE_HEAD(stop_ct_initsync_thread_wait);
-static atomic_t stop_ct_initsync_thread = ATOMIC_INIT(0);
 
-struct ct_sync_stat ct_sync_stats[NR_CPUS];
+DEFINE_PER_CPU(struct ct_sync_stat, ct_sync_stats);
 
 /* configuration data */
 static struct ct_sync_cfg
@@ -109,13 +94,13 @@
 	char devname[IFNAMSIZ];		/* dedicated sync network device */
 	int ifindex;			/* ifindex of the network device */
 	struct cts_protoh *protoh;	/* protocol handle */
-	u8 nodeid;			/* node id in cluster */
 } cts_cfg;
 
 /***********************************************************************
  * FILLING CTSYNC MESSAGES WITH DATA
  ***********************************************************************/
 
+#if 0
 static int
 fill_expectmsg(void *buff, __u8 event,
 	       struct ip_conntrack *master,
@@ -155,6 +140,7 @@
 
 	return 0;
 }
+#endif
 
 static int
 fill_ctmsg(void *buff, __u8 event, struct ip_conntrack *ct, __u8 flags)
@@ -206,7 +192,6 @@
 	memcpy(&sct->proto, &ct->proto, sizeof(sct->proto));
 
 #ifdef CONFIG_IP_NF_NAT_NEEDED
-	//if (likely(ct->nat.info.initialized && ct->nat.info.num_manips)) {
 	if (likely(ct->nat.info.initialized)) {
 		const struct ip_nat_info *nat = &ct->nat.info;
 
@@ -248,19 +233,6 @@
  * BACKEND FOR CONNTRACK MODIFICATION
  ***********************************************************************/
 
-static inline int
-_helper_name_cmp(const struct ip_conntrack_helper *i,
-		 const char *name)
-{
-	return strncmp(i->name, name, CT_SYNC_CTHELPERSIZE - 1);
-}
-
-static inline int
-_nat_helper_name_cmp(const struct ip_nat_helper *i, const char *name)
-{
-	return strncmp(i->name, name, CT_SYNC_NATHELPERSIZE - 1);
-}
-
 /*
  * update data in the conntrack entry
  */
@@ -295,10 +267,6 @@
 	//CT_SYNC_DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
 	//CT_SYNC_DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
 
-	/* optimization: done by conntrack_alloc */
-	//ct->tuplehash[IP_CT_DIR_ORIGINAL].ctrack = ct;
-	//ct->tuplehash[IP_CT_DIR_REPLY].ctrack = ct;
-
 	/* timeout */
 	if (!timer_pending(&ct->timeout)) {
 		ct->timeout.expires = sct->expires;
@@ -337,11 +305,9 @@
 
 	/* conntrack helper */
 	if (unlikely(sct->helper[0] != '\0')) {
+		sct->helper[CT_SYNC_CTHELPERSIZE - 1] = '\0';
 		READ_LOCK(&ip_conntrack_lock);
-		helper = LIST_FIND(&ip_conntrack_helpers, 
-				   _helper_name_cmp,
-				   struct ip_conntrack_helper *,
-				   sct->helper);
+		helper = __ip_ct_find_helper_by_name(sct->helper);
 		if (unlikely(!helper)) {
 			CT_SYNC_ERR("Unknown conntrack helper `%s', "
 				    "ignoring.\n", sct->helper);
@@ -353,8 +319,6 @@
 		READ_UNLOCK(&ip_conntrack_lock);
 	}
 
-	/* nf_ct_infos filled in by conntrack_alloc */
-	
 	/* protocol data */
 	memcpy(&ct->proto, &sct->proto, sizeof(ct->proto));
 
@@ -364,8 +328,8 @@
 	{
 		struct ip_nat_info *nat = &ct->nat.info;
 		/* DEBUG: initialize list heads to avoid oops */
-		INIT_LIST_HEAD(&nat->bysource.list);
-		INIT_LIST_HEAD(&nat->byipsproto.list);
+		INIT_LIST_HEAD(&nat->bysource);
+		INIT_LIST_HEAD(&nat->byipsproto);
 	}
 
 	//if (likely(sct->nat_initialized && sct->nat_num_manips)) {
@@ -388,10 +352,9 @@
 			if (unlikely(sct->nat_helper[0] != '\0')) {
 				struct ip_nat_helper *helper;
 				/* look up nat helper */
+				sct->nat_helper[CT_SYNC_NATHELPERSIZE - 1] = '\0';
 				READ_LOCK(&ip_nat_lock);
-				helper = LIST_FIND(&ip_nat_helpers, _nat_helper_name_cmp,
-						   struct ip_nat_helper *,
-						   sct->nat_helper);
+				helper = __ip_nat_find_helper_by_name(sct->nat_helper);
 				if (unlikely(!helper)) {
 					CT_SYNC_ERR("Unknown NAT helper `%s', ignoring\n", sct->nat_helper);
 					nat->helper = NULL;
@@ -426,16 +389,15 @@
 		WRITE_LOCK(&ip_conntrack_lock);
 		if (!__ip_conntrack_find(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, NULL) 
 		    && !__ip_conntrack_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple, NULL)) {
-			u_int32_t hash, repl_hash;
-			hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
-			repl_hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
+#if 0
 			/* place in ordered list */
 			ct->id = ip_conntrack_next_id++;
 			list_add_tail(&ct->olist, &ip_conntrack_ordered_list);
+#endif
 			/* put in conntrack hash */
-                	list_prepend(&ip_conntrack_hash[hash], &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
-                	list_prepend(&ip_conntrack_hash[repl_hash], &ct->tuplehash[IP_CT_DIR_REPLY]);
-                	atomic_inc(&ct->ct_general.use);
+			__ip_conntrack_hash_insert(ct);
+			atomic_inc(&ct->ct_general.use);
+
 			/* put in NAT hashes if necessary */
 			if (sct->nat_initialized) {
 				CT_SYNC_ASSERT(previous_nat_initialized == 0);
@@ -456,90 +418,16 @@
 	return 0;
 }
 
-static inline void
-__ct_sync_unexpect_related(struct ip_conntrack_expect *expect)
-{
-	if (unlikely(expect->sibling != NULL)) {
-		CT_SYNC_ERR("Cannot delete a confirmed expectation!\n");
-		return;
-	}
-
-	list_del(&expect->list);
-	list_del(&expect->expected_list);
-
-	if (likely(expect->expectant != NULL))
-		expect->expectant->expecting--;
-
-	ip_conntrack_expect_put(expect);
-}
-
-static inline void
-_ct_sync_unexpect_related(struct ip_conntrack_expect *expect)
-{
-	if (unlikely(!expect->expectant || !expect->expectant->helper))
-		return;
-	if (unlikely(expect->expectant->helper->timeout 
-		     && !del_timer(&expect->timeout)))
-		return;
-	
-	__ct_sync_unexpect_related(expect);
-}
-
-static inline void
-_ct_sync_conntrack_remove_expectations(struct ip_conntrack *ct)
-{
-	struct list_head *exp_entry, *next;
-	struct ip_conntrack_expect *exp;
-
-	CT_SYNC_ENTER();
-	
-        for (exp_entry = ct->sibling_list.next;
-             exp_entry != &ct->sibling_list; exp_entry = next) {
-                next = exp_entry->next;
-                exp = list_entry(exp_entry, struct ip_conntrack_expect,
-                                 expected_list);
-
-                if (exp->sibling)
-                        continue;
-
-                _ct_sync_unexpect_related(exp);
-        }
-
-	CT_SYNC_LEAVE();
-}
-
-static inline void
-_ct_sync_conntrack_clean_lists(struct ip_conntrack *ct)
-{
-	u_int32_t hash, repl_hash;
-
-	CT_SYNC_ENTER();
-
-	WRITE_LOCK(&ip_conntrack_lock);
-
-	hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
-	repl_hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
-	LIST_DELETE(&ip_conntrack_hash[hash], 
-		    &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
-	LIST_DELETE(&ip_conntrack_hash[repl_hash],
-		    &ct->tuplehash[IP_CT_DIR_REPLY]);
-	LIST_DELETE(&ip_conntrack_ordered_list, &ct->olist);
-
-	WRITE_UNLOCK(&ip_conntrack_lock);
-
-	_ct_sync_conntrack_remove_expectations(ct);
-
-	CT_SYNC_LEAVE();
-}
-
-/* delete conntrack entry */
+/* delete conntrack entry, but do not generate an event */
 static inline int
 _ct_sync_remove_conntrack(struct ip_conntrack *ct)
 {
 	CT_SYNC_ENTER();
 
 	del_timer(&ct->timeout);
-	_ct_sync_conntrack_clean_lists(ct);
+	WRITE_LOCK(&ip_conntrack_lock);
+	ip_conntrack_clean_from_lists(ct);
+	WRITE_UNLOCK(&ip_conntrack_lock);
 	ip_conntrack_put(ct);
 
 	CT_SYNC_LEAVE();
@@ -645,12 +533,7 @@
 	CT_SYNC_LEAVE();
 }
 
-static int kill_all(const struct ip_conntrack *i, void *data)
-{
-	return 1;
-}
 
-
 /***********************************************************************
  * MESSAGE PROCESSING FUNCTIONS
  ***********************************************************************/
@@ -859,7 +742,6 @@
 {
 	int ret;
 	u16 pktseq = ntohs(pkthdr->pktseq);
-	//u16 minseq = ntohs(pkthdr->minseq);
 
 	CT_SYNC_ENTER();
 
@@ -891,12 +773,6 @@
 	if (cts_proto_is_master(cts_cfg.protoh) &&
 	    !atomic_read(&ct_sync_initsync_active)) {
 		CTS_STAT_INC(initsyncs);
-		/* signal that an initsync is to follow */
-		if (cts_proto_initsync_follows(cph) < 0) {
-			CT_SYNC_LEAVE();
-			return -1;
-		}
-		/* wake up initsync thread */
 		wake_up(&ct_sync_initsync_wait);
 	} else
 		CT_SYNC_INFO("not master, or initsync already in progress\n");
@@ -907,33 +783,251 @@
 }
 
 /***********************************************************************
+ * SYSCTL HANDLING
+ ***********************************************************************/
+
+/* sysctl variables */
+static int cts_sysctl_state;
+static int cts_sysctl_maxage;
+static int cts_sysctl_send_burst = 100;
+static int cts_sysctl_recv_burst = 400;
+
+#define CTS_SYSCTL_STATE_NONE	0
+#define CTS_SYSCTL_STATE_SLAVE	1
+#define CTS_SYSCTL_STATE_MASTER	2
+
+static int
+cts_sysctl_change_state(int state)
+{
+	CT_SYNC_ENTER();
+
+	switch (state) {
+	case CTS_SYSCTL_STATE_NONE:
+		/* cannot set state to NONE */
+		CT_SYNC_ERR("cannot switch to state none!\n");
+		CT_SYNC_LEAVE();
+		return -EINVAL;
+		break;
+
+	case CTS_SYSCTL_STATE_SLAVE:
+		if (cts_proto_is_master(cts_cfg.protoh)) {
+			CTS_STAT_INC(master2slave);
+			CT_SYNC_ERR("cannot switch active master to client!\n");
+			CT_SYNC_LEAVE();
+			return -EINVAL;
+		} else if (cts_proto_get_state(cts_cfg.protoh) == CT_SYNC_PSTATE_NONE) {
+			cts_proto_become_slave(cts_cfg.protoh);
+		}
+		break;
+
+	case CTS_SYSCTL_STATE_MASTER:
+		if (!cts_proto_is_master(cts_cfg.protoh)) {
+			if (cts_proto_become_master(cts_cfg.protoh) < 0) {
+				CT_SYNC_ERR("proto said we cannot become master\n");
+				CT_SYNC_LEAVE();
+				return -EINVAL;
+			}
+		} else {
+			CT_SYNC_INFO("we already are master; staying cool");
+		}
+		break;
+
+	default:
+		/* unknown state */
+		CT_SYNC_ERR("cannot switch to unknown state!\n");
+		CT_SYNC_LEAVE();
+		return -EINVAL;
+		break;
+		break;
+	}
+
+	CT_SYNC_LEAVE();
+
+	return 0;
+}
+
+static void
+cts_sysctl_update_state(void)
+{
+	CT_SYNC_ENTER();
+
+	switch (cts_proto_get_state(cts_cfg.protoh)) {
+	case CT_SYNC_PSTATE_NONE:
+		cts_sysctl_state = CTS_SYSCTL_STATE_NONE;
+		break;
+	case CT_SYNC_PSTATE_SLAVE_INIT:
+	case CT_SYNC_PSTATE_SLAVE_SYNSENT:
+	case CT_SYNC_PSTATE_SLAVE_SYNRECV:
+	case CT_SYNC_PSTATE_SLAVE_RUNNING:
+		cts_sysctl_state = CTS_SYSCTL_STATE_SLAVE;
+		break;
+	case CT_SYNC_PSTATE_MASTER_INIT:
+	case CT_SYNC_PSTATE_MASTER_ADVSENT:
+	case CT_SYNC_PSTATE_MASTER_RUNNING:
+		cts_sysctl_state = CTS_SYSCTL_STATE_MASTER;
+		break;
+	default:
+		CT_SYNC_ERR("invalid state\n");
+		break;
+	}
+
+	CT_SYNC_LEAVE();
+}
+
+static int
+cts_sysctl_state_handler(ctl_table *table, int write,
+			 struct file *filp, void *buffer,
+			 size_t *lenp, loff_t *ppos)
+{
+	int res;
+	
+	if (write) {
+		res = proc_dointvec(table, write, filp, buffer, lenp, ppos);
+		if (res < 0)
+			return res;
+		return cts_sysctl_change_state(cts_sysctl_state);
+	} else {
+		cts_sysctl_update_state();
+		return proc_dointvec(table, write, filp, buffer, lenp, ppos);
+	}
+}
+
+static int
+cts_sysctl_maxage_handler(ctl_table *table, int write,
+			  struct file *filp, void *buffer,
+			  size_t *lenp, loff_t *ppos)
+{
+	int res;
+
+	if (write) {
+		res = proc_dointvec(table, write, filp, buffer, lenp, ppos);
+		if (res < 0)
+			return res;
+		return cts_proto_set_max_age(cts_sysctl_maxage);
+	} else {
+		cts_sysctl_maxage = cts_proto_get_max_age();
+		return proc_dointvec(table, write, filp, buffer, lenp, ppos);
+	}
+}
+
+/* FIXME: define this in sysctl.h */
+#define NET_IPV4_NF_CONNTRACK_SYNC 20
+
+enum {
+	CTS_SYSCTL_STATE = 1,
+	CTS_SYSCTL_MAXAGE = 2,
+	CTS_SYSCTL_SEND_BURST = 3,
+	CTS_SYSCTL_RECV_BURST = 4,
+	CTS_SYSCTL_RECOVERY_THRESHOLD = 5,
+};
+
+static ctl_table ct_sync_sysctl_table[] = {
+	{
+		.ctl_name	= CTS_SYSCTL_STATE,
+		.procname	= "state",
+		.mode		= 0644,
+		.data		= &cts_sysctl_state,
+		.maxlen		= sizeof(int),
+		.proc_handler	= &cts_sysctl_state_handler,
+	},
+	{
+		.ctl_name	= CTS_SYSCTL_MAXAGE,
+		.procname	= "maxage",
+		.mode		= 0644,
+		.data		= &cts_sysctl_maxage,
+		.maxlen		= sizeof(int),
+		.proc_handler	= &cts_sysctl_maxage_handler,
+	},
+	{
+		.ctl_name	= CTS_SYSCTL_SEND_BURST,
+		.procname	= "send_burst",
+		.mode		= 0644,
+		.data		= &cts_sysctl_send_burst,
+		.maxlen		= sizeof(int),
+		.proc_handler	= &proc_dointvec,
+	},
+	{
+		.ctl_name	= CTS_SYSCTL_RECV_BURST,
+		.procname	= "recv_burst",
+		.mode		= 0644,
+		.data		= &cts_sysctl_recv_burst,
+		.maxlen		= sizeof(int),
+		.proc_handler	= &proc_dointvec,
+	},
+	{
+		.ctl_name	= CTS_SYSCTL_RECOVERY_THRESHOLD,
+		.procname	= "recovery_threshold",
+		.mode		= 0644,
+		.data		= &cts_proto_recovery_threshold,
+		.maxlen		= sizeof(int),
+		.proc_handler	= &proc_dointvec_minmax,
+		.extra1		= 0,
+		.extra2		= 32767,
+	},
+	{ .ctl_name = 0 }
+};
+
+static ctl_table ct_sync_cts_table[] = {
+	{
+		.ctl_name	= NET_IPV4_NF_CONNTRACK_SYNC,
+		.procname	= "ct_sync",
+		.mode		= 0555,
+		.child		= ct_sync_sysctl_table,
+	},
+	{ .ctl_name = 0 }
+};
+
+static ctl_table ct_sync_netfilter_table[] = {
+	{
+		.ctl_name	= NET_IPV4_NETFILTER,
+		.procname	= "netfilter",
+		.mode		= 0555,
+		.child		= ct_sync_cts_table,
+	},
+	{ .ctl_name = 0 }
+};
+
+static ctl_table ct_sync_net_table[] = {
+	{
+		.ctl_name	= NET_IPV4,
+		.procname	= "ipv4",
+		.mode		= 0555,
+		.child		= ct_sync_netfilter_table,
+	},
+	{ .ctl_name = 0 }
+};
+
+static ctl_table ct_sync_root_table[] = {
+	{
+		.ctl_name	= CTL_NET,
+		.procname	= "net",
+		.mode		= 0555,
+		.child		= ct_sync_net_table,
+	},
+	{ .ctl_name = 0 }
+};
+
+static struct ctl_table_header *ct_sync_sysctl_header;
+
+/***********************************************************************
  * KERNEL THREADS
  ***********************************************************************/
 
-#define CT_SYNC_SEND_BURST 	100
 /* sync kernel thread: sender */
 static int
-ct_sync_send_thread_main(void *ct_thread_startup)
+ct_sync_send_thread_main(void *data)
 {
-	mm_segment_t oldmm;
 	unsigned long remaining;
 	DECLARE_WAITQUEUE(wait, current);
 
 	CT_SYNC_ENTER();
 
-	/* daemonize kernel thread, set values */
-	daemonize();
-	oldmm = get_fs();
-	set_fs(KERNEL_DS);
-	sigfillset(&current->blocked);
-	sprintf(current->comm, "ct_sync_send");
-	
-	complete((struct completion *) ct_thread_startup);
-
         for (;;) {
 		int i = 0;
-		if (unlikely(atomic_read(&stop_ct_send_thread))) {
-			CT_SYNC_DEBUG("stop_ct_send_thread == 1\n");
+
+		/* check if we should stop */
+		if (kthread_should_stop()) {
+			CT_SYNC_DEBUG("send thread stopping\n");
 			break;
 		}
 
@@ -941,12 +1035,13 @@
 		 * all of them */
 		while (cts_proto_send_pending(cts_cfg.protoh)) {
 			cts_proto_send_dequeue(cts_cfg.protoh);
-			i++;
-			if (i >= CT_SYNC_SEND_BURST)
+
+			if (++i >= cts_sysctl_send_burst)
 				break;
 		}
 
-		cts_proto_initsync_retransmit(cts_cfg.protoh);
+		/* send an initsync request if necessary */
+		cts_proto_initsync_request(cts_cfg.protoh);
 
 		__set_current_state(TASK_INTERRUPTIBLE);
 		add_wait_queue(&ct_sync_send_wait, &wait);
@@ -964,39 +1059,19 @@
 			CT_SYNC_DEBUG2("woken up after schedule_timeout() because we had an event\n");
         }
 
-	set_fs(oldmm);
-
-	atomic_set(&stop_ct_send_thread, 0);
-	wake_up(&stop_ct_send_thread_wait);
-
 	CT_SYNC_LEAVE();
 	
 	return 0;
 }
 
-/* FIXME: these should be configurable */
-#define CT_SYNC_RECV_BURST 200
-//#define CT_SYNC_INITSYNC_RATE 20
 /* sync kernel thread: receiver */
 static int
-ct_sync_rcv_thread_main(void *ct_thread_startup)
+ct_sync_rcv_thread_main(void *data)
 {
-	mm_segment_t oldmm;
 	DECLARE_WAITQUEUE(wait, current);
 	
 	CT_SYNC_ENTER();
 	
-	/* daemonize kernel thread, set values */
-	daemonize();
-	oldmm = get_fs();
-	set_fs(KERNEL_DS);
-	sigfillset(&current->blocked);
-	sprintf(current->comm, "ct_sync_rcv");
-
-	complete((struct completion *) ct_thread_startup);
-
-	CT_SYNC_DEBUG("ct_sync_rcv: entering main loop\n");
-
 	for (;;) {
 		int pkts_enqueued = 0;
 		int pkts_received = 0;
@@ -1004,8 +1079,8 @@
 		struct ct_sync_msghdr *msghdr;
 		struct ct_sync_pkthdr *pkthdr;
 
-	  	if (unlikely(atomic_read(&stop_ct_rcv_thread)))
-		  	break;
+	  	if (kthread_should_stop())
+			break;
 
 		/* wait for a new packet to arrive */
 		if (!cts_proto_recv_pending(cts_cfg.protoh)) {
@@ -1015,7 +1090,7 @@
 			for (;;) {
 				__set_current_state(TASK_INTERRUPTIBLE);
 				if (cts_proto_recv_pending(cts_cfg.protoh) ||
-				    unlikely(atomic_read(&stop_ct_rcv_thread)))
+				    kthread_should_stop())
 					break;
 
 				CT_SYNC_DEBUG2("falling asleep\n");
@@ -1049,10 +1124,10 @@
 				   and dropped the packet */
 				break;
 			}
-			
+
 			pkts_received++;
 			CTS_STAT_INC(rx.pkts_tot);
-			if (pkts_received >= CT_SYNC_RECV_BURST)
+			if (pkts_received >= cts_sysctl_recv_burst)
 				break;
 		}
 
@@ -1072,7 +1147,7 @@
 			}
 
 		/* give chance for other processes to run */
-		if (pkts_received >= CT_SYNC_RECV_BURST)
+		if (pkts_received >= cts_sysctl_recv_burst)
 			cond_resched();
 			
 		/* FIXME: implement another way to detect end of initsync,
@@ -1092,11 +1167,6 @@
 	}
 
 error:
-	set_fs(oldmm);
-
-	atomic_set(&stop_ct_rcv_thread, 0);
-	wake_up(&stop_ct_rcv_thread_wait);
-
 	CT_SYNC_LEAVE();
 
 	return 0;
@@ -1112,7 +1182,7 @@
 
 	if (likely(is_confirmed(ct)
 #ifdef CONFIG_IP_NF_CONNTRACK_MARK
-	    /* stop timer only if this is a synchronized connection */
+	    /* send only if this is a synchronized connection */
 	    && test_bit(cmarkbit, &ct->mark)
 #endif
 	    )) {
@@ -1132,7 +1202,8 @@
 	return 0;
 } 
 
-static int _send_empty_initsync(void)
+static int
+_send_empty_initsync(u8 flags)
 {
 	struct cts_buff *csb;
 	struct ct_sync_msghdr *hdr;
@@ -1149,7 +1220,7 @@
 	hdr->type = CT_SYNC_MSG_UPDATE;
 	hdr->resource = CT_SYNC_RES_CONNTRACK;
 	hdr->len = 0;
-	hdr->flags = CTS_UPD_F_INITSYNC;
+	hdr->flags = flags;
 
 	csb_use_dec(cts_cfg.protoh, csb);
 
@@ -1158,24 +1229,12 @@
 
 /* sync kernel thread: recover */
 static int
-ct_sync_initsync_thread_main(void *ct_thread_startup)
+ct_sync_initsync_thread_main(void *data)
 {
 	DECLARE_WAITQUEUE(wait, current);
-	mm_segment_t oldmm;
 
 	CT_SYNC_ENTER();
 
-	/* daemonize kernel thread, set values */
-	daemonize();
-	oldmm = get_fs();
-	set_fs(KERNEL_DS);
-	sigfillset(&current->blocked);
-	sprintf(current->comm, "ct_sync_initsync");
-
-	complete((struct completion *) ct_thread_startup);
-
-	CT_SYNC_DEBUG("ct_sync_initsync: entering main loop\n");
-
 	for (;;) {
 		int i; 
 		int num_sent_total;
@@ -1187,29 +1246,32 @@
 		__set_current_state(TASK_RUNNING);
 
 		/* somebody woke us.  either initsync or thread termination
-		   request */
+		 * request */
 
-		if (unlikely(atomic_read(&stop_ct_initsync_thread)))
+		if (kthread_should_stop())
 			break;
 
 		CT_SYNC_INFO("starting initsync dump\n");
-		/* Send master announce in order to assure slave(s)
-		 * learn about current (correct) seqno */
-		cts_proto_master_announce(cts_cfg.protoh);
+		atomic_set(&ct_sync_initsync_active, 1);
 
+		/* Send an INITSYNC_FOLLOWS packet indicating that a full
+		 * re-sync follows and all nodes waiting for re-sent
+		 * packets should go to SLAVE_INIT state and forget
+		 * current receiver state */
+		cts_proto_initsync_follows(cts_cfg.protoh);
+
 		/* speed: 40 conntracks per schedule, 100 schedules per
-		   second: 4000 conntracks per second.  This makes about
-		   25 seconds for 100,000 connections.  Please note that
-		   we have four conntracks per packet, so the wire would
-		   see something like 1000 packets per second, or in
-		   other words: 1.5mbits */
+		 * second: 4000 conntracks per second.  This makes about
+		 * 25 seconds for 100,000 connections.  Please note that
+		 * we have four conntracks per packet, so the wire would
+		 * see something like 1000 packets per second, or in
+		 * other words: 1.5mbits */
 
 		num_sent_total = 0;
-		atomic_set(&ct_sync_initsync_active, 1);
 		for (i = 0; i < ip_conntrack_htable_size; i++) {
 			unsigned int num_sent = 0;
 
-			if (unlikely(atomic_read(&stop_ct_initsync_thread)))
+			if (kthread_should_stop())
 				break;
 
 			READ_LOCK(&ip_conntrack_lock);
@@ -1237,45 +1299,27 @@
 			__set_current_state(TASK_RUNNING);
 			CT_SYNC_DEBUG2("woken up\n");
 		}
+
 		if (!num_sent_total) {
 			/* need to send an empty PKT_SYCN/UPD_F_INITSYNC
 			 * packet in order to provoke state transition
 			 * in slave */
-			_send_empty_initsync();
+			_send_empty_initsync(CTS_UPD_F_INITSYNC);
 		}
+
+		/* signal that the initsync is over */
+		_send_empty_initsync(CTS_UPD_F_INITSYNC_DONE);
+
 		atomic_set(&ct_sync_initsync_active, 0);
 
 		CT_SYNC_INFO("finished initsync dump\n");
 	}
 
-	set_fs(oldmm);
-
-	atomic_set(&stop_ct_initsync_thread, 0);
-	wake_up(&stop_ct_initsync_thread_wait);
-
 	CT_SYNC_LEAVE();
 
 	return 0;
 }
 
-/* thread startup helper: double fork to reparent to init */
-static int
-fork_ct_thread(void *p)
-{
-	struct ct_thread_startup *c = (struct ct_thread_startup *)p;
-	CT_SYNC_ENTER();
-	
-	if (kernel_thread(c->function, c->completion, 0) < 0) {
-		CT_SYNC_ERR("Failed to fork ct_sync thread.\n");
-		CT_SYNC_LEAVE();
-		return -1;
-	}
-
-	CT_SYNC_LEAVE();
-	
-	return 0;
-}
-
 /***********************************************************************
  * NOTIFIER HANDLERS
  ***********************************************************************/
@@ -1309,7 +1353,7 @@
 			CT_SYNC_LEAVE();
 			return;
 		}
-		fill_ctmsg(buff, CT_SYNC_MSG_UPDATE, ct, new ? CTS_UPD_F_NEW:0);
+		fill_ctmsg(buff, CT_SYNC_MSG_UPDATE, ct, new ? CTS_UPD_F_NEW : 0);
 		csb_use_dec(cts_cfg.protoh, csb);
 	}
 
@@ -1361,6 +1405,7 @@
 	CT_SYNC_LEAVE();
 }
 
+#if 0
 /* conntrack expectation created notification */
 static void
 ct_sync_expect_create(struct ip_conntrack_expect *exp)
@@ -1418,10 +1463,8 @@
 
 	return;
 }
+#endif
 
-/* event processing macros */
-#define EVENT(e) (1 << (e))
-
 static int
 ct_sync_notify(struct notifier_block *this,
 	       unsigned long events, void *ct)
@@ -1429,14 +1472,14 @@
 	if ((struct ip_conntrack *)ct == &ip_conntrack_untracked)
 		return NOTIFY_DONE;
 
-	if (events & EVENT(IPCT_NEW)) {
+	if (events & IPCT_NEW) {
 		ct_sync_create((struct ip_conntrack *)ct, 1);
 
-	} else if (events & (EVENT(IPCT_STATUS) | EVENT(IPCT_PROTOINFO) |
-		      EVENT(IPCT_HELPINFO) | EVENT(IPCT_NATINFO))) {
+	} else if (events & (IPCT_STATUS | IPCT_PROTOINFO |
+		      IPCT_HELPINFO | IPCT_NATINFO)) {
 		ct_sync_create((struct ip_conntrack *)ct, 0);
 
-	} else if (events & EVENT(IPCT_DESTROY)) {
+	} else if (events & IPCT_DESTROY) {
 		ct_sync_destroy((struct ip_conntrack *)ct);
 
 	}
@@ -1451,7 +1494,7 @@
 };
 
 /***********************************************************************
- * conntrack exemptions
+ * NOTRACK (conntrack exemptions)
  ***********************************************************************/
 
 static unsigned int
@@ -1467,7 +1510,6 @@
 	/* all traffic coming in or going out sync interface is not
 	   to be tracked. Also, loopback traffic is ignored */
 
-	/* FIXME: implement this based on ifindex matching */
 	if ((hook == NF_IP_PRE_ROUTING && indev && 
 	     indev->ifindex == cts_cfg.ifindex) ||
 	    (hook == NF_IP_LOCAL_OUT && outdev &&
@@ -1476,7 +1518,8 @@
 	    (outdev && outdev == &loopback_dev)) {
 
 		/* Attach fake conntrack entry */
-		(*pskb)->nfct = &ip_conntrack_untracked.infos[IP_CT_NEW];
+		(*pskb)->nfct = &ip_conntrack_untracked.ct_general;
+		(*pskb)->nfctinfo = IP_CT_NEW;
 		nf_conntrack_get((*pskb)->nfct);
 	}
 
@@ -1510,7 +1553,6 @@
 	return NF_ACCEPT;
 }
 
-
 static struct nf_hook_ops cts_hook_ops[] = {
 	{ .hook = notrack_hook,
 	  .pf = PF_INET,
@@ -1531,182 +1573,96 @@
 };
 
 /***********************************************************************
- * SYSCTL HANDLING
+ * CT_SYNC_PROTO CALLBACK
  ***********************************************************************/
 
-/* sysctl variables */
-static int cts_sysctl_state;
-
-static int
-cts_sysctl_change_state(int state)
+/* This could be converted to notifiers ... */
+static void
+ct_sync_state_transition(struct cts_protoh *cph,
+			 enum cts_proto_state oldstate,
+			 enum cts_proto_state newstate,
+			 void *data)
 {
 	CT_SYNC_ENTER();
 
-	if ((state == 0) && cts_proto_is_master(cts_cfg.protoh)) {
-		CTS_STAT_INC(master2slave);
-		CT_SYNC_ERR("cannot switch active master to client!\n");
-		CT_SYNC_LEAVE();
-		return -EINVAL;
-	} else if (state == 1) {
-		if (!cts_proto_is_master(cts_cfg.protoh)) {
+	switch (newstate) {
+	case CT_SYNC_PSTATE_NONE:
+		break;
 
-			ct_sync_start_timers();
+	case CT_SYNC_PSTATE_SLAVE_INIT:
+	case CT_SYNC_PSTATE_SLAVE_SYNRECV:
+		if (oldstate == CT_SYNC_PSTATE_NONE) {
+			/* initial slave synchronization: we don't stop
+			 * conntrack timers when being initialized to
+			 * slave: this could cause connections left in
+			 * the conntrack hash for an indefinite amount
+			 * of time... */
+		} else if (oldstate >= CT_SYNC_PSTATE_MASTER_INIT) {
+			/* transition from master to slave */
+			ip_conntrack_unregister_notifier(&ct_sync_notifier);
+			ct_sync_stop_timers();
+		}
+		break;
 
-			if (ip_conntrack_notify_register(&ct_sync_notifier) < 0) {
+	case CT_SYNC_PSTATE_MASTER_INIT:
+		if (oldstate < CT_SYNC_PSTATE_MASTER_INIT) {
+			/* transition from none/slave to master */
+			ct_sync_start_timers();
+			if (ip_conntrack_register_notifier(&ct_sync_notifier) < 0) {
 				CT_SYNC_ERR("cannot register notifier\n");
-				CT_SYNC_LEAVE();
-				return -EINVAL;
 			}
-
-			if (cts_proto_become_master(cts_cfg.protoh) < 0) {
-				CT_SYNC_ERR("proto said we cannot become master\n");
-				CT_SYNC_LEAVE();
-				return -EINVAL;
-			}
-		} else {
-			CT_SYNC_INFO("we already are master; staying cool");
 		}
+		break;
+
+	default:
+		break;
 	}
 
 	CT_SYNC_LEAVE();
-
-	return 0;
 }
 
-static void
-cts_sysctl_update_state(void)
-{
-	cts_sysctl_state = cts_proto_is_master(cts_cfg.protoh);
-}
-
-static int
-cts_sysctl_state_handler(ctl_table *table, int write,
-		 struct file *filp, void *buffer,
-		 size_t *lenp)
-{
-	int res;
-	
-	if (write) {
-		res = proc_dointvec(table, write, filp, buffer, lenp);
-		if (res < 0)
-			return res;
-		return cts_sysctl_change_state(cts_sysctl_state);
-	} else {
-		cts_sysctl_update_state();
-		return proc_dointvec(table, write, filp, buffer, lenp);
-	}
-}
-
-/* FIXME: define this in sysctl.h */
-#define NET_IPV4_NF_CONNTRACK_SYNC 20
-
-enum {
-	CTS_SYSCTL_STATE = 1,
-};
-
-static ctl_table ct_sync_sysctl_table[] = {
-	{
-		.ctl_name	= CTS_SYSCTL_STATE,
-		.procname	= "state",
-		.mode		= 0644,
-		.data		= &cts_sysctl_state,
-		.maxlen		= sizeof(int),
-		.proc_handler	= &cts_sysctl_state_handler
-	},
-	{ .ctl_name = 0 }
-};
-
-static ctl_table ct_sync_cts_table[] = {
-	{
-		.ctl_name	= NET_IPV4_NF_CONNTRACK_SYNC,
-		.procname	= "ct_sync",
-		.mode		= 0555,
-		.child		= ct_sync_sysctl_table,
-	},
-	{ .ctl_name = 0 }
-};
-
-static ctl_table ct_sync_netfilter_table[] = {
-	{
-		.ctl_name	= NET_IPV4_NETFILTER,
-		.procname	= "netfilter",
-		.mode		= 0555,
-		.child		= ct_sync_cts_table,
-	},
-	{ .ctl_name = 0 }
-};
-
-static ctl_table ct_sync_net_table[] = {
-	{
-		.ctl_name	= NET_IPV4,
-		.procname	= "ipv4",
-		.mode		= 0555,
-		.child		= ct_sync_netfilter_table,
-	},
-	{ .ctl_name = 0 }
-};
-
-static ctl_table ct_sync_root_table[] = {
-	{
-		.ctl_name	= CTL_NET,
-		.procname	= "net",
-		.mode		= 0555,
-		.child		= ct_sync_net_table,
-	},
-	{ .ctl_name = 0 }
-};
-
-static struct ctl_table_header *ct_sync_sysctl_header;
-
 /***********************************************************************
- * CT_SYNC_PROTO CALLBACK
- ***********************************************************************/
-
-/* This could be converted to notifiers ... */
-
-static void
-ct_sync_became_slave(struct cts_protoh *cph, void *data)
-{
-	ip_conntrack_notify_unregister(&ct_sync_notifier);
-	ct_sync_stop_timers();
-}
-
-/***********************************************************************
  * STATISTICS
  ***********************************************************************/
 
-static void *cts_stat_seq_start(struct seq_file *seq, loff_t *pos)
+static void *
+cts_stat_seq_start(struct seq_file *seq, loff_t *pos)
 {
-	int lcpu;
+	int cpu;
 
 	if (*pos == 0)
 		return SEQ_START_TOKEN;
 
-	for (lcpu = *pos-1; lcpu < smp_num_cpus; ++lcpu) {
-		int i = cpu_logical_map(lcpu);
-		*pos = lcpu+1;
-		return &ct_sync_stats[i];
+	for (cpu = *pos-1; cpu < NR_CPUS; ++cpu) {
+		if (!cpu_possible(cpu))
+			continue;
+		*pos = cpu+1;
+		return &per_cpu(ct_sync_stats, cpu);
 	}
 	return NULL;
 }
 
-static void *cts_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+static void *
+cts_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
-	int lcpu;
+	int cpu;
 	
-	for (lcpu = *pos; lcpu < smp_num_cpus; ++lcpu) {
-		int i = cpu_logical_map(lcpu);
-		*pos = lcpu+1;
-		return &ct_sync_stats[i];
+	for (cpu = *pos; cpu < NR_CPUS; ++cpu) {
+		if (!cpu_possible(cpu))
+			continue;
+		*pos = cpu+1;
+		return &per_cpu(ct_sync_stats, cpu);
 	}
 	return NULL;
 }
 
-static void cts_stat_seq_stop(struct seq_file *seq, void *v)
+static void
+cts_stat_seq_stop(struct seq_file *seq, void *v)
 {
 }
 
-static void cts_stat_seq_show_st(struct seq_file *seq, struct ct_sync_st *s)
+static void
+cts_stat_seq_show_st(struct seq_file *seq, struct ct_sync_st *s)
 {
 	seq_printf(seq, "%lu %lu %lu %lu %lu %lu %lu "
 			"%lu %lu %lu %lu %lu %lu %lu  ",
@@ -1718,14 +1674,24 @@
 		   s->exp_upd_tot, s->exp_del_tot);
 }
 
-static int cts_stat_seq_show(struct seq_file *seq, void *v)
+static int
+cts_stat_seq_show(struct seq_file *seq, void *v)
 {
 	struct ct_sync_stat *stats = v;
 
 	if (v == SEQ_START_TOKEN) {
-		seq_printf(seq, "tx_pkts_tot tx_pkts_ooseq tx_pkts_recover tx_msgs tx_error tx_upd_tot tx_upd_new tx_upd_initial tx_upd_newbutexist tx_upd_nothere tx_del_tot tx_del_nothere tx_exp_upd_tot tx_exp_del_tot  ");
-		seq_printf(seq, "rx_pkts_tot rx_pkts_ooseq rx_pkts_recover rx_msgs rx_error rx_upd_tot rx_upd_new rx_upd_initial rx_upd_newbutexist rx_upd_nothere rx_del_tot rx_del_nothere rx_exp_upd_tot rx_exp_del_tot  ");
-		seq_printf(seq, "slave2master master2slave master2slave_auto initsyncs\n");
+		seq_printf(seq, "tx_pkts_tot tx_pkts_ooseq tx_pkts_recover "
+			   "tx_msgs tx_error tx_upd_tot tx_upd_new "
+			   "tx_upd_initial tx_upd_newbutexist tx_upd_nothere " 
+			   "tx_del_tot tx_del_nothere tx_exp_upd_tot "
+			   "tx_exp_del_tot  ");
+		seq_printf(seq, "rx_pkts_tot rx_pkts_ooseq rx_pkts_recover "
+			   "rx_msgs rx_error rx_upd_tot rx_upd_new "
+			   "rx_upd_initial rx_upd_newbutexist rx_upd_nothere "
+			   "rx_del_tot rx_del_nothere rx_exp_upd_tot "
+			   "rx_exp_del_tot  ");
+		seq_printf(seq, "slave2master master2slave master2slave_auto "
+			   "initsyncs\n");
 		return 0;
 	}
 
@@ -1762,15 +1728,20 @@
  * MODULE INITIALIZATION
  ***********************************************************************/
 
+static int
+kill_all(const struct ip_conntrack *i, void *data)
+{
+	return 1;
+}
+
+static struct task_struct *rcv_thread, *send_thread, *initsync_thread;
+
 /* DO NOT declare this as __init!! */
-int init_or_cleanup(int fini)
+static int
+init_or_cleanup(int fini)
 {
-	int ret = -1;
-	pid_t pid;
-	struct ct_thread_startup startup;
-	DECLARE_WAITQUEUE(wait, current);
-	DECLARE_COMPLETION(ct_thread_comp);
-	struct net_device *sync_netdev;
+	int err, ret = -1;
+      	struct net_device *sync_netdev;
 	struct proc_dir_entry *ct_sync_stat;
 
 	if (fini)
@@ -1788,25 +1759,12 @@
 	CT_SYNC_DEBUG("ct_sync_msghdr: %d bytes\n", 
 			sizeof(struct ct_sync_msghdr));
 	CT_SYNC_DEBUG("cmarkbit: %d\n", cmarkbit);
-	if (id == -1) {
-		CT_SYNC_ERR("Required parameter id is missing.\n");
-		return -1;
-	}
+
 	if (strcmp(syncdev, "") == 0) {
 		CT_SYNC_ERR("Required parameter syncdev is missing.\n");
 		return -1;
 	}
-	if (state == -1) {
-		CT_SYNC_ERR("Required parameter state is missing; "
-			    " give 1 for master and 0 for slave.\n");
-		return -1;
-	}
-	if (state != 0 && state != 1) {
-		CT_SYNC_ERR("State has to be either 0 or 1\n");
-		return -1;
-	}
 
-	cts_cfg.nodeid = id;
 	strcpy(cts_cfg.devname, syncdev);
 	cts_cfg.addr.sin_family = AF_INET;
 	cts_cfg.addr.sin_port = __constant_htons(1999);
@@ -1824,8 +1782,8 @@
 	}
 
 	/* init protocol layer */
-	cts_cfg.protoh = cts_proto_init(cts_cfg.devname, &cts_cfg.addr, id,
-					state, &ct_sync_became_slave, NULL,
+	cts_cfg.protoh = cts_proto_init(cts_cfg.devname, &cts_cfg.addr,
+					&ct_sync_state_transition, NULL,
 					&ct_sync_send_wait, &ct_sync_rcv_wait);
 	if (!cts_cfg.protoh) {
 		CT_SYNC_ERR("Failed to initialize protocol.\n");
@@ -1859,9 +1817,11 @@
 		goto error_sysctl;
 	ct_sync_stat->proc_fops = &cts_stat_seq_fops;
 
+#if 0
+	/* FIXME: should use the unified state change functions */
 	if (state) {
 		/* master: register notify callbacks */
-		ret = ip_conntrack_notify_register(&ct_sync_notifier);
+		ret = ip_conntrack_register_notifier(&ct_sync_notifier);
 		if (ret < 0) {
 			CT_SYNC_ERR("unable to register notifier\n");
 			goto error_stat;
@@ -1880,102 +1840,59 @@
 
 		/* initsync request is handled by kernel thread */
 	}
+#endif
 
 	/* start threads */
-	startup.completion = &ct_thread_comp;
-	startup.function = ct_sync_send_thread_main;
-	if ((pid = kernel_thread(fork_ct_thread, &startup, 0)) < 0)
-	{
-		CT_SYNC_ERR("Failed to start fork thread.\n");
-		ret = pid;
-		if (state)
-			goto error_notify;
-		else
-			goto error_stat;
+	rcv_thread = kthread_run(ct_sync_rcv_thread_main, NULL,
+				 "ct_sync_rcv");
+	if (IS_ERR(rcv_thread)) {
+		ret = PTR_ERR(rcv_thread);
+		goto error_notify;
 	}
-	if ((ret = waitpid(pid, NULL, __WCLONE)) != pid)
-	{
-		CT_SYNC_ERR("Fork thread exit problem.\n");
-		if (state)
-			goto error_notify;
-		else
-			goto error_stat;
+
+	send_thread = kthread_run(ct_sync_send_thread_main, NULL,
+				  "ct_sync_send");
+	if (IS_ERR(send_thread)) {
+		ret = PTR_ERR(send_thread);
+		goto error_rthread;
 	}
-	wait_for_completion(&ct_thread_comp);
 
-	init_completion(&ct_thread_comp);
-	startup.completion = &ct_thread_comp;
-	startup.function = ct_sync_rcv_thread_main;
-	if ((pid = kernel_thread(fork_ct_thread, &startup, 0)) < 0)
-	{
-		CT_SYNC_ERR("Failed to start fork thread.\n");
-		ret = pid;
+	initsync_thread = kthread_run(ct_sync_initsync_thread_main, NULL,
+				      "ct_sync_initsync");
+	if (IS_ERR(initsync_thread)) {
+		ret = PTR_ERR(initsync_thread);
 		goto error_sthread;
 	}
-	if ((ret = waitpid(pid, NULL, __WCLONE)) != pid)
-	{
-		CT_SYNC_ERR("Fork thread exit problem.\n");
-		goto error_sthread;
-	}
-	wait_for_completion(&ct_thread_comp);
 
-	init_completion(&ct_thread_comp);
-	startup.completion = &ct_thread_comp;
-	startup.function = ct_sync_initsync_thread_main;
-	if ((pid = kernel_thread(fork_ct_thread, &startup, 0)) < 0)
-	{
-		CT_SYNC_ERR("Failed to start fork thread.\n");
-		ret = pid;
-		goto error_rthread;
-	}
-	if ((ret = waitpid(pid, NULL, __WCLONE)) != pid)
-	{
-		CT_SYNC_ERR("Fork thread exit problem.\n");
-		goto error_rthread;
-	}
-	wait_for_completion(&ct_thread_comp);
-
 	/* Now we have all of our infrastructure up and running */
+	printk(KERN_NOTICE "netfilter conntrack_sync version %s loaded\n",
+	       CT_SYNC_VERSION);
+	CT_SYNC_INFO("parameters: 'syncdev=%s l2drop=%u'\n",
+		     syncdev, l2drop);
 
-
-	printk(KERN_NOTICE "netfilter conntrack_sync Version %s loaded\n",
-		CT_SYNC_VERSION);
-	CT_SYNC_INFO("parameters: 'id=%u state=%u syncdev=%s l2drop=%u'\n",
-			id, state, syncdev, l2drop);
-
         return 0;
 
 cleanup:
-error_ithread:
 	CT_SYNC_DEBUG("stopping initsync thread\n");
-	__set_current_state(TASK_INTERRUPTIBLE);
-	wake_up(&ct_sync_initsync_wait);
-	atomic_set(&stop_ct_initsync_thread, 1);
-	add_wait_queue(&stop_ct_initsync_thread_wait, &wait);
-	schedule();
-	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(&stop_ct_initsync_thread_wait, &wait);
-error_rthread:
-	CT_SYNC_DEBUG("stopping receive thread\n");
-	__set_current_state(TASK_INTERRUPTIBLE);
-	atomic_set(&stop_ct_rcv_thread, 1);
-	add_wait_queue(&stop_ct_rcv_thread_wait, &wait);
-	wake_up(&ct_sync_rcv_wait);
-	schedule();
-	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(&stop_ct_rcv_thread_wait, &wait);
+	err = kthread_stop(initsync_thread);
+	if (err < 0) {
+		CT_SYNC_INFO("unable to stop initsync thread\n");
+	}
 error_sthread:
 	CT_SYNC_DEBUG("stopping send thread\n");
-	__set_current_state(TASK_INTERRUPTIBLE);
-	atomic_set(&stop_ct_send_thread, 1);
-	add_wait_queue(&stop_ct_send_thread_wait, &wait);
-	wake_up(&ct_sync_send_wait);
-	schedule();
-	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(&stop_ct_send_thread_wait, &wait);
+	err = kthread_stop(send_thread);
+	if (err < 0) {
+		CT_SYNC_INFO("unable to stop send thread\n");
+	}
+error_rthread:
+	CT_SYNC_DEBUG("stopping receive thread\n");
+	err = kthread_stop(rcv_thread);
+	if (err < 0) {
+		CT_SYNC_INFO("unable to stop receive thread\n");
+	}
 error_notify:
 	CT_SYNC_DEBUG("unregistering conntrack notifier\n");
-	ip_conntrack_notify_unregister(&ct_sync_notifier);
+	ip_conntrack_unregister_notifier(&ct_sync_notifier);
 error_stat:
 	remove_proc_entry("ct_sync_stat", proc_net_stat);
 error_sysctl:
@@ -2009,10 +1926,9 @@
 void __exit fini(void)
 {
 	init_or_cleanup(1);
-	printk(KERN_NOTICE "netfilter conntrack_sync Version %s unloaded\n",
+	printk(KERN_NOTICE "netfilter conntrack_sync version %s unloaded\n",
 		CT_SYNC_VERSION);
 }
 
 module_init(init);
 module_exit(fini);
-

Deleted: branches/netfilter-ha/linux-2.6/ct_sync/ct_sync_main.h
===================================================================
--- branches/netfilter-ha/linux-2.6/ct_sync/ct_sync_main.h	2005-01-02 22:40:48 UTC (rev 3550)
+++ branches/netfilter-ha/linux-2.6/ct_sync/ct_sync_main.h	2005-01-02 23:13:27 UTC (rev 3551)
@@ -1,6 +0,0 @@
-#ifndef _CT_SYNC_MAIN_H
-#define _CT_SYNC_MAIN_H
-
-extern atomic_t stop_ct_send_thread;
-
-#endif /* _CT_SYNC_MAIN_H */

Modified: branches/netfilter-ha/linux-2.6/ct_sync/ct_sync_proto.c
===================================================================
--- branches/netfilter-ha/linux-2.6/ct_sync/ct_sync_proto.c	2005-01-02 22:40:48 UTC (rev 3550)
+++ branches/netfilter-ha/linux-2.6/ct_sync/ct_sync_proto.c	2005-01-02 23:13:27 UTC (rev 3551)
@@ -1,7 +1,7 @@
 /*
  * Connection tracking state replication for Netfilter
  *
- * (C) 2002-2003, KOVACS Krisztian <hidden at sch.bme.hu>
+ * (C) 2002-2004, KOVACS Krisztian <hidden at sch.bme.hu>
  * (C) 2003-2004, Harald Welte <laforge at netfilter.org>
  * (C) 2004, BalaBit IT Ltd. <www.balabit.com>
  *
@@ -9,8 +9,6 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
- * $Id$
- *
  */
 
 #include <linux/config.h>
@@ -53,8 +51,6 @@
 				 -sizeof(struct ct_sync_pkthdr))
 #define CT_SYNC_SEND_BACKLOG	32
 
-#define CT_SYNC_MAX_MSG_AGE	(2 * HZ)
-
 struct cts_proto_sock {
 	struct csb_ring ring;
 	struct socket *socket;
@@ -62,12 +58,20 @@
 };
 
 struct cts_protoh {
+	/* tx and rx sockets */
 	struct cts_proto_sock send;
 	struct cts_proto_sock recv;
+	/* node state */
 	atomic_t state;
-	u8 nodeid;
-	void (*became_slave)(struct cts_protoh *, void *);
-	void *became_slave_arg;
+	/* callback function to call on state transitions */
+	void (*transition_callback)(struct cts_protoh *,
+				    enum cts_proto_state,
+				    enum cts_proto_state,
+				    void *);
+	void *transition_callback_data;
+	/* timestamp of last initsync request */
+	unsigned long last_initsync;
+	/* recovery state of the node */
 	struct {
 		atomic_t active;
 		__u16 seq;
@@ -75,19 +79,6 @@
 	} recovery_request;
 };
 
-/* node status */
-enum cts_proto_state
-{
-	CT_SYNC_PSTATE_NONE 	     = 0x00,	/* unknown, illegal */
-	CT_SYNC_PSTATE_SLAVE_INIT    = 0x01,	/* has just started */
-	CT_SYNC_PSTATE_SLAVE_SYNSENT = 0x02,	/* has requested initial sync */
-	CT_SYNC_PSTATE_SLAVE_SYNRECV = 0x03,	/* is receiving initial sync */
-	CT_SYNC_PSTATE_SLAVE_RUNNING = 0x04,	/* slave, fully synced */
-	CT_SYNC_PSTATE_MASTER_INIT   = 0x11,	/* master has just started */
-	CT_SYNC_PSTATE_MASTER_ADVSENT= 0x12,	/* master has announced */
-	CT_SYNC_PSTATE_MASTER_RUNNING= 0x14,	/* master, running */
-};
-
 static const char *cts_proto_statenames[0x15] = {
 	[CT_SYNC_PSTATE_NONE] 		= "NONE",
 	[CT_SYNC_PSTATE_SLAVE_INIT] 	= "SLAVE_INIT",
@@ -105,16 +96,52 @@
 	unsigned int oldstate = atomic_read(&cph->state);
 	atomic_set(&cph->state, state);
 	CT_SYNC_INFO("changed state: %s -> %s\n",
-			cts_proto_statenames[oldstate],
-			cts_proto_statenames[state]);
+		     cts_proto_statenames[oldstate],
+		     cts_proto_statenames[state]);
+	if (oldstate != state
+	    && cph->transition_callback != NULL)
+		cph->transition_callback(cph, oldstate, state,
+					 cph->transition_callback_data);
 }
 
-const char *cts_proto_get_state_name(struct cts_protoh *cph)
+int 
+cts_proto_is_master(struct cts_protoh *cph)
 {
-	return cts_proto_statenames[atomic_read(&cph->state)];
+	return (atomic_read(&cph->state) >= CT_SYNC_PSTATE_MASTER_INIT);
 }
 
+int
+cts_proto_get_state(struct cts_protoh *cph)
+{
+	return atomic_read(&cph->state);
+}
+
 /***********************************************************************
+ * SYSCTL functions
+ ***********************************************************************/
+
+/* upper limit is one minute */
+#define MSG_AGE_LIMIT 60000
+static unsigned long max_msg_age = 2 * HZ;
+
+unsigned int
+cts_proto_get_max_age(void)
+{
+	return jiffies_to_msecs(max_msg_age);
+}
+
+int
+cts_proto_set_max_age(unsigned int msecs)
+{
+	if (msecs > MSG_AGE_LIMIT)
+		return -EINVAL;
+
+	max_msg_age = msecs_to_jiffies(msecs);
+
+	return 0;
+}
+
+/***********************************************************************
  * CTS_BUFF / CSB_RING util functions
  ***********************************************************************/
 static inline void
@@ -124,7 +151,6 @@
 	hdr->version = 2;
 	hdr->pkttype = type;
 	hdr->pktseq = htons(seq);
-	hdr->node_id = cph->nodeid;
 	hdr->count = 0;
 }
 
@@ -288,8 +314,9 @@
  * after advancing to the next buffer, while the receiver code handles the seqno
  * of the ring specially (it is the sequence number of the last successfully
  * received packet). */
-static struct cts_buff * __csb_ring_advance_alloc(struct cts_protoh *cph,
-						  struct csb_ring *csr)
+static struct cts_buff *
+__csb_ring_advance_alloc(struct cts_protoh *cph,
+			 struct csb_ring *csr)
 { 
 	struct cts_buff *csb;
 
@@ -330,13 +357,6 @@
  * CONTROL MESSAGES
  ***********************************************************************/
 
-int 
-cts_proto_is_master(struct cts_protoh *cph)
-{
-	return (atomic_read(&cph->state) >= CT_SYNC_PSTATE_MASTER_INIT);
-}
-
-
 /* we have just been told to become master; tell other nodes */
 int
 cts_proto_master_announce(struct cts_protoh *cph)
@@ -352,6 +372,7 @@
 	CT_SYNC_DEBUG("sending master_announce with seqno=%u\n",
 		      cph->send.ring.seqno);
 
+	memset(&pkt, 0, sizeof(pkt));
 	csb_hdr_fill(cph, &pkt.hdr, CT_SYNC_PKT_MASTER_ANNOUNCE, 
 		     cph->send.ring.seqno);
 
@@ -396,6 +417,19 @@
 	return 0;
 }
 
+/* externally triggered: we become slave */
+int
+cts_proto_become_slave(struct cts_protoh *cph)
+{
+	CT_SYNC_ENTER();
+
+	set_state(cph, CT_SYNC_PSTATE_SLAVE_INIT);
+
+	CT_SYNC_LEAVE();
+
+	return 0;
+}
+
 /* externally triggered: we're signalling a full re-sync */
 int
 cts_proto_initsync_follows(struct cts_protoh *cph)
@@ -407,6 +441,7 @@
 
 	CT_SYNC_ENTER();
 
+	memset(&pkt, 0, sizeof(pkt));
 	csb_hdr_fill(cph, &pkt.hdr, CT_SYNC_PKT_INITSYNC_FOLLOWS, 0);
 
 	len = cts_sock_send(cph->send.socket, (unsigned char *)&pkt, sizeof(pkt));
@@ -421,8 +456,9 @@
 	return 0;
 }
 
-int
-cts_proto_request_initsync(struct cts_protoh *cph)
+/* send an initsync request */
+static int
+cts_proto_send_initsync_request(struct cts_protoh *cph)
 {
 	size_t len;
 	struct {
@@ -432,18 +468,12 @@
 
 	CT_SYNC_ENTER();
 
-	if (atomic_read(&cph->state) != CT_SYNC_PSTATE_SLAVE_INIT) {
-		CT_SYNC_DEBUG("not sending initsync request from wrong state\n");
-		CT_SYNC_LEAVE();
-		return 0;
-	}
-	
 	CTS_STAT_INC(initsyncs);
 
 	CT_SYNC_DEBUG("sending INITSYNC request\n");
 
+	memset(&pkt, 0, sizeof(pkt));
 	csb_hdr_fill(cph, &pkt.hdr, CT_SYNC_PKT_SLAVE_INITSYNC, 0);
-	pkt.is.master = 0;
 
 	len = cts_sock_send(cph->send.socket, (unsigned char*)&pkt, sizeof(pkt));
 	if (unlikely(len < sizeof(pkt))) {
@@ -458,41 +488,25 @@
 	return 0;
 }
 
+/* externally triggered: transmit an initsync request if necessary:
+ *   - we're in state CT_SYNC_PSTATE_SLAVE_INIT 
+ *   - we're in state CT_SYNC_PSTATE_SLAVE_SYNSENT but at least five seconds
+ *      have elapsed since the last request
+ */
 int
-cts_proto_initsync_retransmit(struct cts_protoh *cph)
+cts_proto_initsync_request(struct cts_protoh *cph)
 {
-	static unsigned long last_initsync;
+	if ((atomic_read(&cph->state) == CT_SYNC_PSTATE_SLAVE_INIT)
+	    || (atomic_read(&cph->state) == CT_SYNC_PSTATE_SLAVE_SYNSENT
+		&& jiffies >= cph->last_initsync + 5 * HZ)) {
+		cts_proto_send_initsync_request(cph);
+		cph->last_initsync = jiffies;
+		set_state(cph, CT_SYNC_PSTATE_SLAVE_SYNSENT);
+	}
 
-	if (atomic_read(&cph->state) == CT_SYNC_PSTATE_NONE)
-		atomic_set(&cph->state, CT_SYNC_PSTATE_SLAVE_INIT);
-
-	/* if we are waiting for a reply to an initial sync,
-	 * retransmit request */
-	if (atomic_read(&cph->state) == CT_SYNC_PSTATE_SLAVE_INIT
-	    && jiffies >= last_initsync + 5*HZ) {
-		cts_proto_request_initsync(cph);
-		last_initsync = jiffies;
-	}
 	return 0;
 }
 
-/* protocol has detected another master.  we have to tell our user
- * that we just became slave */
-static void
-cts_proto_become_slave(struct cts_protoh *cph)
-{
-	CT_SYNC_ENTER();
-
-	CTS_STAT_INC(master2slave_auto);
-
-	set_state(cph, CT_SYNC_PSTATE_SLAVE_RUNNING);
-	if (likely(cph->became_slave != NULL))
-		cph->became_slave(cph, cph->became_slave_arg);
-
-	CT_SYNC_LEAVE();
-}
-
-
 /***********************************************************************
  * SENDER
  ***********************************************************************/
@@ -528,7 +542,8 @@
 }
 
 /* decrement usage count and advance csb->cur if we hit zero */
-void csb_use_dec(struct cts_protoh *cph, struct cts_buff *csb)
+void
+csb_use_dec(struct cts_protoh *cph, struct cts_buff *csb)
 {
 	CT_SYNC_ENTER();
 	DUMP_CTS_BUFF(csb);
@@ -577,7 +592,7 @@
 	 */
 	if (!csb_used(tmp)
 	    && (tmp != (struct cts_buff *)csr->cur)
-	    && tmp->firstuse && (jiffies - tmp->firstuse > CT_SYNC_MAX_MSG_AGE)) {
+	    && tmp->firstuse && (jiffies - tmp->firstuse > max_msg_age)) {
 		tmp = __csb_ring_advance_alloc(cph, csr);
 		if (unlikely(tmp == NULL)) {
 			spin_unlock_bh(&csr->lock);
@@ -600,7 +615,6 @@
 
 	return 0;
 }
-	
 
 /* caller wants to enqueue `size' bytes. we have to return pointer to csb that
  * is capable of that many bytes */
@@ -628,7 +642,7 @@
 	 *   3. not enough space, need to advance/allocate new csb
 	 */
 	if (tmp == (struct cts_buff *)csr->cur
-	    || (tmp->firstuse && (jiffies - tmp->firstuse >= CT_SYNC_MAX_MSG_AGE))
+	    || (tmp->firstuse && (jiffies - tmp->firstuse >= max_msg_age))
 	    || !(retbuf = csb_put(tmp, size))) {
 		tmp = __csb_ring_advance_alloc(cph, csr);
 		if (unlikely(!tmp)) {
@@ -643,7 +657,7 @@
 	CT_SYNC_ASSERT(retbuf);
 
 	csb_use_inc(tmp);
-	
+
 	CT_SYNC_DEBUG2("using buffer %p: ", tmp);
 	DUMP_CTS_BUFF(tmp);
 
@@ -847,7 +861,6 @@
 	return 0;
 }
 
-
 /***********************************************************************
  * RECEIVER
  ***********************************************************************/
@@ -863,7 +876,8 @@
 	cph->recovery_request.diff = 0;
 }
 
-#define CTS_RECOVERY_THRESHOLD 8
+unsigned int cts_proto_recovery_threshold = 8;
+
 /*
  * request recovery, last seen packet is seq
  */
@@ -877,18 +891,19 @@
 
 	/* check if we already have a pending request */
 	if (atomic_read(&cph->recovery_request.active)) {
-		/* if there are at least CTS_RECOVERY_THRESHOLD lost messages
+		/* if there are at least recovery_threshold lost messages
 		 * since the last request, repeat; return immediately otherwise */
-		if (diff < cph->recovery_request.diff + CTS_RECOVERY_THRESHOLD) {
+		if (diff < cph->recovery_request.diff + cts_proto_recovery_threshold) {
 			CT_SYNC_LEAVE();
 			return 0;
 		}
 	}
 
+	atomic_set(&cph->recovery_request.active, 1);
 	cph->recovery_request.seq = seq;
 	cph->recovery_request.diff = diff;
-	atomic_set(&cph->recovery_request.active, 1);
 
+	memset(&hdr, 0, sizeof(hdr));
 	csb_hdr_fill(cph, &hdr, CT_SYNC_PKT_NACK, seq);
 
 	len = cts_sock_send(cph->send.socket, (char *)&hdr, 
@@ -942,7 +957,6 @@
 	return ret;
 }
 
-
 /* Receive packet, process packet header info. That is:
  *  - For invalid packets, discard the packet.
  *    Return value: CTS_PROTO_RCV_DISCARDED
@@ -971,7 +985,7 @@
 
 	CT_SYNC_ENTER();
 
-	/* FIXME: do we need spinlock here? Only called from kthread,
+	/* FIXME: do we need a spinlock here? Only called from kthread,
 	 * which is serialized. Seems that the receive ring is accessed
 	 * only from the receiver thread, so locking shouldn't be a problem.
 	 */
@@ -1019,7 +1033,6 @@
 			/* do we really want to accept sync pkts before we
 			 * requested them? For now, fallthrough */
 		case CT_SYNC_PSTATE_SLAVE_SYNSENT:
-			break;
 			/* set initial seqno */
 			csr->seqno = ntohs(csb->pkt.hdr.pktseq) - 1;
 			printk(KERN_DEBUG "setting initial seqno to %u\n",
@@ -1074,8 +1087,7 @@
 			goto done_ignore;
 		}
 		recover_seq = ntohs(csb->pkt.hdr.pktseq);
-		CT_SYNC_DEBUG("node %u requested recovery of seq %u\n",
-				csb->pkt.hdr.node_id, recover_seq);
+		CT_SYNC_DEBUG("requested recovery of seq %u\n", recover_seq);
 		/* need to go back one in order to overwrite this one */
 		csr->alloc = csr->alloc->prev;
 		/* free spinlock early to avoid deadlock with send lock */
@@ -1094,7 +1106,8 @@
 		case CT_SYNC_PSTATE_MASTER_ADVSENT:
 		case CT_SYNC_PSTATE_MASTER_RUNNING:
 			CT_SYNC_INFO("new master, degrading to client\n");
-			cts_proto_become_slave(cph);
+			CTS_STAT_INC(master2slave_auto);
+			set_state(cph, CT_SYNC_PSTATE_SLAVE_SYNSENT);
 			/* fall thru */
 		default:
 			/* we have a new master, we have to update our receiver's
@@ -1131,7 +1144,6 @@
 		break;
 
 	case CT_SYNC_PKT_INITSYNC_FOLLOWS:
-#if 0
 		switch (atomic_read(&cph->state)) {
 		case CT_SYNC_PSTATE_MASTER_INIT:
 		case CT_SYNC_PSTATE_MASTER_ADVSENT:
@@ -1146,10 +1158,9 @@
 		case CT_SYNC_PSTATE_SLAVE_RUNNING:
 			CT_SYNC_DEBUG("received initsync announcement while being slave, reinit\n");
 			cts_proto_recovery_init(cph);
-			set_state(cph, CT_SYNC_PSTATE_SLAVE_INIT);
+			set_state(cph, CT_SYNC_PSTATE_SLAVE_SYNSENT);
 			break;
 		}
-#endif
 		goto done_ignore;
 		break;
 
@@ -1179,17 +1190,9 @@
 int
 cts_proto_recv_pending(struct cts_protoh *cph)
 {
-	return (!skb_queue_empty(&cph->recv.socket->sk->receive_queue));
+	return (!skb_queue_empty(&cph->recv.socket->sk->sk_receive_queue));
 }
 
-/* Set receiver to running state if it's in SYNRECV state. */
-void
-cts_proto_recv_running(struct cts_protoh *cph)
-{
-	if (atomic_read(&cph->state) == CT_SYNC_PSTATE_SLAVE_SYNRECV)
-		set_state(cph, CT_SYNC_PSTATE_SLAVE_RUNNING);
-}
-
 /* get a pointer to the next to-be-processed message */
 struct ct_sync_msghdr *
 cts_proto_recvmsg(struct cts_protoh *cph, struct ct_sync_pkthdr **hdr)
@@ -1263,11 +1266,18 @@
 	csr_print(csr);
 	//spin_unlock(&csr->lock);
 
+	/* upon receiving a message with the INITSYNC flag set, we
+	 * transition from SLAVE_INIT to SLAVE_SYNRECV */
 	if (unlikely(msghdr->type == CT_SYNC_MSG_UPDATE
 	             && msghdr->flags & CTS_UPD_F_INITSYNC
 		     && atomic_read(&cph->state) == CT_SYNC_PSTATE_SLAVE_INIT))
 		set_state(cph, CT_SYNC_PSTATE_SLAVE_SYNRECV);
 
+	if (unlikely(msghdr->type == CT_SYNC_MSG_UPDATE
+		     && msghdr->flags & CTS_UPD_F_INITSYNC_DONE
+		     && atomic_read(&cph->state) == CT_SYNC_PSTATE_SLAVE_SYNRECV))
+		set_state(cph, CT_SYNC_PSTATE_SLAVE_RUNNING);
+
 	CT_SYNC_LEAVE();
 
 	return msghdr;
@@ -1275,31 +1285,31 @@
 
 /* data ready callback: wake up rcv thread */
 static void
-cts_data_ready(struct sock *sk, int count)
+cts_proto_data_ready(struct sock *sk, int count)
 {
 	struct cts_protoh *cph;
 
 	CT_SYNC_ENTER();
 
-	cph = (struct cts_protoh *)sk->user_data;
+	cph = (struct cts_protoh *)sk->sk_user_data;
 	if (cph && cph->recv.wait && waitqueue_active(cph->recv.wait))
 		wake_up_interruptible(cph->recv.wait);
 
-	if (sk->sleep && waitqueue_active(sk->sleep))
-		wake_up_interruptible(sk->sleep);
+	if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
+		wake_up_interruptible(sk->sk_sleep);
 
 	CT_SYNC_LEAVE();
 }
 
-
 /* initialize protocol */
 struct cts_protoh *
 cts_proto_init(char *devname, 
 	       const struct sockaddr_in *addr, 
-	       u8 nodeid, 
-	       int master,
-	       void (*became_slave)(struct cts_protoh*, void*),
-	       void *became_slave_arg,
+	       void (*transition_callback)(struct cts_protoh*,
+					   enum cts_proto_state,
+					   enum cts_proto_state,
+					   void*),
+	       void *transition_callback_data,
 	       wait_queue_head_t *send_wait,
 	       wait_queue_head_t *rcv_wait)
 {
@@ -1315,11 +1325,12 @@
 		goto error;
 	}
 
+	memset(cph, 0, sizeof(*cph));
+
 	/* don't call set_state since cph->state is not initialized yet */
 	atomic_set(&cph->state, CT_SYNC_PSTATE_NONE);
-	cph->nodeid = nodeid;
-	cph->became_slave = became_slave;
-	cph->became_slave_arg = became_slave_arg;
+	cph->transition_callback = transition_callback;
+	cph->transition_callback_data = transition_callback_data;
 
 	/* init recovery structure */
 	cts_proto_recovery_init(cph);
@@ -1356,10 +1367,11 @@
 		CT_SYNC_ERR("Failed to create rcv socket.\n");
 		goto error_ssock;
 	}
-	/* setup data_ready callback of receive socket */
-	cph->recv.socket->sk->user_data = cph;
-	cph->recv.socket->sk->data_ready = cts_data_ready;
 
+	/* setup sk_data_ready callback of receive socket */
+	cph->recv.socket->sk->sk_user_data = cph;
+	cph->recv.socket->sk->sk_data_ready = cts_proto_data_ready;
+
 	if (ret < 0)
 		goto error_rsock;
 
@@ -1396,4 +1408,3 @@
 
 	CT_SYNC_LEAVE();
 }
-

Modified: branches/netfilter-ha/linux-2.6/ct_sync/ct_sync_proto.h
===================================================================
--- branches/netfilter-ha/linux-2.6/ct_sync/ct_sync_proto.h	2005-01-02 22:40:48 UTC (rev 3550)
+++ branches/netfilter-ha/linux-2.6/ct_sync/ct_sync_proto.h	2005-01-02 23:13:27 UTC (rev 3551)
@@ -1,17 +1,36 @@
 #ifndef _CT_SYNC_PROTO_H
 #define _CT_SYNC_PROTO_H
 
+#include <linux/in.h>
+
 /* no need for a public declaration of cts_buff structure */
 struct cts_buff;
 struct cts_protoh;
 
-/* protocol intialization functions */
+/* protocol state machine */
+/* node status */
+enum cts_proto_state
+{
+	CT_SYNC_PSTATE_NONE 	     = 0x00,	/* unknown, illegal */
+	CT_SYNC_PSTATE_SLAVE_INIT    = 0x01,	/* has just started */
+	CT_SYNC_PSTATE_SLAVE_SYNSENT = 0x02,	/* has requested initial sync */
+	CT_SYNC_PSTATE_SLAVE_SYNRECV = 0x03,	/* is receiving initial sync */
+	CT_SYNC_PSTATE_SLAVE_RUNNING = 0x04,	/* slave, fully synced */
+	CT_SYNC_PSTATE_MASTER_INIT   = 0x11,	/* master has just started */
+	CT_SYNC_PSTATE_MASTER_ADVSENT= 0x12,	/* master has announced */
+	CT_SYNC_PSTATE_MASTER_RUNNING= 0x14,	/* master, running */
+};
+
+/* GENERAL PROTOCOL LAYER FUNCTIONS */
+
+/* protocol intialization function */
 struct cts_protoh *cts_proto_init(char *devname, 
 				  const struct sockaddr_in *addr, 
-				  u8 nodeid, int master,
-				  void (*became_slave)(struct cts_protoh*,
-					  		void *),
-				  void *became_slave_arg,
+				  void (*transition_callback)(struct cts_protoh*,
+							      enum cts_proto_state oldstate,
+							      enum cts_proto_state newstate,
+							      void *),
+				  void *transition_callback_data,
 				  wait_queue_head_t *send_wait,
 				  wait_queue_head_t *rcv_wait);
 
@@ -21,18 +40,30 @@
 /* is protocol state currently 'master' ? */
 int cts_proto_is_master(struct cts_protoh *cph);
 
+/* return protocol state */
+int cts_proto_get_state(struct cts_protoh *cph);
+
 /* tell protocol to make local node master */
 int cts_proto_become_master(struct cts_protoh *cph);
 
+/* tell protocol to make local node slave (only from NONE!) */
+int cts_proto_become_slave(struct cts_protoh *cph);
+
+/* send a master announcement */
 int cts_proto_master_announce(struct cts_protoh *cph);
 
 /* signal that an initsync is to follow */
 int cts_proto_initsync_follows(struct cts_protoh *cph);
 
-/* request initial re-sync from master */
-int cts_proto_request_initsync(struct cts_protoh *cph);
-int cts_proto_initsync_retransmit(struct cts_protoh *cph);
+/* request initial re-sync from master if necessary */
+int cts_proto_initsync_request(struct cts_protoh *cph);
 
+/* PARAMETERS */
+unsigned int cts_proto_get_max_age(void);
+int cts_proto_set_max_age(unsigned int msecs);
+
+extern unsigned int cts_proto_recovery_threshold;
+
 /* SENDER */
 
 /* advance current buffer of send ring if it's old enough,
@@ -49,8 +80,6 @@
 /* dequeue a to-be-send cts_buff, otherwise put current task to sleep */
 int cts_proto_send_dequeue(struct cts_protoh *cph);
 
-
-
 /* RECEIVER */
 
 /* possible return values of cts_proto_rcv_pkt() */
@@ -61,13 +90,12 @@
 #define CTS_PROTO_RCV_MASTERANN		3
 #define CTS_PROTO_RCV_INITSYNC		4
 
-/* check if we have pending packets in the receive buffer */
+/* check if we have pending packets in the receive queue of the rcv socket */
 int cts_proto_recv_pending(struct cts_protoh *cph);
+
 /* receive a packet, and enqueue it in the ring buffer if needed */
 int cts_proto_recv_pkt(struct cts_protoh *cph);
 
-void cts_proto_recv_running(struct cts_protoh *cph);
-
 /* get next message out of packet receiver queue */
 struct ct_sync_msghdr *cts_proto_recvmsg(struct cts_protoh *cph, struct ct_sync_pkthdr **hdr);
 

Modified: branches/netfilter-ha/linux-2.6/ct_sync/ct_sync_sock.c
===================================================================
--- branches/netfilter-ha/linux-2.6/ct_sync/ct_sync_sock.c	2005-01-02 22:40:48 UTC (rev 3550)
+++ branches/netfilter-ha/linux-2.6/ct_sync/ct_sync_sock.c	2005-01-02 23:13:27 UTC (rev 3551)
@@ -1,7 +1,7 @@
 /*
  * Connection tracking state replication for Netfilter
  *
- * (C) 2002-2003, KOVACS Krisztian <hidden at sch.bme.hu>
+ * (C) 2002-2004, KOVACS Krisztian <hidden at sch.bme.hu>
  * (C) 2003-2004, Harald Welte <laforge at netfilter.org>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -11,8 +11,6 @@
  * Based on previous work from the LVS project
  * (C) Wensong Zwang <wensong at linuxvirtualserver.org>
  *
- * $Id$
- *
  */
 
 #define __KERNEL_SYSCALLS__
@@ -35,6 +33,7 @@
 #include <linux/rtnetlink.h>
 #include <linux/inetdevice.h>
 #include <linux/igmp.h>
+#include <linux/ip.h>
 
 #include <asm/uaccess.h>
 
@@ -48,7 +47,7 @@
 {
         /* setsockopt(sock, SOL_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)); */
         lock_sock(sk);
-        sk->protinfo.af_inet.mc_loop = loop ? 1 : 0;
+        inet_sk(sk)->mc_loop = loop ? 1 : 0;
         release_sock(sk);
 }
 
@@ -60,7 +59,7 @@
 {
         /* setsockopt(sock, SOL_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)); */
         lock_sock(sk);
-        sk->protinfo.af_inet.mc_ttl = ttl;
+        inet_sk(sk)->mc_ttl = ttl;
         release_sock(sk);
 }
 
@@ -73,12 +72,12 @@
         if ((dev = __dev_get_by_name(ifname)) == NULL)
                 return -ENODEV;
 
-        if (sk->bound_dev_if && dev->ifindex != sk->bound_dev_if)
+        if (sk->sk_bound_dev_if && dev->ifindex != sk->sk_bound_dev_if)
                 return -EINVAL;
 
         lock_sock(sk);
-        sk->protinfo.af_inet.mc_index = dev->ifindex;
-        /*  sk->protinfo.af_inet.mc_addr  = 0; */
+        inet_sk(sk)->mc_index = dev->ifindex;
+        /*  inet_sk(sk)->mc_addr  = 0; */
         release_sock(sk);
 
         return 0;
@@ -127,7 +126,7 @@
 
         if ((dev = __dev_get_by_name(ifname)) == NULL)
                 return -ENODEV;
-        if (sk->bound_dev_if && dev->ifindex != sk->bound_dev_if)
+        if (sk->sk_bound_dev_if && dev->ifindex != sk->sk_bound_dev_if)
                 return -EINVAL;
 
         mreq.imr_ifindex = dev->ifindex;
@@ -185,7 +184,7 @@
 		return NULL;
 	}
 
-	sock->sk->reuse = 1;
+	sock->sk->sk_reuse = 1;
 
 	if (sock->ops->bind(sock, (struct sockaddr *)addr, sizeof(struct sockaddr)) < 0) {
 		CT_SYNC_ERR("Error binding to the multicast addr.\n");

Modified: branches/netfilter-ha/linux-2.6/patches/connmark.patch
===================================================================
--- branches/netfilter-ha/linux-2.6/patches/connmark.patch	2005-01-02 22:40:48 UTC (rev 3550)
+++ branches/netfilter-ha/linux-2.6/patches/connmark.patch	2005-01-02 23:13:27 UTC (rev 3551)
@@ -1,10 +1,22 @@
-Netfilter CONNMARK patch
-
-%patch
-Index: linux-2.4.26-ct_sync/include/linux/netfilter_ipv4/ipt_CONNMARK.h
+Index: linux-2.6.9/include/linux/netfilter_ipv4/ip_conntrack.h
 ===================================================================
---- linux-2.4.26-ct_sync.orig/include/linux/netfilter_ipv4/ipt_CONNMARK.h	2004-06-16 09:19:51.000000000 +0200
-+++ linux-2.4.26-ct_sync/include/linux/netfilter_ipv4/ipt_CONNMARK.h	2004-06-28 12:58:18.000000000 +0200
+--- linux-2.6.9.orig/include/linux/netfilter_ipv4/ip_conntrack.h	2004-11-27 00:29:34.768960072 +0100
++++ linux-2.6.9/include/linux/netfilter_ipv4/ip_conntrack.h	2004-11-27 00:44:47.467208848 +0100
+@@ -264,6 +264,10 @@
+ 	} nat;
+ #endif /* CONFIG_IP_NF_NAT_NEEDED */
+ 
++#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
++	unsigned long mark;
++#endif
++
+ 	/* Traversed often, so hopefully in different cacheline to top */
+ 	/* These are my tuples; original and reply */
+ 	struct ip_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX];
+Index: linux-2.6.9/include/linux/netfilter_ipv4/ipt_CONNMARK.h
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.9/include/linux/netfilter_ipv4/ipt_CONNMARK.h	2004-11-27 00:44:47.469208544 +0100
 @@ -0,0 +1,25 @@
 +#ifndef _IPT_CONNMARK_H_target
 +#define _IPT_CONNMARK_H_target
@@ -31,10 +43,10 @@
 +};
 +
 +#endif /*_IPT_CONNMARK_H_target*/
-Index: linux-2.4.26-ct_sync/include/linux/netfilter_ipv4/ipt_connmark.h
+Index: linux-2.6.9/include/linux/netfilter_ipv4/ipt_connmark.h
 ===================================================================
---- linux-2.4.26-ct_sync.orig/include/linux/netfilter_ipv4/ipt_connmark.h	2004-06-16 09:19:51.000000000 +0200
-+++ linux-2.4.26-ct_sync/include/linux/netfilter_ipv4/ipt_connmark.h	2004-06-28 12:58:18.000000000 +0200
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.9/include/linux/netfilter_ipv4/ipt_connmark.h	2004-11-27 00:44:47.470208392 +0100
 @@ -0,0 +1,18 @@
 +#ifndef _IPT_CONNMARK_H
 +#define _IPT_CONNMARK_H
@@ -54,25 +66,116 @@
 +};
 +
 +#endif /*_IPT_CONNMARK_H*/
-Index: linux-2.4.26-ct_sync/include/linux/netfilter_ipv4/ip_conntrack.h
+Index: linux-2.6.9/net/ipv4/netfilter/Kconfig
 ===================================================================
---- linux-2.4.26-ct_sync.orig/include/linux/netfilter_ipv4/ip_conntrack.h	2004-06-14 14:52:11.000000000 +0200
-+++ linux-2.4.26-ct_sync/include/linux/netfilter_ipv4/ip_conntrack.h	2004-06-28 12:58:18.000000000 +0200
-@@ -207,6 +207,10 @@
- 	} nat;
- #endif /* CONFIG_IP_NF_NAT_NEEDED */
+--- linux-2.6.9.orig/net/ipv4/netfilter/Kconfig	2004-11-27 00:29:34.775959008 +0100
++++ linux-2.6.9/net/ipv4/netfilter/Kconfig	2004-11-27 00:44:47.475207632 +0100
+@@ -32,6 +32,14 @@
  
+ 	  If unsure, say `N'.
+ 
++config IP_NF_CONNTRACK_MARK
++	bool  'Connection mark tracking support'
++	help
++	  This option enables support for connection marks, used by the
++	  `CONNMARK' target and `connmark' match. Similar to the mark value
++	  of packets, but this mark value is kept in the conntrack session
++	  instead of the individual packets.
++	
+ config IP_NF_CT_PROTO_SCTP
+ 	tristate  'SCTP protocol connection tracking support (EXPERIMENTAL)'
+ 	depends on IP_NF_CONNTRACK && EXPERIMENTAL
+@@ -342,6 +350,17 @@
+ 	  If you want to compile it as a module, say M here and read
+ 	  Documentation/modules.txt.  If unsure, say `N'.
+ 
++config IP_NF_MATCH_CONNMARK
++	tristate  'Connection mark match support'
++	depends on IP_NF_CONNTRACK_MARK && IP_NF_IPTABLES
++	help
++	  This option adds a `connmark' match, which allows you to match the
++	  connection mark value previously set for the session by `CONNMARK'. 
++	
++	  If you want to compile it as a module, say M here and read
++	  Documentation/modules.txt.  The module will be called
++	  ipt_connmark.o.  If unsure, say `N'.
++
+ # `filter', generic and specific targets
+ config IP_NF_FILTER
+ 	tristate "Packet filtering"
+@@ -597,6 +616,18 @@
+ 
+ 	  To compile it as a module, choose M here.  If unsure, say N.
+ 
++config IP_NF_TARGET_CONNMARK
++	tristate  'CONNMARK target support'
++	depends on IP_NF_CONNTRACK_MARK && IP_NF_MANGLE
++	help
++	  This option adds a `CONNMARK' target, which allows one to manipulate
++	  the connection mark value.  Similar to the MARK target, but
++	  affects the connection mark value rather than the packet mark value.
++	
++	  If you want to compile it as a module, say M here and read
++	  Documentation/modules.txt.  The module will be called
++	  ipt_CONNMARK.o.  If unsure, say `N'.
++
+ # raw + specific targets
+ config IP_NF_RAW
+ 	tristate  'raw table support (required for NOTRACK/TRACE)'
+Index: linux-2.6.9/net/ipv4/netfilter/Makefile
+===================================================================
+--- linux-2.6.9.orig/net/ipv4/netfilter/Makefile	2004-11-27 00:25:43.826068728 +0100
++++ linux-2.6.9/net/ipv4/netfilter/Makefile	2004-11-27 00:44:47.476207480 +0100
+@@ -61,6 +61,7 @@
+ obj-$(CONFIG_IP_NF_MATCH_LENGTH) += ipt_length.o
+ obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
+ obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o
++obj-$(CONFIG_IP_NF_MATCH_CONNMARK) += ipt_connmark.o
+ obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o
+ obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o
+ obj-$(CONFIG_IP_NF_MATCH_REALM) += ipt_realm.o
+@@ -81,6 +82,7 @@
+ obj-$(CONFIG_IP_NF_TARGET_CLASSIFY) += ipt_CLASSIFY.o
+ obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o
+ obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
++obj-$(CONFIG_IP_NF_TARGET_CONNMARK) += ipt_CONNMARK.o
+ obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
+ obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o
+ obj-$(CONFIG_IP_NF_TARGET_NOTRACK) += ipt_NOTRACK.o
+Index: linux-2.6.9/net/ipv4/netfilter/ip_conntrack_core.c
+===================================================================
+--- linux-2.6.9.orig/net/ipv4/netfilter/ip_conntrack_core.c	2004-11-27 00:30:59.285111664 +0100
++++ linux-2.6.9/net/ipv4/netfilter/ip_conntrack_core.c	2004-11-27 00:44:47.481206720 +0100
+@@ -611,6 +611,9 @@
+ 		__set_bit(IPS_EXPECTED_BIT, &conntrack->status);
+ 		conntrack->master = expected;
+ 		expected->sibling = conntrack;
++#if CONFIG_IP_NF_CONNTRACK_MARK
++		conntrack->mark = expected->expectant->mark;
++#endif
+ 		LIST_DELETE(&ip_conntrack_expect_list, expected);
+ 		expected->expectant->expecting--;
+ 		nf_conntrack_get(&master_ct(conntrack)->ct_general);
+Index: linux-2.6.9/net/ipv4/netfilter/ip_conntrack_standalone.c
+===================================================================
+--- linux-2.6.9.orig/net/ipv4/netfilter/ip_conntrack_standalone.c	2004-11-27 00:29:34.796955816 +0100
++++ linux-2.6.9/net/ipv4/netfilter/ip_conntrack_standalone.c	2004-11-27 00:44:47.485206112 +0100
+@@ -146,6 +146,11 @@
+ 		if (seq_printf(s, "[ASSURED] "))
+ 			return 1;
+ 
 +#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
-+	unsigned long mark;
++	if (seq_printf(s, "mark=%ld ", conntrack->mark))
++		return 1;
 +#endif
 +
- };
+ 	if (seq_printf(s, "use=%u\n", atomic_read(&conntrack->ct_general.use)))
+ 		return 1;
  
- /* get master conntrack via master expectation */
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/ipt_CONNMARK.c
+Index: linux-2.6.9/net/ipv4/netfilter/ipt_CONNMARK.c
 ===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/ipt_CONNMARK.c	2004-06-16 09:19:51.000000000 +0200
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/ipt_CONNMARK.c	2004-06-28 12:58:18.000000000 +0200
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.9/net/ipv4/netfilter/ipt_CONNMARK.c	2004-11-27 00:44:47.487205808 +0100
 @@ -0,0 +1,118 @@
 +/* This kernel module is used to modify the connection mark values, or
 + * to optionally restore the skb nfmark from the connection mark
@@ -109,9 +212,9 @@
 +
 +static unsigned int
 +target(struct sk_buff **pskb,
-+       unsigned int hooknum,
 +       const struct net_device *in,
 +       const struct net_device *out,
++       unsigned int hooknum,
 +       const void *targinfo,
 +       void *userinfo)
 +{
@@ -192,77 +295,11 @@
 +
 +module_init(init);
 +module_exit(fini);
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_standalone.c
+Index: linux-2.6.9/net/ipv4/netfilter/ipt_connmark.c
 ===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/ip_conntrack_standalone.c	2004-06-14 14:52:11.000000000 +0200
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_standalone.c	2004-06-28 12:58:18.000000000 +0200
-@@ -107,6 +107,9 @@
- 		len += sprintf(buffer + len, "[ASSURED] ");
- 	len += sprintf(buffer + len, "use=%u ",
- 		       atomic_read(&conntrack->ct_general.use));
-+#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
-+	len += sprintf(buffer + len, "mark=%ld ", conntrack->mark);
-+#endif
- 	len += sprintf(buffer + len, "\n");
- 
- 	return len;
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/Config.in
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/Config.in	2004-06-14 14:52:11.000000000 +0200
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/Config.in	2004-06-28 12:58:18.000000000 +0200
-@@ -7,6 +7,7 @@
- tristate 'Connection tracking (required for masq/NAT)' CONFIG_IP_NF_CONNTRACK
- if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then
-   dep_tristate '  FTP protocol support' CONFIG_IP_NF_FTP $CONFIG_IP_NF_CONNTRACK
-+  bool '  Connection mark tracking support' CONFIG_IP_NF_CONNTRACK_MARK
-   dep_tristate '  Amanda protocol support' CONFIG_IP_NF_AMANDA $CONFIG_IP_NF_CONNTRACK
-   dep_tristate '  TFTP protocol support' CONFIG_IP_NF_TFTP $CONFIG_IP_NF_CONNTRACK
-   dep_tristate '  IRC protocol support' CONFIG_IP_NF_IRC $CONFIG_IP_NF_CONNTRACK
-@@ -38,6 +39,9 @@
-   fi
-   if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then
-     dep_tristate '  Connection state match support' CONFIG_IP_NF_MATCH_STATE $CONFIG_IP_NF_CONNTRACK $CONFIG_IP_NF_IPTABLES 
-+    if [ "$CONFIG_IP_NF_CONNTRACK_MARK" != "n" ]; then
-+      dep_tristate '  Connection mark match support' CONFIG_IP_NF_MATCH_CONNMARK $CONFIG_IP_NF_IPTABLES
-+    fi
-     dep_tristate '  Connection tracking match support' CONFIG_IP_NF_MATCH_CONNTRACK $CONFIG_IP_NF_CONNTRACK $CONFIG_IP_NF_IPTABLES 
-   fi
-   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-@@ -106,6 +110,9 @@
-     dep_tristate '    MARK target support' CONFIG_IP_NF_TARGET_MARK $CONFIG_IP_NF_MANGLE
-   fi
-   dep_tristate '  LOG target support' CONFIG_IP_NF_TARGET_LOG $CONFIG_IP_NF_IPTABLES
-+  if [ "$CONFIG_IP_NF_CONNTRACK_MARK" != "n" ]; then
-+    dep_tristate '  CONNMARK target support' CONFIG_IP_NF_TARGET_CONNMARK $CONFIG_IP_NF_IPTABLES
-+  fi
-   dep_tristate '  ULOG target support' CONFIG_IP_NF_TARGET_ULOG $CONFIG_IP_NF_IPTABLES
-   dep_tristate '  TCPMSS target support' CONFIG_IP_NF_TARGET_TCPMSS $CONFIG_IP_NF_IPTABLES
-   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/Makefile
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/Makefile	2004-06-14 14:52:11.000000000 +0200
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/Makefile	2004-06-28 12:58:18.000000000 +0200
-@@ -84,6 +84,7 @@
- 
- obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
- obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o
-+obj-$(CONFIG_IP_NF_MATCH_CONNMARK) += ipt_connmark.o
- obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o
- obj-$(CONFIG_IP_NF_MATCH_UNCLEAN) += ipt_unclean.o
- obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o
-@@ -99,6 +100,7 @@
- obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
- obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o
- obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
-+obj-$(CONFIG_IP_NF_TARGET_CONNMARK) += ipt_CONNMARK.o
- obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
- obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o
- obj-$(CONFIG_IP_NF_TARGET_NOTRACK) += ipt_NOTRACK.o
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/ipt_connmark.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/ipt_connmark.c	2004-06-16 09:19:51.000000000 +0200
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/ipt_connmark.c	2004-06-28 12:58:18.000000000 +0200
-@@ -0,0 +1,83 @@
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.9/net/ipv4/netfilter/ipt_connmark.c	2004-11-27 00:44:47.489205504 +0100
+@@ -0,0 +1,81 @@
 +/* This kernel module matches connection mark values set by the
 + * CONNMARK target
 + *
@@ -301,15 +338,13 @@
 +      const struct net_device *out,
 +      const void *matchinfo,
 +      int offset,
-+      const void *hdr,
-+      u_int16_t datalen,
 +      int *hotdrop)
 +{
 +	const struct ipt_connmark_info *info = matchinfo;
 +	enum ip_conntrack_info ctinfo;
 +	struct ip_conntrack *ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
 +	if (!ct)
-+	    return 0;
++		return 0;
 +
 +	return ((ct->mark & info->mask) == info->mark) ^ info->invert;
 +}
@@ -346,55 +381,3 @@
 +
 +module_init(init);
 +module_exit(fini);
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_core.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/ip_conntrack_core.c	2004-06-14 14:52:11.000000000 +0200
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_core.c	2004-06-28 12:58:18.000000000 +0200
-@@ -735,6 +735,9 @@
- 		__set_bit(IPS_EXPECTED_BIT, &conntrack->status);
- 		conntrack->master = expected;
- 		expected->sibling = conntrack;
-+#if CONFIG_IP_NF_CONNTRACK_MARK
-+		conntrack->mark = expected->expectant->mark;
-+#endif
- 		LIST_DELETE(&ip_conntrack_expect_list, expected);
- 		expected->expectant->expecting--;
- 		nf_conntrack_get(&master_ct(conntrack)->infos[0]);
-Index: linux-2.4.26-ct_sync/Documentation/Configure.help
-===================================================================
---- linux-2.4.26-ct_sync.orig/Documentation/Configure.help	2004-06-14 14:52:11.000000000 +0200
-+++ linux-2.4.26-ct_sync/Documentation/Configure.help	2004-06-28 12:58:18.000000000 +0200
-@@ -2803,6 +2803,32 @@
-   If you want to compile it as a module, say M here and read
-   <file:Documentation/modules.txt>.  If unsure, say `Y'.
- 
-+Per connection mark support
-+CONFIG_IP_NF_CONNTRACK_MARK
-+  This option enables support for connection marks, used by the
-+  `CONNMARK' target and `connmark' match. Similar to the mark value
-+  of packets, but this mark value is kept in the conntrack session
-+  instead of the individual packets.
-+
-+CONNMARK target support
-+CONFIG_IP_NF_TARGET_CONNMARK
-+  This option adds a `CONNMARK' target, which allows one to manipulate
-+  the connection mark value.  Similar to the MARK target, but
-+  affects the connection mark value rather than the packet mark value.
-+
-+  If you want to compile it as a module, say M here and read
-+  Documentation/modules.txt.  The module will be called
-+  ipt_CONNMARK.o.  If unsure, say `N'.
-+
-+connmark match support
-+CONFIP_IP_NF_MATCH_CONNMARK
-+  This option adds a `connmark' match, which allows you to match the
-+  connection mark value previously set for the session by `CONNMARK'. 
-+
-+  If you want to compile it as a module, say M here and read
-+  Documentation/modules.txt.  The module will be called
-+  ipt_connmark.o.  If unsure, say `N'.
-+
- User space queueing via NETLINK
- CONFIG_IP_NF_QUEUE
-   Netfilter has the ability to queue packets to user space: the
-

Added: branches/netfilter-ha/linux-2.6/patches/conntrack_alloc.patch
===================================================================
--- branches/netfilter-ha/linux-2.6/patches/conntrack_alloc.patch	2005-01-02 22:40:48 UTC (rev 3550)
+++ branches/netfilter-ha/linux-2.6/patches/conntrack_alloc.patch	2005-01-02 23:13:27 UTC (rev 3551)
@@ -0,0 +1,176 @@
+Index: linux-2.6.9/net/ipv4/netfilter/ip_conntrack_standalone.c
+===================================================================
+--- linux-2.6.9.orig/net/ipv4/netfilter/ip_conntrack_standalone.c	2004-12-11 21:04:35.000000000 +0100
++++ linux-2.6.9/net/ipv4/netfilter/ip_conntrack_standalone.c	2004-12-12 00:20:26.944339960 +0100
+@@ -888,6 +888,8 @@
+ EXPORT_SYMBOL(ip_conntrack_protocol_register);
+ EXPORT_SYMBOL(ip_conntrack_protocol_unregister);
+ EXPORT_SYMBOL(invert_tuplepr);
++EXPORT_SYMBOL(ip_conntrack_alloc);
++EXPORT_SYMBOL(ip_conntrack_free);
+ EXPORT_SYMBOL(ip_conntrack_alter_reply);
+ EXPORT_SYMBOL(ip_conntrack_destroyed);
+ EXPORT_SYMBOL(need_ip_conntrack);
+Index: linux-2.6.9/include/linux/netfilter_ipv4/ip_conntrack.h
+===================================================================
+--- linux-2.6.9.orig/include/linux/netfilter_ipv4/ip_conntrack.h	2004-12-10 00:10:57.000000000 +0100
++++ linux-2.6.9/include/linux/netfilter_ipv4/ip_conntrack.h	2004-12-12 00:20:26.949339200 +0100
+@@ -336,10 +336,20 @@
+ ip_ct_gather_frags(struct sk_buff *skb);
+ 
+ /* Delete all conntracks which match. */
+-extern void
++void
+ ip_ct_selective_cleanup(int (*kill)(const struct ip_conntrack *i, void *data),
+ 			void *data);
+ 
++/* Allocates and initializes a new ip_conntrack structure, increment allocated
++ * conntrack count.
++ * Returns: ERR_PTR(-ENOMEM) in case of failure, conntrack pointer otherwise */
++struct ip_conntrack *
++ip_conntrack_alloc(const struct ip_conntrack_tuple *orig,
++		   const struct ip_conntrack_tuple *reply);
++
++/* Free conntrack structure and decrement number of allocated conntrack entries. */
++extern void ip_conntrack_free(struct ip_conntrack *);
++
+ /* It's confirmed if it is, or has been in the hash table. */
+ static inline int is_confirmed(struct ip_conntrack *ct)
+ {
+Index: linux-2.6.9/net/ipv4/netfilter/ip_conntrack_core.c
+===================================================================
+--- linux-2.6.9.orig/net/ipv4/netfilter/ip_conntrack_core.c	2004-12-12 00:20:22.049084152 +0100
++++ linux-2.6.9/net/ipv4/netfilter/ip_conntrack_core.c	2004-12-12 00:20:26.957337984 +0100
+@@ -278,6 +278,13 @@
+ 	remove_expectations(ct, 1);
+ }
+ 
++inline void
++ip_conntrack_free(struct ip_conntrack *conntrack)
++{
++	kmem_cache_free(ip_conntrack_cachep, conntrack);
++	atomic_dec(&ip_conntrack_count);
++}
++
+ static void
+ destroy_conntrack(struct nf_conntrack *nfct)
+ {
+@@ -321,8 +328,7 @@
+ 		ip_conntrack_put(master);
+ 
+ 	DEBUGP("destroy_conntrack: returning ct=%p to slab\n", ct);
+-	kmem_cache_free(ip_conntrack_cachep, ct);
+-	atomic_dec(&ip_conntrack_count);
++	ip_conntrack_free(ct);
+ 	CONNTRACK_STAT_INC(delete);
+ }
+ 
+@@ -559,22 +565,19 @@
+ 
+ /* Allocate a new conntrack: we return -ENOMEM if classification
+    failed due to stress.  Otherwise it really is unclassifiable. */
+-static struct ip_conntrack_tuple_hash *
+-init_conntrack(const struct ip_conntrack_tuple *tuple,
+-	       struct ip_conntrack_protocol *protocol,
+-	       struct sk_buff *skb)
++struct ip_conntrack *
++ip_conntrack_alloc(const struct ip_conntrack_tuple *orig,
++		   const struct ip_conntrack_tuple *reply)
+ {
+ 	struct ip_conntrack *conntrack;
+-	struct ip_conntrack_tuple repl_tuple;
+ 	size_t hash;
+-	struct ip_conntrack_expect *expected;
+ 
+ 	if (!ip_conntrack_hash_rnd_initted) {
+ 		get_random_bytes(&ip_conntrack_hash_rnd, 4);
+ 		ip_conntrack_hash_rnd_initted = 1;
+ 	}
+ 
+-	hash = hash_conntrack(tuple);
++	hash = hash_conntrack(orig);
+ 
+ 	if (ip_conntrack_max
+ 	    && atomic_read(&ip_conntrack_count) >= ip_conntrack_max) {
+@@ -588,11 +591,6 @@
+ 		}
+ 	}
+ 
+-	if (!ip_ct_invert_tuple(&repl_tuple, tuple, protocol)) {
+-		DEBUGP("Can't invert tuple.\n");
+-		return NULL;
+-	}
+-
+ 	conntrack = kmem_cache_alloc(ip_conntrack_cachep, GFP_ATOMIC);
+ 	if (!conntrack) {
+ 		DEBUGP("Can't allocate conntrack.\n");
+@@ -602,20 +600,46 @@
+ 	memset(conntrack, 0, sizeof(*conntrack));
+ 	atomic_set(&conntrack->ct_general.use, 1);
+ 	conntrack->ct_general.destroy = destroy_conntrack;
+-	conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *tuple;
++	conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *orig;
+ 	conntrack->tuplehash[IP_CT_DIR_ORIGINAL].ctrack = conntrack;
+-	conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = repl_tuple;
++	conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *reply;
+ 	conntrack->tuplehash[IP_CT_DIR_REPLY].ctrack = conntrack;
+-	if (!protocol->new(conntrack, skb)) {
+-		kmem_cache_free(ip_conntrack_cachep, conntrack);
+-		return NULL;
+-	}
++
+ 	/* Don't set timer yet: wait for confirmation */
+ 	init_timer(&conntrack->timeout);
+ 	conntrack->timeout.data = (unsigned long)conntrack;
+ 	conntrack->timeout.function = death_by_timeout;
+ 
+ 	INIT_LIST_HEAD(&conntrack->sibling_list);
++	atomic_inc(&ip_conntrack_count);
++
++	return conntrack;
++}
++
++static struct ip_conntrack_tuple_hash *
++init_conntrack(const struct ip_conntrack_tuple *tuple,
++	       struct ip_conntrack_protocol *protocol,
++	       struct sk_buff *skb)
++{
++	struct ip_conntrack *conntrack;
++	struct ip_conntrack_tuple repl_tuple;
++	struct ip_conntrack_expect *expected;
++
++	if (!ip_ct_invert_tuple(&repl_tuple, tuple, protocol)) {
++		DEBUGP("Can't invert tuple.\n");
++		return NULL;
++	}
++
++	conntrack = ip_conntrack_alloc(tuple, &repl_tuple);
++	if (!conntrack || IS_ERR(conntrack)) {
++		DEBUGP("Can't allocate conntrack.\n");
++		return ERR_PTR(-ENOMEM);
++	}
++
++	if (!protocol->new(conntrack, skb)) {
++		ip_conntrack_free(conntrack);
++		return NULL;
++	}
+ 
+ 	WRITE_LOCK(&ip_conntrack_lock);
+ 	/* Need finding and deleting of expected ONLY if we win race */
+@@ -655,7 +679,6 @@
+ 		nf_conntrack_get(&master_ct(conntrack)->ct_general);
+ 
+ 		/* this is a braindead... --pablo */
+-		atomic_inc(&ip_conntrack_count);
+ 		WRITE_UNLOCK(&ip_conntrack_lock);
+ 
+ 		if (expected->expectfn)
+@@ -670,7 +693,7 @@
+ 		CONNTRACK_STAT_INC(new);
+ 	}
+ 
+-end:	atomic_inc(&ip_conntrack_count);
++end:
+ 	WRITE_UNLOCK(&ip_conntrack_lock);
+ 
+ ret:	return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL];

Added: branches/netfilter-ha/linux-2.6/patches/conntrack_hash_manip.patch
===================================================================
--- branches/netfilter-ha/linux-2.6/patches/conntrack_hash_manip.patch	2005-01-02 22:40:48 UTC (rev 3550)
+++ branches/netfilter-ha/linux-2.6/patches/conntrack_hash_manip.patch	2005-01-02 23:13:27 UTC (rev 3551)
@@ -0,0 +1,82 @@
+Index: linux-2.6.9/net/ipv4/netfilter/ip_conntrack_standalone.c
+===================================================================
+--- linux-2.6.9.orig/net/ipv4/netfilter/ip_conntrack_standalone.c	2004-12-15 22:00:02.732832552 +0100
++++ linux-2.6.9/net/ipv4/netfilter/ip_conntrack_standalone.c	2004-12-15 22:02:17.056412264 +0100
+@@ -914,5 +914,7 @@
+ EXPORT_SYMBOL(ip_conntrack_untracked);
+ EXPORT_SYMBOL_GPL(ip_conntrack_find_get);
+ EXPORT_SYMBOL_GPL(__ip_conntrack_find);
++EXPORT_SYMBOL_GPL(__ip_conntrack_hash_insert);
++EXPORT_SYMBOL_GPL(__ip_conntrack_hash_remove);
+ EXPORT_SYMBOL_GPL(ip_conntrack_clean_from_lists);
+ EXPORT_SYMBOL_GPL(ip_conntrack_put);
+Index: linux-2.6.9/include/linux/netfilter_ipv4/ip_conntrack_core.h
+===================================================================
+--- linux-2.6.9.orig/include/linux/netfilter_ipv4/ip_conntrack_core.h	2004-12-15 22:00:31.513457232 +0100
++++ linux-2.6.9/include/linux/netfilter_ipv4/ip_conntrack_core.h	2004-12-15 22:01:18.850260944 +0100
+@@ -56,6 +56,10 @@
+ 
+ extern void ip_conntrack_clean_from_lists(struct ip_conntrack *ct);
+ 
++/* Non-locked conntrack hash insert and remove function: for ct_sync. */
++void __ip_conntrack_hash_insert(struct ip_conntrack *ct);
++void __ip_conntrack_hash_remove(struct ip_conntrack *ct);
++
+ extern struct list_head *ip_conntrack_hash;
+ extern struct list_head ip_conntrack_expect_list;
+ DECLARE_RWLOCK_EXTERN(ip_conntrack_lock);
+Index: linux-2.6.9/net/ipv4/netfilter/ip_conntrack_core.c
+===================================================================
+--- linux-2.6.9.orig/net/ipv4/netfilter/ip_conntrack_core.c	2004-12-15 22:01:02.899685800 +0100
++++ linux-2.6.9/net/ipv4/netfilter/ip_conntrack_core.c	2004-12-15 22:02:59.406974000 +0100
+@@ -269,15 +269,10 @@
+ void
+ ip_conntrack_clean_from_lists(struct ip_conntrack *ct)
+ {
+-	unsigned int ho, hr;
+-	
+ 	DEBUGP("ip_conntrack_clean_from_lists(%p)\n", ct);
+ 	MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
+ 
+-	ho = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+-	hr = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
+-	LIST_DELETE(&ip_conntrack_hash[ho], &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
+-	LIST_DELETE(&ip_conntrack_hash[hr], &ct->tuplehash[IP_CT_DIR_REPLY]);
++	__ip_conntrack_hash_remove(ct);
+ 
+ 	/* Destroy all un-established, pending expectations */
+ 	remove_expectations(ct, 1);
+@@ -391,6 +386,33 @@
+ 	return h;
+ }
+ 
++/* Insert a conntrack into the hash. Caller holds a write lock on
++ * the conntrack hash. */
++void
++__ip_conntrack_hash_insert(struct ip_conntrack *ct)
++{
++	unsigned int ho, hr;
++
++	ho = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
++	hr = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
++
++	list_prepend(&ip_conntrack_hash[ho], &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
++	list_prepend(&ip_conntrack_hash[hr], &ct->tuplehash[IP_CT_DIR_REPLY]);
++}
++
++/* Remove a conntrack from the hash. Caller holds a write lock on
++ * the conntrack hash. */
++void
++__ip_conntrack_hash_remove(struct ip_conntrack *ct)
++{
++	unsigned int ho, hr;
++
++	ho = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
++	hr = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
++	LIST_DELETE(&ip_conntrack_hash[ho], &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
++	LIST_DELETE(&ip_conntrack_hash[hr], &ct->tuplehash[IP_CT_DIR_REPLY]);
++}
++
+ /* Confirm a connection given skb; places it in hash table */
+ int
+ __ip_conntrack_confirm(struct sk_buff *skb)

Added: branches/netfilter-ha/linux-2.6/patches/ct_notifier_pkt.patch
===================================================================
--- branches/netfilter-ha/linux-2.6/patches/ct_notifier_pkt.patch	2005-01-02 22:40:48 UTC (rev 3550)
+++ branches/netfilter-ha/linux-2.6/patches/ct_notifier_pkt.patch	2005-01-02 23:13:27 UTC (rev 3551)
@@ -0,0 +1,486 @@
+===== include/linux/netfilter.h 1.13 vs edited =====
+Index: linux-2.6.9/include/linux/netfilter.h
+===================================================================
+--- linux-2.6.9.orig/include/linux/netfilter.h	2004-11-27 00:25:40.442583096 +0100
++++ linux-2.6.9/include/linux/netfilter.h	2004-11-27 00:29:34.763960832 +0100
+@@ -21,7 +21,7 @@
+ #define NF_MAX_VERDICT NF_REPEAT
+ 
+ /* Generic cache responses from hook functions.
+-   <= 0x2000 is used for protocol-flags. */
++   <= 0x2000 is reserved for conntrack event cache. */
+ #define NFC_UNKNOWN 0x4000
+ #define NFC_ALTERED 0x8000
+ 
+Index: linux-2.6.9/include/linux/netfilter_ipv4.h
+===================================================================
+--- linux-2.6.9.orig/include/linux/netfilter_ipv4.h	2004-08-14 07:37:39.000000000 +0200
++++ linux-2.6.9/include/linux/netfilter_ipv4.h	2004-11-27 00:29:34.765960528 +0100
+@@ -8,34 +8,6 @@
+ #include <linux/config.h>
+ #include <linux/netfilter.h>
+ 
+-/* IP Cache bits. */
+-/* Src IP address. */
+-#define NFC_IP_SRC		0x0001
+-/* Dest IP address. */
+-#define NFC_IP_DST		0x0002
+-/* Input device. */
+-#define NFC_IP_IF_IN		0x0004
+-/* Output device. */
+-#define NFC_IP_IF_OUT		0x0008
+-/* TOS. */
+-#define NFC_IP_TOS		0x0010
+-/* Protocol. */
+-#define NFC_IP_PROTO		0x0020
+-/* IP options. */
+-#define NFC_IP_OPTIONS		0x0040
+-/* Frag & flags. */
+-#define NFC_IP_FRAG		0x0080
+-
+-/* Per-protocol information: only matters if proto match. */
+-/* TCP flags. */
+-#define NFC_IP_TCPFLAGS		0x0100
+-/* Source port. */
+-#define NFC_IP_SRC_PT		0x0200
+-/* Dest port. */
+-#define NFC_IP_DST_PT		0x0400
+-/* Something else about the proto */
+-#define NFC_IP_PROTO_UNKNOWN	0x2000
+-
+ /* IP Hooks */
+ /* After promisc drops, checksum checks. */
+ #define NF_IP_PRE_ROUTING	0
+Index: linux-2.6.9/include/linux/netfilter_ipv4/ip_conntrack.h
+===================================================================
+--- linux-2.6.9.orig/include/linux/netfilter_ipv4/ip_conntrack.h	2004-11-27 00:25:40.498574584 +0100
++++ linux-2.6.9/include/linux/netfilter_ipv4/ip_conntrack.h	2004-11-27 00:29:34.768960072 +0100
+@@ -47,6 +47,58 @@
+ 	/* Connection is confirmed: originating packet has left box */
+ 	IPS_CONFIRMED_BIT = 3,
+ 	IPS_CONFIRMED = (1 << IPS_CONFIRMED_BIT),
++
++	/* Connection is destroyed (removed from lists), can not be unset. */
++	IPS_DESTROYED_BIT = 4,
++	IPS_DESTROYED = (1 << IPS_DESTROYED_BIT),
++};
++
++/* Connection tracking event bits */
++enum ip_conntrack_events
++{
++	/* New conntrack */
++	IPCT_NEW_BIT = 0,
++	IPCT_NEW = (1 << IPCT_NEW_BIT),
++
++	/* Expected connection */
++	IPCT_RELATED_BIT = 1,
++	IPCT_RELATED = (1 << IPCT_RELATED_BIT),
++
++	/* Destroyed conntrack */
++	IPCT_DESTROY_BIT = 2,
++	IPCT_DESTROY = (1 << IPCT_DESTROY_BIT),
++
++	/* Timer has been refreshed */
++	IPCT_REFRESH_BIT = 3,
++	IPCT_REFRESH = (1 << IPCT_REFRESH_BIT),
++
++	/* Status has changed */
++	IPCT_STATUS_BIT = 4,
++	IPCT_STATUS = (1 << IPCT_STATUS_BIT),
++
++	/* Update of protocol info */
++	IPCT_PROTOINFO_BIT = 5,
++	IPCT_PROTOINFO = (1 << IPCT_PROTOINFO_BIT),
++
++	/* Volatile protocol info */
++	IPCT_PROTOINFO_VOLATILE_BIT = 6,
++	IPCT_PROTOINFO_VOLATILE = (1 << IPCT_PROTOINFO_VOLATILE_BIT),
++
++	/* New helper for conntrack */
++	IPCT_HELPER_BIT = 7,
++	IPCT_HELPER = (1 << IPCT_HELPER_BIT),
++
++	/* Update of helper info */
++	IPCT_HELPINFO_BIT = 8,
++	IPCT_HELPINFO = (1 << IPCT_HELPINFO_BIT),
++
++	/* Volatile helper info */
++	IPCT_HELPINFO_VOLATILE_BIT = 9,
++	IPCT_HELPINFO_VOLATILE = (1 << IPCT_HELPINFO_VOLATILE_BIT),
++
++	/* NAT info */
++	IPCT_NATINFO_BIT = 10,
++	IPCT_NATINFO = (1 << IPCT_NATINFO_BIT),
+ };
+ 
+ #include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
+@@ -259,7 +311,7 @@
+ /* Refresh conntrack for this many jiffies */
+ extern void ip_ct_refresh_acct(struct ip_conntrack *ct,
+ 			       enum ip_conntrack_info ctinfo,
+-			       const struct sk_buff *skb,
++			       struct sk_buff *skb,
+ 			       unsigned long extra_jiffies);
+ 
+ /* These are for NAT.  Icky. */
+@@ -290,6 +342,11 @@
+ 	return test_bit(IPS_CONFIRMED_BIT, &ct->status);
+ }
+ 
++static inline int is_destroyed(struct ip_conntrack *ct)
++{
++	return test_bit(IPS_DESTROYED_BIT, &ct->status);
++}
++
+ extern unsigned int ip_conntrack_htable_size;
+  
+ struct ip_conntrack_stat
+@@ -313,6 +370,57 @@
+ 
+ #define CONNTRACK_STAT_INC(count) (__get_cpu_var(ip_conntrack_stat).count++)
+ 
++#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
++#include <linux/notifier.h>
++ 
++extern struct notifier_block *ip_conntrack_chain;
++ 
++static inline int ip_conntrack_register_notifier(struct notifier_block *nb)
++{
++	return notifier_chain_register(&ip_conntrack_chain, nb);
++}
++
++static inline int ip_conntrack_unregister_notifier(struct notifier_block *nb)
++{
++	return notifier_chain_unregister(&ip_conntrack_chain, nb);
++}
++
++static inline void ip_conntrack_event_cache_init(struct sk_buff *skb)
++{
++	/* Set to zero first 14 bits, see netfilter.h */
++	skb->nfcache &= 0xc000;
++}
++
++static inline void 
++ip_conntrack_event_cache(enum ip_conntrack_events event, struct sk_buff *skb)
++{
++	skb->nfcache |= event;
++}
++
++static inline void 
++ip_conntrack_deliver_cached_events(struct sk_buff *skb)
++{
++	struct ip_conntrack *ct = (struct ip_conntrack *) skb->nfct;
++
++	if (ct != NULL && is_confirmed(ct) && !is_destroyed(ct) && skb->nfcache)
++		notifier_call_chain(&ip_conntrack_chain, skb->nfcache, ct);
++}
++
++static inline void ip_conntrack_event(enum ip_conntrack_events event,
++				      struct ip_conntrack *ct)
++{
++	if (is_confirmed(ct) && !is_destroyed(ct))
++		notifier_call_chain(&ip_conntrack_chain, event, ct);
++}
++#else /* CONFIG_IP_NF_CONNTRACK_EVENTS */
++static inline void ip_conntrack_event_cache_init(struct sk_buff *skb) {}
++static inline void ip_conntrack_event_cache(enum ip_conntrack_events event,
++					    struct sk_buff *skb) {}
++static inline void ip_conntrack_event(enum ip_conntrack_events event,
++				      struct ip_conntrack *ct) {}
++static inline void ip_conntrack_deliver_cached_events(struct sk_buff *skb) {}
++#endif /* CONFIG_IP_NF_CONNTRACK_EVENTS */
++
+ /* eg. PROVIDES_CONNTRACK(ftp); */
+ #define PROVIDES_CONNTRACK(name)                        \
+         int needs_ip_conntrack_##name;                  \
+Index: linux-2.6.9/include/linux/netfilter_ipv4/ip_conntrack_core.h
+===================================================================
+--- linux-2.6.9.orig/include/linux/netfilter_ipv4/ip_conntrack_core.h	2004-11-27 00:25:40.500574280 +0100
++++ linux-2.6.9/include/linux/netfilter_ipv4/ip_conntrack_core.h	2004-11-27 00:29:34.770959768 +0100
+@@ -39,10 +39,14 @@
+ /* Confirm a connection: returns NF_DROP if packet must be dropped. */
+ static inline int ip_conntrack_confirm(struct sk_buff *skb)
+ {
++	int ret = NF_ACCEPT;
++	
+ 	if (skb->nfct
+ 	    && !is_confirmed((struct ip_conntrack *)skb->nfct))
+-		return __ip_conntrack_confirm(skb);
+-	return NF_ACCEPT;
++		ret = __ip_conntrack_confirm(skb);
++	ip_conntrack_deliver_cached_events(skb);
++
++	return ret;
+ }
+ 
+ extern struct list_head *ip_conntrack_hash;
+Index: linux-2.6.9/include/linux/netfilter_ipv4/ip_conntrack_protocol.h
+===================================================================
+--- linux-2.6.9.orig/include/linux/netfilter_ipv4/ip_conntrack_protocol.h	2004-11-27 00:25:40.507573216 +0100
++++ linux-2.6.9/include/linux/netfilter_ipv4/ip_conntrack_protocol.h	2004-11-27 00:29:34.771959616 +0100
+@@ -34,7 +34,7 @@
+ 
+ 	/* Returns verdict for packet, or -1 for invalid. */
+ 	int (*packet)(struct ip_conntrack *conntrack,
+-		      const struct sk_buff *skb,
++		      struct sk_buff *skb,
+ 		      enum ip_conntrack_info ctinfo);
+ 
+ 	/* Called when a new connection for this protocol found;
+Index: linux-2.6.9/net/ipv4/netfilter/Kconfig
+===================================================================
+--- linux-2.6.9.orig/net/ipv4/netfilter/Kconfig	2004-11-27 00:25:43.824069032 +0100
++++ linux-2.6.9/net/ipv4/netfilter/Kconfig	2004-11-27 00:29:34.775959008 +0100
+@@ -677,5 +677,15 @@
+ 
+ 	  To compile it as a module, choose M here.  If unsure, say N.
+ 
++config IP_NF_CONNTRACK_EVENTS
++	bool "Connection tracking events"
++	depends on IP_NF_CONNTRACK
++	help
++	  If this option is enabled, the connection tracking code will
++	  provide a notifier chain that can be used by other kernel code
++	  to get notified about changes in the connection tracking state.
++	  
++	  IF unsure, say `N'.
++
+ endmenu
+ 
+Index: linux-2.6.9/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
+===================================================================
+--- linux-2.6.9.orig/net/ipv4/netfilter/ip_conntrack_proto_icmp.c	2004-11-27 00:25:43.863063104 +0100
++++ linux-2.6.9/net/ipv4/netfilter/ip_conntrack_proto_icmp.c	2004-11-27 00:29:34.777958704 +0100
+@@ -89,7 +89,7 @@
+ 
+ /* Returns verdict for packet, or -1 for invalid. */
+ static int icmp_packet(struct ip_conntrack *ct,
+-		       const struct sk_buff *skb,
++		       struct sk_buff *skb,
+ 		       enum ip_conntrack_info ctinfo)
+ {
+ 	/* Try to delete connection immediately after all replies:
+@@ -102,6 +102,7 @@
+ 			ct->timeout.function((unsigned long)ct);
+ 	} else {
+ 		atomic_inc(&ct->proto.icmp.count);
++		ip_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb);
+ 		ip_ct_refresh_acct(ct, ctinfo, skb, ip_ct_icmp_timeout);
+ 	}
+ 
+Index: linux-2.6.9/net/ipv4/netfilter/ip_conntrack_proto_generic.c
+===================================================================
+--- linux-2.6.9.orig/net/ipv4/netfilter/ip_conntrack_proto_generic.c	2004-11-27 00:25:43.860063560 +0100
++++ linux-2.6.9/net/ipv4/netfilter/ip_conntrack_proto_generic.c	2004-11-27 00:29:34.779958400 +0100
+@@ -49,7 +49,7 @@
+ 
+ /* Returns verdict for packet, or -1 for invalid. */
+ static int packet(struct ip_conntrack *conntrack,
+-		  const struct sk_buff *skb,
++		  struct sk_buff *skb,
+ 		  enum ip_conntrack_info ctinfo)
+ {
+ 	ip_ct_refresh_acct(conntrack, ctinfo, skb, ip_ct_generic_timeout);
+Index: linux-2.6.9/net/ipv4/netfilter/ip_conntrack_proto_sctp.c
+===================================================================
+--- linux-2.6.9.orig/net/ipv4/netfilter/ip_conntrack_proto_sctp.c	2004-11-27 00:25:43.935052160 +0100
++++ linux-2.6.9/net/ipv4/netfilter/ip_conntrack_proto_sctp.c	2004-11-27 00:29:34.782957944 +0100
+@@ -310,7 +310,7 @@
+ 
+ /* Returns verdict for packet, or -1 for invalid. */
+ static int sctp_packet(struct ip_conntrack *conntrack,
+-		       const struct sk_buff *skb,
++		       struct sk_buff *skb,
+ 		       enum ip_conntrack_info ctinfo)
+ {
+ 	enum sctp_conntrack newconntrack, oldsctpstate;
+@@ -405,6 +405,8 @@
+ 		}
+ 
+ 		conntrack->proto.sctp.state = newconntrack;
++		if (oldsctpstate != newconntrack)
++			ip_conntrack_event_cache(IPCT_PROTOINFO, skb);
+ 		WRITE_UNLOCK(&sctp_lock);
+ 	}
+ 
+Index: linux-2.6.9/net/ipv4/netfilter/ip_conntrack_core.c
+===================================================================
+--- linux-2.6.9.orig/net/ipv4/netfilter/ip_conntrack_core.c	2004-11-27 00:25:43.846065688 +0100
++++ linux-2.6.9/net/ipv4/netfilter/ip_conntrack_core.c	2004-11-27 00:30:59.285111664 +0100
+@@ -37,6 +37,7 @@
+ #include <linux/err.h>
+ #include <linux/percpu.h>
+ #include <linux/moduleparam.h>
++#include <linux/notifier.h>
+ 
+ /* This rwlock protects the main hash table, protocol/helper/expected
+    registrations, conntrack timers*/
+@@ -76,6 +77,10 @@
+ struct ip_conntrack ip_conntrack_untracked;
+ unsigned int ip_ct_log_invalid;
+ 
++#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
++struct notifier_block *ip_conntrack_chain;
++#endif /* CONFIG_IP_NF_CONNTRACK_EVENTS */
++
+ DEFINE_PER_CPU(struct ip_conntrack_stat, ip_conntrack_stat);
+ 
+ inline void 
+@@ -288,6 +293,8 @@
+ 	IP_NF_ASSERT(atomic_read(&nfct->use) == 0);
+ 	IP_NF_ASSERT(!timer_pending(&ct->timeout));
+ 
++	set_bit(IPS_DESTROYED_BIT, &ct->status);
++
+ 	/* To make sure we don't get any weird locking issues here:
+ 	 * destroy_conntrack() MUST NOT be called with a write lock
+ 	 * to ip_conntrack_lock!!! -HW */
+@@ -330,6 +337,7 @@
+ 
+ 	CONNTRACK_STAT_INC(delete_list);
+ 
++	ip_conntrack_event(IPCT_DESTROY, ct);
+ 	WRITE_LOCK(&ip_conntrack_lock);
+ 	clean_from_lists(ct);
+ 	WRITE_UNLOCK(&ip_conntrack_lock);
+@@ -436,8 +444,16 @@
+ 		add_timer(&ct->timeout);
+ 		atomic_inc(&ct->ct_general.use);
+ 		set_bit(IPS_CONFIRMED_BIT, &ct->status);
+-		WRITE_UNLOCK(&ip_conntrack_lock);
+ 		CONNTRACK_STAT_INC(insert);
++		WRITE_UNLOCK(&ip_conntrack_lock);
++		if (ct->helper)
++			ip_conntrack_event_cache(IPCT_HELPER, skb);
++#ifdef CONFIG_IP_NF_NAT_NEEDED
++		if (ct->nat.info.initialized)
++			ip_conntrack_event_cache(IPCT_NATINFO, skb);
++#endif
++		ip_conntrack_event_cache(master_ct(ct) ?
++					 IPCT_RELATED : IPCT_NEW, skb);
+ 		return NF_ACCEPT;
+ 	}
+ 
+@@ -706,6 +722,8 @@
+ 	/* FIXME: Do this right please. --RR */
+ 	(*pskb)->nfcache |= NFC_UNKNOWN;
+ 
++	ip_conntrack_event_cache_init(*pskb);
++
+ /* Doesn't cover locally-generated broadcast, so not worth it. */
+ #if 0
+ 	/* Ignore broadcast: no `connection'. */
+@@ -767,8 +785,10 @@
+ 			return NF_ACCEPT;
+ 		}
+ 	}
+-	if (set_reply)
++	if (set_reply && !test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
+ 		set_bit(IPS_SEEN_REPLY_BIT, &ct->status);
++		ip_conntrack_event_cache(IPCT_STATUS, *pskb);
++	}
+ 
+ 	return ret;
+ }
+@@ -1050,6 +1070,7 @@
+ 	if (i->ctrack->helper == me) {
+ 		/* Get rid of any expected. */
+ 		remove_expectations(i->ctrack, 0);
++		ip_conntrack_event(IPCT_HELPER, i->ctrack);
+ 		/* And *then* set helper to NULL */
+ 		i->ctrack->helper = NULL;
+ 	}
+@@ -1090,7 +1111,7 @@
+ /* Refresh conntrack for this many jiffies and do accounting (if skb != NULL) */
+ void ip_ct_refresh_acct(struct ip_conntrack *ct, 
+ 		        enum ip_conntrack_info ctinfo,
+-			const struct sk_buff *skb,
++			struct sk_buff *skb,
+ 			unsigned long extra_jiffies)
+ {
+ 	IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct);
+@@ -1105,6 +1126,7 @@
+ 		if (del_timer(&ct->timeout)) {
+ 			ct->timeout.expires = jiffies + extra_jiffies;
+ 			add_timer(&ct->timeout);
++			ip_conntrack_event_cache(IPCT_REFRESH, skb);
+ 		}
+ 		ct_add_counters(ct, ctinfo, skb);
+ 		WRITE_UNLOCK(&ip_conntrack_lock);
+Index: linux-2.6.9/net/ipv4/netfilter/ip_conntrack_ftp.c
+===================================================================
+--- linux-2.6.9.orig/net/ipv4/netfilter/ip_conntrack_ftp.c	2004-11-27 00:25:43.854064472 +0100
++++ linux-2.6.9/net/ipv4/netfilter/ip_conntrack_ftp.c	2004-11-27 00:29:34.793956272 +0100
+@@ -300,6 +300,7 @@
+ 			ct_ftp_info->seq_aft_nl[dir] = 
+ 						ntohl(th->seq) + datalen;
+ 			ct_ftp_info->seq_aft_nl_set[dir] = 1;
++			ip_conntrack_event_cache(IPCT_HELPINFO_VOLATILE, skb);
+ 		}
+ 	}
+ 
+Index: linux-2.6.9/net/ipv4/netfilter/ip_conntrack_standalone.c
+===================================================================
+--- linux-2.6.9.orig/net/ipv4/netfilter/ip_conntrack_standalone.c	2004-11-27 00:25:43.956048968 +0100
++++ linux-2.6.9/net/ipv4/netfilter/ip_conntrack_standalone.c	2004-11-27 00:29:34.796955816 +0100
+@@ -875,6 +875,11 @@
+ {
+ }
+ 
++#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
++EXPORT_SYMBOL(ip_conntrack_chain);
++EXPORT_SYMBOL(ip_conntrack_register_notifier);
++EXPORT_SYMBOL(ip_conntrack_unregister_notifier);
++#endif
+ EXPORT_SYMBOL(ip_conntrack_protocol_register);
+ EXPORT_SYMBOL(ip_conntrack_protocol_unregister);
+ EXPORT_SYMBOL(invert_tuplepr);
+Index: linux-2.6.9/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
+===================================================================
+--- linux-2.6.9.orig/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	2004-11-27 00:25:43.944050792 +0100
++++ linux-2.6.9/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	2004-11-27 00:29:34.801955056 +0100
+@@ -825,7 +825,7 @@
+ 
+ /* Returns verdict for packet, or -1 for invalid. */
+ static int tcp_packet(struct ip_conntrack *conntrack,
+-		      const struct sk_buff *skb,
++		      struct sk_buff *skb,
+ 		      enum ip_conntrack_info ctinfo)
+ {
+ 	enum tcp_conntrack new_state, old_state;
+@@ -944,6 +944,10 @@
+ 		  ? ip_ct_tcp_timeout_max_retrans : *tcp_timeouts[new_state];
+ 	WRITE_UNLOCK(&tcp_lock);
+ 
++	ip_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb);
++	if (new_state != old_state)
++		ip_conntrack_event_cache(IPCT_PROTOINFO, skb);
++
+ 	if (!test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) {
+ 		/* If only reply is a RST, we can consider ourselves not to
+ 		   have an established connection: this is a fairly common
+Index: linux-2.6.9/net/ipv4/netfilter/ip_conntrack_proto_udp.c
+===================================================================
+--- linux-2.6.9.orig/net/ipv4/netfilter/ip_conntrack_proto_udp.c	2004-11-27 00:25:43.947050336 +0100
++++ linux-2.6.9/net/ipv4/netfilter/ip_conntrack_proto_udp.c	2004-11-27 00:29:34.803954752 +0100
+@@ -64,7 +64,7 @@
+ 
+ /* Returns verdict for packet, and may modify conntracktype */
+ static int udp_packet(struct ip_conntrack *conntrack,
+-		      const struct sk_buff *skb,
++		      struct sk_buff *skb,
+ 		      enum ip_conntrack_info ctinfo)
+ {
+ 	/* If we've seen traffic both ways, this is some kind of UDP
+@@ -73,7 +73,10 @@
+ 		ip_ct_refresh_acct(conntrack, ctinfo, skb, 
+ 				   ip_ct_udp_timeout_stream);
+ 		/* Also, more likely to be important, and not a probe */
+-		set_bit(IPS_ASSURED_BIT, &conntrack->status);
++		if (!test_bit(IPS_ASSURED_BIT, &conntrack->status)) {
++			set_bit(IPS_ASSURED_BIT, &conntrack->status);
++			ip_conntrack_event_cache(IPCT_STATUS, skb);
++		}
+ 	} else
+ 		ip_ct_refresh_acct(conntrack, ctinfo, skb, ip_ct_udp_timeout);
+ 

Modified: branches/netfilter-ha/linux-2.6/patches/ct_sync_config_and_makefile.patch
===================================================================
--- branches/netfilter-ha/linux-2.6/patches/ct_sync_config_and_makefile.patch	2005-01-02 22:40:48 UTC (rev 3550)
+++ branches/netfilter-ha/linux-2.6/patches/ct_sync_config_and_makefile.patch	2005-01-02 23:13:27 UTC (rev 3551)
@@ -1,47 +1,40 @@
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/Config.in
+Index: linux-2.6.9/net/ipv4/netfilter/Makefile
 ===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/Config.in	2004-06-28 12:58:22.000000000 +0200
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/Config.in	2004-07-08 13:42:59.000000000 +0200
-@@ -14,6 +14,7 @@
-   else
-     dep_tristate '  Connection tracking netlink interface' CONFIG_IP_NF_NETLINK_CONNTRACK $CONFIG_IP_NF_CONNTRACK
-   fi
-+  dep_tristate '  Connection tracking state synchronization' CONFIG_IP_NF_CT_SYNC $CONFIG_IP_NF_CONNTRACK_EVENTS
-   dep_tristate '  FTP protocol support' CONFIG_IP_NF_FTP $CONFIG_IP_NF_CONNTRACK
-   bool '  Connection mark tracking support' CONFIG_IP_NF_CONNTRACK_MARK
-   dep_tristate '  Amanda protocol support' CONFIG_IP_NF_AMANDA $CONFIG_IP_NF_CONNTRACK
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/Makefile
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/Makefile	2004-07-08 13:42:53.000000000 +0200
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/Makefile	2004-07-08 13:42:59.000000000 +0200
-@@ -12,11 +12,12 @@
- export-objs = ip_conntrack_standalone.o ip_fw_compat.o ip_nat_standalone.o ip_tables.o arp_tables.o
+--- linux-2.6.9.orig/net/ipv4/netfilter/Makefile	2004-12-10 00:10:57.000000000 +0100
++++ linux-2.6.9/net/ipv4/netfilter/Makefile	2004-12-15 22:03:22.000000000 +0100
+@@ -16,6 +16,9 @@
+ ipfwadm-objs		:= $(ip_nf_compat-objs) ipfwadm_core.o
+ ipchains-objs		:= $(ip_nf_compat-objs) ipchains_core.o
  
- # Multipart objects.
--list-multi		:= ip_conntrack.o iptable_nat.o ipfwadm.o ipchains.o
-+list-multi		:= ip_conntrack.o iptable_nat.o ipfwadm.o ipchains.o ct_sync.o
- 
- # objects for the conntrack and NAT core (used by standalone and backw. compat)
- ip_nf_conntrack-objs	:= ip_conntrack_core.o ip_conntrack_proto_generic.o ip_conntrack_proto_tcp.o ip_conntrack_proto_udp.o ip_conntrack_proto_icmp.o
- ip_nf_nat-objs		:= ip_nat_core.o ip_nat_helper.o ip_nat_proto_unknown.o ip_nat_proto_tcp.o ip_nat_proto_udp.o ip_nat_proto_icmp.o
++# conntrack state synchronization
 +ct_sync-objs		:= ct_sync_main.o ct_sync_proto.o ct_sync_sock.o
++
+ # connection tracking
+ obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o
  
- # objects for the standalone - connection tracking / NAT
- ip_conntrack-objs	:= ip_conntrack_standalone.o $(ip_nf_conntrack-objs)
-@@ -127,6 +128,9 @@
+@@ -99,3 +102,5 @@
+ obj-$(CONFIG_IP_NF_COMPAT_IPFWADM) += ipfwadm.o
  
  obj-$(CONFIG_IP_NF_QUEUE) += ip_queue.o
- 
-+# connection tracking state synchronization
-+obj-$(CONFIG_IP_NF_CT_SYNC) += ct_sync.o
 +
- include $(TOPDIR)/Rules.make
++obj-$(CONFIG_IP_NF_CT_SYNC) += ct_sync.o
+Index: linux-2.6.9/net/ipv4/netfilter/Kconfig
+===================================================================
+--- linux-2.6.9.orig/net/ipv4/netfilter/Kconfig	2004-12-10 00:10:57.000000000 +0100
++++ linux-2.6.9/net/ipv4/netfilter/Kconfig	2004-12-15 22:03:22.000000000 +0100
+@@ -718,5 +718,15 @@
+ 	  
+ 	  IF unsure, say `N'.
  
- ip_conntrack.o: $(ip_conntrack-objs)
-@@ -140,3 +144,6 @@
- 
- ipchains.o: $(ipchains-objs)
- 	$(LD) -r -o $@ $(ipchains-objs)
++config IP_NF_CT_SYNC
++	tristate "Connection tracking state synchronization"
++	depends on IP_NF_CONNTRACK_EVENTS
++	help
++	  If option enables connection tracking state synchronization support
++	  for the IPv4 connection tracking subsystem. Beware: this feature is
++	  highly experimental.
 +
-+ct_sync.o: $(ct_sync-objs)
-+	$(LD) -r -o $@ $(ct_sync-objs)
++	  If unsure, say `N'.
++
+ endmenu
+ 

Deleted: branches/netfilter-ha/linux-2.6/patches/export_ct_id.patch
===================================================================
--- branches/netfilter-ha/linux-2.6/patches/export_ct_id.patch	2005-01-02 22:40:48 UTC (rev 3550)
+++ branches/netfilter-ha/linux-2.6/patches/export_ct_id.patch	2005-01-02 23:13:27 UTC (rev 3551)
@@ -1,43 +0,0 @@
-Index: linux-2.4.26-ct_sync/include/linux/netfilter_ipv4/ip_conntrack_core.h
-===================================================================
---- linux-2.4.26-ct_sync.orig/include/linux/netfilter_ipv4/ip_conntrack_core.h	2004-06-28 12:58:30.000000000 +0200
-+++ linux-2.4.26-ct_sync/include/linux/netfilter_ipv4/ip_conntrack_core.h	2004-07-06 15:36:00.000000000 +0200
-@@ -59,6 +59,10 @@
- extern struct list_head ip_conntrack_ordered_list;
- extern struct list_head ip_conntrack_expect_list;
- extern struct list_head ip_conntrack_helpers;
-+
-+extern unsigned int ip_conntrack_next_id;
-+extern unsigned int ip_conntrack_exp_next_id;
-+
- DECLARE_RWLOCK_EXTERN(ip_conntrack_lock);
- #endif /* _IP_CONNTRACK_CORE_H */
- 
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_standalone.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/ip_conntrack_standalone.c	2004-06-28 12:58:30.000000000 +0200
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_standalone.c	2004-07-06 15:14:39.000000000 +0200
-@@ -534,6 +534,8 @@
- EXPORT_SYMBOL(ip_conntrack_lock);
- EXPORT_SYMBOL(ip_conntrack_hash);
- EXPORT_SYMBOL_GPL(hash_conntrack);
-+EXPORT_SYMBOL_GPL(ip_conntrack_next_id);
-+EXPORT_SYMBOL_GPL(ip_conntrack_exp_next_id);
- EXPORT_SYMBOL(ip_conntrack_untracked);
- EXPORT_SYMBOL_GPL(ip_conntrack_find_get);
- EXPORT_SYMBOL_GPL(__ip_conntrack_find_get);
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_core.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/ip_conntrack_core.c	2004-06-28 12:58:30.000000000 +0200
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_core.c	2004-07-06 15:13:50.000000000 +0200
-@@ -72,8 +72,8 @@
- 
- /* for ctnetlink */
- LIST_HEAD(ip_conntrack_ordered_list);
--static unsigned int ip_conntrack_next_id = 1;
--static unsigned int ip_conntrack_exp_next_id = 1;
-+unsigned int ip_conntrack_next_id = 1;
-+unsigned int ip_conntrack_exp_next_id = 1;
- #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
- struct notifier_block *ip_conntrack_chain = NULL;
- unsigned long ip_conntrack_event_cache[NR_CPUS];

Deleted: branches/netfilter-ha/linux-2.6/patches/export_hash_conntrack.patch
===================================================================
--- branches/netfilter-ha/linux-2.6/patches/export_hash_conntrack.patch	2005-01-02 22:40:48 UTC (rev 3550)
+++ branches/netfilter-ha/linux-2.6/patches/export_hash_conntrack.patch	2005-01-02 23:13:27 UTC (rev 3551)
@@ -1,38 +0,0 @@
-Index: linux-2.4.26-ct_sync/include/linux/netfilter_ipv4/ip_conntrack_core.h
-===================================================================
---- linux-2.4.26-ct_sync.orig/include/linux/netfilter_ipv4/ip_conntrack_core.h	2004-06-28 12:56:25.000000000 +0200
-+++ linux-2.4.26-ct_sync/include/linux/netfilter_ipv4/ip_conntrack_core.h	2004-06-28 12:56:29.000000000 +0200
-@@ -42,6 +42,8 @@
- __ip_conntrack_find(const struct ip_conntrack_tuple *tuple,
- 		    const struct ip_conntrack *ignored_conntrack);
- 
-+u_int32_t hash_conntrack(const struct ip_conntrack_tuple *tuple);
-+
- extern int __ip_conntrack_confirm(struct nf_ct_info *nfct);
- 
- /* Confirm a connection: returns NF_DROP if packet must be dropped. */
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_standalone.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/ip_conntrack_standalone.c	2004-06-28 12:56:25.000000000 +0200
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_standalone.c	2004-06-28 12:56:29.000000000 +0200
-@@ -533,6 +533,7 @@
- EXPORT_SYMBOL(ip_conntrack_ordered_list);
- EXPORT_SYMBOL(ip_conntrack_lock);
- EXPORT_SYMBOL(ip_conntrack_hash);
-+EXPORT_SYMBOL_GPL(hash_conntrack);
- EXPORT_SYMBOL(ip_conntrack_untracked);
- EXPORT_SYMBOL_GPL(ip_conntrack_find_get);
- EXPORT_SYMBOL_GPL(__ip_conntrack_find_get);
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_core.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/ip_conntrack_core.c	2004-06-28 12:56:25.000000000 +0200
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_core.c	2004-06-28 12:56:29.000000000 +0200
-@@ -123,7 +123,7 @@
- static int ip_conntrack_hash_rnd_initted;
- static unsigned int ip_conntrack_hash_rnd;
- 
--static u_int32_t
-+u_int32_t
- hash_conntrack(const struct ip_conntrack_tuple *tuple)
- {
- #if 0

Added: branches/netfilter-ha/linux-2.6/patches/export_ip_conntrack_clean_from_lists.patch
===================================================================
--- branches/netfilter-ha/linux-2.6/patches/export_ip_conntrack_clean_from_lists.patch	2005-01-02 22:40:48 UTC (rev 3550)
+++ branches/netfilter-ha/linux-2.6/patches/export_ip_conntrack_clean_from_lists.patch	2005-01-02 23:13:27 UTC (rev 3551)
@@ -0,0 +1,52 @@
+Index: linux-2.6.9/net/ipv4/netfilter/ip_conntrack_standalone.c
+===================================================================
+--- linux-2.6.9.orig/net/ipv4/netfilter/ip_conntrack_standalone.c	2004-12-15 21:25:16.000000000 +0100
++++ linux-2.6.9/net/ipv4/netfilter/ip_conntrack_standalone.c	2004-12-15 22:00:02.732832552 +0100
+@@ -914,4 +914,5 @@
+ EXPORT_SYMBOL(ip_conntrack_untracked);
+ EXPORT_SYMBOL_GPL(ip_conntrack_find_get);
+ EXPORT_SYMBOL_GPL(__ip_conntrack_find);
++EXPORT_SYMBOL_GPL(ip_conntrack_clean_from_lists);
+ EXPORT_SYMBOL_GPL(ip_conntrack_put);
+Index: linux-2.6.9/include/linux/netfilter_ipv4/ip_conntrack_core.h
+===================================================================
+--- linux-2.6.9.orig/include/linux/netfilter_ipv4/ip_conntrack_core.h	2004-12-15 21:25:16.000000000 +0100
++++ linux-2.6.9/include/linux/netfilter_ipv4/ip_conntrack_core.h	2004-12-15 22:00:31.513457232 +0100
+@@ -54,6 +54,8 @@
+ 	return ret;
+ }
+ 
++extern void ip_conntrack_clean_from_lists(struct ip_conntrack *ct);
++
+ extern struct list_head *ip_conntrack_hash;
+ extern struct list_head ip_conntrack_expect_list;
+ DECLARE_RWLOCK_EXTERN(ip_conntrack_lock);
+Index: linux-2.6.9/net/ipv4/netfilter/ip_conntrack_core.c
+===================================================================
+--- linux-2.6.9.orig/net/ipv4/netfilter/ip_conntrack_core.c	2004-12-15 21:25:16.000000000 +0100
++++ linux-2.6.9/net/ipv4/netfilter/ip_conntrack_core.c	2004-12-15 22:01:02.899685800 +0100
+@@ -266,12 +266,12 @@
+ 	}
+ }
+ 
+-static void
+-clean_from_lists(struct ip_conntrack *ct)
++void
++ip_conntrack_clean_from_lists(struct ip_conntrack *ct)
+ {
+ 	unsigned int ho, hr;
+ 	
+-	DEBUGP("clean_from_lists(%p)\n", ct);
++	DEBUGP("ip_conntrack_clean_from_lists(%p)\n", ct);
+ 	MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
+ 
+ 	ho = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+@@ -339,7 +339,7 @@
+ 
+ 	ip_conntrack_event(IPCT_DESTROY, ct);
+ 	WRITE_LOCK(&ip_conntrack_lock);
+-	clean_from_lists(ct);
++	ip_conntrack_clean_from_lists(ct);
+ 	WRITE_UNLOCK(&ip_conntrack_lock);
+ 	ip_conntrack_put(ct);
+ }

Modified: branches/netfilter-ha/linux-2.6/patches/export_ip_conntrack_find.patch
===================================================================
--- branches/netfilter-ha/linux-2.6/patches/export_ip_conntrack_find.patch	2005-01-02 22:40:48 UTC (rev 3550)
+++ branches/netfilter-ha/linux-2.6/patches/export_ip_conntrack_find.patch	2005-01-02 23:13:27 UTC (rev 3551)
@@ -1,36 +1,34 @@
-Index: linux-2.4.26-ct_sync/include/linux/netfilter_ipv4/ip_conntrack_core.h
+Index: linux-2.6.9/net/ipv4/netfilter/ip_conntrack_standalone.c
 ===================================================================
---- linux-2.4.26-ct_sync.orig/include/linux/netfilter_ipv4/ip_conntrack_core.h	2004-06-28 12:56:18.000000000 +0200
-+++ linux-2.4.26-ct_sync/include/linux/netfilter_ipv4/ip_conntrack_core.h	2004-06-28 12:56:25.000000000 +0200
-@@ -37,7 +37,10 @@
- struct ip_conntrack_tuple_hash *
- __ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple,
-                         const struct ip_conntrack *ignored_conntrack);
--
-+/* non-locked, non-referenced */
-+struct ip_conntrack_tuple_hash *
-+__ip_conntrack_find(const struct ip_conntrack_tuple *tuple,
-+		    const struct ip_conntrack *ignored_conntrack);
- 
- extern int __ip_conntrack_confirm(struct nf_ct_info *nfct);
- 
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_standalone.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/ip_conntrack_standalone.c	2004-06-28 12:56:18.000000000 +0200
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_standalone.c	2004-06-28 12:56:25.000000000 +0200
-@@ -536,6 +536,7 @@
+--- linux-2.6.9.orig/net/ipv4/netfilter/ip_conntrack_standalone.c	2004-12-09 23:24:59.920244832 +0100
++++ linux-2.6.9/net/ipv4/netfilter/ip_conntrack_standalone.c	2004-12-09 23:34:40.690954264 +0100
+@@ -913,4 +913,5 @@
+ EXPORT_SYMBOL(ip_conntrack_hash);
  EXPORT_SYMBOL(ip_conntrack_untracked);
  EXPORT_SYMBOL_GPL(ip_conntrack_find_get);
- EXPORT_SYMBOL_GPL(__ip_conntrack_find_get);
 +EXPORT_SYMBOL_GPL(__ip_conntrack_find);
  EXPORT_SYMBOL_GPL(ip_conntrack_put);
- EXPORT_SYMBOL_GPL(ip_conntrack_helpers);
- #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_core.c
+Index: linux-2.6.9/include/linux/netfilter_ipv4/ip_conntrack_core.h
 ===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/ip_conntrack_core.c	2004-06-28 12:56:18.000000000 +0200
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_core.c	2004-06-28 12:56:25.000000000 +0200
-@@ -414,7 +414,7 @@
+--- linux-2.6.9.orig/include/linux/netfilter_ipv4/ip_conntrack_core.h	2004-12-09 23:21:07.153630736 +0100
++++ linux-2.6.9/include/linux/netfilter_ipv4/ip_conntrack_core.h	2004-12-09 23:33:26.697203024 +0100
+@@ -34,6 +34,11 @@
+ ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple,
+ 		      const struct ip_conntrack *ignored_conntrack);
+ 
++/* Non-locked, non-referenced version, for ct_sync */
++struct ip_conntrack_tuple_hash *
++__ip_conntrack_find(const struct ip_conntrack_tuple *tuple,
++		    const struct ip_conntrack *ignored_conntrack);
++
+ extern int __ip_conntrack_confirm(struct sk_buff *skb);
+ 
+ /* Confirm a connection: returns NF_DROP if packet must be dropped. */
+Index: linux-2.6.9/net/ipv4/netfilter/ip_conntrack_core.c
+===================================================================
+--- linux-2.6.9.orig/net/ipv4/netfilter/ip_conntrack_core.c	2004-12-09 23:24:21.091147752 +0100
++++ linux-2.6.9/net/ipv4/netfilter/ip_conntrack_core.c	2004-12-09 23:34:08.402862800 +0100
+@@ -354,7 +354,7 @@
  		&& ip_ct_tuple_equal(tuple, &i->tuple);
  }
  

Modified: branches/netfilter-ha/linux-2.6/patches/export_ip_conntrack_helpers.patch
===================================================================
--- branches/netfilter-ha/linux-2.6/patches/export_ip_conntrack_helpers.patch	2005-01-02 22:40:48 UTC (rev 3550)
+++ branches/netfilter-ha/linux-2.6/patches/export_ip_conntrack_helpers.patch	2005-01-02 23:13:27 UTC (rev 3551)
@@ -1,73 +1,50 @@
-Index: linux-2.4.26-ct_sync/include/linux/netfilter_ipv4/ip_conntrack_core.h
+Index: linux-2.6.9/net/ipv4/netfilter/ip_conntrack_standalone.c
 ===================================================================
---- linux-2.4.26-ct_sync.orig/include/linux/netfilter_ipv4/ip_conntrack_core.h	2004-06-24 15:35:16.000000000 +0200
-+++ linux-2.4.26-ct_sync/include/linux/netfilter_ipv4/ip_conntrack_core.h	2004-06-28 12:56:18.000000000 +0200
-@@ -53,6 +53,7 @@
- extern struct list_head *ip_conntrack_hash;
- extern struct list_head ip_conntrack_ordered_list;
- extern struct list_head ip_conntrack_expect_list;
-+extern struct list_head ip_conntrack_helpers;
- DECLARE_RWLOCK_EXTERN(ip_conntrack_lock);
- #endif /* _IP_CONNTRACK_CORE_H */
- 
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_standalone.c
+--- linux-2.6.9.orig/net/ipv4/netfilter/ip_conntrack_standalone.c	2004-11-27 00:44:47.000000000 +0100
++++ linux-2.6.9/net/ipv4/netfilter/ip_conntrack_standalone.c	2004-12-09 23:24:59.920244832 +0100
+@@ -898,6 +898,7 @@
+ EXPORT_SYMBOL(ip_ct_protos);
+ EXPORT_SYMBOL(ip_ct_find_proto);
+ EXPORT_SYMBOL(ip_ct_find_helper);
++EXPORT_SYMBOL_GPL(__ip_ct_find_helper_by_name);
+ EXPORT_SYMBOL(ip_conntrack_expect_alloc);
+ EXPORT_SYMBOL(ip_conntrack_expect_related);
+ EXPORT_SYMBOL(ip_conntrack_change_expect);
+Index: linux-2.6.9/net/ipv4/netfilter/ip_conntrack_core.c
 ===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/ip_conntrack_standalone.c	2004-06-28 12:56:01.000000000 +0200
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_standalone.c	2004-06-28 12:56:18.000000000 +0200
-@@ -537,6 +537,7 @@
- EXPORT_SYMBOL_GPL(ip_conntrack_find_get);
- EXPORT_SYMBOL_GPL(__ip_conntrack_find_get);
- EXPORT_SYMBOL_GPL(ip_conntrack_put);
-+EXPORT_SYMBOL_GPL(ip_conntrack_helpers);
- #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
- EXPORT_SYMBOL(ip_conntrack_chain);
- EXPORT_SYMBOL(ip_conntrack_event_cache);
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_core.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/ip_conntrack_core.c	2004-06-28 12:56:01.000000000 +0200
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_core.c	2004-06-28 12:56:18.000000000 +0200
-@@ -62,7 +62,7 @@
- void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack) = NULL;
- LIST_HEAD(ip_conntrack_expect_list);
- LIST_HEAD(protocol_list);
--static LIST_HEAD(helpers);
-+LIST_HEAD(ip_conntrack_helpers);
- unsigned int ip_conntrack_htable_size = 0;
- int ip_conntrack_max = 0;
- static atomic_t ip_conntrack_count = ATOMIC_INIT(0);
-@@ -693,7 +693,7 @@
- 
- struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple)
- {
--	return LIST_FIND(&helpers, helper_cmp,
-+	return LIST_FIND(&ip_conntrack_helpers, helper_cmp,
- 			 struct ip_conntrack_helper *,
+--- linux-2.6.9.orig/net/ipv4/netfilter/ip_conntrack_core.c	2004-11-27 00:44:47.000000000 +0100
++++ linux-2.6.9/net/ipv4/netfilter/ip_conntrack_core.c	2004-12-09 23:24:21.091147752 +0100
+@@ -521,6 +521,20 @@
  			 tuple);
  }
-@@ -1217,7 +1217,7 @@
  
- 	conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
- 	if (!conntrack->master)
--		conntrack->helper = LIST_FIND(&helpers, helper_cmp,
-+		conntrack->helper = LIST_FIND(&ip_conntrack_helpers, helper_cmp,
- 					      struct ip_conntrack_helper *,
- 					      newreply);
- 	WRITE_UNLOCK(&ip_conntrack_lock);
-@@ -1230,7 +1230,7 @@
- 	MOD_INC_USE_COUNT;
++static inline int
++helper_name_cmp(const struct ip_conntrack_helper *helper,
++		const char *name)
++{
++	return strcmp(helper->name, name);
++}
++
++struct ip_conntrack_helper *
++__ip_ct_find_helper_by_name(const char *name)
++{
++	return LIST_FIND(&helpers, helper_name_cmp,
++			 struct ip_conntrack_helper *, name);
++}
++
+ /* Allocate a new conntrack: we return -ENOMEM if classification
+    failed due to stress.  Otherwise it really is unclassifiable. */
+ static struct ip_conntrack_tuple_hash *
+Index: linux-2.6.9/include/linux/netfilter_ipv4/ip_conntrack_helper.h
+===================================================================
+--- linux-2.6.9.orig/include/linux/netfilter_ipv4/ip_conntrack_helper.h	2004-08-14 07:36:17.000000000 +0200
++++ linux-2.6.9/include/linux/netfilter_ipv4/ip_conntrack_helper.h	2004-12-09 23:21:04.976961640 +0100
+@@ -35,6 +35,8 @@
  
- 	WRITE_LOCK(&ip_conntrack_lock);
--	list_prepend(&helpers, me);
-+	list_prepend(&ip_conntrack_helpers, me);
- 	WRITE_UNLOCK(&ip_conntrack_lock);
+ extern struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple);
  
- 	return 0;
-@@ -1255,7 +1255,7 @@
++/* Lookup conntrack helper by name: for ct_sync */
++extern struct ip_conntrack_helper *__ip_ct_find_helper_by_name(const char *name);
  
- 	/* Need write lock here, to delete helper. */
- 	WRITE_LOCK(&ip_conntrack_lock);
--	LIST_DELETE(&helpers, me);
-+	LIST_DELETE(&ip_conntrack_helpers, me);
- 
- 	/* Get rid of expecteds, set helpers to NULL. */
- 	for (i = 0; i < ip_conntrack_htable_size; i++)
+ /* Allocate space for an expectation: this is mandatory before calling 
+    ip_conntrack_expect_related. */

Deleted: branches/netfilter-ha/linux-2.6/patches/export_ip_nat_hash.patch
===================================================================
--- branches/netfilter-ha/linux-2.6/patches/export_ip_nat_hash.patch	2005-01-02 22:40:48 UTC (rev 3550)
+++ branches/netfilter-ha/linux-2.6/patches/export_ip_nat_hash.patch	2005-01-02 23:13:27 UTC (rev 3551)
@@ -1,11 +0,0 @@
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_nat_standalone.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/ip_nat_standalone.c	Mon Jun 14 15:08:55 2004
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_nat_standalone.c	Mon Jun 14 15:08:58 2004
-@@ -363,4 +363,6 @@
- EXPORT_SYMBOL(ip_nat_used_tuple);
- EXPORT_SYMBOL_GPL(ip_nat_helpers);
- EXPORT_SYMBOL_GPL(ip_nat_lock);
-+EXPORT_SYMBOL_GPL(place_in_hashes);
-+EXPORT_SYMBOL_GPL(replace_in_hashes);
- MODULE_LICENSE("GPL");

Modified: branches/netfilter-ha/linux-2.6/patches/export_ip_nat_helpers.patch
===================================================================
--- branches/netfilter-ha/linux-2.6/patches/export_ip_nat_helpers.patch	2005-01-02 22:40:48 UTC (rev 3550)
+++ branches/netfilter-ha/linux-2.6/patches/export_ip_nat_helpers.patch	2005-01-02 23:13:27 UTC (rev 3551)
@@ -1,70 +1,49 @@
-Index: linux-2.4.26-ct_sync/include/linux/netfilter_ipv4/ip_nat_core.h
+Index: linux-2.6.9/include/linux/netfilter_ipv4/ip_nat_helper.h
 ===================================================================
---- linux-2.4.26-ct_sync.orig/include/linux/netfilter_ipv4/ip_nat_core.h	Mon Dec 11 22:31:32 2000
-+++ linux-2.4.26-ct_sync/include/linux/netfilter_ipv4/ip_nat_core.h	Mon Jun 14 15:08:42 2004
-@@ -30,4 +30,5 @@
- extern struct ip_nat_protocol ip_nat_protocol_tcp;
- extern struct ip_nat_protocol ip_nat_protocol_udp;
- extern struct ip_nat_protocol ip_nat_protocol_icmp;
-+extern struct list_head ip_nat_helpers;
- #endif /* _IP_NAT_CORE_H */
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_nat_standalone.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/ip_nat_standalone.c	Wed Apr 14 15:05:41 2004
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_nat_standalone.c	Mon Jun 14 15:08:42 2004
-@@ -361,4 +361,5 @@
- EXPORT_SYMBOL(ip_nat_mangle_tcp_packet);
- EXPORT_SYMBOL(ip_nat_mangle_udp_packet);
- EXPORT_SYMBOL(ip_nat_used_tuple);
-+EXPORT_SYMBOL_GPL(ip_nat_helpers);
- MODULE_LICENSE("GPL");
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_nat_core.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/ip_nat_core.c	Mon Jun 14 14:55:19 2004
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_nat_core.c	Mon Jun 14 15:08:42 2004
-@@ -43,7 +43,7 @@
- static struct list_head *bysource;
- static struct list_head *byipsproto;
- LIST_HEAD(protos);
--LIST_HEAD(helpers);
-+LIST_HEAD(ip_nat_helpers);
+--- linux-2.6.9.orig/include/linux/netfilter_ipv4/ip_nat_helper.h	2004-12-09 23:13:19.899664136 +0100
++++ linux-2.6.9/include/linux/netfilter_ipv4/ip_nat_helper.h	2004-12-09 23:13:41.428391272 +0100
+@@ -47,6 +47,10 @@
+ extern struct ip_nat_helper *
+ __ip_nat_find_helper(const struct ip_conntrack_tuple *tuple);
  
- extern struct ip_nat_protocol unknown_nat_protocol;
- 
-@@ -636,7 +636,7 @@
- 
- 	/* If there's a helper, assign it; based on new tuple. */
- 	if (!conntrack->master)
--		info->helper = LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,
-+		info->helper = LIST_FIND(&ip_nat_helpers, helper_cmp, struct ip_nat_helper *,
- 					 &reply);
- 
- 	/* It's done. */
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_nat_helper.c
++/* For ct_sync: look up helper by name */
++extern struct ip_nat_helper *
++__ip_nat_find_helper_by_name(const char *name);
++
+ /* These return true or false. */
+ extern int ip_nat_mangle_tcp_packet(struct sk_buff **skb,
+ 				struct ip_conntrack *ct,
+Index: linux-2.6.9/net/ipv4/netfilter/ip_nat_helper.c
 ===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/ip_nat_helper.c	Fri Nov 28 19:26:21 2003
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_nat_helper.c	Mon Jun 14 15:08:42 2004
-@@ -508,10 +508,10 @@
- 		}
- 	}
+--- linux-2.6.9.orig/net/ipv4/netfilter/ip_nat_helper.c	2004-11-27 00:25:43.000000000 +0100
++++ linux-2.6.9/net/ipv4/netfilter/ip_nat_helper.c	2004-12-09 23:11:08.798594528 +0100
+@@ -455,6 +455,19 @@
+ 	return ret;
+ }
+ 
++static inline int
++helper_name_cmp(const struct ip_nat_helper *helper,
++		const char *name)
++{
++	return strcmp(helper->name, name);
++}
++
++struct ip_nat_helper *
++__ip_nat_find_helper_by_name(const char *name)
++{
++	return LIST_FIND(&helpers, helper_name_cmp, struct ip_nat_helper *, name);
++}
++
+ void ip_nat_helper_unregister(struct ip_nat_helper *me)
+ {
  	WRITE_LOCK(&ip_nat_lock);
--	if (LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,&me->tuple))
-+	if (LIST_FIND(&ip_nat_helpers, helper_cmp, struct ip_nat_helper *,&me->tuple))
- 		ret = -EBUSY;
- 	else {
--		list_prepend(&helpers, me);
-+		list_prepend(&ip_nat_helpers, me);
- 		MOD_INC_USE_COUNT;
- 	}
- 	WRITE_UNLOCK(&ip_nat_lock);
-@@ -537,8 +537,8 @@
- 	
- 	WRITE_LOCK(&ip_nat_lock);
- 	/* Autoloading conntrack helper might have failed */
--	if (LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,&me->tuple)) {
--		LIST_DELETE(&helpers, me);
-+	if (LIST_FIND(&ip_nat_helpers, helper_cmp, struct ip_nat_helper *,&me->tuple)) {
-+		LIST_DELETE(&ip_nat_helpers, me);
- 		found = 1;
- 	}
- 	WRITE_UNLOCK(&ip_nat_lock);
+Index: linux-2.6.9/net/ipv4/netfilter/ip_nat_standalone.c
+===================================================================
+--- linux-2.6.9.orig/net/ipv4/netfilter/ip_nat_standalone.c	2004-11-27 00:25:44.000000000 +0100
++++ linux-2.6.9/net/ipv4/netfilter/ip_nat_standalone.c	2004-12-09 23:11:43.402333960 +0100
+@@ -391,4 +391,5 @@
+ EXPORT_SYMBOL(ip_nat_used_tuple);
+ EXPORT_SYMBOL(ip_nat_find_helper);
+ EXPORT_SYMBOL(__ip_nat_find_helper);
++EXPORT_SYMBOL_GPL(__ip_nat_find_helper_by_name);
+ MODULE_LICENSE("GPL");

Deleted: branches/netfilter-ha/linux-2.6/patches/export_ip_nat_lock.patch
===================================================================
--- branches/netfilter-ha/linux-2.6/patches/export_ip_nat_lock.patch	2005-01-02 22:40:48 UTC (rev 3550)
+++ branches/netfilter-ha/linux-2.6/patches/export_ip_nat_lock.patch	2005-01-02 23:13:27 UTC (rev 3551)
@@ -1,10 +0,0 @@
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_nat_standalone.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/ip_nat_standalone.c	Mon Jun 14 15:08:42 2004
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_nat_standalone.c	Mon Jun 14 15:08:55 2004
-@@ -362,4 +362,5 @@
- EXPORT_SYMBOL(ip_nat_mangle_udp_packet);
- EXPORT_SYMBOL(ip_nat_used_tuple);
- EXPORT_SYMBOL_GPL(ip_nat_helpers);
-+EXPORT_SYMBOL_GPL(ip_nat_lock);
- MODULE_LICENSE("GPL");

Added: branches/netfilter-ha/linux-2.6/patches/export_ip_nat_lock_and_hash.patch
===================================================================
--- branches/netfilter-ha/linux-2.6/patches/export_ip_nat_lock_and_hash.patch	2005-01-02 22:40:48 UTC (rev 3550)
+++ branches/netfilter-ha/linux-2.6/patches/export_ip_nat_lock_and_hash.patch	2005-01-02 23:13:27 UTC (rev 3551)
@@ -0,0 +1,11 @@
+Index: linux-2.6.9/net/ipv4/netfilter/ip_nat_standalone.c
+===================================================================
+--- linux-2.6.9.orig/net/ipv4/netfilter/ip_nat_standalone.c	2004-12-09 23:25:14.341052536 +0100
++++ linux-2.6.9/net/ipv4/netfilter/ip_nat_standalone.c	2004-12-10 00:02:24.684988720 +0100
+@@ -392,4 +392,6 @@
+ EXPORT_SYMBOL(ip_nat_find_helper);
+ EXPORT_SYMBOL(__ip_nat_find_helper);
+ EXPORT_SYMBOL_GPL(__ip_nat_find_helper_by_name);
++EXPORT_SYMBOL_GPL(ip_nat_lock);
++EXPORT_SYMBOL_GPL(place_in_hashes);
+ MODULE_LICENSE("GPL");

Deleted: branches/netfilter-ha/linux-2.6/patches/kgdb-1.9.patch
===================================================================
--- branches/netfilter-ha/linux-2.6/patches/kgdb-1.9.patch	2005-01-02 22:40:48 UTC (rev 3550)
+++ branches/netfilter-ha/linux-2.6/patches/kgdb-1.9.patch	2005-01-02 23:13:27 UTC (rev 3551)
@@ -1,4698 +0,0 @@
-%patch
-Index: linux-2.4.26-ct_sync/kernel/Makefile
-===================================================================
---- linux-2.4.26-ct_sync.orig/kernel/Makefile	2001-09-17 06:22:40.000000000 +0200
-+++ linux-2.4.26-ct_sync/kernel/Makefile	2004-06-28 12:56:07.000000000 +0200
-@@ -19,6 +19,7 @@
- obj-$(CONFIG_UID16) += uid16.o
- obj-$(CONFIG_MODULES) += ksyms.o
- obj-$(CONFIG_PM) += pm.o
-+obj-$(CONFIG_KGDB) += kgdbstub.o
- 
- ifneq ($(CONFIG_IA64),y)
- # According to Alan Modra <alan at linuxcare.com.au>, the -fno-omit-frame-pointer is
-Index: linux-2.4.26-ct_sync/kernel/module.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/kernel/module.c	2003-08-25 13:44:44.000000000 +0200
-+++ linux-2.4.26-ct_sync/kernel/module.c	2004-06-28 12:56:07.000000000 +0200
-@@ -57,6 +57,8 @@
- 
- #endif	/* defined(CONFIG_MODULES) || defined(CONFIG_KALLSYMS) */
- 
-+void module_event (void);
-+
- /* inter_module functions are always available, even when the kernel is
-  * compiled without modules.  Consumers of inter_module_xxx routines
-  * will always work, even when both are built into the kernel, this
-@@ -560,7 +562,9 @@
- 	/* Initialize the module.  */
- 	atomic_set(&mod->uc.usecount,1);
- 	mod->flags |= MOD_INITIALIZING;
-+	module_event();
- 	if (mod->init && (error = mod->init()) != 0) {
-+		module_event();
- 		atomic_set(&mod->uc.usecount,0);
- 		mod->flags &= ~MOD_INITIALIZING;
- 		if (error > 0)	/* Buggy module */
-@@ -678,6 +682,7 @@
- 	error = 0;
- out:
- 	unlock_kernel();
-+	module_event();
- 	return error;
- }
- 
-@@ -1248,6 +1253,13 @@
- 	show:	s_show
- };
- 
-+/* GDB can place a breakpoint in this function to probe changes in the list of
-+ * modules loaded in a kernel. */
-+void module_event (void)
-+{
-+	/* Do nothing */
-+}
-+
- #else		/* CONFIG_MODULES */
- 
- /* Dummy syscalls for people who don't want modules */
-Index: linux-2.4.26-ct_sync/kernel/kgdbstub.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/kernel/kgdbstub.c	2004-06-16 09:19:51.000000000 +0200
-+++ linux-2.4.26-ct_sync/kernel/kgdbstub.c	2004-06-28 12:56:07.000000000 +0200
-@@ -0,0 +1,1074 @@
-+/*
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License as published by the
-+ * Free Software Foundation; either version 2, or (at your option) any
-+ * later version.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-+ * General Public License for more details.
-+ *
-+ */
-+
-+/*
-+ * Generic KGDB Support
-+ * Copyright (C) 2002-2003 Timesys Corporation
-+ * Implemented by Anurekh Saxena (anurekh.saxena at timesys.com)
-+ * 
-+ * Copyright (C) 2000-2001 VERITAS Software Corporation.
-+ * Contributor:     Lake Stevens Instrument Division
-+ * Written by:      Glenn Engel
-+ *  
-+ * Modified for 386 by Jim Kingdon, Cygnus Support.
-+ * Origianl kgdb, compatibility with 2.1.xx kernel by David Grothe <dave at gcom.com>
-+ * Integrated into 2.2.5 kernel by Tigran Aivazian <tigran at sco.com>
-+ *  
-+ * thread support, support for multiple processors,support for ia-32(x86) 
-+ * hardware debugging, Console support, handling nmi watchdog
-+ * - Amit S. Kale ( amitkale at emsyssoft.com )
-+ *  
-+ */
-+
-+#include <linux/string.h>
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <linux/smp.h>
-+#include <linux/spinlock.h>
-+#include <linux/delay.h>
-+#include <linux/mm.h>
-+#include <asm/system.h>
-+#include <asm/ptrace.h>		/* for linux pt_regs struct */
-+#include <asm/uaccess.h>
-+#include <linux/kgdb.h>
-+#include <asm/atomic.h>
-+ 
-+#ifdef CONFIG_GDB_CONSOLE
-+#include <linux/console.h>
-+#endif
-+ 
-+#include <linux/init.h>
-+
-+
-+
-+/* DEBUGGING THE DEBUGGER */
-+#undef KGDB_DEG
-+/**************************/
-+
-+struct kgdb_arch *kgdb_ops = &arch_kgdb_ops;
-+gdb_breakpoint_t kgdb_break[MAX_BREAKPOINTS];
-+
-+int kgdb_initialized = 0;
-+static const char hexchars[] = "0123456789abcdef";
-+
-+int get_char(char *addr, unsigned char *data, int can_fault);
-+int set_char(char *addr, int data, int can_fault);
-+
-+spinlock_t slavecpulocks[KGDB_MAX_NO_CPUS];
-+volatile int procindebug[KGDB_MAX_NO_CPUS];
-+volatile unsigned kgdb_step;
-+atomic_t kgdb_lock;
-+atomic_t kgdb_setting_breakpoint;
-+atomic_t kgdb_killed_or_detached;
-+atomic_t kgdb_might_be_resumed;
-+struct task_struct *kgdb_usethread, *kgdb_contthread;
-+
-+/* 
-+ * Indicate to caller of mem2hex or hex2mem that there has been an
-+ * error.  
-+ */
-+volatile int kgdb_memerr = 0;
-+volatile int kgdb_memerr_expected = 0;
-+
-+/* This will point to kgdb_handle_exception by default.
-+ * The architecture code can override this in its init function
-+ */
-+gdb_debug_hook *linux_debug_hook;
-+
-+
-+static char remcomInBuffer[BUFMAX];
-+static char remcomOutBuffer[BUFMAX];
-+static short error;
-+
-+int hex(char ch)
-+{
-+	if ((ch >= 'a') && (ch <= 'f'))
-+		return (ch - 'a' + 10);
-+	if ((ch >= '0') && (ch <= '9'))
-+		return (ch - '0');
-+	if ((ch >= 'A') && (ch <= 'F'))
-+		return (ch - 'A' + 10);
-+	return (-1);
-+}
-+
-+
-+/* scan for the sequence $<data>#<checksum>	*/
-+
-+void getpacket(char *buffer)
-+{
-+	unsigned char checksum;
-+	unsigned char xmitcsum;
-+	int i;
-+	int count;
-+	char ch;
-+
-+	do {
-+	/* wait around for the start character, ignore all other characters */
-+		while ((ch = (getDebugChar() & 0x7f)) != '$');
-+		checksum = 0;
-+		xmitcsum = -1;
-+
-+		count = 0;
-+
-+		/* now, read until a # or end of buffer is found */
-+		while (count < BUFMAX) {
-+			ch = getDebugChar() & 0x7f;
-+			if (ch == '#')
-+				break;
-+			checksum = checksum + ch;
-+			buffer[count] = ch;
-+			count = count + 1;
-+		}
-+		buffer[count] = 0;
-+
-+		if (ch == '#') {
-+			xmitcsum = hex(getDebugChar() & 0x7f) << 4;
-+			xmitcsum += hex(getDebugChar() & 0x7f);
-+
-+			if (checksum != xmitcsum)
-+				putDebugChar('-');	/* failed checksum */
-+			else {
-+				putDebugChar('+');	/* successful transfer */
-+				/* if a sequence char is present, reply the sequence ID */
-+				if (buffer[2] == ':') {
-+					putDebugChar(buffer[0]);
-+					putDebugChar(buffer[1]);
-+					/* remove sequence chars from buffer */
-+					count = strlen(buffer);
-+					for (i = 3; i <= count; i++)
-+						buffer[i - 3] = buffer[i];
-+				}
-+			}
-+		}
-+	} while (checksum != xmitcsum);
-+
-+}
-+
-+
-+/* send the packet in buffer.*/
-+void putpacket(char *buffer)
-+{
-+	unsigned char checksum;
-+	int count;
-+	char ch;
-+
-+	/*  $<packet info>#<checksum>. */
-+	do {
-+		putDebugChar('$');
-+		checksum = 0;
-+		count = 0;
-+
-+		while ((ch = buffer[count])) {
-+			putDebugChar(ch);
-+			checksum += ch;
-+			count += 1;
-+		}
-+
-+		putDebugChar('#');
-+		putDebugChar(hexchars[checksum >> 4]);
-+		putDebugChar(hexchars[checksum % 16]);
-+
-+	} while ((getDebugChar() & 0x7f) != '+');
-+
-+}
-+
-+/* convert the memory pointed to by mem into hex, placing result in buf */
-+/* return a pointer to the last char put in buf (null) */
-+/* If MAY_FAULT is non-zero, then we should set kgdb_memerr in response to
-+   a fault; if zero treat a fault like any other fault in the stub.  */
-+
-+char *mem2hex(char *mem, char *buf, int count, int can_fault)
-+{
-+	int i;
-+	unsigned char ch;
-+	
-+	for (i = 0; i < count; i++) {
-+
-+		if (get_char(mem++, &ch, can_fault) < 0) 
-+			break;
-+		
-+		*buf++ = hexchars[ch >> 4];
-+		*buf++ = hexchars[ch % 16];
-+	}
-+	*buf = 0;
-+	return (buf);
-+}
-+
-+/* convert the hex array pointed to by buf into binary to be placed in mem */
-+/* return a pointer to the character AFTER the last byte written */
-+
-+char *hex2mem(char *buf, char *mem, int count, int can_fault)
-+{
-+	int i;
-+	unsigned char ch;
-+	
-+	for (i = 0; i < count; i++) {
-+		ch = hex(*buf++) << 4;
-+		ch = ch + hex(*buf++);
-+		if (set_char(mem++, ch, can_fault) < 0) 
-+			break;
-+	}
-+	return (mem);
-+}
-+
-+
-+/*
-+ * WHILE WE FIND NICE HEX CHARS, BUILD AN INT 
-+ * RETURN NUMBER OF CHARS PROCESSED           
-+ */
-+int hexToInt(char **ptr, int *intValue)
-+{
-+	int numChars = 0;
-+	int hexValue;
-+
-+	*intValue = 0;
-+
-+	while (**ptr) {
-+		hexValue = hex(**ptr);
-+		if (hexValue >= 0) {
-+			*intValue = (*intValue << 4) | hexValue;
-+			numChars++;
-+		} else
-+			break;
-+
-+		(*ptr)++;
-+	}
-+
-+	return (numChars);
-+}
-+
-+static int stubhex(int ch)
-+{
-+	if (ch >= 'a' && ch <= 'f')
-+		return ch - 'a' + 10;
-+	if (ch >= '0' && ch <= '9')
-+		return ch - '0';
-+	if (ch >= 'A' && ch <= 'F')
-+		return ch - 'A' + 10;
-+	return -1;
-+}
-+
-+
-+static int stub_unpack_int(char *buff, int fieldlength)
-+{
-+	int nibble;
-+	int retval = 0;
-+
-+	while (fieldlength) {
-+		nibble = stubhex(*buff++);
-+		retval |= nibble;
-+		fieldlength--;
-+		if (fieldlength)
-+			retval = retval << 4;
-+	}
-+	return retval;
-+}
-+
-+static inline char *pack_hex_byte(char *pkt, int byte)
-+{
-+	*pkt++ = hexchars[(byte >> 4) & 0xf];
-+	*pkt++ = hexchars[(byte & 0xf)];
-+	return pkt;
-+}
-+
-+#define BUF_THREAD_ID_SIZE 16
-+
-+static char *pack_threadid(char *pkt, threadref *id)
-+{
-+	char *limit;
-+	unsigned char *altid;
-+
-+	altid = (unsigned char *) id;
-+	limit = pkt + BUF_THREAD_ID_SIZE;
-+	while (pkt < limit)
-+		pkt = pack_hex_byte(pkt, *altid++);
-+
-+	return pkt;
-+}
-+
-+static char *unpack_byte(char *buf, int *value)
-+{
-+	*value = stub_unpack_int(buf, 2);
-+	return buf + 2;
-+}
-+
-+static char *unpack_threadid(char *inbuf, threadref *id)
-+{
-+	char *altref;
-+	char *limit = inbuf + BUF_THREAD_ID_SIZE;
-+	int x, y;
-+
-+	altref = (char *) id;
-+
-+	while (inbuf < limit) {
-+		x = stubhex(*inbuf++);
-+		y = stubhex(*inbuf++);
-+		*altref++ = (x << 4) | y;
-+	}
-+	return inbuf;
-+}
-+
-+void int_to_threadref(threadref *id, int value)
-+{
-+	unsigned char *scan;
-+
-+	scan = (unsigned char *) id;
-+	{
-+		int i = 4;
-+		while (i--)
-+			*scan++ = 0;
-+	}
-+	*scan++ = (value >> 24) & 0xff;
-+	*scan++ = (value >> 16) & 0xff;
-+	*scan++ = (value >> 8) & 0xff;
-+	*scan++ = (value & 0xff);
-+}
-+
-+static int threadref_to_int(threadref * ref)
-+{
-+	int i, value = 0;
-+	unsigned char *scan;
-+
-+	scan = (char *) ref;
-+	scan += 4;
-+	i = 4;
-+	while (i-- > 0)
-+		value = (value << 8) | ((*scan++) & 0xff);
-+	return value;
-+}
-+
-+
-+struct task_struct *getthread(int tid)
-+{
-+#if CONFIG_SMP
-+	if (tid >= PID_MAX && tid < PID_MAX + smp_num_cpus)
-+		return init_tasks[tid - PID_MAX];
-+#else
-+	if (tid == PID_MAX)
-+		tid = 0;
-+#endif
-+	return find_task_by_pid(tid);
-+}
-+
-+#ifdef CONFIG_SMP
-+void gdb_wait(struct pt_regs *regs)
-+{
-+	unsigned flags;
-+	int processor;
-+
-+	local_irq_save(flags);
-+	processor = smp_processor_id();
-+	procindebug[processor] = 1;
-+	current->thread.kgdbregs = regs;
-+
-+	/* Wait till master processor goes completely into the debugger */
-+	while (!procindebug[atomic_read(&kgdb_lock) - 1]) {
-+		int i = 10;	/* an arbitrary number */
-+
-+		while (--i)
-+			asm volatile ("nop": : : "memory");
-+		barrier();
-+	}
-+
-+	/* Wait till master processor is done with debugging */
-+	spin_lock(slavecpulocks + processor);
-+
-+	/* This has been taken from x86 kgdb implementation and
-+	 * will be needed by architectures that have SMP support
-+	 */
-+	if (kgdb_ops->correct_hw_break)
-+		kgdb_ops->correct_hw_break();
-+
-+	/* Signal the master processor that we are done */
-+	procindebug[processor] = 0;
-+	spin_unlock(slavecpulocks + processor);
-+	local_irq_restore(flags);
-+}
-+
-+#endif
-+
-+static void get_mem (char *addr, unsigned char *buf, int count)
-+{
-+	while (count) {
-+		if(get_char(addr++, buf, 1) <  0) 
-+			return;
-+		buf++;
-+		count--;
-+	}
-+}
-+
-+static void set_mem (char *addr,unsigned char *buf, int count)
-+{
-+	while (count) {
-+		if (set_char(addr++,*buf++, 1) < 0) 
-+			return;
-+		count--;
-+	}
-+}
-+
-+
-+
-+static int set_break (unsigned long addr)
-+{
-+	int i, breakno = -1;
-+
-+	for (i = 0; i < MAX_BREAKPOINTS; i++) {
-+		if ((kgdb_break[i].state == bp_enabled) &&
-+		    (kgdb_break[i].bpt_addr == addr)) {
-+			breakno = -1;
-+			break;
-+		}
-+
-+		if (kgdb_break[i].state == bp_disabled) {
-+			if ((breakno == -1) || (kgdb_break[i].bpt_addr == addr))
-+				breakno = i;
-+		}
-+	}
-+	if (breakno == -1)
-+		return -1;
-+
-+	get_mem((char *)addr, kgdb_break[breakno].saved_instr, BREAK_INSTR_SIZE);
-+	if (kgdb_memerr)
-+		return -1;
-+
-+	set_mem((char *)addr, kgdb_ops->gdb_bpt_instr, BREAK_INSTR_SIZE);
-+	flush_cache_range (current->mm, addr, addr + BREAK_INSTR_SIZE);
-+	flush_icache_range (addr, addr + BREAK_INSTR_SIZE);
-+	if (kgdb_memerr)
-+		return -1;
-+
-+	kgdb_break[breakno].state = bp_enabled;
-+	kgdb_break[breakno].type = bp_breakpoint;
-+	kgdb_break[breakno].bpt_addr = addr;
-+	
-+	return 0;
-+}	
-+
-+static int remove_break (unsigned addr)
-+{
-+	int i;
-+
-+	for (i=0; i < MAX_BREAKPOINTS; i++) {
-+		if ((kgdb_break[i].state == bp_enabled) &&
-+		   (kgdb_break[i].bpt_addr == addr)) {
-+			set_mem((char *)addr, kgdb_break[i].saved_instr,
-+			        BREAK_INSTR_SIZE);
-+			flush_cache_range (current->mm, addr, addr + BREAK_INSTR_SIZE);
-+			flush_icache_range (addr, addr + BREAK_INSTR_SIZE);
-+			if (kgdb_memerr)
-+				return -1;
-+			kgdb_break[i].state = bp_disabled;
-+			return 0;
-+		}
-+	}
-+	return -1;
-+}
-+
-+int remove_all_break(void)
-+{
-+	int i;
-+	for (i=0; i < MAX_BREAKPOINTS; i++) {
-+		if(kgdb_break[i].state == bp_enabled) {
-+			unsigned long addr = kgdb_break[i].bpt_addr;
-+			set_mem((char *)addr, kgdb_break[i].saved_instr,
-+			       BREAK_INSTR_SIZE);
-+			flush_cache_range (current->mm, addr, addr + BREAK_INSTR_SIZE);
-+			flush_icache_range (addr, addr + BREAK_INSTR_SIZE);
-+		}
-+		kgdb_break[i].state = bp_disabled;
-+	}
-+	return 0;
-+}
-+		
-+int get_char(char *addr, unsigned char *data, int can_fault)
-+{
-+	mm_segment_t fs;
-+	int ret = 0;
-+	
-+	kgdb_memerr = 0;
-+	
-+	if (can_fault)
-+		kgdb_memerr_expected = 1;
-+	wmb();
-+	fs = get_fs();
-+	set_fs(KERNEL_DS);
-+	
-+	if (get_user(*data, addr) != 0) {
-+		ret = -EFAULT;
-+		kgdb_memerr = 1;
-+	}
-+	
-+	kgdb_memerr_expected = 0;	
-+	set_fs(fs);
-+	return ret;
-+}
-+
-+int set_char(char *addr, int data, int can_fault)
-+{
-+	mm_segment_t fs;
-+	int ret = 0;
-+	
-+	kgdb_memerr = 0;
-+	
-+	if (can_fault)
-+		kgdb_memerr_expected = 1;
-+	wmb();
-+	fs = get_fs();
-+	set_fs(KERNEL_DS);
-+
-+	if (put_user(data, addr) != 0) {
-+		ret = -EFAULT;
-+		kgdb_memerr = 1;
-+	}
-+	
-+	kgdb_memerr_expected = 0;
-+	set_fs(fs);
-+	return ret;
-+}
-+
-+/*
-+ * This function does all command procesing for interfacing to gdb.
-+ */
-+
-+int kgdb_handle_exception(int exVector, int signo, int err_code, 
-+                     struct pt_regs *linux_regs)
-+{
-+	int length, addr;
-+	char *ptr;
-+	unsigned long flags;
-+	int gdb_regs[NUMREGBYTES / 4];
-+	int i;
-+	int threadid;
-+#ifdef CONFIG_KGDB_THREAD
-+	threadref thref;
-+	struct task_struct *thread = NULL;
-+	int nothreads;
-+	int maxthreads;
-+#endif
-+	unsigned procid;
-+	int ret = 0;
-+	struct pt_regs *oldregs = current->thread.kgdbregs;
-+
-+	/* 
-+	 * Interrupts will be restored by the 'trap return' code, except when
-+	 * single stepping.
-+	 */
-+	local_irq_save(flags);
-+	
-+	/* Hold kgdb_lock */
-+	procid = smp_processor_id();
-+	while (cmpxchg(&atomic_read(&kgdb_lock), 0, (procid + 1)) != 0) {
-+		int i = 25;	/* an arbitrary number */
-+
-+		while (--i)
-+			asm volatile ("nop": : : "memory");
-+	}
-+	
-+	kgdb_step = 0;
-+
-+
-+	local_irq_save(flags);
-+
-+	current->thread.kgdbregs = linux_regs;
-+
-+	if (kgdb_ops->disable_hw_debug)
-+		kgdb_ops->disable_hw_debug(linux_regs);
-+	
-+	
-+	for (i = 0; i < smp_num_cpus; i++) {
-+		spin_lock(&slavecpulocks[i]);
-+	}
-+
-+	/* spin_lock code is good enough as a barrier so we don't
-+	 * need one here */
-+	procindebug[smp_processor_id()] = 1;
-+
-+	/* Master processor is completely in the debugger */
-+
-+	if (kgdb_ops->post_master_code)
-+		kgdb_ops->post_master_code(linux_regs, exVector, err_code);
-+
-+	if (atomic_read(&kgdb_killed_or_detached) &&
-+	    atomic_read(&kgdb_might_be_resumed)) {
-+		getpacket(remcomInBuffer);
-+		if(remcomInBuffer[0] == 'H' && remcomInBuffer[1] =='c') {
-+			remove_all_break();
-+			atomic_set(&kgdb_killed_or_detached, 0);
-+			remcomOutBuffer[0] = 'O';
-+			remcomOutBuffer[1] = 'K';
-+			remcomOutBuffer[2] = 0;
-+		}
-+		else
-+			return 1;
-+	}
-+	else {
-+
-+		/* reply to host that an exception has occurred */
-+		remcomOutBuffer[0] = 'S';
-+		remcomOutBuffer[1] = hexchars[signo >> 4];
-+		remcomOutBuffer[2] = hexchars[signo % 16];
-+		remcomOutBuffer[3] = 'p';
-+
-+		int_to_threadref(&thref, current->pid ? 
-+		                 current->pid :
-+		                 PID_MAX + cpu_number_map(smp_processor_id()));
-+
-+		*pack_threadid(remcomOutBuffer + 4, &thref) = 0;
-+	}		
-+	putpacket(remcomOutBuffer);
-+	
-+	kgdb_usethread = current;
-+
-+	while (1) {
-+		int bpt_type = 0;
-+		error = 0;
-+		remcomOutBuffer[0] = 0;
-+		remcomOutBuffer[1] = 0;
-+		getpacket(remcomInBuffer);
-+
-+#if KGDB_DEBUG
-+		bust_spinlocks(1);
-+		printk("CPU%d pid%d GDB packet: %s\n", 
-+		       smp_processor_id(), current->pid, remcomInBuffer);
-+		bust_spinlocks(0);
-+#endif
-+		switch (remcomInBuffer[0]) {
-+		case '?':
-+			remcomOutBuffer[0] = 'S';
-+			remcomOutBuffer[1] = hexchars[signo >> 4];
-+			remcomOutBuffer[2] = hexchars[signo % 16];
-+			remcomOutBuffer[3] = 0;
-+			break;
-+
-+		case 'g':	/* return the value of the CPU registers */
-+			thread = kgdb_usethread;
-+				
-+			if (!thread)
-+				thread = current;
-+			
-+			/* All threads that don't have kgdbregs should be
-+			   in __schedule() sleeping, since all other CPUs
-+			   are in gdbwait, and thus have kgdbregs. */
-+			   
-+			if (thread->thread.kgdbregs) 
-+				kgdb_ops->regs_to_gdb_regs(gdb_regs, thread->thread.kgdbregs);
-+			else {
-+				/* Pull stuff saved during 
-+				 * switch_to; nothing else is
-+				   accessible (or even particularly relevant).
-+				   This should be enough for a stack trace. */
-+				kgdb_ops->sleeping_thread_to_gdb_regs(gdb_regs, thread);
-+			}
-+				
-+			mem2hex((char *) gdb_regs, remcomOutBuffer, NUMREGBYTES, 0);
-+			break;
-+
-+		case 'G':	/* set the value of the CPU registers - return OK */
-+			hex2mem(&remcomInBuffer[1], (char *) gdb_regs,
-+				NUMREGBYTES, 0);
-+				
-+			if (kgdb_usethread && kgdb_usethread != current)
-+				strcpy(remcomOutBuffer, "E00");
-+			else {
-+				kgdb_ops->gdb_regs_to_regs(gdb_regs, current->thread.kgdbregs);
-+				strcpy(remcomOutBuffer, "OK");
-+			}
-+
-+			break;
-+
-+			/* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
-+		case 'm':
-+			/* TRY TO READ %x,%x.  IF SUCCEED, SET PTR = 0 */
-+			ptr = &remcomInBuffer[1];
-+			if (hexToInt(&ptr, &addr) && *ptr++ == ',' &&
-+			    hexToInt(&ptr, &length)) {
-+				ptr = 0;
-+				mem2hex((char *) addr, remcomOutBuffer, length, 1);
-+				if (kgdb_memerr)
-+					strcpy(remcomOutBuffer, "E03");
-+					
-+			}
-+
-+			if (ptr) 
-+				strcpy(remcomOutBuffer, "E01");
-+			break;
-+
-+		/* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
-+		case 'M':
-+			/* TRY TO READ '%x,%x:'.  IF SUCCEED, SET PTR = 0 */
-+			ptr = &remcomInBuffer[1];
-+			if (hexToInt(&ptr, &addr) && *(ptr++) == ',' && 
-+			    hexToInt(&ptr, &length) && *(ptr++) == ':') {
-+				hex2mem(ptr, (char *)addr, length, 1);
-+				if (kgdb_memerr)
-+					strcpy(remcomOutBuffer, "E03");
-+				else
-+					strcpy(remcomOutBuffer, "OK");
-+				ptr = 0;
-+			}
-+			if (ptr) {
-+				strcpy(remcomOutBuffer, "E02");
-+			}
-+			break;
-+
-+			
-+			/* Continue and Single Step are Architecture specific
-+			 * and will not be handled by the generic code.
-+			 */
-+
-+
-+			/* kill the program. KGDB should treat this like a 
-+			 * continue.
-+			 */
-+		case 'D':
-+			remcomOutBuffer[0] = 'O';
-+			remcomOutBuffer[1] = 'K';
-+			remcomOutBuffer[2] = '\0';
-+			remove_all_break();
-+			putpacket(remcomOutBuffer);
-+			goto default_handle;
-+
-+		case 'k':
-+			remove_all_break();
-+			goto default_handle;
-+
-+			/* query */
-+		case 'q':
-+			switch (remcomInBuffer[1]) {
-+			case 'L':
-+				/* List threads */
-+				unpack_byte(remcomInBuffer + 3,
-+					    &maxthreads);
-+				unpack_threadid(remcomInBuffer + 5,
-+						&thref);
-+
-+				remcomOutBuffer[0] = 'q';
-+				remcomOutBuffer[1] = 'M';
-+				remcomOutBuffer[4] = '0';
-+				pack_threadid(remcomOutBuffer + 5, &thref);
-+
-+				threadid = threadref_to_int(&thref);
-+				for (nothreads = 0;
-+				     nothreads < maxthreads
-+				     && threadid < PID_MAX + smp_num_cpus; threadid++) {
-+					thread = getthread(threadid);
-+					if (thread) {
-+						int_to_threadref(&thref,
-+								 threadid);
-+						pack_threadid
-+						    (remcomOutBuffer + 21 +
-+						     nothreads * 16,
-+						     &thref);
-+						nothreads++;
-+					}
-+				}
-+				
-+				
-+				if (threadid == PID_MAX + smp_num_cpus) {
-+					remcomOutBuffer[4] = '1';
-+				}
-+				pack_hex_byte(remcomOutBuffer + 2,
-+					      nothreads);
-+				remcomOutBuffer[21 + nothreads * 16] = '\0';
-+				break;
-+
-+			case 'C':
-+				/* Current thread id */
-+				remcomOutBuffer[0] = 'Q';
-+				remcomOutBuffer[1] = 'C';
-+				threadid = current->pid;
-+				
-+				if (threadid == 0)
-+					threadid = cpu_number_map(smp_processor_id()) + PID_MAX;
-+				
-+				int_to_threadref(&thref, threadid);
-+				pack_threadid(remcomOutBuffer + 2, &thref);
-+				remcomOutBuffer[18] = '\0';
-+				break;
-+
-+			case 'E':
-+				/* Print exception info */
-+				if (kgdb_ops->printexpinfo)
-+					kgdb_ops->printexpinfo(exVector,
-+                   			                       err_code,
-+					                       remcomOutBuffer);
-+				break;
-+			}
-+			break;
-+
-+			/* task related */
-+		case 'H':
-+			switch (remcomInBuffer[1]) {
-+			case 'g':
-+				ptr = &remcomInBuffer[2];
-+				hexToInt(&ptr, &threadid);
-+				thread = getthread(threadid);
-+				if (!thread && threadid > 0) {
-+					remcomOutBuffer[0] = 'E';
-+					remcomOutBuffer[1] = '\0';
-+					break;
-+				}
-+				kgdb_usethread = thread;
-+				remcomOutBuffer[0] = 'O';
-+				remcomOutBuffer[1] = 'K';
-+				remcomOutBuffer[2] = '\0';
-+				break;
-+
-+			case 'c':
-+				atomic_set(&kgdb_killed_or_detached, 0);
-+				ptr = &remcomInBuffer[2];
-+				hexToInt(&ptr, &threadid);
-+				thread = getthread(threadid);
-+				if (!thread && threadid > 0) {
-+					remcomOutBuffer[0] = 'E';
-+					remcomOutBuffer[1] = '\0';
-+					break;
-+				}
-+				kgdb_contthread = thread;
-+				remcomOutBuffer[0] = 'O';
-+				remcomOutBuffer[1] = 'K';
-+				remcomOutBuffer[2] = '\0';
-+				break;
-+			}
-+			break;
-+
-+			/* Query thread status */
-+		case 'T':
-+			ptr = &remcomInBuffer[1];
-+			hexToInt(&ptr, &threadid);
-+			thread = getthread(threadid);
-+			if (thread) {
-+				remcomOutBuffer[0] = 'O';
-+				remcomOutBuffer[1] = 'K';
-+				remcomOutBuffer[2] = '\0';
-+			} else {
-+				remcomOutBuffer[0] = 'E';
-+				remcomOutBuffer[1] = '\0';
-+			}
-+			break;
-+		case 'z':
-+		case 'Z':
-+			ptr = &remcomInBuffer[2];
-+			if (*(ptr++) != ',') {
-+				strcpy(remcomOutBuffer, "ERROR");
-+				break;
-+			}
-+			hexToInt(&ptr, &addr);
-+			
-+			bpt_type = remcomInBuffer[1];
-+			if (bpt_type != bp_breakpoint) {
-+				if (bpt_type == bp_hardware_breakpoint && 
-+				    !(kgdb_ops->flags & KGDB_HW_BREAKPOINT))
-+					break;
-+
-+				/* if set_break is not defined, then
-+				 * remove_break does not matter
-+				 */
-+				if(!kgdb_ops->set_break)
-+					break;
-+			}
-+			
-+			if (remcomInBuffer[0] == 'Z') {
-+				if (bpt_type == bp_breakpoint)
-+					ret = set_break(addr);
-+				else
-+					ret = kgdb_ops->set_break(addr, bpt_type);
-+			}
-+			else {
-+				if (bpt_type == bp_breakpoint)
-+					ret = remove_break(addr);
-+				else
-+					ret = kgdb_ops->remove_break(addr, bpt_type);
-+			}
-+			
-+			if (ret == 0)
-+				strcpy(remcomOutBuffer, "OK");
-+			else
-+				strcpy(remcomOutBuffer, "ERROR");
-+			
-+			break;
-+
-+		default:
-+		default_handle:
-+			ret = 0;
-+			if (kgdb_ops->handle_buffer)
-+				ret= kgdb_ops->handle_buffer(exVector, signo, 
-+				                             err_code,
-+				                             remcomInBuffer,
-+				                             remcomOutBuffer,
-+				                             linux_regs);
-+			if(ret >= 0 || remcomInBuffer[0] == 'D' ||
-+			    remcomInBuffer[0] == 'k')
-+				goto kgdb_exit;
-+
-+
-+		}		/* switch */
-+#if KGDB_DEBUG
-+		bust_spinlocks(1);
-+		printk("Response to GDB: %s\n", remcomOutBuffer);
-+		bust_spinlocks(0);
-+#endif
-+
-+		/* reply to the request */
-+		putpacket(remcomOutBuffer);
-+	}
-+kgdb_exit:
-+	
-+	if(kgdb_ops->handler_exit)
-+		kgdb_ops->handler_exit();
-+	
-+	procindebug[smp_processor_id()] = 0;	
-+	
-+	for (i = 0; i < smp_num_cpus; i++) {
-+		spin_unlock(&slavecpulocks[i]);
-+	}
-+	/* Wait till all the processors have quit
-+	 * from the debugger 
-+	 */
-+	for (i = 0; i < smp_num_cpus; i++) { 
-+		while (procindebug[i]) {
-+			int j = 10; /* an arbitrary number */
-+
-+			while (--j) {
-+				asm volatile ("nop" : : : "memory");
-+			}
-+			barrier();
-+		}
-+	}
-+
-+	/* Free kgdb_lock */
-+	atomic_set(&kgdb_lock, 0);
-+	current->thread.kgdbregs = oldregs;
-+	atomic_set(&kgdb_killed_or_detached, 1);
-+	local_irq_restore(flags);
-+	return ret;
-+}
-+
-+/* this function is used to set up exception handlers for tracing and
-+   breakpoints */
-+void set_debug_traps(void)
-+{
-+	int i;
-+	
-+	for (i = 0; i < KGDB_MAX_NO_CPUS; i++) 
-+		spin_lock_init(&slavecpulocks[i]);
-+
-+	/* Free kgdb_lock */
-+	atomic_set(&kgdb_lock, 0);
-+
-+	/* This flag is used, if gdb has detached and wants to start
-+	 * another session
-+	 */
-+	atomic_set(&kgdb_killed_or_detached, 0);
-+	atomic_set(&kgdb_might_be_resumed, 0);
-+
-+	for (i = 0; i < MAX_BREAKPOINTS; i++) 
-+		kgdb_break[i].state = bp_disabled;
-+
-+	
-+	/*
-+	 * In case GDB is started before us, ack any packets (presumably
-+	 * "$?#xx") sitting there.  */
-+	putDebugChar('+');
-+
-+	linux_debug_hook = kgdb_handle_exception;
-+	
-+	if (kgdb_ops->kgdb_init)
-+		kgdb_ops->kgdb_init();
-+
-+	kgdb_initialized = 1;
-+	atomic_set(&kgdb_setting_breakpoint, 0);
-+}
-+
-+/* This function will generate a breakpoint exception.  It is used at the
-+   beginning of a program to sync up with a debugger and can be used
-+   otherwise as a quick means to stop program execution and "break" into
-+   the debugger. */
-+
-+void breakpoint(void)
-+{
-+	if (kgdb_initialized) {
-+		atomic_set(&kgdb_setting_breakpoint, 1);
-+		wmb();
-+		BREAKPOINT();
-+		wmb();
-+		atomic_set(&kgdb_setting_breakpoint, 0);
-+	}
-+}
-+
-+#ifdef CONFIG_GDB_CONSOLE
-+char gdbconbuf[BUFMAX];
-+
-+void gdb_console_write(struct console *co, const char *s, unsigned count)
-+{
-+	int i;
-+	int wcount;
-+	char *bufptr;
-+	int flags;
-+
-+	if (!gdb_initialized || atomic_read(&kgdb_killed_or_detached)) {
-+		return;
-+	}
-+	local_irq_save(flags);
-+
-+	gdbconbuf[0] = 'O';
-+	bufptr = gdbconbuf + 1;
-+	while (count > 0) {
-+		if ((count << 1) > (BUFMAX - 2)) {
-+			wcount = (BUFMAX - 2) >> 1;
-+		} else {
-+			wcount = count;
-+		}
-+		count -= wcount;
-+		for (i = 0; i < wcount; i++) {
-+			bufptr = pack_hex_byte(bufptr, s[i]);
-+		}
-+		*bufptr = '\0';
-+		s += wcount;
-+
-+		putpacket(gdbconbuf);
-+
-+	}
-+	local_irq_restore(flags);
-+}
-+#endif
-+
-+int gdb_enter;
-+int gdb_baud = 115200;
-+int gdb_ttyS;
-+int gdb_initialized;
-+
-+static int __init kgdb_opt_gdb(char *str)
-+{
-+	gdb_enter = 1;
-+	return 1;
-+}
-+static int __init kgdb_opt_gdbttyS(char *str)
-+{
-+	gdb_ttyS = simple_strtoul(str, NULL, 10);
-+	return 1;
-+}
-+static int __init kgdb_opt_gdbbaud(char *str)
-+{
-+	gdb_baud = simple_strtoul(str, NULL, 10);
-+	return 1;
-+}
-+
-+/*
-+ * Sequence of these lines has to be maintained because gdb option is a prefix
-+ * of the other two options
-+ */
-+
-+__setup("gdbttyS=", kgdb_opt_gdbttyS);
-+__setup("gdbbaud=", kgdb_opt_gdbbaud);
-+__setup("gdb", kgdb_opt_gdb);
-Index: linux-2.4.26-ct_sync/kernel/ksyms.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/kernel/ksyms.c	2004-02-18 14:36:32.000000000 +0100
-+++ linux-2.4.26-ct_sync/kernel/ksyms.c	2004-06-28 12:56:07.000000000 +0200
-@@ -51,6 +51,9 @@
- #include <linux/crc32.h>
- #include <linux/firmware.h>
- #include <asm/checksum.h>
-+#ifdef CONFIG_KGDB
-+#include <linux/kgdb.h>
-+#endif
- 
- #if defined(CONFIG_PROC_FS)
- #include <linux/proc_fs.h>
-@@ -467,7 +470,13 @@
- EXPORT_SYMBOL(sleep_on_timeout);
- EXPORT_SYMBOL(interruptible_sleep_on);
- EXPORT_SYMBOL(interruptible_sleep_on_timeout);
--EXPORT_SYMBOL(schedule);
-+EXPORT_SYMBOL(do_schedule);
-+#ifdef CONFIG_KGDB
-+EXPORT_SYMBOL(breakpoint);
-+#ifdef CONFIG_KGDB_THREAD
-+EXPORT_SYMBOL(kern_schedule);
-+#endif
-+#endif
- EXPORT_SYMBOL(schedule_timeout);
- #if CONFIG_SMP
- EXPORT_SYMBOL(set_cpus_allowed);
-Index: linux-2.4.26-ct_sync/kernel/sched.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/kernel/sched.c	2003-11-28 19:26:21.000000000 +0100
-+++ linux-2.4.26-ct_sync/kernel/sched.c	2004-06-28 12:56:07.000000000 +0200
-@@ -544,7 +544,7 @@
-  * tasks can run. It can not be killed, and it cannot sleep. The 'state'
-  * information in task[0] is never used.
-  */
--asmlinkage void schedule(void)
-+asmlinkage void do_schedule(void)
- {
- 	struct schedule_data * sched_data;
- 	struct task_struct *prev, *next, *p;
-@@ -702,6 +702,22 @@
- 	return;
- }
- 
-+asmlinkage void user_schedule(void)
-+{
-+#ifdef CONFIG_KGDB_THREAD
-+	current->thread.kgdbregs = NULL;
-+#endif
-+	do_schedule();
-+}
-+
-+#ifdef CONFIG_KGDB_THREAD
-+asmlinkage void kern_do_schedule(struct pt_regs regs)
-+{
-+	current->thread.kgdbregs = &regs;
-+	do_schedule();
-+}
-+#endif
-+
- /*
-  * The core wakeup function.  Non-exclusive wakeups (nr_exclusive == 0) just wake everything
-  * up.  If it's an exclusive wakeup (nr_exclusive == small +ve number) then we wake all the
-Index: linux-2.4.26-ct_sync/include/asm-ppc/kgdb.h
-===================================================================
---- linux-2.4.26-ct_sync.orig/include/asm-ppc/kgdb.h	2003-06-13 16:51:38.000000000 +0200
-+++ linux-2.4.26-ct_sync/include/asm-ppc/kgdb.h	2004-06-28 12:56:07.000000000 +0200
-@@ -2,47 +2,40 @@
-  * kgdb.h: Defines and declarations for serial line source level
-  *         remote debugging of the Linux kernel using gdb.
-  *
-+ * PPC Mods (C) 2003 John Whitney (john.whitney at timesys.com)
-+ *
-  * PPC Mods (C) 1998 Michael Tesch (tesch at cs.wisc.edu)
-  *
-  * Copyright (C) 1995 David S. Miller (davem at caip.rutgers.edu)
-  */
- #ifdef __KERNEL__
--#ifndef _PPC_KGDB_H
--#define _PPC_KGDB_H
--
--#ifndef __ASSEMBLY__
--/* To initialize the serial, first thing called */
--extern void kgdb_map_scc(void);
--/* To init the kgdb engine. (called by serial hook)*/
--extern void set_debug_traps(void);
--
--/* To enter the debugger explicitly. */
--extern void breakpoint(void);
-+#ifndef _ASMPPC_KGDB_H
-+#define _ASMPPC_KGDB_H
- 
--/* For taking exceptions
-- * these are defined in traps.c
-+/*
-+ * For taking exceptions these are defined in traps.c
-  */
--extern void (*debugger)(struct pt_regs *regs);
--extern int (*debugger_bpt)(struct pt_regs *regs);
--extern int (*debugger_sstep)(struct pt_regs *regs);
--extern int (*debugger_iabr_match)(struct pt_regs *regs);
--extern int (*debugger_dabr_match)(struct pt_regs *regs);
--extern void (*debugger_fault_handler)(struct pt_regs *regs);
--
--/* What we bring to the party */
--int kgdb_bpt(struct pt_regs *regs);
--int kgdb_sstep(struct pt_regs *regs);
--void kgdb(struct pt_regs *regs);
--int kgdb_iabr_match(struct pt_regs *regs);
--int kgdb_dabr_match(struct pt_regs *regs);
-+extern void (*debugger)               (struct pt_regs *regs);
-+extern int  (*debugger_bpt)           (struct pt_regs *regs);
-+extern int  (*debugger_sstep)         (struct pt_regs *regs);
-+extern int  (*debugger_iabr_match)    (struct pt_regs *regs);
-+extern int  (*debugger_dabr_match)    (struct pt_regs *regs);
-+extern void (*debugger_fault_handler) (struct pt_regs *regs);
- 
- /*
-  * external low-level support routines (ie macserial.c)
-  */
--extern void kgdb_interruptible(int); /* control interrupts from serial */
--extern void putDebugChar(char);   /* write a single character      */
--extern char getDebugChar(void);   /* read and return a single char */
-+extern void kgdb_interruptible (int); /* control interrupts from serial */
-+extern void putDebugChar (char);      /* write a single character       */
-+extern char getDebugChar (void);      /* read and return a single char  */
-+
-+#define BREAK_INSTR_SIZE	4
-+#define MAXREG				(PT_FPSCR+1)
-+#define NUMREGBYTES			(MAXREG * sizeof (int))
-+#define BUFMAX				((NUMREGBYTES * 2) + 512)
-+#define OUTBUFMAX			((NUMREGBYTES * 2) + 512)
-+
-+#define BREAKPOINT()        asm (".long	0x7d821008");
- 
--#endif /* !(__ASSEMBLY__) */
--#endif /* !(_PPC_KGDB_H) */
-+#endif /* !(_ASMPPC_KGDB_H) */
- #endif /* __KERNEL__ */
-Index: linux-2.4.26-ct_sync/include/asm-ppc/ioctls.h
-===================================================================
---- linux-2.4.26-ct_sync.orig/include/asm-ppc/ioctls.h	2003-06-13 16:51:38.000000000 +0200
-+++ linux-2.4.26-ct_sync/include/asm-ppc/ioctls.h	2004-06-28 12:56:07.000000000 +0200
-@@ -105,4 +105,6 @@
- #define TIOCMIWAIT	0x545C	/* wait for a change on serial input line(s) */
- #define TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
- 
-+#define TIOCGDB         0x547F  /* enable GDB stub mode on this tty */
-+
- #endif /* _ASM_PPC_IOCTLS_H */
-Index: linux-2.4.26-ct_sync/include/asm-ppc/processor.h
-===================================================================
---- linux-2.4.26-ct_sync.orig/include/asm-ppc/processor.h	2004-04-14 15:05:40.000000000 +0200
-+++ linux-2.4.26-ct_sync/include/asm-ppc/processor.h	2004-06-28 12:56:07.000000000 +0200
-@@ -843,6 +843,9 @@
- 	/* Saved 4xx debug registers */
- 	unsigned long dbcr0;
- #endif
-+#ifdef CONFIG_KGDB
-+	struct pt_regs *kgdbregs;
-+#endif
- };
- 
- #define INIT_SP		(sizeof(init_stack) + (unsigned long) &init_stack)
-Index: linux-2.4.26-ct_sync/include/linux/kgdb-asserts.h
-===================================================================
---- linux-2.4.26-ct_sync.orig/include/linux/kgdb-asserts.h	2004-06-16 09:19:51.000000000 +0200
-+++ linux-2.4.26-ct_sync/include/linux/kgdb-asserts.h	2004-06-28 12:56:07.000000000 +0200
-@@ -0,0 +1,31 @@
-+#ifndef _GDB_ASSERTS_H_
-+#define _GDB_ASSERTS_H_
-+
-+/*
-+ * Copyright (C) 2001 Amit S. Kale
-+ */
-+
-+#define KGDB_ASSERT(message, condition)	do {			\
-+	if (!(condition)) {					\
-+		printk("kgdb assertion failed: %s\n", message); \
-+		breakpoint();					\
-+	}							\
-+} while (0)
-+
-+#define KA_VALID_ERRNO(errno) ((errno) > 0 && (errno) <= EMEDIUMTYPE)
-+
-+#define KA_VALID_PTR_ERR(ptr) KA_VALID_ERRNO(-PTR_ERR(ptr))
-+
-+#define KA_VALID_KPTR(ptr)  (!(ptr) ||	\
-+	       ((void *)(ptr) >= (void *)PAGE_OFFSET &&  \
-+	       (void *)(ptr) < ERR_PTR(-EMEDIUMTYPE)))
-+
-+#define KA_VALID_PTRORERR(errptr) (KA_VALID_KPTR(errptr) || KA_VALID_PTR_ERR(errptr))
-+
-+#ifndef CONFIG_SMP
-+#define KA_HELD_GKL()	1
-+#else
-+#define KA_HELD_GKL()	(current->lock_depth >= 0)
-+#endif
-+
-+#endif /* _GDB_ASSERTS_H_ */
-Index: linux-2.4.26-ct_sync/include/linux/kgdb.h
-===================================================================
---- linux-2.4.26-ct_sync.orig/include/linux/kgdb.h	2004-06-16 09:19:51.000000000 +0200
-+++ linux-2.4.26-ct_sync/include/linux/kgdb.h	2004-06-28 12:56:07.000000000 +0200
-@@ -0,0 +1,80 @@
-+#ifndef _GDB_H_
-+#define _GDB_H_
-+
-+/*
-+ * Copyright (C) 2001 Amit S. Kale
-+ */
-+
-+#include <linux/ptrace.h>
-+#include <asm/kgdb.h>
-+#include <linux/spinlock.h>
-+#include <linux/kgdb-defs.h>
-+
-+enum gdb_bptype
-+{
-+	bp_breakpoint = '0',
-+	bp_hardware_breakpoint,
-+	bp_write_watchpoint,
-+	bp_read_watchpoint,
-+	bp_access_watchpoint
-+};
-+
-+enum gdb_bpstate
-+{
-+       bp_disabled,
-+       bp_enabled
-+};
-+
-+#ifndef BREAK_INSTR_SIZE
-+#error BREAK_INSTR_SIZE  needed by kgdb
-+#endif
-+
-+struct gdb_breakpoint
-+{
-+       unsigned int            bpt_addr;
-+       unsigned char           saved_instr[BREAK_INSTR_SIZE];
-+       enum gdb_bptype         type;
-+       enum gdb_bpstate        state;
-+};
-+
-+typedef struct gdb_breakpoint gdb_breakpoint_t;
-+
-+#ifndef MAX_BREAKPOINTS
-+#define MAX_BREAKPOINTS        16
-+#endif
-+
-+#define KGDB_HW_BREAKPOINT          1
-+
-+struct kgdb_arch {
-+	unsigned char gdb_bpt_instr[BREAK_INSTR_SIZE];
-+	unsigned long flags;
-+	
-+	int  (*kgdb_init) (void);
-+	void (*regs_to_gdb_regs)(int *gdb_regs, struct pt_regs *regs);
-+	void (*sleeping_thread_to_gdb_regs)(int *gdb_regs,struct task_struct *p);
-+	void (*gdb_regs_to_regs)(int *gdb_regs, struct pt_regs *regs);
-+	void (*printexpinfo)(int exceptionNo, int errorcode, char *buffer);
-+	void (*disable_hw_debug) (struct pt_regs *regs);
-+	void (*post_master_code) (struct pt_regs *regs, int eVector, int err_code);
-+	int  (*handle_buffer) (int vector, int signo, int err_code,
-+			       char *InBuffer, char *outBuffer,
-+			       struct pt_regs *regs);
-+	int  (*set_break) (unsigned long addr, int type);
-+	int  (*remove_break) (unsigned long addr, int type);
-+	void (*correct_hw_break) (void);
-+	void (*handler_exit) (void);
-+};			
-+
-+
-+/* Thread reference */
-+typedef unsigned char threadref[8];
-+
-+/* Routine prototypes */
-+struct console;
-+extern void gdb_console_write(struct console *co, const char *s, unsigned count);
-+
-+#ifdef CONFIG_GDB_CONSOLE
-+extern void gdb_console_init(void);
-+#endif /* CONFIG_GDB_CONSOLE */
-+
-+#endif /* _GDB_H_ */
-Index: linux-2.4.26-ct_sync/include/linux/dcache.h
-===================================================================
---- linux-2.4.26-ct_sync.orig/include/linux/dcache.h	2002-11-29 00:53:15.000000000 +0100
-+++ linux-2.4.26-ct_sync/include/linux/dcache.h	2004-06-28 12:56:07.000000000 +0200
-@@ -4,6 +4,7 @@
- #ifdef __KERNEL__
- 
- #include <asm/atomic.h>
-+#include <linux/kgdb.h>
- #include <linux/mount.h>
- #include <linux/kernel.h>
- 
-Index: linux-2.4.26-ct_sync/include/linux/kgdb-defs.h
-===================================================================
---- linux-2.4.26-ct_sync.orig/include/linux/kgdb-defs.h	2004-06-16 09:19:51.000000000 +0200
-+++ linux-2.4.26-ct_sync/include/linux/kgdb-defs.h	2004-06-28 12:56:07.000000000 +0200
-@@ -0,0 +1,58 @@
-+#ifndef _GDB_DEFS_H_
-+#define _GDB_DEFS_H_
-+
-+#include <asm/atomic.h>
-+
-+/* Wait for GDB to connect. */
-+int gdb_hook(void);
-+
-+/* To init the kgdb engine. (called by serial hook) */
-+void set_debug_traps(void);
-+
-+/* To enter the debugger explicitly. */
-+void breakpoint(void);
-+
-+/* Output a string via the GDB console.  Returns non-zero on success. */
-+int kgdb_output_string(const char *s, unsigned int count);
-+
-+extern int gdb_enter; /* 1 = enter debugger on boot */
-+extern int gdb_ttyS;
-+extern int gdb_baud;
-+extern int gdb_initialized;
-+
-+void putDebugChar(char);   /* write a single character      */
-+char getDebugChar(void);   /* read and return a single char */
-+int hexToInt(char **ptr, int *intValue);
-+int kgdb_handle_exception(int exVector, int signo, int err_code,
-+                          struct pt_regs *linux_regs);
-+char *hex2mem(char *buf, char *mem, int count, int can_fault);
-+char *mem2hex(char *mem, char *buf, int count, int can_fault);
-+void putpacket(char *buffer);
-+
-+#ifdef CONFIG_KGDB
-+extern volatile int kgdb_memerr_expected;
-+#else
-+static const int kgdb_memerr_expected = 0;
-+#endif
-+
-+typedef int gdb_debug_hook(int exVector, int signo, int err_code,
-+                            struct pt_regs *regs);
-+
-+#ifndef KGDB_MAX_NO_CPUS
-+#define KGDB_MAX_NO_CPUS 8
-+#endif
-+
-+extern gdb_debug_hook  *linux_debug_hook;
-+extern atomic_t kgdb_lock;
-+extern spinlock_t slavecpulocks[KGDB_MAX_NO_CPUS];
-+extern volatile int procindebug[KGDB_MAX_NO_CPUS];
-+extern int kgdb_initialized;
-+extern struct kgdb_arch arch_kgdb_ops;
-+extern struct task_struct *kgdb_usethread, *kgdb_contthread;
-+extern  volatile int kgdb_memerr;
-+extern atomic_t kgdb_setting_breakpoint;
-+extern atomic_t kgdb_killed_or_detached;
-+extern atomic_t kgdb_might_be_resumed;
-+extern volatile unsigned kgdb_step;
-+	 
-+#endif /* _GDB_DEFS_H_ */
-Index: linux-2.4.26-ct_sync/include/linux/crypto.h
-===================================================================
---- linux-2.4.26-ct_sync.orig/include/linux/crypto.h	2004-02-18 14:36:32.000000000 +0100
-+++ linux-2.4.26-ct_sync/include/linux/crypto.h	2004-06-28 12:56:07.000000000 +0200
-@@ -21,6 +21,7 @@
- #include <linux/types.h>
- #include <linux/list.h>
- #include <linux/string.h>
-+#include <linux/kgdb.h>
- #include <asm/page.h>
- 
- /*
-Index: linux-2.4.26-ct_sync/include/linux/sched.h
-===================================================================
---- linux-2.4.26-ct_sync.orig/include/linux/sched.h	2004-02-18 14:36:32.000000000 +0100
-+++ linux-2.4.26-ct_sync/include/linux/sched.h	2004-06-28 12:56:07.000000000 +0200
-@@ -146,7 +146,9 @@
- 
- #define	MAX_SCHEDULE_TIMEOUT	LONG_MAX
- extern signed long FASTCALL(schedule_timeout(signed long timeout));
--asmlinkage void schedule(void);
-+asmlinkage void do_schedule(void);
-+asmlinkage void kern_schedule(void);
-+asmlinkage void kern_do_schedule(struct pt_regs);
- 
- extern int schedule_task(struct tq_struct *task);
- extern void flush_scheduled_tasks(void);
-@@ -958,5 +960,14 @@
- 		__cond_resched();
- }
- 
-+static inline void schedule(void)
-+{
-+#ifdef CONFIG_KGDB_THREAD
-+	kern_schedule();
-+#else
-+	do_schedule();
-+#endif
-+}
-+
- #endif /* __KERNEL__ */
- #endif
-Index: linux-2.4.26-ct_sync/include/asm-i386/kgdb.h
-===================================================================
---- linux-2.4.26-ct_sync.orig/include/asm-i386/kgdb.h	2004-06-16 09:19:51.000000000 +0200
-+++ linux-2.4.26-ct_sync/include/asm-i386/kgdb.h	2004-06-28 12:56:07.000000000 +0200
-@@ -0,0 +1,62 @@
-+#ifndef _ASM_KGDB_H_
-+#define _ASM_KGDB_H_
-+
-+/*
-+ * Copyright (C) 2001 Amit S. Kale
-+ */
-+
-+#include <linux/ptrace.h>
-+
-+/* gdb locks */
-+#define KGDB_MAX_NO_CPUS 8
-+
-+extern int gdb_enter;	/* 1 = enter debugger on boot */
-+extern int gdb_ttyS;
-+extern int gdb_baud;
-+extern int gdb_initialized;
-+extern int gdb_irq;
-+
-+/************************************************************************/
-+/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
-+/* at least NUMREGBYTES*2 are needed for register packets */
-+/* Longer buffer is needed to list all threads */
-+#define BUFMAX 1024
-+
-+/* Number of bytes of registers.  */
-+#define NUMREGBYTES 64
-+/*
-+ *  Note that this register image is in a different order than
-+ *  the register image that Linux produces at interrupt time.
-+ *  
-+ *  Linux's register image is defined by struct pt_regs in ptrace.h.
-+ *  Just why GDB uses a different order is a historical mystery.
-+ */
-+enum regnames { _EAX,  /* 0 */
-+	_ECX,  /* 1 */
-+	_EDX,  /* 2 */
-+	_EBX,  /* 3 */
-+	_ESP,  /* 4 */
-+	_EBP,  /* 5 */
-+	_ESI,  /* 6 */
-+	_EDI,  /* 7 */
-+	_PC,   /* 8 also known as eip */
-+	_PS,   /* 9 also known as eflags */
-+	_CS,   /* 10 */
-+	_SS,   /* 11 */
-+	_DS,   /* 12 */
-+	_ES,   /* 13 */
-+	_FS,   /* 14 */
-+	_GS    /* 15 */
-+};
-+
-+#define BREAKPOINT() asm("   int $3");
-+#define BREAK_INSTR_SIZE       1
-+struct console;
-+void gdb_console_write(struct console *co, const char *s,
-+				unsigned count);
-+void gdb_console_init(void);
-+
-+void gdb_wait(struct pt_regs *regs);
-+
-+
-+#endif /* _ASM_KGDB_H_ */
-Index: linux-2.4.26-ct_sync/include/asm-i386/ioctls.h
-===================================================================
---- linux-2.4.26-ct_sync.orig/include/asm-i386/ioctls.h	2003-08-25 13:44:43.000000000 +0200
-+++ linux-2.4.26-ct_sync/include/asm-i386/ioctls.h	2004-06-28 12:56:07.000000000 +0200
-@@ -68,6 +68,7 @@
- #define TIOCGHAYESESP   0x545E  /* Get Hayes ESP configuration */
- #define TIOCSHAYESESP   0x545F  /* Set Hayes ESP configuration */
- #define FIOQSIZE	0x5460
-+#define TIOCGDB         0x547F  /* enable GDB stub mode on this tty */
- 
- /* Used for packet mode */
- #define TIOCPKT_DATA		 0
-Index: linux-2.4.26-ct_sync/include/asm-i386/page.h
-===================================================================
---- linux-2.4.26-ct_sync.orig/include/asm-i386/page.h	2002-08-03 02:39:45.000000000 +0200
-+++ linux-2.4.26-ct_sync/include/asm-i386/page.h	2004-06-28 12:56:07.000000000 +0200
-@@ -95,6 +95,10 @@
-  * undefined" opcode for parsing in the trap handler.
-  */
- 
-+#ifdef CONFIG_KGDB
-+#include <linux/kgdb-asserts.h>
-+#define BUG() KGDB_ASSERT("BUG", 0)
-+#else
- #if 1	/* Set to zero for a slightly smaller kernel */
- #define BUG()				\
-  __asm__ __volatile__(	"ud2\n"		\
-@@ -104,6 +108,7 @@
- #else
- #define BUG() __asm__ __volatile__("ud2\n")
- #endif
-+#endif
- 
- #define PAGE_BUG(page) do { \
- 	BUG(); \
-Index: linux-2.4.26-ct_sync/include/asm-i386/processor.h
-===================================================================
---- linux-2.4.26-ct_sync.orig/include/asm-i386/processor.h	2004-02-18 14:36:32.000000000 +0100
-+++ linux-2.4.26-ct_sync/include/asm-i386/processor.h	2004-06-28 12:56:07.000000000 +0200
-@@ -376,6 +376,9 @@
- /* IO permissions */
- 	int		ioperm;
- 	unsigned long	io_bitmap[IO_BITMAP_SIZE+1];
-+#ifdef CONFIG_KGDB
-+	struct pt_regs *kgdbregs;
-+#endif
- };
- 
- #define INIT_THREAD  {						\
-Index: linux-2.4.26-ct_sync/init/main.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/init/main.c	2003-11-28 19:26:21.000000000 +0100
-+++ linux-2.4.26-ct_sync/init/main.c	2004-06-28 12:56:07.000000000 +0200
-@@ -61,6 +61,10 @@
- #include <linux/nubus.h>
- #endif
- 
-+#ifdef CONFIG_KGDB
-+#include <linux/kgdb.h>
-+#endif
-+
- #ifdef CONFIG_ISAPNP
- #include <linux/isapnp.h>
- #endif
-@@ -434,6 +438,11 @@
- 	 *	make syscalls (and thus be locked).
- 	 */
- 	smp_init();
-+#ifdef CONFIG_KGDB
-+	if (gdb_enter) {
-+		gdb_hook();		/* right at boot time */
-+	}
-+#endif
- #if defined(CONFIG_SYSVIPC)
- 	ipc_init();
- #endif
-Index: linux-2.4.26-ct_sync/Makefile
-===================================================================
---- linux-2.4.26-ct_sync.orig/Makefile	2004-06-14 14:52:07.000000000 +0200
-+++ linux-2.4.26-ct_sync/Makefile	2004-06-28 12:56:07.000000000 +0200
-@@ -93,9 +93,13 @@
- 
- CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -O2 \
- 	  -fno-strict-aliasing -fno-common
-+ifeq ($(CONFIG_KGDB),y)
-+CFLAGS += -g
-+else
- ifndef CONFIG_FRAME_POINTER
- CFLAGS += -fomit-frame-pointer
- endif
-+endif
- AFLAGS := -D__ASSEMBLY__ $(CPPFLAGS)
- 
- #
-Index: linux-2.4.26-ct_sync/drivers/char/serial.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/drivers/char/serial.c	2004-02-18 14:36:31.000000000 +0100
-+++ linux-2.4.26-ct_sync/drivers/char/serial.c	2004-06-28 12:56:07.000000000 +0200
-@@ -4,6 +4,7 @@
-  *  Copyright (C) 1991, 1992  Linus Torvalds
-  *  Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 
-  * 		1998, 1999  Theodore Ts'o
-+ *  Copyright (C) 2000 VERITAS Software Corporation.
-  *
-  *  Extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92.  Now
-  *  much more extensible to support other serial cards based on the
-@@ -34,6 +35,10 @@
-  *  4/98: Added changes to support the ARM architecture proposed by
-  * 	  Russell King
-  *
-+ *  3/99: Added TIOCGDB for remote debugging with gdb if compiled with
-+ *        CONFIG_KGDB
-+ * 	  Tigran Aivazian
-+ *
-  *  5/99: Updated to include support for the XR16C850 and ST16C654
-  *        uarts.  Stuart MacDonald <stuartm at connecttech.com>
-  *
-@@ -210,7 +215,7 @@
- #include <asm/uaccess.h>
- #endif
- #include <linux/delay.h>
--#ifdef CONFIG_SERIAL_CONSOLE
-+#if defined(CONFIG_SERIAL_CONSOLE) || defined (CONFIG_GDB_CONSOLE)
- #include <linux/console.h>
- #endif
- #ifdef ENABLE_SERIAL_PCI
-@@ -1591,6 +1596,13 @@
- 	restore_flags(flags);
- }
- 
-+#ifdef CONFIG_KGDB
-+void shutdown_for_gdb(struct async_struct * info)
-+{
-+    shutdown(info) ;
-+}
-+#endif
-+
- #if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
- static int baud_table[] = {
- 	0, 50, 75, 110, 134, 150, 200, 300,
-@@ -2701,7 +2713,12 @@
- 			/* "setserial -W" is called in Debian boot */
- 			printk ("TIOCSER?WILD ioctl obsolete, ignored.\n");
- 			return 0;
--
-+#ifdef CONFIG_KGDB
-+		case TIOCGDB:
-+			gdb_ttyS = MINOR(tty->device) & 0x03F ;
-+			gdb_baud = tty_get_baud_rate(tty) ;
-+			return gdb_hook();
-+#endif
- 		default:
- 			return -ENOIOCTLCMD;
- 		}
-@@ -4957,12 +4974,17 @@
-  *
-  * Accept a maximum of eight boards
-  *
-+ * 10/00: added console support for kgdb. Amit Kale <akale at veritas.com>
-+ *
-  */
- static void __devinit probe_serial_pci(void) 
- {
- #ifdef SERIAL_DEBUG_PCI
- 	printk(KERN_DEBUG "Entered probe_serial_pci()\n");
- #endif
-+#ifdef CONFIG_KGDB
-+#include <linux/kgdb.h>
-+#endif
- 
- 	/* Register call PCI serial devices.  Null out
- 	 * the driver name upon failure, as a signal
-@@ -6031,6 +6053,129 @@
- #endif
- 
- /*
-+ * ------------------------------------------------------------
-+ * Serial GDB driver (most in gdbserial.c)
-+ * ------------------------------------------------------------
-+ */
-+
-+#ifdef CONFIG_KGDB
-+#ifdef CONFIG_GDB_CONSOLE
-+static struct console gdbcons = {
-+	name: "gdb",
-+	write: gdb_console_write,
-+	flags: CON_PRINTBUFFER | CON_ENABLED,
-+	index: -1,
-+};
-+#endif
-+
-+
-+/* 
-+ *  Takes:
-+ *	ttyS - integer specifying which serial port to use for debugging
-+ *	baud - baud rate of specified serial port
-+ *  Returns:
-+ *	port for use by the gdb serial driver
-+ */
-+struct serial_state *
-+gdb_serial_setup(int ttyS, int baud)
-+{
-+        struct serial_state *ser;
-+        unsigned cval;
-+        int     bits = 8;
-+        int     parity = 'n';
-+        int     cflag = CREAD | HUPCL | CLOCAL;
-+        int     quot = 0;
-+
-+        /*
-+         *      Now construct a cflag setting.
-+         */
-+        switch(baud) {
-+                case 1200:
-+                        cflag |= B1200;
-+                        break;
-+                case 2400:
-+                        cflag |= B2400;
-+                        break;
-+                case 4800:
-+                        cflag |= B4800;
-+                        break;
-+                case 19200:
-+                        cflag |= B19200;
-+                        break;
-+                case 38400:
-+                        cflag |= B38400;
-+                        break;
-+                case 57600:
-+                        cflag |= B57600;
-+                        break;
-+                case 115200:
-+                        cflag |= B115200;
-+                        break;
-+                case 9600:
-+                default:
-+                        cflag |= B9600;
-+                        break;
-+        }
-+        switch(bits) {
-+                case 7:
-+                        cflag |= CS7;
-+                        break;
-+                default:
-+                case 8:
-+                        cflag |= CS8;
-+                        break;
-+        }
-+        switch(parity) {
-+                case 'o': case 'O':
-+                        cflag |= PARODD;
-+                        break;
-+                case 'e': case 'E':
-+                        cflag |= PARENB;
-+                        break;
-+        }
-+
-+        /*
-+         *      Divisor, bytesize and parity
-+         */
-+
-+        ser = rs_table + ttyS;
-+	ser->flags &= ~ASYNC_BOOT_AUTOCONF;
-+        quot = ser->baud_base / baud;
-+        cval = cflag & (CSIZE | CSTOPB);
-+        cval >>= 4;
-+        if (cflag & PARENB)
-+                cval |= UART_LCR_PARITY;
-+        if (!(cflag & PARODD))
-+                cval |= UART_LCR_EPAR;
-+
-+        /*
-+         *      Disable UART interrupts, set DTR and RTS high
-+         *      and set speed.
-+         */
-+	cval = 0x3;
-+        outb(cval | UART_LCR_DLAB, ser->port + UART_LCR);       /* set DLAB */
-+        outb(quot & 0xff, ser->port + UART_DLL);         /* LS of divisor */
-+        outb(quot >> 8, ser->port + UART_DLM);           /* MS of divisor */
-+        outb(cval, ser->port + UART_LCR);                /* reset DLAB */
-+        outb(UART_IER_RDI, ser->port + UART_IER);        /* turn on interrupts*/
-+        outb(UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS, ser->port + UART_MCR);
-+
-+        /*
-+         *      If we read 0xff from the LSR, there is no UART here.
-+         */
-+        if (inb(ser->port + UART_LSR) == 0xff)
-+                return 0;
-+        return ser;
-+}
-+#ifdef CONFIG_GDB_CONSOLE
-+void __init gdb_console_init(void)
-+{
-+	register_console(&gdbcons);
-+}
-+#endif
-+#endif /* CONFIG_KGDB */
-+
-+/*
-   Local variables:
-   compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -pipe -fno-strength-reduce -march=i586 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h   -DEXPORT_SYMTAB -c serial.c"
-   End:
-Index: linux-2.4.26-ct_sync/drivers/char/gdbserial.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/drivers/char/gdbserial.c	2004-06-16 09:19:51.000000000 +0200
-+++ linux-2.4.26-ct_sync/drivers/char/gdbserial.c	2004-06-28 12:56:07.000000000 +0200
-@@ -0,0 +1,304 @@
-+/*
-+ * Serial interface GDB stub
-+ *
-+ * Written (hacked together) by David Grothe (dave at gcom.com)
-+ *
-+ * Modified by Scott Foehner (sfoehner at engr.sgi.com) to allow connect
-+ * on boot-up
-+ *
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/errno.h>
-+#include <linux/signal.h>
-+#include <linux/sched.h>
-+#include <linux/timer.h>
-+#include <linux/interrupt.h>
-+#include <linux/tty.h>
-+#include <linux/tty_flip.h>
-+#include <linux/serial.h>
-+#include <linux/serial_reg.h>
-+#include <linux/serialP.h>
-+#include <linux/config.h>
-+#include <linux/major.h>
-+#include <linux/string.h>
-+#include <linux/fcntl.h>
-+#include <linux/termios.h>
-+#include <linux/kgdb.h>
-+
-+#include <asm/system.h>
-+#include <asm/io.h>
-+#include <asm/segment.h>
-+#include <asm/bitops.h>
-+#include <asm/system.h>
-+#include <asm/irq.h>
-+#include <asm/atomic.h>
-+
-+#undef	PRNT				/* define for debug printing */
-+
-+#define	GDB_BUF_SIZE	512		/* power of 2, please */
-+
-+static char	gdb_buf[GDB_BUF_SIZE] ;
-+static int	gdb_buf_in_inx ;
-+static atomic_t	gdb_buf_in_cnt ;
-+static int	gdb_buf_out_inx ;
-+
-+
-+static int gdb_got_dollar = -3, gdb_got_H = -3, gdb_interrupt_iteration = 0;
-+
-+extern void	set_debug_traps(void) ;		/* GDB routine */
-+extern struct serial_state *	gdb_serial_setup(int ttyS, int baud);
-+extern void	shutdown_for_gdb(struct async_struct * info) ;
-+						/* in serial.c */
-+
-+int gdb_irq;
-+int gdb_port;
-+
-+static int initialized = -1;
-+
-+/*
-+ * Get a byte from the hardware data buffer and return it
-+ */
-+static int	read_data_bfr(void)
-+{
-+    if (inb(gdb_port + UART_LSR) & UART_LSR_DR)
-+	return(inb(gdb_port + UART_RX));
-+
-+    return( -1 ) ;
-+
-+} /* read_data_bfr */
-+
-+
-+/*
-+ * Get a char if available, return -1 if nothing available.
-+ * Empty the receive buffer first, then look at the interface hardware.
-+ */
-+static int	read_char(void)
-+{
-+    if (atomic_read(&gdb_buf_in_cnt) != 0)	/* intr routine has q'd chars */
-+    {
-+	int		chr ;
-+
-+	chr = gdb_buf[gdb_buf_out_inx++] ;
-+	gdb_buf_out_inx &= (GDB_BUF_SIZE - 1) ;
-+	atomic_dec(&gdb_buf_in_cnt) ;
-+	return(chr) ;
-+    }
-+
-+    return(read_data_bfr()) ;	/* read from hardware */
-+
-+} /* read_char */
-+
-+/*
-+ * Wait until the interface can accept a char, then write it.
-+ */
-+static void	write_char(int chr)
-+{
-+    while ( !(inb(gdb_port + UART_LSR) & UART_LSR_THRE) ) ;
-+
-+    outb(chr, gdb_port+UART_TX);
-+
-+} /* write_char */
-+
-+/*
-+ * This is the receiver interrupt routine for the GDB stub.
-+ * It will receive a limited number of characters of input
-+ * from the gdb  host machine and save them up in a buffer.
-+ *
-+ * When the gdb stub routine getDebugChar() is called it
-+ * draws characters out of the buffer until it is empty and
-+ * then reads directly from the serial port.
-+ *
-+ * We do not attempt to write chars from the interrupt routine
-+ * since the stubs do all of that via putDebugChar() which
-+ * writes one byte after waiting for the interface to become
-+ * ready.
-+ *
-+ * The debug stubs like to run with interrupts disabled since,
-+ * after all, they run as a consequence of a breakpoint in
-+ * the kernel.
-+ *
-+ * Perhaps someone who knows more about the tty driver than I
-+ * care to learn can make this work for any low level serial
-+ * driver.
-+ */
-+static void gdb_interrupt(int irq, void *dev_id, struct pt_regs * regs)
-+{
-+    int			 chr ;
-+    int			 iir ;
-+
-+    do
-+    {
-+	chr = read_data_bfr() ;
-+	iir = inb(gdb_port + UART_IIR) ;
-+#ifdef PRNT
-+	printk("gdb_interrupt: chr=%02x '%c'  after read iir=%02x\n", chr,
-+		chr > ' ' && chr < 0x7F ? chr : ' ', iir) ;
-+#endif
-+	if (chr < 0) continue ;
-+
-+        if (chr == 3)                   /* Ctrl-C means remote interrupt */
-+        {
-+            breakpoint();
-+            continue ;
-+        }
-+
-+	if(atomic_read(&kgdb_killed_or_detached)) {
-+	    if (chr == '$') 
-+		gdb_got_dollar = gdb_interrupt_iteration;
-+	    else if (gdb_interrupt_iteration == gdb_got_dollar + 1 &&
-+	 	chr == 'H') 
-+		gdb_got_H  = gdb_interrupt_iteration;
-+	    else if (gdb_interrupt_iteration == gdb_got_H + 1 && 
-+		chr == 'c') {
-+		gdb_buf[gdb_buf_in_inx++] = chr;
-+		atomic_inc(&gdb_buf_in_cnt);
-+		atomic_set(&kgdb_might_be_resumed, 1);
-+		wmb();
-+		breakpoint();
-+		atomic_set(&kgdb_might_be_resumed, 0);
-+		gdb_interrupt_iteration = 0;
-+		gdb_got_dollar = -3;
-+		gdb_got_H = -3;
-+		continue;
-+	    }
-+	}
-+
-+	if (atomic_read(&gdb_buf_in_cnt) >= GDB_BUF_SIZE)
-+	{				/* buffer overflow, clear it */
-+	    gdb_buf_in_inx = 0 ;
-+	    atomic_set(&gdb_buf_in_cnt, 0) ;
-+	    gdb_buf_out_inx = 0 ;
-+	    break ;
-+	}
-+
-+	gdb_buf[gdb_buf_in_inx++] = chr ;
-+	gdb_buf_in_inx &= (GDB_BUF_SIZE - 1) ;
-+	atomic_inc(&gdb_buf_in_cnt) ;
-+    }
-+    while (iir & UART_IIR_RDI);
-+
-+    if (atomic_read(&kgdb_killed_or_detached))
-+	gdb_interrupt_iteration ++; 
-+
-+
-+} /* gdb_interrupt */
-+
-+/*
-+ * Just a NULL routine for testing.
-+ */
-+void gdb_null(void)
-+{
-+} /* gdb_null */
-+
-+
-+int     gdb_hook(void)
-+{
-+    int         retval ;
-+    struct serial_state *ser;
-+
-+#ifdef CONFIG_SMP
-+    if (smp_num_cpus > KGDB_MAX_NO_CPUS) { 
-+        printk("kgdb: too manu cpus. Cannot enable debugger with more than 8 cpus\n");
-+	return (-1);
-+    }
-+#endif
-+
-+    /*
-+     * Call first time just to get the ser ptr
-+     */
-+    if((ser = gdb_serial_setup(gdb_ttyS, gdb_baud)) == 0) {
-+        printk ("gdb_serial_setup() error");
-+        return(-1);
-+    }
-+
-+    gdb_port = ser->port;
-+    gdb_irq = ser->irq;
-+
-+    if (ser->info != NULL)
-+    {
-+	shutdown_for_gdb(ser->info) ;
-+	/*
-+	 * Call second time to do the setup now that we have
-+	 * shut down the previous user of the interface.
-+	 */
-+	gdb_serial_setup(gdb_ttyS, gdb_baud) ;
-+    }
-+
-+    retval = request_irq(gdb_irq,
-+                         gdb_interrupt,
-+                         SA_INTERRUPT,
-+                         "GDB-stub", NULL);
-+    if (retval == 0)
-+        initialized = 1;
-+    else
-+    {
-+        initialized = 0;
-+	printk("gdb_hook: request_irq(irq=%d) failed: %d\n", gdb_irq, retval);
-+    }
-+
-+    /*
-+     * Call GDB routine to setup the exception vectors for the debugger
-+     */
-+    set_debug_traps() ;
-+
-+    /*
-+     * Call the breakpoint() routine in GDB to start the debugging
-+     * session.
-+     */
-+    printk("Waiting for connection from remote gdb... ") ;
-+    breakpoint() ;
-+    gdb_null() ;
-+
-+    printk("Connected.\n");
-+
-+    gdb_initialized = 1;
-+    return(0) ;
-+
-+} /* gdb_hook_interrupt2 */
-+
-+/*
-+ * getDebugChar
-+ *
-+ * This is a GDB stub routine.  It waits for a character from the
-+ * serial interface and then returns it.  If there is no serial
-+ * interface connection then it returns a bogus value which will
-+ * almost certainly cause the system to hang.
-+ */
-+char	getDebugChar(void)
-+{
-+    volatile int	chr ;
-+
-+#ifdef PRNT
-+    printk("getDebugChar: ") ;
-+#endif
-+
-+    while ( (chr = read_char()) < 0 ) ;
-+
-+
-+#ifdef PRNT
-+    printk("%c\n", chr > ' ' && chr < 0x7F ? chr : ' ') ;
-+#endif
-+    return(chr) ;
-+
-+} /* getDebugChar */
-+
-+/*
-+ * putDebugChar
-+ *
-+ * This is a GDB stub routine.  It waits until the interface is ready
-+ * to transmit a char and then sends it.  If there is no serial
-+ * interface connection then it simply returns to its caller, having
-+ * pretended to send the char.
-+ */
-+void	putDebugChar(char chr)
-+{
-+#ifdef PRNT
-+    printk("putDebugChar: chr=%02x '%c'\n", chr,
-+		chr > ' ' && chr < 0x7F ? chr : ' ') ;
-+#endif
-+
-+    write_char(chr) ;	/* this routine will wait */
-+
-+} /* putDebugChar */
-+
-Index: linux-2.4.26-ct_sync/drivers/char/Makefile
-===================================================================
---- linux-2.4.26-ct_sync.orig/drivers/char/Makefile	2004-02-18 14:36:31.000000000 +0100
-+++ linux-2.4.26-ct_sync/drivers/char/Makefile	2004-06-28 12:56:07.000000000 +0200
-@@ -169,6 +169,7 @@
-   KEYBD = dummy_keyb.o
- endif
- 
-+obj-$(CONFIG_KGDB) += gdbserial.o
- obj-$(CONFIG_VT) += vt.o vc_screen.o consolemap.o consolemap_deftbl.o $(CONSOLE) selection.o
- obj-$(CONFIG_SERIAL) += $(SERIAL)
- obj-$(CONFIG_SERIAL_HCDP) += hcdp_serial.o
-Index: linux-2.4.26-ct_sync/drivers/char/tty_io.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/drivers/char/tty_io.c	2004-04-14 15:05:29.000000000 +0200
-+++ linux-2.4.26-ct_sync/drivers/char/tty_io.c	2004-06-28 12:56:07.000000000 +0200
-@@ -90,6 +90,9 @@
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/smp_lock.h>
-+#ifdef CONFIG_GDB_CONSOLE
-+#include <linux/kgdb.h>
-+#endif
- 
- #include <asm/uaccess.h>
- #include <asm/system.h>
-@@ -2248,6 +2251,9 @@
- #ifdef CONFIG_AU1X00_SERIAL_CONSOLE
- 	au1x00_serial_console_init();
- #endif
-+#ifdef CONFIG_GDB_CONSOLE
-+	gdb_console_init();
-+#endif
- #ifdef CONFIG_SERIAL_CONSOLE
- #if (defined(CONFIG_8xx) || defined(CONFIG_CPM2))
- 	console_8xx_init();
-Index: linux-2.4.26-ct_sync/arch/i386/kernel/i386-stub.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/arch/i386/kernel/i386-stub.c	2004-06-16 09:19:51.000000000 +0200
-+++ linux-2.4.26-ct_sync/arch/i386/kernel/i386-stub.c	2004-06-28 12:56:07.000000000 +0200
-@@ -0,0 +1,457 @@
-+/*
-+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License as published by the
-+ * Free Software Foundation; either version 2, or (at your option) any
-+ * later version.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-+ * General Public License for more details.
-+ *
-+ */
-+
-+/*
-+ * Copyright (C) 2000-2001 VERITAS Software Corporation.
-+ */
-+/****************************************************************************
-+ *  Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
-+ *
-+ *  Module name: remcom.c $
-+ *  Revision: 1.34 $
-+ *  Date: 91/03/09 12:29:49 $
-+ *  Contributor:     Lake Stevens Instrument Division$
-+ *
-+ *  Description:     low level support for gdb debugger. $
-+ *
-+ *  Considerations:  only works on target hardware $
-+ *
-+ *  Written by:      Glenn Engel $
-+ *  Updated by:	     Amit Kale<akale at veritas.com>
-+ *  ModuleState:     Experimental $
-+ *
-+ *  NOTES:           See Below $
-+ *
-+ *  Modified for 386 by Jim Kingdon, Cygnus Support.
-+ *  Origianl kgdb, compatibility with 2.1.xx kernel by David Grothe <dave at gcom.com>
-+ *  Integrated into 2.2.5 kernel by Tigran Aivazian <tigran at sco.com>
-+ *      thread support,
-+ *      support for multiple processors,
-+ *  	support for ia-32(x86) hardware debugging,
-+ *  	Console support,
-+ *  	handling nmi watchdog
-+ *  	Amit S. Kale ( amitkale at emsyssoft.com )
-+ *
-+ *
-+ *  To enable debugger support, two things need to happen.  One, a
-+ *  call to set_debug_traps() is necessary in order to allow any breakpoints
-+ *  or error conditions to be properly intercepted and reported to gdb.
-+ *  Two, a breakpoint needs to be generated to begin communication.  This
-+ *  is most easily accomplished by a call to breakpoint().  Breakpoint()
-+ *  simulates a breakpoint by executing an int 3.
-+ *
-+ *************
-+ *
-+ *    The following gdb commands are supported:
-+ *
-+ * command          function                               Return value
-+ *
-+ *    g             return the value of the CPU registers  hex data or ENN
-+ *    G             set the value of the CPU registers     OK or ENN
-+ *
-+ *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
-+ *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
-+ *
-+ *    c             Resume at current address              SNN   ( signal NN)
-+ *    cAA..AA       Continue at address AA..AA             SNN
-+ *
-+ *    s             Step one instruction                   SNN
-+ *    sAA..AA       Step one instruction from AA..AA       SNN
-+ *
-+ *    k             kill
-+ *
-+ *    ?             What was the last sigval ?             SNN   (signal NN)
-+ *
-+ * All commands and responses are sent with a packet which includes a
-+ * checksum.  A packet consists of
-+ *
-+ * $<packet info>#<checksum>.
-+ *
-+ * where
-+ * <packet info> :: <characters representing the command or response>
-+ * <checksum>    :: < two hex digits computed as modulo 256 sum of <packetinfo>>
-+ *
-+ * When a packet is received, it is first acknowledged with either '+' or '-'.
-+ * '+' indicates a successful transfer.  '-' indicates a failed transfer.
-+ *
-+ * Example:
-+ *
-+ * Host:                  Reply:
-+ * $m0,10#2a               +$00010203040506070809101112131415#42
-+ *
-+ ****************************************************************************/
-+
-+#include <linux/string.h>
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <linux/smp.h>
-+#include <linux/spinlock.h>
-+#include <linux/delay.h>
-+#include <asm/vm86.h>
-+#include <asm/system.h>
-+#include <asm/ptrace.h>			/* for linux pt_regs struct */
-+#include <linux/kgdb.h>
-+#ifdef CONFIG_GDB_CONSOLE
-+#include <linux/console.h>
-+#endif
-+#include <linux/init.h>
-+
-+/* Put the error code here just in case the user cares.  */
-+int gdb_i386errcode;
-+/* Likewise, the vector number here (since GDB only gets the signal
-+   number through the usual means, and that's not very specific).  */
-+int gdb_i386vector = -1;
-+
-+#if KGDB_MAX_NO_CPUS != 8
-+#error change the definition of slavecpulocks
-+#endif
-+
-+static void i386_regs_to_gdb_regs(int *gdb_regs, struct pt_regs *regs)
-+{
-+    gdb_regs[_EAX] =  regs->eax;
-+    gdb_regs[_EBX] =  regs->ebx;
-+    gdb_regs[_ECX] =  regs->ecx;
-+    gdb_regs[_EDX] =  regs->edx;
-+    gdb_regs[_ESI] =  regs->esi;
-+    gdb_regs[_EDI] =  regs->edi;
-+    gdb_regs[_EBP] =  regs->ebp;
-+    gdb_regs[ _DS] =  regs->xds;
-+    gdb_regs[ _ES] =  regs->xes;
-+    gdb_regs[ _PS] =  regs->eflags;
-+    gdb_regs[ _CS] =  regs->xcs;
-+    gdb_regs[ _PC] =  regs->eip;
-+    gdb_regs[_ESP] =  (int) (&regs->esp) ;
-+    gdb_regs[ _SS] =  __KERNEL_DS;
-+    gdb_regs[ _FS] =  0xFFFF;
-+    gdb_regs[ _GS] =  0xFFFF;
-+} /* regs_to_gdb_regs */
-+
-+static void i386_sleeping_thread_to_gdb_regs(int *gdb_regs, struct task_struct *p)
-+{
-+	gdb_regs[_EAX] = 0;
-+	gdb_regs[_EBX] = 0;
-+	gdb_regs[_ECX] = 0;
-+	gdb_regs[_EDX] = 0;
-+	gdb_regs[_ESI] = 0;
-+	gdb_regs[_EDI] = 0;
-+	gdb_regs[_EBP] = *(int *)p->thread.esp;
-+	gdb_regs[_DS]  = __KERNEL_DS;
-+	gdb_regs[_ES]  = __KERNEL_DS;
-+	gdb_regs[_PS]  = 0;
-+	gdb_regs[_CS]  = __KERNEL_CS;
-+	gdb_regs[_PC]  = p->thread.eip;
-+	gdb_regs[_ESP] = p->thread.esp;
-+	gdb_regs[_SS]  = __KERNEL_DS;
-+	gdb_regs[_FS]  = 0xFFFF;
-+	gdb_regs[_GS]  = 0xFFFF;
-+}
-+
-+static void i386_gdb_regs_to_regs(int *gdb_regs, struct pt_regs *regs)
-+{
-+    regs->eax	=     gdb_regs[_EAX] ;
-+    regs->ebx	=     gdb_regs[_EBX] ;
-+    regs->ecx	=     gdb_regs[_ECX] ;
-+    regs->edx	=     gdb_regs[_EDX] ;
-+    regs->esi	=     gdb_regs[_ESI] ;
-+    regs->edi	=     gdb_regs[_EDI] ;
-+    regs->ebp	=     gdb_regs[_EBP] ;
-+    regs->xds	=     gdb_regs[ _DS] ;
-+    regs->xes	=     gdb_regs[ _ES] ;
-+    regs->eflags=     gdb_regs[ _PS] ;
-+    regs->xcs	=     gdb_regs[ _CS] ;
-+    regs->eip	=     gdb_regs[ _PC] ;
-+#if 0					/* can't change these */
-+    regs->esp	=     gdb_regs[_ESP] ;
-+    regs->xss	=     gdb_regs[ _SS] ;
-+    regs->fs	=     gdb_regs[ _FS] ;
-+    regs->gs	=     gdb_regs[ _GS] ;
-+#endif
-+
-+} /* gdb_regs_to_regs */
-+
-+struct hw_breakpoint {
-+	unsigned enabled;
-+	unsigned type;
-+	unsigned len;
-+	unsigned addr;
-+} breakinfo[4] = { {
-+enabled:0}, {
-+enabled:0}, {
-+enabled:0}, {
-+enabled:0}};
-+
-+void i386_correct_hw_break(void)
-+{
-+	int breakno;
-+	int correctit;
-+	int breakbit;
-+	unsigned dr7;
-+
-+	asm volatile ("movl %%db7, %0\n":"=r" (dr7)
-+		      :);
-+	do {
-+		unsigned addr0, addr1, addr2, addr3;
-+		asm volatile ("movl %%db0, %0\n"
-+			      "movl %%db1, %1\n"
-+			      "movl %%db2, %2\n"
-+			      "movl %%db3, %3\n":"=r" (addr0), "=r"(addr1),
-+			      "=r"(addr2), "=r"(addr3):);
-+	} while (0);
-+	correctit = 0;
-+	for (breakno = 0; breakno < 3; breakno++) {
-+		breakbit = 2 << (breakno << 1);
-+		if (!(dr7 & breakbit) && breakinfo[breakno].enabled) {
-+			correctit = 1;
-+			dr7 |= breakbit;
-+			dr7 &= ~(0xf0000 << (breakno << 2));
-+			dr7 |= (((breakinfo[breakno].len << 2) |
-+				 breakinfo[breakno].type) << 16) <<
-+			    (breakno << 2);
-+			switch (breakno) {
-+			case 0:
-+				asm volatile ("movl %0, %%dr0\n"::"r"
-+					      (breakinfo[breakno].addr));
-+				break;
-+
-+			case 1:
-+				asm volatile ("movl %0, %%dr1\n"::"r"
-+					      (breakinfo[breakno].addr));
-+				break;
-+
-+			case 2:
-+				asm volatile ("movl %0, %%dr2\n"::"r"
-+					      (breakinfo[breakno].addr));
-+				break;
-+
-+			case 3:
-+				asm volatile ("movl %0, %%dr3\n"::"r"
-+					      (breakinfo[breakno].addr));
-+				break;
-+			}
-+		} else if ((dr7 & breakbit) && !breakinfo[breakno].enabled) {
-+			correctit = 1;
-+			dr7 &= ~breakbit;
-+			dr7 &= ~(0xf0000 << (breakno << 2));
-+		}
-+	}
-+	if (correctit) {
-+		asm volatile ("movl %0, %%db7\n"::"r" (dr7));
-+	}
-+}
-+
-+int i386_remove_hw_break(unsigned long addr, int type)
-+{
-+	int i, idx = -1;
-+	for (i = 0; i < 4; i ++) {
-+		if (breakinfo[i].addr == addr && breakinfo[i].enabled) {
-+			idx = i;
-+			break;
-+		}
-+	}
-+	if (idx == -1)
-+		return -1;
-+
-+	breakinfo[idx].enabled = 0;
-+	return 0;
-+}
-+
-+int i386_set_hw_break(unsigned long addr, int type)
-+{
-+	int i, idx = -1;
-+	for (i = 0; i < 4; i ++) {
-+		if (!breakinfo[i].enabled) {
-+			idx = i;
-+			break;
-+		}
-+	}
-+	if (idx == -1)
-+		return -1;
-+
-+	breakinfo[idx].enabled = 1;
-+	breakinfo[idx].type = type;
-+	breakinfo[idx].len = 1;
-+	breakinfo[idx].addr = addr;
-+	return 0;
-+}
-+
-+int remove_hw_break(unsigned breakno)
-+{
-+	if (!breakinfo[breakno].enabled) {
-+		return -1;
-+	}
-+	breakinfo[breakno].enabled = 0;
-+	return 0;
-+}
-+
-+int set_hw_break(unsigned breakno,
-+		 unsigned type, unsigned len, unsigned addr)
-+{
-+	if (breakinfo[breakno].enabled) {
-+		return -1;
-+	}
-+	breakinfo[breakno].enabled = 1;
-+	breakinfo[breakno].type = type;
-+	breakinfo[breakno].len = len;
-+	breakinfo[breakno].addr = addr;
-+	return 0;
-+}
-+
-+static void i386_printexceptioninfo(int exceptionNo, int errorcode, char *buffer)
-+{
-+	unsigned	dr6;
-+	int		i;
-+	switch (exceptionNo) {
-+	case 1:		/* debug exception */
-+		break;
-+	case 3:		/* breakpoint */
-+		sprintf(buffer, "Software breakpoint");
-+		return;
-+	default:
-+		sprintf(buffer, "Details not available");
-+		return;
-+	}
-+	asm volatile ("movl %%db6, %0\n":"=r" (dr6)
-+		      :);
-+	if (dr6 & 0x4000) {
-+		sprintf(buffer, "Single step");
-+		return;
-+	}
-+	for (i = 0; i < 4; ++i) {
-+		if (dr6 & (1 << i)) {
-+			sprintf(buffer, "Hardware breakpoint %d", i);
-+			return;
-+		}
-+	}
-+	sprintf(buffer, "Unknown trap");
-+	return;
-+}
-+
-+static void i386_disable_hw_debug(struct pt_regs *regs) 
-+{
-+	/* Disable hardware debugging while we are in kgdb */
-+	asm volatile("movl %0,%%db7": /* no output */ : "r"(0));
-+}
-+
-+static void i386_post_master_code(struct pt_regs *regs, int eVector, int err_code)
-+{
-+	/* Master processor is completely in the debugger */
-+	gdb_i386vector = eVector;
-+	gdb_i386errcode = err_code;
-+}
-+static int i386_handle_exception(int exceptionVector, int signo, int err_code,
-+                                 char *remcomInBuffer, char *remcomOutBuffer,
-+                                 struct pt_regs *linux_regs)
-+{
-+	int addr, length;
-+	int breakno, breaktype;
-+	char *ptr;
-+	int newPC;
-+	int dr6;
-+	
-+	switch (remcomInBuffer[0]) {
-+	case 'c':
-+	case 's':
-+		if (kgdb_contthread && kgdb_contthread != current) {
-+			strcpy(remcomOutBuffer, "E00");
-+			break;
-+		}
-+
-+		kgdb_contthread = NULL;
-+
-+		/* try to read optional parameter, pc unchanged if no parm */
-+		ptr = &remcomInBuffer[1];
-+		if (hexToInt(&ptr, &addr)) {
-+			linux_regs->eip = addr;
-+		} 
-+		newPC = linux_regs->eip;
-+		
-+		/* clear the trace bit */
-+		linux_regs->eflags &= 0xfffffeff;
-+
-+		/* set the trace bit if we're stepping */
-+		if (remcomInBuffer[0] == 's') {
-+			linux_regs->eflags |= 0x100;
-+			kgdb_step = 1;
-+		}
-+
-+		asm volatile ("movl %%db6, %0\n" : "=r" (dr6));
-+		if (!(dr6 & 0x4000)) {
-+			for (breakno = 0; breakno < 4; ++breakno) {
-+				if (dr6 & (1 << breakno)) {
-+					if (breakinfo[breakno].type == 0) {
-+						/* Set restore flag */
-+						linux_regs->eflags |= 0x10000;
-+						break;
-+					}
-+				}
-+			}
-+		}
-+		i386_correct_hw_break();
-+		asm volatile ("movl %0, %%db6\n"::"r" (0));
-+
-+		return (0);
-+
-+	case 'Y':
-+		ptr = &remcomInBuffer[1];
-+		hexToInt(&ptr, &breakno);
-+		ptr++;
-+		hexToInt(&ptr, &breaktype);
-+		ptr++;
-+		hexToInt(&ptr, &length);
-+		ptr++;
-+		hexToInt(&ptr, &addr);
-+		if (set_hw_break(breakno & 0x3, breaktype & 0x3, 
-+				 length & 0x3, addr) == 0) {
-+			strcpy(remcomOutBuffer, "OK");
-+		} else {
-+			strcpy(remcomOutBuffer, "ERROR");
-+		}
-+		break;
-+
-+		/* Remove hardware breakpoint */
-+	case 'y':
-+		ptr = &remcomInBuffer[1];
-+		hexToInt(&ptr, &breakno);
-+		if (remove_hw_break(breakno & 0x3) == 0) {
-+			strcpy(remcomOutBuffer, "OK");
-+		} else {
-+			strcpy(remcomOutBuffer, "ERROR");
-+		}
-+		break;
-+
-+	}		/* switch */
-+	return -1; /* this means that we do not want to exit from the handler */
-+}
-+
-+int i386_kgdb_init(void)
-+{
-+	return 0;
-+}
-+
-+struct kgdb_arch arch_kgdb_ops =  {
-+	{0xcc},
-+	KGDB_HW_BREAKPOINT,
-+	i386_kgdb_init,
-+	i386_regs_to_gdb_regs,
-+	i386_sleeping_thread_to_gdb_regs,
-+	i386_gdb_regs_to_regs,
-+	i386_printexceptioninfo,
-+	i386_disable_hw_debug,
-+	i386_post_master_code,
-+	i386_handle_exception,
-+	i386_set_hw_break,
-+	i386_remove_hw_break,
-+	i386_correct_hw_break,
-+	NULL,
-+};
-Index: linux-2.4.26-ct_sync/arch/i386/kernel/Makefile
-===================================================================
---- linux-2.4.26-ct_sync.orig/arch/i386/kernel/Makefile	2003-11-28 19:26:19.000000000 +0100
-+++ linux-2.4.26-ct_sync/arch/i386/kernel/Makefile	2004-06-28 12:56:07.000000000 +0200
-@@ -10,7 +10,15 @@
- .S.o:
- 	$(CC) $(AFLAGS) -traditional -c $< -o $*.o
- 
--all: kernel.o head.o init_task.o
-+ifeq ($(CONFIG_KGDB),y)
-+GDBSTART=gdbstart
-+GDBCLEAN= -rm -f gdbstart /sbin/gdbstart
-+else
-+GDBSTART=
-+GDBCLEAN=
-+endif
-+
-+all: kernel.o head.o init_task.o $(GDBSTART)
- 
- O_TARGET := kernel.o
- 
-@@ -32,6 +40,7 @@
- 
- obj-$(CONFIG_MCA)		+= mca.o
- obj-$(CONFIG_MTRR)		+= mtrr.o
-+obj-$(CONFIG_KGDB)		+= i386-stub.o
- obj-$(CONFIG_X86_MSR)		+= msr.o
- obj-$(CONFIG_X86_CPUID)		+= cpuid.o
- obj-$(CONFIG_MICROCODE)		+= microcode.o
-@@ -44,4 +53,11 @@
- obj-$(CONFIG_X86_VISWS_APIC)	+= visws_apic.o
- obj-$(CONFIG_EDD)             	+= edd.o
- 
-+gdbstart:	gdbstart.o
-+		${HOSTCC} -o gdbstart gdbstart.o
-+gdbstart.o:	gdbstart.c
-+		${HOSTCC} -c -o gdbstart.o gdbstart.c
-+
-+kernelclean:	dummy
-+
- include $(TOPDIR)/Rules.make
-Index: linux-2.4.26-ct_sync/arch/i386/kernel/gdbstart.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/arch/i386/kernel/gdbstart.c	2004-06-16 09:19:51.000000000 +0200
-+++ linux-2.4.26-ct_sync/arch/i386/kernel/gdbstart.c	2004-06-28 12:56:07.000000000 +0200
-@@ -0,0 +1,148 @@
-+/*
-+ * This program opens a tty file and issues the GDB stub activating
-+ * ioctl on it.
-+ */
-+
-+#include <sys/types.h>
-+#include <sys/wait.h>
-+#include <asm/ioctls.h>
-+#include <stdio.h>
-+#include <string.h>
-+#include <fcntl.h>
-+#include <sys/ioctl.h>
-+#include <stdlib.h>
-+#include <termios.h>
-+#include <unistd.h>
-+
-+#define TIOCGDB		0x547F
-+
-+char		*tty_name = "/dev/ttyS0" ;	/* COM1 port */
-+int		 speed = 9600 ;			/* default speed */
-+struct termios	 save_ts ;			/* original term struct */
-+
-+void print_usage(void)
-+{
-+    printf("gdbstub [-s speed] [-t tty-dev]\n") ;
-+    printf("  defaults:  /dev/ttyS0 with speed unmodified by this program\n");
-+
-+} /* print_usage */
-+
-+void tty_err(char *msg)
-+{
-+    char	buf[100] ;
-+
-+    strcpy(buf, msg) ;
-+    strcat(buf, ": ") ;
-+    strcat(buf, tty_name) ;
-+    perror(buf) ;
-+    exit(1) ;
-+
-+} /* tty_err */
-+
-+
-+void setup_term(int fd)
-+{
-+    struct termios	ts ;
-+    int			speed_code ;
-+
-+    if (tcgetattr(fd, &ts) < 0) tty_err("tcgetattr") ;
-+
-+    save_ts = ts ;
-+    switch (speed)
-+    {
-+    case 4800:
-+	speed_code = B4800 ;
-+	break ;
-+    case 9600:
-+	speed_code = B9600 ;
-+	break ;
-+    case 19200:
-+	speed_code = B19200 ;
-+	break ;
-+    case 38400:
-+	speed_code = B38400 ;
-+	break ;
-+    case 57600:
-+	speed_code = B57600 ;
-+	break ;
-+    case 115200:
-+	speed_code = B115200 ;
-+	break ;
-+    case 230400:
-+	speed_code = B230400 ;
-+	break ;
-+    default:
-+	printf("Invalid speed: %d\n", speed) ;
-+	exit(1) ;
-+    }
-+
-+    ts.c_cflag = CS8 | CREAD | CLOCAL ;
-+    if (cfsetospeed(&ts, speed_code) < 0) tty_err("cfsetospeed") ;
-+    if (cfsetispeed(&ts, speed_code) < 0) tty_err("cfsetispeed") ;
-+
-+    if (tcsetattr(fd, TCSANOW, &ts) < 0) tty_err("tcsetattr") ;
-+
-+} /* setup_term */
-+
-+void main(int argc, char **argv)
-+{
-+    int		opt ;
-+    int		fil ;
-+    int		rslt ;
-+
-+    while ((opt = getopt(argc, argv, "hs:t:")) > 0)
-+    {
-+	switch (opt)
-+	{
-+	case 's':
-+	    speed = atol(optarg) ;
-+	    break ;
-+	case 't':
-+	    tty_name = optarg ;
-+	    break ;
-+	case ':':
-+	    printf("Invalid option\n") ;
-+	    break ;
-+	case '?':
-+	case 'h':
-+	default:
-+	    print_usage() ;
-+	    return ;
-+	}
-+    }
-+
-+    fil = open(tty_name, O_RDWR) ;
-+    if (fil < 0)
-+    {
-+	perror(tty_name) ;
-+	return ;
-+    }
-+
-+
-+    setup_term(fil) ;
-+
-+    /*
-+     * When we issue this ioctl, control will not return until
-+     * the debugger running on the remote host machine says "go".
-+     */
-+    printf("\nAbout to activate GDB stub in the kernel on %s\n", tty_name) ;
-+    printf("Hit CR to continue, kill program to abort -- ") ;
-+    getchar() ;
-+    sync() ;
-+    rslt = ioctl(fil, TIOCGDB, 0) ;
-+    if (rslt < 0)
-+    {
-+	perror("TIOCGDB ioctl") ;
-+	return ;
-+    }
-+
-+    printf("\nGDB stub successfully activated\n") ;
-+
-+    for (;;)
-+    {
-+	pause() ;
-+    }
-+
-+    if (tcsetattr(fil, TCSANOW, &save_ts) < 0) tty_err("tcsetattr") ;
-+
-+} /* main */
-Index: linux-2.4.26-ct_sync/arch/i386/kernel/nmi.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/arch/i386/kernel/nmi.c	2003-06-13 16:51:29.000000000 +0200
-+++ linux-2.4.26-ct_sync/arch/i386/kernel/nmi.c	2004-06-28 12:56:07.000000000 +0200
-@@ -25,6 +25,20 @@
- #include <asm/mtrr.h>
- #include <asm/mpspec.h>
- 
-+#ifdef CONFIG_KGDB
-+extern gdb_debug_hook * linux_debug_hook;
-+#define	CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after)		\
-+   {									\
-+	if (linux_debug_hook != (gdb_debug_hook *) NULL && !user_mode(regs)) \
-+	{								\
-+		(*linux_debug_hook)(trapnr, signr, error_code, regs) ;	\
-+		after;							\
-+	}								\
-+    }
-+#else
-+#define	CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after)	
-+#endif
-+
- unsigned int nmi_watchdog = NMI_NONE;
- static unsigned int nmi_hz = HZ;
- unsigned int nmi_perfctr_msr;	/* the MSR to reset in NMI handler */
-@@ -347,7 +361,20 @@
- 	int sum, cpu = smp_processor_id();
- 
- 	sum = apic_timer_irqs[cpu];
-+#if defined(CONFIG_KGDB) && defined(CONFIG_SMP)
-+	if (atomic_read(&kgdb_lock)) {
-+
-+		/*
-+		 * The machine is in kgdb, hold this cpu if already
-+		 * not held.
-+		 */
- 
-+		if (!procindebug[cpu] && atomic_read(&kgdb_lock) != (cpu + 1)) {
-+			gdb_wait(regs);
-+		}
-+		alert_counter[cpu] = 0;
-+	} else
-+#endif
- 	if (last_irq_sums[cpu] == sum) {
- 		/*
- 		 * Ayiee, looks like this CPU is stuck ...
-@@ -355,6 +382,9 @@
- 		 */
- 		alert_counter[cpu]++;
- 		if (alert_counter[cpu] == 5*nmi_hz) {
-+
-+			CHK_REMOTE_DEBUG(2,SIGSEGV,0,regs,)
-+
- 			spin_lock(&nmi_print_lock);
- 			/*
- 			 * We are in trouble anyway, lets at least try
-Index: linux-2.4.26-ct_sync/arch/i386/kernel/traps.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/arch/i386/kernel/traps.c	2002-11-29 00:53:09.000000000 +0100
-+++ linux-2.4.26-ct_sync/arch/i386/kernel/traps.c	2004-06-28 12:56:07.000000000 +0200
-@@ -48,8 +48,24 @@
- #endif
- 
- #include <linux/irq.h>
-+#ifdef CONFIG_KGDB
-+#include <linux/kgdb.h>
-+#endif
- #include <linux/module.h>
- 
-+#ifdef CONFIG_KGDB
-+#define	CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after)		\
-+    {									\
-+	if (linux_debug_hook != (gdb_debug_hook *) NULL && !user_mode(regs)) \
-+	{								\
-+		(*linux_debug_hook)(trapnr, signr, error_code, regs) ;	\
-+		after;							\
-+	}								\
-+    }
-+#else
-+#define	CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after)	
-+#endif
-+
- asmlinkage int system_call(void);
- asmlinkage void lcall7(void);
- asmlinkage void lcall27(void);
-@@ -289,6 +305,7 @@
- 	bust_spinlocks(1);
- 	handle_BUG(regs);
- 	printk("%s: %04lx\n", str, err & 0xffff);
-+	CHK_REMOTE_DEBUG(1,SIGTRAP,err,regs,)
- 	show_registers(regs);
- 	bust_spinlocks(0);
- 	spin_unlock_irq(&die_lock);
-@@ -353,6 +370,7 @@
- #define DO_ERROR(trapnr, signr, str, name) \
- asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
- { \
-+	CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,)\
- 	do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \
- }
- 
-@@ -370,7 +388,10 @@
- #define DO_VM86_ERROR(trapnr, signr, str, name) \
- asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
- { \
-+	CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,goto skip_trap)\
- 	do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \
-+skip_trap: \
-+	return; \
- }
- 
- #define DO_VM86_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
-@@ -422,6 +443,7 @@
- 			regs->eip = fixup;
- 			return;
- 		}
-+		CHK_REMOTE_DEBUG(13,SIGSEGV,error_code,regs,)
- 		die("general protection fault", regs, error_code);
- 	}
- }
-@@ -533,7 +555,7 @@
- 	__asm__ __volatile__("movl %%db6,%0" : "=r" (condition));
- 
- 	/* If the user set TF, it's simplest to clear it right away. */
--	if ((eip >=PAGE_OFFSET) && (regs->eflags & TF_MASK))
-+	if ((eip >=PAGE_OFFSET) && (regs->eflags & TF_MASK) && !kgdb_step)
- 		goto clear_TF;
- 
- 	/* Mask out spurious debug traps due to lazy DR7 setting */
-@@ -549,7 +571,7 @@
- 	tsk->thread.debugreg[6] = condition;
- 
- 	/* Mask out spurious TF errors due to lazy TF clearing */
--	if (condition & DR_STEP) {
-+	if (condition & DR_STEP && !kgdb_step) {
- 		/*
- 		 * The TF error should be masked out only if the current
- 		 * process is not traced and if the TRAP flag has been set
-@@ -572,11 +594,13 @@
- 	info.si_errno = 0;
- 	info.si_code = TRAP_BRKPT;
- 	
--	/* If this is a kernel mode trap, save the user PC on entry to 
--	 * the kernel, that's what the debugger can make sense of.
--	 */
--	info.si_addr = ((regs->xcs & 3) == 0) ? (void *)tsk->thread.eip : 
--	                                        (void *)regs->eip;
-+
-+	/* If this is a kernel mode trap, we need to reset db7 to allow us
-+	 * to continue sanely */
-+	if ((regs->xcs & 3) == 0)
-+		goto clear_dr7;
-+
-+	info.si_addr = (void *)regs->eip;
- 	force_sig_info(SIGTRAP, &info, tsk);
- 
- 	/* Disable additional traps. They'll be re-enabled when
-@@ -586,6 +610,7 @@
- 	__asm__("movl %0,%%db7"
- 		: /* no output */
- 		: "r" (0));
-+	CHK_REMOTE_DEBUG(1,SIGTRAP,error_code,regs,)
- 	return;
- 
- debug_vm86:
-Index: linux-2.4.26-ct_sync/arch/i386/kernel/signal.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/arch/i386/kernel/signal.c	2002-08-03 02:39:42.000000000 +0200
-+++ linux-2.4.26-ct_sync/arch/i386/kernel/signal.c	2004-06-28 12:56:07.000000000 +0200
-@@ -695,7 +695,8 @@
- 		 * have been cleared if the watchpoint triggered
- 		 * inside the kernel.
- 		 */
--		__asm__("movl %0,%%db7"	: : "r" (current->thread.debugreg[7]));
-+		if (current->thread.debugreg[7])
-+			__asm__("movl %0,%%db7"	: : "r" (current->thread.debugreg[7]));
- 
- 		/* Whee!  Actually deliver the signal.  */
- 		handle_signal(signr, ka, &info, oldset, regs);
-Index: linux-2.4.26-ct_sync/arch/i386/kernel/entry.S
-===================================================================
---- linux-2.4.26-ct_sync.orig/arch/i386/kernel/entry.S	2003-06-13 16:51:29.000000000 +0200
-+++ linux-2.4.26-ct_sync/arch/i386/kernel/entry.S	2004-06-28 12:56:07.000000000 +0200
-@@ -264,7 +264,7 @@
- 
- 	ALIGN
- reschedule:
--	call SYMBOL_NAME(schedule)    # test
-+	call SYMBOL_NAME(user_schedule)    # test
- 	jmp ret_from_sys_call
- 
- ENTRY(divide_error)
-@@ -402,6 +402,31 @@
- 	pushl $ SYMBOL_NAME(do_spurious_interrupt_bug)
- 	jmp error_code
- 
-+#ifdef CONFIG_KGDB_THREAD
-+ENTRY(kern_schedule)
-+	pushl	%ebp
-+	movl	%esp, %ebp
-+	pushl	%ss		
-+	pushl	%ebp
-+	pushfl
-+	pushl	%cs
-+	pushl	4(%ebp)
-+	pushl	%eax		
-+	pushl	%es
-+	pushl	%ds
-+	pushl	%eax
-+	pushl	(%ebp)
-+	pushl	%edi
-+	pushl	%esi
-+	pushl	%edx
-+	pushl	%ecx
-+	pushl	%ebx
-+	call	kern_do_schedule
-+	movl	%ebp, %esp
-+	pop	%ebp
-+	ret
-+#endif
-+
- .data
- ENTRY(sys_call_table)
- 	.long SYMBOL_NAME(sys_ni_syscall)	/* 0  -  old "setup()" system call*/
-Index: linux-2.4.26-ct_sync/arch/i386/Makefile
-===================================================================
---- linux-2.4.26-ct_sync.orig/arch/i386/Makefile	2003-06-13 16:51:29.000000000 +0200
-+++ linux-2.4.26-ct_sync/arch/i386/Makefile	2004-06-28 12:56:07.000000000 +0200
-@@ -113,6 +113,11 @@
- 	$(MAKE) linuxsubdirs SUBDIRS=arch/i386/mm
- 
- MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
-+ifeq ($(CONFIG_X86_REMOTE_DEBUG),y)
-+CLEANKERNEL = $(MAKE) -C arch/$(ARCH)/kernel kernelclean
-+else
-+CLEANKERNEL =
-+endif
- 
- vmlinux: arch/i386/vmlinux.lds
- 
-@@ -148,6 +153,7 @@
- 
- archclean:
- 	@$(MAKEBOOT) clean
-+	@$(CLEANKERNEL)
- 
- archmrproper:
- 
-Index: linux-2.4.26-ct_sync/arch/i386/mm/fault.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/arch/i386/mm/fault.c	2004-02-18 14:36:30.000000000 +0100
-+++ linux-2.4.26-ct_sync/arch/i386/mm/fault.c	2004-06-28 12:56:07.000000000 +0200
-@@ -2,6 +2,11 @@
-  *  linux/arch/i386/mm/fault.c
-  *
-  *  Copyright (C) 1995  Linus Torvalds
-+ *
-+ *  Change History
-+ *
-+ *	Tigran Aivazian <tigran at sco.com>	Remote debugging support.
-+ *
-  */
- 
- #include <linux/signal.h>
-@@ -19,6 +24,9 @@
- #include <linux/init.h>
- #include <linux/tty.h>
- #include <linux/vt_kern.h>		/* For unblank_screen() */
-+#ifdef CONFIG_KGDB
-+#include <linux/kgdb.h>
-+#endif
- 
- #include <asm/system.h>
- #include <asm/uaccess.h>
-@@ -183,6 +191,13 @@
- 	if (in_interrupt() || !mm)
- 		goto no_context;
- 
-+#ifdef CONFIG_KGDB
-+	if (kgdb_memerr_expected) {
-+		/* We are in kgdb. Can't handle the fault */
-+		goto no_context;
-+	}
-+#endif
-+
- 	down_read(&mm->mmap_sem);
- 
- 	vma = find_vma(mm, address);
-@@ -302,6 +317,12 @@
- 		return;
- 	}
- 
-+#ifdef CONFIG_KGDB
-+	if (linux_debug_hook != (gdb_debug_hook *) NULL) {
-+		(*linux_debug_hook)(14, SIGSEGV, error_code, regs);
-+	}
-+#endif
-+
- /*
-  * Oops. The kernel tried to access some bad page. We'll have to
-  * terminate things with extreme prejudice.
-@@ -309,6 +330,7 @@
- 
- 	bust_spinlocks(1);
- 
-+
- 	if (address < PAGE_SIZE)
- 		printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
- 	else
-Index: linux-2.4.26-ct_sync/arch/i386/config.in
-===================================================================
---- linux-2.4.26-ct_sync.orig/arch/i386/config.in	2004-02-18 14:36:30.000000000 +0100
-+++ linux-2.4.26-ct_sync/arch/i386/config.in	2004-06-28 12:56:07.000000000 +0200
-@@ -470,15 +470,21 @@
- mainmenu_option next_comment
- comment 'Kernel hacking'
- 
--bool 'Kernel debugging' CONFIG_DEBUG_KERNEL
--if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then
--   bool '  Check for stack overflows' CONFIG_DEBUG_STACKOVERFLOW
--   bool '  Debug high memory support' CONFIG_DEBUG_HIGHMEM
--   bool '  Debug memory allocations' CONFIG_DEBUG_SLAB
--   bool '  Memory mapped I/O debugging' CONFIG_DEBUG_IOVIRT
--   bool '  Magic SysRq key' CONFIG_MAGIC_SYSRQ
--   bool '  Spinlock debugging' CONFIG_DEBUG_SPINLOCK
--   bool '  Compile the kernel with frame pointers' CONFIG_FRAME_POINTER
-+bool 'KGDB: Remote (serial) kernel debugging with gdb' CONFIG_KGDB
-+if [ "$CONFIG_KGDB" != "n" ]; then
-+   bool 'KGDB: Thread analysis' CONFIG_KGDB_THREAD
-+   bool 'KGDB: Console messages through gdb' CONFIG_GDB_CONSOLE
-+else
-+   bool 'Kernel debugging' CONFIG_DEBUG_KERNEL
-+   if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then
-+      bool '  Check for stack overflows' CONFIG_DEBUG_STACKOVERFLOW
-+      bool '  Debug high memory support' CONFIG_DEBUG_HIGHMEM
-+      bool '  Debug memory allocations' CONFIG_DEBUG_SLAB
-+      bool '  Memory mapped I/O debugging' CONFIG_DEBUG_IOVIRT
-+      bool '  Magic SysRq key' CONFIG_MAGIC_SYSRQ
-+      bool '  Spinlock debugging' CONFIG_DEBUG_SPINLOCK
-+      bool '  Compile the kernel with frame pointers' CONFIG_FRAME_POINTER
-+   fi
- fi
- 
- int 'Kernel messages buffer length shift (0 = default)' CONFIG_LOG_BUF_SHIFT 0
-Index: linux-2.4.26-ct_sync/arch/ppc/kernel/ppc-stub.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/arch/ppc/kernel/ppc-stub.c	2003-11-28 19:26:19.000000000 +0100
-+++ linux-2.4.26-ct_sync/arch/ppc/kernel/ppc-stub.c	2004-06-28 12:56:07.000000000 +0200
-@@ -1,742 +1,261 @@
- /*
-- * ppc-stub.c:  KGDB support for the Linux kernel.
-  *
-- * adapted from arch/sparc/kernel/sparc-stub.c for the PowerPC
-- * some stuff borrowed from Paul Mackerras' xmon
-- * Copyright (C) 1998 Michael AK Tesch (tesch at cs.wisc.edu)
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License as published by the
-+ * Free Software Foundation; either version 2, or (at your option) any
-+ * later version.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-+ * General Public License for more details.
-  *
-- * Modifications to run under Linux
-- * Copyright (C) 1995 David S. Miller (davem at caip.rutgers.edu)
-- *
-- * This file originally came from the gdb sources, and the
-- * copyright notices have been retained below.
-  */
- 
--/****************************************************************************
--
--		THIS SOFTWARE IS NOT COPYRIGHTED
--
--   HP offers the following for use in the public domain.  HP makes no
--   warranty with regard to the software or its performance and the
--   user accepts the software "AS IS" with all faults.
--
--   HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
--   TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
--   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
--
--****************************************************************************/
--
--/****************************************************************************
-- *  Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
-- *
-- *  Module name: remcom.c $
-- *  Revision: 1.34 $
-- *  Date: 91/03/09 12:29:49 $
-- *  Contributor:     Lake Stevens Instrument Division$
-- *
-- *  Description:     low level support for gdb debugger. $
-- *
-- *  Considerations:  only works on target hardware $
-- *
-- *  Written by:      Glenn Engel $
-- *  ModuleState:     Experimental $
-- *
-- *  NOTES:           See Below $
-- *
-- *  Modified for SPARC by Stu Grossman, Cygnus Support.
-- *
-- *  This code has been extensively tested on the Fujitsu SPARClite demo board.
-- *
-- *  To enable debugger support, two things need to happen.  One, a
-- *  call to set_debug_traps() is necessary in order to allow any breakpoints
-- *  or error conditions to be properly intercepted and reported to gdb.
-- *  Two, a breakpoint needs to be generated to begin communication.  This
-- *  is most easily accomplished by a call to breakpoint().  Breakpoint()
-- *  simulates a breakpoint by executing a trap #1.
-- *
-- *************
-- *
-- *    The following gdb commands are supported:
-- *
-- * command          function                               Return value
-- *
-- *    g             return the value of the CPU registers  hex data or ENN
-- *    G             set the value of the CPU registers     OK or ENN
-- *    qOffsets      Get section offsets.  Reply is Text=xxx;Data=yyy;Bss=zzz
-- *
-- *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
-- *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
-- *
-- *    c             Resume at current address              SNN   ( signal NN)
-- *    cAA..AA       Continue at address AA..AA             SNN
-- *
-- *    s             Step one instruction                   SNN
-- *    sAA..AA       Step one instruction from AA..AA       SNN
-- *
-- *    k             kill
-- *
-- *    ?             What was the last sigval ?             SNN   (signal NN)
-- *
-- *    bBB..BB	    Set baud rate to BB..BB		   OK or BNN, then sets
-- *							   baud rate
-- *
-- * All commands and responses are sent with a packet which includes a
-- * checksum.  A packet consists of
-- *
-- * $<packet info>#<checksum>.
-- *
-- * where
-- * <packet info> :: <characters representing the command or response>
-- * <checksum>    :: <two hex digits computed as modulo 256 sum of <packetinfo>>
-- *
-- * When a packet is received, it is first acknowledged with either '+' or '-'.
-- * '+' indicates a successful transfer.  '-' indicates a failed transfer.
-- *
-- * Example:
-- *
-- * Host:                  Reply:
-- * $m0,10#2a               +$00010203040506070809101112131415#42
-- *
-- ****************************************************************************/
-+/*
-+ * Copyright (C) 2003 Timesys Corporation.
-+ * KGDB for the PowerPC processor
-+ */
- 
--#include <linux/config.h>
--#include <linux/kernel.h>
- #include <linux/string.h>
--#include <linux/mm.h>
--#include <linux/smp.h>
--#include <linux/smp_lock.h>
--
--#include <asm/system.h>
--#include <asm/signal.h>
--#include <asm/kgdb.h>
--#include <asm/pgtable.h>
-+#include <linux/kernel.h>
-+#include <linux/config.h>
-+#include <linux/kgdb.h>
-+#include <linux/sched.h>
-+#include <asm/current.h>
- #include <asm/ptrace.h>
--
--void breakinst(void);
-+#include <asm/processor.h>
-+#include <asm/signal.h>
- 
- /*
-- * BUFMAX defines the maximum number of characters in inbound/outbound buffers
-- * at least NUMREGBYTES*2 are needed for register packets
-+ * Forward prototypes
-  */
--#define BUFMAX 2048
--static char remcomInBuffer[BUFMAX];
--static char remcomOutBuffer[BUFMAX];
--
--static int initialized;
--static int kgdb_active;
--static int kgdb_started;
--static u_int fault_jmp_buf[100];
--static int kdebug;
--
--static const char hexchars[]="0123456789abcdef";
--
--/* Place where we save old trap entries for restoration - sparc*/
--/* struct tt_entry kgdb_savettable[256]; */
--/* typedef void (*trapfunc_t)(void); */
--
--static void kgdb_fault_handler(struct pt_regs *regs);
--static int handle_exception (struct pt_regs *regs);
--
--#if 0
--/* Install an exception handler for kgdb */
--static void exceptionHandler(int tnum, unsigned int *tfunc)
--{
--	/* We are dorking with a live trap table, all irqs off */
--}
--#endif
-+static void kgdb_debugger (struct pt_regs *regs);
-+static int kgdb_breakpoint (struct pt_regs *regs);
-+static int kgdb_singlestep (struct pt_regs *regs);
-+static int kgdb_iabr_match(struct pt_regs *regs);
-+static int kgdb_dabr_match(struct pt_regs *regs);
-+static int ppc_kgdb_init (void);
-+static void ppc_regs_to_gdb_regs(int *gdb_regs, struct pt_regs *regs);
-+static void ppc_sleeping_thread_to_gdb_regs(int *gdb_regs, struct task_struct *p);
-+static void ppc_gdb_regs_to_regs(int *gdb_regs, struct pt_regs *regs);
-+void ppc_exit_handler (void);
-+int ppc_handle_exception (int            vector,
-+                           int            signo,
-+                           int            err_code,
-+                           char           *remcomInBuffer,
-+                           char           *remcomOutBuffer,
-+                           struct pt_regs *linux_regs);
- 
--int
--kgdb_setjmp(long *buf)
--{
--	asm ("mflr 0; stw 0,0(%0);"
--	     "stw 1,4(%0); stw 2,8(%0);"
--	     "mfcr 0; stw 0,12(%0);"
--	     "stmw 13,16(%0)"
--	     : : "r" (buf));
--	/* XXX should save fp regs as well */
--	return 0;
--}
--void
--kgdb_longjmp(long *buf, int val)
--{
--	if (val == 0)
--		val = 1;
--	asm ("lmw 13,16(%0);"
--	     "lwz 0,12(%0); mtcrf 0x38,0;"
--	     "lwz 0,0(%0); lwz 1,4(%0); lwz 2,8(%0);"
--	     "mtlr 0; mr 3,%1"
--	     : : "r" (buf), "r" (val));
--}
--/* Convert ch from a hex digit to an int */
--static int
--hex(unsigned char ch)
--{
--	if (ch >= 'a' && ch <= 'f')
--		return ch-'a'+10;
--	if (ch >= '0' && ch <= '9')
--		return ch-'0';
--	if (ch >= 'A' && ch <= 'F')
--		return ch-'A'+10;
--	return -1;
--}
--
--/* Convert the memory pointed to by mem into hex, placing result in buf.
-- * Return a pointer to the last char put in buf (null), in case of mem fault,
-- * return 0.
-+/*
-+ * Global data
-  */
--static unsigned char *
--mem2hex(const char *mem, char *buf, int count)
-+struct kgdb_arch arch_kgdb_ops =
- {
--	unsigned char ch;
--
--	if (kgdb_setjmp((long*)fault_jmp_buf) == 0) {
--		debugger_fault_handler = kgdb_fault_handler;
--		while (count-- > 0) {
--			ch = *mem++;
--			*buf++ = hexchars[ch >> 4];
--			*buf++ = hexchars[ch & 0xf];
--		}
--	} else {
--		/* error condition */
--	}
--	debugger_fault_handler = 0;
--	*buf = 0;
--	return buf;
--}
--
--/* convert the hex array pointed to by buf into binary to be placed in mem
-- * return a pointer to the character AFTER the last byte written.
--*/
--static char *
--hex2mem(char *buf, char *mem, int count)
--{
--	int i;
--	unsigned char ch;
--
--	if (kgdb_setjmp((long*)fault_jmp_buf) == 0) {
--		debugger_fault_handler = kgdb_fault_handler;
--		for (i=0; i<count; i++) {
--			ch = hex(*buf++) << 4;
--			ch |= hex(*buf++);
--			*mem++ = ch;
--		}
--		flush_icache_range((int)mem, (int)mem+count);
--	} else {
--		/* error condition */
--	}
--	debugger_fault_handler = 0;
--	return mem;
--}
-+	{ 0x7d, 0x82, 0x10, 0x08 },       /* gdb_bpt_instr               */
-+	0,                                /* flags                       */
-+	ppc_kgdb_init,                   /* kgdb_init                   */
-+	ppc_regs_to_gdb_regs,            /* regs_to_gdb_regs            */
-+	ppc_sleeping_thread_to_gdb_regs, /* sleeping_thread_to_gdb_regs */
-+	ppc_gdb_regs_to_regs,            /* gdb_regs_to_regs            */
-+	NULL,                             /* printexpinfo                */
-+	NULL,                             /* disable_hw_debug            */
-+	NULL,                             /* post_master_code            */
-+	ppc_handle_exception,             /* handle_buffer               */
-+	NULL,                             /* set_break                   */
-+	NULL,                             /* remove_break                */
-+	NULL,                             /* correct_hw_break            */
-+	ppc_exit_handler,                /* handler_exit                */
-+};
- 
- /*
-- * While we find nice hex chars, build an int.
-- * Return number of chars processed.
-+ * Routines
-  */
--static int
--hexToInt(char **ptr, int *intValue)
-+static void kgdb_debugger (struct pt_regs *regs)
- {
--	int numChars = 0;
--	int hexValue;
--
--	*intValue = 0;
--
--	if (kgdb_setjmp((long*)fault_jmp_buf) == 0) {
--		debugger_fault_handler = kgdb_fault_handler;
--		while (**ptr) {
--			hexValue = hex(**ptr);
--			if (hexValue < 0)
--				break;
--
--			*intValue = (*intValue << 4) | hexValue;
--			numChars ++;
--
--			(*ptr)++;
--		}
--	} else {
--	     /* error condition */
--	}
--	debugger_fault_handler = 0;
--
--	return (numChars);
--}
--
--/* scan for the sequence $<data>#<checksum>     */
--static void
--getpacket(char *buffer)
--{
--	unsigned char checksum;
--	unsigned char xmitcsum;
--	int i;
--	int count;
--	unsigned char ch;
--
--	do {
--		/* wait around for the start character, ignore all other
--		 * characters */
--		while ((ch = (getDebugChar() & 0x7f)) != '$') ;
--
--		checksum = 0;
--		xmitcsum = -1;
--
--		count = 0;
--
--		/* now, read until a # or end of buffer is found */
--		while (count < BUFMAX) {
--			ch = getDebugChar() & 0x7f;
--			if (ch == '#')
--				break;
--			checksum = checksum + ch;
--			buffer[count] = ch;
--			count = count + 1;
--		}
--
--		if (count >= BUFMAX)
--			continue;
--
--		buffer[count] = 0;
--
--		if (ch == '#') {
--			xmitcsum = hex(getDebugChar() & 0x7f) << 4;
--			xmitcsum |= hex(getDebugChar() & 0x7f);
--			if (checksum != xmitcsum)
--				putDebugChar('-');	/* failed checksum */
--			else {
--				putDebugChar('+'); /* successful transfer */
--				/* if a sequence char is present, reply the ID */
--				if (buffer[2] == ':') {
--					putDebugChar(buffer[0]);
--					putDebugChar(buffer[1]);
--					/* remove sequence chars from buffer */
--					count = strlen(buffer);
--					for (i=3; i <= count; i++)
--						buffer[i-3] = buffer[i];
--				}
--			}
--		}
--	} while (checksum != xmitcsum);
-+	kgdb_handle_exception (0, 0, 0, regs);
-+	return;
- }
- 
--/* send the packet in buffer.  */
--static void putpacket(unsigned char *buffer)
-+static int kgdb_breakpoint (struct pt_regs *regs)
- {
--	unsigned char checksum;
--	int count;
--	unsigned char ch, recv;
--
--	/*  $<packet info>#<checksum>. */
--	do {
--		putDebugChar('$');
--		checksum = 0;
--		count = 0;
--
--		while ((ch = buffer[count])) {
--			putDebugChar(ch);
--			checksum += ch;
--			count += 1;
--		}
--
--		putDebugChar('#');
--		putDebugChar(hexchars[checksum >> 4]);
--		putDebugChar(hexchars[checksum & 0xf]);
--		recv = getDebugChar();
--	} while ((recv & 0x7f) != '+');
--}
-+	extern atomic_t kgdb_setting_breakpoint;
- 
--static void kgdb_flush_cache_all(void)
--{
--	flush_instruction_cache();
--}
-+	kgdb_handle_exception (0, SIGTRAP, 0, regs);
- 
--/* Set up exception handlers for tracing and breakpoints
-- * [could be called kgdb_init()]
-- */
--void set_debug_traps(void)
--{
--#if 0
--	unsigned char c;
--
--	save_and_cli(flags);
--
--	/* In case GDB is started before us, ack any packets (presumably
--	 * "$?#xx") sitting there.
--	 *
--	 * I've found this code causes more problems than it solves,
--	 * so that's why it's commented out.  GDB seems to work fine
--	 * now starting either before or after the kernel   -bwb
--	 */
--
--	while((c = getDebugChar()) != '$');
--	while((c = getDebugChar()) != '#');
--	c = getDebugChar(); /* eat first csum byte */
--	c = getDebugChar(); /* eat second csum byte */
--	putDebugChar('+'); /* ack it */
--#endif
--	debugger = kgdb;
--	debugger_bpt = kgdb_bpt;
--	debugger_sstep = kgdb_sstep;
--	debugger_iabr_match = kgdb_iabr_match;
--	debugger_dabr_match = kgdb_dabr_match;
-+	if (atomic_read (&kgdb_setting_breakpoint))
-+		regs->nip += 4;
- 
--	initialized = 1;
-+	return 1;
- }
- 
--static void kgdb_fault_handler(struct pt_regs *regs)
-+static int kgdb_singlestep (struct pt_regs *regs)
- {
--	kgdb_longjmp((long*)fault_jmp_buf, 1);
-+	kgdb_handle_exception (0, SIGTRAP, 0, regs);
-+	return 1;
- }
- 
--int kgdb_bpt(struct pt_regs *regs)
-+static int kgdb_iabr_match(struct pt_regs *regs)
- {
--	return handle_exception(regs);
-+	kgdb_handle_exception (0, 0, 0, regs);
-+	return 1;
- }
- 
--int kgdb_sstep(struct pt_regs *regs)
-+static int kgdb_dabr_match(struct pt_regs *regs)
- {
--	return handle_exception(regs);
-+	kgdb_handle_exception (0, 0, 0, regs);
-+	return 1;
- }
- 
--void kgdb(struct pt_regs *regs)
-+static int ppc_kgdb_init (void)
- {
--	handle_exception(regs);
--}
-+	debugger = kgdb_debugger;
-+	debugger_bpt = kgdb_breakpoint;
-+	debugger_sstep = kgdb_singlestep;
-+	debugger_iabr_match = kgdb_iabr_match;
-+	debugger_dabr_match = kgdb_dabr_match;
- 
--int kgdb_iabr_match(struct pt_regs *regs)
--{
--	printk(KERN_ERR "kgdb doesn't support iabr, what?!?\n");
--	return handle_exception(regs);
-+	return 0;
-+	
- }
- 
--int kgdb_dabr_match(struct pt_regs *regs)
-+static void ppc_regs_to_gdb_regs(int *gdb_regs, struct pt_regs *regs)
- {
--	printk(KERN_ERR "kgdb doesn't support dabr, what?!?\n");
--	return handle_exception(regs);
--}
-+	int reg;
-+	int *ptr = gdb_regs;
- 
--/* Convert the SPARC hardware trap type code to a unix signal number. */
--/*
-- * This table contains the mapping between PowerPC hardware trap types, and
-- * signals, which are primarily what GDB understands.
-- */
--static struct hard_trap_info
--{
--	unsigned int tt;		/* Trap type code for powerpc */
--	unsigned char signo;		/* Signal that we map this trap into */
--} hard_trap_info[] = {
--	{ 0x200, SIGSEGV },			/* machine check */
--	{ 0x300, SIGSEGV },			/* address error (store) */
--	{ 0x400, SIGBUS },			/* instruction bus error */
--	{ 0x500, SIGINT },			/* interrupt */
--	{ 0x600, SIGBUS },			/* alingment */
--	{ 0x700, SIGTRAP },			/* breakpoint trap */
--	{ 0x800, SIGFPE },			/* fpu unavail */
--	{ 0x900, SIGALRM },			/* decrementer */
--	{ 0xa00, SIGILL },			/* reserved */
--	{ 0xb00, SIGILL },			/* reserved */
--	{ 0xc00, SIGCHLD },			/* syscall */
--	{ 0xd00, SIGTRAP },			/* single-step/watch */
--	{ 0xe00, SIGFPE },			/* fp assist */
--	{ 0, 0}				/* Must be last */
--};
-+	memset(gdb_regs, 0, MAXREG*4);
- 
--static int computeSignal(unsigned int tt)
--{
--	struct hard_trap_info *ht;
-+	for (reg = 0; reg < 32; reg++)
-+		*(ptr++) = regs->gpr[reg];
- 
--	for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
--		if (ht->tt == tt)
--			return ht->signo;
-+	for (reg = 0; reg < 64; reg++)
-+		*(ptr++) = 0;
- 
--	return SIGHUP;         /* default for things we don't know about */
--}
-+	*(ptr++) = regs->nip;
-+	*(ptr++) = regs->msr;
-+	*(ptr++) = regs->ccr;
-+	*(ptr++) = regs->link;
-+	*(ptr++) = regs->ctr;
-+	*(ptr++) = regs->xer;
- 
--#define PC_REGNUM 64
--#define SP_REGNUM 1
-+	return;
-+}	/* regs_to_gdb_regs */
- 
--/*
-- * This function does all command processing for interfacing to gdb.
-- */
--static int
--handle_exception (struct pt_regs *regs)
-+static void ppc_sleeping_thread_to_gdb_regs(int *gdb_regs, struct task_struct *p)
- {
--	int sigval;
--	int addr;
--	int length;
--	char *ptr;
--	unsigned int msr;
--
--	/* We don't handle user-mode breakpoints. */
--	if (user_mode(regs))
--		return 0;
--
--	if (debugger_fault_handler) {
--		debugger_fault_handler(regs);
--		panic("kgdb longjump failed!\n");
--	}
--	if (kgdb_active) {
--		printk(KERN_ERR "interrupt while in kgdb, returning\n");
--		return 0;
--	}
--
--	kgdb_active = 1;
--	kgdb_started = 1;
--
--#ifdef KGDB_DEBUG
--	printk("kgdb: entering handle_exception; trap [0x%x]\n",
--	       (unsigned int)regs->trap);
--#endif
--
--	kgdb_interruptible(0);
--	lock_kernel();
--	msr = mfmsr();
--	mtmsr(msr & ~MSR_EE);	/* disable interrupts */
--
--	if (regs->nip == (unsigned long)breakinst) {
--		/* Skip over breakpoint trap insn */
--		regs->nip += 4;
--	}
--
--	/* reply to host that an exception has occurred */
--	sigval = computeSignal(regs->trap);
--	ptr = remcomOutBuffer;
--
--#if 0
--	*ptr++ = 'S';
--	*ptr++ = hexchars[sigval >> 4];
--	*ptr++ = hexchars[sigval & 0xf];
--#else
--	*ptr++ = 'T';
--	*ptr++ = hexchars[sigval >> 4];
--	*ptr++ = hexchars[sigval & 0xf];
--	*ptr++ = hexchars[PC_REGNUM >> 4];
--	*ptr++ = hexchars[PC_REGNUM & 0xf];
--	*ptr++ = ':';
--	ptr = mem2hex((char *)&regs->nip, ptr, 4);
--	*ptr++ = ';';
--	*ptr++ = hexchars[SP_REGNUM >> 4];
--	*ptr++ = hexchars[SP_REGNUM & 0xf];
--	*ptr++ = ':';
--	ptr = mem2hex(((char *)regs) + SP_REGNUM*4, ptr, 4);
--	*ptr++ = ';';
--#endif
--
--	*ptr++ = 0;
-+	struct pt_regs *regs = (struct pt_regs *) (p->thread.ksp +
-+	                                           STACK_FRAME_OVERHEAD);
-+	int reg;
-+	int *ptr = gdb_regs;
- 
--	putpacket(remcomOutBuffer);
-+	memset(gdb_regs, 0, MAXREG*4);
- 
--	/* XXX We may want to add some features dealing with poking the
--	 * XXX page tables, ... (look at sparc-stub.c for more info)
--	 * XXX also required hacking to the gdb sources directly...
--	 */
--
--	while (1) {
--		remcomOutBuffer[0] = 0;
--
--		getpacket(remcomInBuffer);
--		switch (remcomInBuffer[0]) {
--		case '?':               /* report most recent signal */
--			remcomOutBuffer[0] = 'S';
--			remcomOutBuffer[1] = hexchars[sigval >> 4];
--			remcomOutBuffer[2] = hexchars[sigval & 0xf];
--			remcomOutBuffer[3] = 0;
--			break;
--#if 0
--		case 'q': /* this screws up gdb for some reason...*/
--		{
--			extern long _start, sdata, __bss_start;
-+	/* Regs GPR0-2 */
-+	for (reg = 0; reg < 3; reg++)
-+		*(ptr++) = regs->gpr[reg];
- 
--			ptr = &remcomInBuffer[1];
--			if (strncmp(ptr, "Offsets", 7) != 0)
--				break;
--
--			ptr = remcomOutBuffer;
--			sprintf(ptr, "Text=%8.8x;Data=%8.8x;Bss=%8.8x",
--				&_start, &sdata, &__bss_start);
--			break;
--		}
--#endif
--		case 'd':
--			/* toggle debug flag */
--			kdebug ^= 1;
--			break;
--
--		case 'g':	/* return the value of the CPU registers.
--				 * some of them are non-PowerPC names :(
--				 * they are stored in gdb like:
--				 * struct {
--				 *     u32 gpr[32];
--				 *     f64 fpr[32];
--				 *     u32 pc, ps, cnd, lr; (ps=msr)
--				 *     u32 cnt, xer, mq;
--				 * }
--				 */
--		{
--			int i;
--			ptr = remcomOutBuffer;
--			/* General Purpose Regs */
--			ptr = mem2hex((char *)regs, ptr, 32 * 4);
--			/* Floating Point Regs - FIXME */
--			/*ptr = mem2hex((char *), ptr, 32 * 8);*/
--			for(i=0; i<(32*8*2); i++) { /* 2chars/byte */
--				ptr[i] = '0';
--			}
--			ptr += 32*8*2;
--			/* pc, msr, cr, lr, ctr, xer, (mq is unused) */
--			ptr = mem2hex((char *)&regs->nip, ptr, 4);
--			ptr = mem2hex((char *)&regs->msr, ptr, 4);
--			ptr = mem2hex((char *)&regs->ccr, ptr, 4);
--			ptr = mem2hex((char *)&regs->link, ptr, 4);
--			ptr = mem2hex((char *)&regs->ctr, ptr, 4);
--			ptr = mem2hex((char *)&regs->xer, ptr, 4);
--		}
--			break;
-+	/* Regs GPR3-13 are not saved */
-+	for (reg = 3; reg < 14; reg++)
-+		*(ptr++) = 0;
- 
--		case 'G':   /* set the value of the CPU registers */
--		{
--			ptr = &remcomInBuffer[1];
-+	/* Regs GPR14-31 */
-+	for (reg = 14; reg < 32; reg++)
-+		*(ptr++) = regs->gpr[reg];
- 
--			/*
--			 * If the stack pointer has moved, you should pray.
--			 * (cause only god can help you).
--			 */
--
--			/* General Purpose Regs */
--			hex2mem(ptr, (char *)regs, 32 * 4);
--
--			/* Floating Point Regs - FIXME?? */
--			/*ptr = hex2mem(ptr, ??, 32 * 8);*/
--			ptr += 32*8*2;
--
--			/* pc, msr, cr, lr, ctr, xer, (mq is unused) */
--			ptr = hex2mem(ptr, (char *)&regs->nip, 4);
--			ptr = hex2mem(ptr, (char *)&regs->msr, 4);
--			ptr = hex2mem(ptr, (char *)&regs->ccr, 4);
--			ptr = hex2mem(ptr, (char *)&regs->link, 4);
--			ptr = hex2mem(ptr, (char *)&regs->ctr, 4);
--			ptr = hex2mem(ptr, (char *)&regs->xer, 4);
--
--			strcpy(remcomOutBuffer,"OK");
--		}
--			break;
--		case 'H':
--			/* don't do anything, yet, just acknowledge */
--			hexToInt(&ptr, &addr);
--			strcpy(remcomOutBuffer,"OK");
--			break;
-+	for (reg = 0; reg < 64; reg++)
-+		*(ptr++) = 0;
- 
--		case 'm':	/* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
--				/* Try to read %x,%x.  */
-+	*(ptr++) = regs->nip;
-+	*(ptr++) = regs->msr;
-+	*(ptr++) = regs->ccr;
-+	*(ptr++) = regs->link;
-+	*(ptr++) = regs->ctr;
-+	*(ptr++) = regs->xer;
- 
--			ptr = &remcomInBuffer[1];
-+	return;
-+}
- 
--			if (hexToInt(&ptr, &addr)
--			    && *ptr++ == ','
--			    && hexToInt(&ptr, &length))	{
--				if (mem2hex((char *)addr, remcomOutBuffer,length))
--					break;
--				strcpy (remcomOutBuffer, "E03");
--			} else {
--				strcpy(remcomOutBuffer,"E01");
--			}
--			break;
-+static void ppc_gdb_regs_to_regs(int *gdb_regs, struct pt_regs *regs)
-+{
-+	int reg;
-+	int *ptr = gdb_regs;
- 
--		case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
--			/* Try to read '%x,%x:'.  */
-+	for (reg = 0; reg < 32; reg++)
-+		regs->gpr[reg] = *(ptr++);
- 
--			ptr = &remcomInBuffer[1];
-+	for (reg = 0; reg < 64; reg++)
-+		ptr++;
- 
--			if (hexToInt(&ptr, &addr)
--			    && *ptr++ == ','
--			    && hexToInt(&ptr, &length)
--			    && *ptr++ == ':') {
--				if (hex2mem(ptr, (char *)addr, length)) {
--					strcpy(remcomOutBuffer, "OK");
--				} else {
--					strcpy(remcomOutBuffer, "E03");
--				}
--				flush_icache_range(addr, addr+length);
--			} else {
--				strcpy(remcomOutBuffer, "E02");
--			}
--			break;
-+	regs->nip = *(ptr++);
-+	regs->msr = *(ptr++);
-+	regs->ccr = *(ptr++);
-+	regs->link = *(ptr++);
-+	regs->ctr = *(ptr++);
-+	regs->xer = *(ptr++);
- 
-+	return;
-+}	/* gdb_regs_to_regs */
- 
--		case 'k':    /* kill the program, actually just continue */
--		case 'c':    /* cAA..AA  Continue; address AA..AA optional */
--			/* try to read optional parameter, pc unchanged if no parm */
- 
--			ptr = &remcomInBuffer[1];
--			if (hexToInt(&ptr, &addr)) {
--				regs->nip = addr;
--			}
--
--/* Need to flush the instruction cache here, as we may have deposited a
-- * breakpoint, and the icache probably has no way of knowing that a data ref to
-- * some location may have changed something that is in the instruction cache.
-+/* exit_handler:
-+ * 
-+ * This is called by the generic layer when it is about to return from 
-+ * the exception handler
-  */
--			kgdb_flush_cache_all();
--			mtmsr(msr);
--			kgdb_interruptible(1);
--			unlock_kernel();
--			kgdb_active = 0;
--			return 1;
--
--		case 's':
--			kgdb_flush_cache_all();
--			regs->msr |= MSR_SE;
--			unlock_kernel();
--			kgdb_active = 0;
--			return 1;
--
--		case 'r':		/* Reset (if user process..exit ???)*/
--			panic("kgdb reset.");
--			break;
--		}			/* switch */
--		if (remcomOutBuffer[0] && kdebug) {
--			printk("remcomInBuffer: %s\n", remcomInBuffer);
--			printk("remcomOutBuffer: %s\n", remcomOutBuffer);
--		}
--		/* reply to the request */
--		putpacket(remcomOutBuffer);
--	} /* while(1) */
-+void ppc_exit_handler (void)
-+{
-+//	flush_instruction_cache ();
-+	return;
- }
- 
--/* This function will generate a breakpoint exception.  It is used at the
--   beginning of a program to sync up with a debugger and can be used
--   otherwise as a quick means to stop program execution and "break" into
--   the debugger. */
--
--void
--breakpoint(void)
--{
--	if (!initialized) {
--		printk("breakpoint() called b4 kgdb init\n");
--		return;
--	}
--
--	asm("	.globl breakinst	\n\
--	     breakinst: .long 0x7d821008");
--}
- 
--#ifdef CONFIG_KGDB_CONSOLE
- /*
-- * Output string in GDB O-packet format if GDB has connected. If nothing
-- * output, returns 0 (caller must then handle output)
-+ * This function does PoerPC specific procesing for interfacing to gdb.
-  */
--int
--kgdb_output_string (const char* s, unsigned int count)
-+int ppc_handle_exception (int            vector,
-+                          int            signo,
-+                          int            err_code,
-+                          char           *remcomInBuffer,
-+                          char           *remcomOutBuffer,
-+                          struct pt_regs *linux_regs)
- {
--	char buffer[512];
-+	char *ptr;
-+	int addr;
-+	
-+	switch (remcomInBuffer[0])
-+		{
-+		/*
-+		 * sAA..AA   Step one instruction from AA..AA 
-+		 * This will return an error to gdb ..
-+		 */
-+		case 's':
-+		case 'c':
-+			if (kgdb_contthread && kgdb_contthread != current)
-+			{
-+				strcpy(remcomOutBuffer, "E00");
-+				break;
-+			}
- 
--        if (!kgdb_started)
--            return 0;
-+			kgdb_contthread = NULL;
- 
--	count = (count <= (sizeof(buffer) / 2 - 2))
--		? count : (sizeof(buffer) / 2 - 2);
-+			/* handle the optional parameter */
-+			ptr = &remcomInBuffer[1];
-+			if (hexToInt (&ptr, &addr))
-+				linux_regs->nip = addr;
- 
--	buffer[0] = 'O';
--	mem2hex (s, &buffer[1], count);
--	putpacket(buffer);
-+			/* set the trace bit if we're stepping */
-+            if (remcomInBuffer[0] == 's')
-+			{
-+#if defined (CONFIG_4xx)
-+				linux_regs->msr |= MSR_DE;
-+				current->thread.dbcr0 |= (DBCR_IDM | DBCR_IC);
-+#else
-+				linux_regs->msr |= MSR_SE;
-+#endif
-+			}
-+			return 0;
-+	}
- 
--        return 1;
-+	return -1;
- }
--#endif
-Index: linux-2.4.26-ct_sync/arch/ppc/kernel/entry.S
-===================================================================
---- linux-2.4.26-ct_sync.orig/arch/ppc/kernel/entry.S	2004-04-14 15:05:27.000000000 +0200
-+++ linux-2.4.26-ct_sync/arch/ppc/kernel/entry.S	2004-06-28 12:56:07.000000000 +0200
-@@ -295,7 +295,7 @@
- 	lwz	r3,NEED_RESCHED(r2)
- 	cmpi	0,r3,0		/* check need_resched flag */
- 	beq+	7f
--	bl	schedule
-+	bl	user_schedule
- 7:	lwz	r5,SIGPENDING(r2) /* Check for pending unblocked signals */
- 	cmpwi	0,r5,0
- 	beq+	do_signal_ret
-@@ -450,3 +450,53 @@
- 	mtspr	SRR1,r9
- 	RFI			/* return to caller */
- #endif /* CONFIG_ALL_PPC */
-+
-+#ifdef CONFIG_KGDB
-+/*
-+ * These are hooks used by KGDB because switch_to does not save registers
-+ * in pt_regs.  The registers are saved on the stack on behalf of the caller
-+ * of these funtions.
-+ */
-+
-+_GLOBAL(kern_schedule)
-+	stwu	r1,-INT_FRAME_SIZE(r1)	/* Allocate exception frame */
-+	SAVE_8GPRS( 0, r1)
-+	SAVE_8GPRS( 8, r1)
-+	SAVE_8GPRS(16, r1)
-+	SAVE_8GPRS(24, r1)
-+	addi	r3,r1,INT_FRAME_SIZE
-+	stw		r3,GPR1(r1)
-+	mfcr	r3
-+	stw		r3,_CCR(r1)
-+	mflr	r3
-+	stw		r3,_NIP(r1)
-+	mfctr	r3
-+	stw		r3,_CTR(r1)
-+	mfxer	r3
-+	stw		r3,_XER(r1)
-+	mfmsr	r3
-+	stw		r3,_MSR(r1)
-+	lwz		r3,INT_FRAME_SIZE+4(r1)
-+	stw		r3,_LINK(r1)
-+
-+	bl		kern_do_schedule
-+
-+	lwz		r3,_CCR(r1)
-+	mtcr	r3
-+	lwz		r3,_XER(r1)
-+	mtxer	r3
-+	lwz		r3,_NIP(r1)
-+	mtlr	r3
-+	lwz		r3,_CTR(r1)
-+	mtctr	r3
-+	lwz		r3,_MSR(r1)
-+	mtmsr	r3
-+	lwz		r0,GPR0(r1)
-+	REST_2GPRS ( 2, r1)
-+	REST_4GPRS ( 4, r1)
-+	REST_8GPRS ( 8, r1)
-+	REST_8GPRS (16, r1)
-+	REST_8GPRS (24, r1)
-+	addi	r1,r1,INT_FRAME_SIZE
-+	blr
-+#endif
-Index: linux-2.4.26-ct_sync/arch/ppc/config.in
-===================================================================
---- linux-2.4.26-ct_sync.orig/arch/ppc/config.in	2004-04-14 15:05:27.000000000 +0200
-+++ linux-2.4.26-ct_sync/arch/ppc/config.in	2004-06-28 12:56:07.000000000 +0200
-@@ -630,6 +630,8 @@
-   bool '  Wait queue debugging' CONFIG_DEBUG_WAITQ
-   bool '  Include kgdb kernel debugger' CONFIG_KGDB
-   if [ "$CONFIG_KGDB" = "y" ]; then
-+    bool 'KGDB: Thread analysis' CONFIG_KGDB_THREAD
-+    bool 'KGDB: Console messages through gdb' CONFIG_GDB_CONSOLE
-     choice '    Serial Port'		\
- 	"ttyS0	CONFIG_KGDB_TTYS0	\
- 	 ttyS1	CONFIG_KGDB_TTYS1	\
-Index: linux-2.4.26-ct_sync/Documentation/i386/gdb-serial.txt
-===================================================================
---- linux-2.4.26-ct_sync.orig/Documentation/i386/gdb-serial.txt	2004-06-16 09:19:51.000000000 +0200
-+++ linux-2.4.26-ct_sync/Documentation/i386/gdb-serial.txt	2004-06-28 12:56:07.000000000 +0200
-@@ -0,0 +1,386 @@
-+Version
-+=======
-+
-+This version of the gdbstub package was developed and tested on
-+kernel version 2.3.48.  It will not install on a 2.2 kernel.  It may
-+not work on earlier versions of 2.3 kernels.  It is possible that
-+it will continue to work on later versions of 2.3 and then
-+versions of 2.4 (I hope).
-+
-+
-+Debugging Setup
-+===============
-+
-+Designate one machine as the "development" machine.  This is the
-+machine on which you run your compiles and which has your source
-+code for the kernel.  Designate a second machine as the "target"
-+machine.  This is the machine that will run your experimental
-+kernel.
-+
-+The two machines will be connected together via a serial line out
-+one or the other of the COM ports of the PC.  You will need a modem
-+eliminator and the appropriate cables.
-+
-+On the DEVELOPMENT machine you need to apply the patch for the gdb
-+hooks.  You have probably already done that if you are reading this
-+file.
-+
-+On your DEVELOPMENT machine, go to your kernel source directory and
-+do "make menuconfig".  Go down to the kernel hacking menu item and
-+open it up.  Enable the kernel gdb stub code by selecting that item.
-+
-+Save and exit the menuconfig program.  Then do "make clean" and
-+"make bzImage" (or whatever target you want to make).  This gets
-+the kernel compiled with the "-g" option set -- necessary for
-+debugging.
-+
-+You have just built the kernel on your DEVELOPMENT machine that you
-+intend to run on our TARGET machine.
-+
-+To install this new kernel, use the following installation procedure.
-+Remember, you are on the DEVELOPMENT machine patching the kernel source
-+for the kernel that you intend to run on the TARGET machine.
-+
-+Copy this kernel to your target machine using your usual procedures.
-+I usually arrange to copy development:/usr/src/linux/arch/i386/boot/zImage
-+to /vmlinuz on the TARGET machine via a LAN based NFS access.  That is,
-+I run the cp command on the target and copy from the development machine
-+via the LAN.  Run Lilo on the new kernel on the target machine so that it
-+will boot!  Then boot the kernel on the target machine.
-+
-+There is an utility program named "gdbstart" in the
-+development:/usr/src/linux/arch/i386/kernel directory.
-+You should copy this program over to your target machine, probably into
-+/sbin.  This utility program is run on the target machine to
-+activate the kernel hooks for the debugger.  It is invoked as follows:
-+
-+    gdbstart [-s speed] [-t tty-dev]
-+    defaults:  /dev/ttyS0 with speed unmodified by gdbstart
-+
-+Don't run the program just yet.  We'll get to that in a bit.
-+
-+Decide on which tty port you want the machines to communicate, then
-+cable them up back-to-back using the null modem.  COM1 is /dev/ttyS0
-+and COM2 is /dev/ttyS1.
-+
-+On the DEVELOPMENT machine, create a file called .gdbinit in the
-+directory /usr/src/linux.  An example .gdbinit file looks like this:
-+
-+define rmt
-+set remotebaud 38400
-+target remote /dev/ttyS0
-+end
-+
-+Assuming that you added my gdbinit stuff to your .gdbinit, edit .gdbinit
-+and find the section that looks like this:
-+
-+	define rmt
-+	set remotebaud 38400
-+	target remote /dev/ttyS0
-+	end
-+
-+Change the "target" definition so that it specifies the tty port that
-+you intend to use.  Change the "remotebaud" definition to match the
-+data rate that you are going to use for the com line.
-+
-+On the TARGET machine I find it helpful to create shell script file
-+named "debug" in the root home directory with the following contents:
-+
-+	gdbstart -s 38400 -t /dev/ttyS0 <<EOF
-+	<blank line>
-+	EOF
-+
-+This runs the gdbstart program and gives it the carriage return that
-+it prompts for.  This sets the data rate from the target machine's side.
-+
-+You are now ready to try it out.
-+
-+On your TARGET machine, freshly rebooted with your gdbstub-equipped
-+kernel, type "debug" in the root home directory.  The system will appear
-+to hang with some messages on the screen from the debug stub.  What
-+it is doing is waiting for contact from the development machine.
-+
-+On your DEVELOPMENT machine, cd /usr/src/linux and enter "gdb vmlinux".
-+When gdb gets the symbols loaded and prompts you, enter "rmt" (that's
-+the macro from the .gdbinit file that you just edited).  If everything
-+is working correctly you should see gdb print out a few lines indicating
-+that a breakpoint has been taken.  It will actually show a line of
-+code in the target kernel inside the gdbstub activation code.
-+
-+The gdb interaction should look something like this:
-+
-+    linux-dev:/usr/src/linux# gdb vmlinux
-+    GDB is free software and you are welcome to distribute copies of it
-+     under certain conditions; type "show copying" to see the conditions.
-+    There is absolutely no warranty for GDB; type "show warranty" for details.
-+    GDB 4.15.1 (i486-slackware-linux), 
-+    Copyright 1995 Free Software Foundation, Inc...
-+    (gdb) rmt
-+    breakpoint () at i386-stub.c:750
-+    750     }
-+    (gdb) 
-+
-+
-+You can now use whatever gdb commands you like to set breakpoints.
-+Enter "continue" to start your target machine executing again.  At this
-+point the target system will run at full speed until it encounters
-+your breakpoint or gets a segment violation in the kernel, or whatever.
-+
-+
-+Triggering gdbstub at Kernel Boot Time
-+======================================
-+
-+The gdbstub patch now has the ability for gdb to connect to the kernel during
-+bootup (as opposed to waiting for the system to come all the way up and then
-+running the gdbstart program on the target machine).  This new functionality was
-+added by Scott Foehner <sfoehner at engr.sgi.com> at SGI.
-+
-+To force a kernel that has been compiled with gdbstub to pause during the boot
-+process and wait for a connection from gdb, the paramter "gdb" should be passed
-+to the kernel. This can be done by typing "gdb" after the name of the kernel
-+on the LILO command line.  The patch defaults to use ttyS1 at a baud rate of
-+38400. These parameters can be changed by using "gdbttyS=<port number>" and
-+"gdbbaud=<baud rate>" on the command line.
-+
-+Example:
-+
-+LILO boot: linux gdb gdbttyS=1 gdbbaud=38400
-+
-+Note that this command is entered on the TARGET machine as it is booting
-+the kernel that was compiled on the DEVELOPMENT machine.
-+
-+An alternate approach is to place a line in the /etc/lilo.conf file on
-+your TARGET machine.  Under the heading for the kernel that you intend
-+to boot, place a line that looks like this:
-+
-+    append = "gdb gdbttyS=1 gdbbaud=38400"
-+
-+This will cause the kernel to enter the gdbstub automatically at boot
-+time.
-+
-+BE SURE to run "lilo" after changing the /etc/lilo.conf file.
-+
-+
-+The "gdbstart" Program
-+=====================
-+
-+This utility program is used to set up the com port and data rate
-+for the connection from the target system to the development system.
-+Its usage has been described above.
-+
-+This version of the patch uses the same tty ioctl for kernel versions
-+2.0.30 onwards.  Thus, the gdbstart utility does not need to be re-compiled
-+to install the patch in a later version of the kernel.  The ioctl added
-+to the kernel for this purpose is far enough "off the end" of existing
-+ioctls (as of 2.1.120) that it should not interfere with any new kernel
-+tty ioctls for quite some time (famous last words).
-+
-+The source for the gdbstart program resides in the arch/i386/kernel directory.
-+
-+
-+Debugging hints
-+===============
-+
-+You can break into the target machine at any time from the development
-+machine by typing ^C.  If the target machine has interrupts enabled
-+this will stop it in the kernel and enter the debugger.
-+
-+There is unfortunately no way of breaking into the kernel if it is
-+in a loop with interrupts disabled, so if this happens to you then
-+you need to place exploratory breakpoints or printk's into the kernel
-+to find out where it is looping.
-+
-+There is a copy of an e-mail in the kgdb distribution directory which
-+describes how to create an NMI on an ISA bus machine using a paper
-+clip.  I have a sophisticated version of this made by wiring a push
-+button switch into a PC104/ISA bus adapter card.  The adapter card
-+nicely furnishes wire wrap pins for all the ISA bus signals.
-+
-+When you are done debugging the kernel on the target machine it is
-+a good idea to leave it in a running state.  This makes reboots
-+faster, bypassing the fsck.  So do a gdb "continue" as the last gdb
-+command if this is possible.  To terminate gdb itself on the development
-+machine and leave the target machine running, type ^Z to suspend gdb
-+and then kill it with "kill %1" or something similar.
-+
-+If gdbstub Does Not Work
-+========================
-+
-+If it doesn't work, you will have to troubleshoot it.  Do the easy things
-+first like double checking your cabling and data rates.  You might
-+try some non-kernel based programs to see if the back-to-back connection
-+works properly.  Just something simple like cat /etc/hosts >/dev/ttyS0
-+on one machine and cat /dev/ttyS0 on the other will tell you if you
-+can send data from one machine to the other.  There is no point in tearing
-+out your hair in the kernel if the line doesn't work.
-+
-+All of the real action takes place in the file
-+/usr/src/linux/arch/i386/kernel/gdbstub.c.  That is the code on the target
-+machine that interacts with gdb on the development machine.  In gdb you can
-+turn on a debug switch with the following command:
-+
-+	set remotedebug
-+
-+This will print out the protocol messages that gdb is exchanging with
-+the target machine.
-+
-+Another place to look is /usr/src/linux/drivers/char/gdbserial.c
-+That is the code that talks to the serial port on the target side.
-+There might be a problem there.
-+
-+If you are really desperate you can use printk debugging in the
-+gdbstub code in the target kernel until you get it working.  In particular,
-+there is a global variable in /usr/src/linux/arch/i386/kernel/gdbstub.c
-+named "remote_debug".  Compile your kernel with this set to 1, rather
-+than 0 and the debug stub will print out lots of stuff as it does
-+what it does.
-+
-+
-+Debugging Loadable Modules
-+==========================
-+
-+This technique comes courtesy of Edouard Parmelan
-+<Edouard.Parmelan at quadratec.fr>
-+
-+When you run gdb, enter the command
-+
-+source gdbinit-modules
-+
-+This will read in a file of gdb macros that was installed in your
-+kernel source directory with kgdb was installed.  This file implements
-+the following commands:
-+
-+mod-list
-+    Lists the loaded modules in the form <module-address> <module-name>
-+
-+mod-print-symbols <module-address>
-+    Prints all the symbols in the indicated module.
-+
-+mod-add-symbols <module-address> <object-file-path-name>
-+    Loads the symbols from the object file and associates them
-+    with the indicated module.
-+
-+After you have loaded the module that you want to debug, use the command
-+mod-list to find the <module-address> of your module.  Then use that
-+address in the mod-add-symbols command to load your module's symbols.
-+From that point onward you can debug your module as if it were a part
-+of the kernel.
-+
-+The file gdbinit-modules also contains a command named mod-add-lis as
-+an example of how to construct a command of your own to load your
-+favorite module.  The idea is to "can" the pathname of the module
-+in the command so you don't have to type so much.
-+
-+Threads
-+=======
-+
-+Each process in a target machine is seen as a gdb thread. gdb thread related
-+commands (info threads, thread n) can be used. 
-+
-+ia-32 hardware breakpoints
-+==========================
-+
-+gdb stub contains support for hardware breakpoints using debugging features
-+of ia-32(x86) processors. These breakpoints do not need code modification.
-+They use debugging registers. 4 hardware breakpoints are available in ia-32
-+processors.
-+
-+Each hardware breakpoint can be of one of the following three types.
-+1. Execution breakpoint - An Execution breakpoint is triggered when code at the
-+	breakpoint address is executed.
-+
-+	As limited number of hardware breakpoints are available, it is advisable
-+	to use software breakpoints ( break command ) instead of execution
-+	hardware breakpoints, unless modification of code is to be avoided.
-+
-+2. Write breakpoint - A write breakpoint is triggered when memory location at the
-+	breakpoint address is written.
-+
-+	A write or can be placed for data of variable length. Length of a write
-+	breakpoint indicates length of the datatype to be watched. Length is 1
-+	for 1 byte data , 2 for 2 byte data, 3 for 4 byte data.
-+
-+3. Access breakpoint - An access breakpoint is triggered when memory location at
-+	the breakpoint address is either read or written.
-+
-+	Access breakpoints also have lengths similar to write breakpoints.
-+
-+IO breakpoints in ia-32 are not supported.
-+
-+Since gdb stub at present does not use the protocol used by gdb for hardware
-+breakpoints, hardware breakpoints are accessed through gdb macros. gdb macros
-+for hardware breakpoints are described below.
-+
-+hwebrk	- Places an execution breakpoint
-+	hwebrk breakpointno address
-+hwwbrk	- Places a write breakpoint
-+	hwwbrk breakpointno length address
-+hwabrk	- Places an access breakpoint
-+	hwabrk breakpointno length address
-+hwrmbrk	- Removes a breakpoint
-+	hwrmbrk breakpointno
-+exinfo	- Tells whether a software or hardware breakpoint has occured.
-+	Prints number of the hardware breakpoint if a hardware breakpoint has
-+	occured.
-+
-+Arguments required by these commands are as follows
-+breakpointno	- 0 to 3
-+length		- 1 to 3
-+address		- Memory location in hex digits ( without 0x ) e.g c015e9bc
-+
-+MP support
-+==========
-+
-+When a breakpoint occurs or user issues a break ( Ctrl + C ) to gdb client,
-+all the processors are forced to enter the debugger. Current thread
-+corresponds to the thread running on the processor where breakpoint occured.
-+Threads running on other processor(s) appear similar to other non running
-+threads in the 'info threads' output.
-+
-+ia-32 hardware debugging registers on all processors are set to same values.
-+Hence any hardware breakpoints may occur on any processor.
-+
-+gdb troubleshooting
-+===================
-+
-+1. gdb hangs
-+Kill it. restart gdb. Connect to target machine.
-+
-+2. gdb cannot connect to target machine (after killing a gdb and restarting
-+another)
-+If the target machine was not inside debugger when you killed gdb, gdb cannot
-+connect because the target machine won't respond.
-+In this case echo "Ctrl+C"(ascii 3) in the serial line.
-+e.g. echo -e "\003" > /dev/ttyS1 
-+This forces that target machine into debugger after which you can connect.
-+
-+3. gdb cannot connect even after echoing Ctrl+C into serial line
-+Try changing serial line settings min to 1 and time to 0
-+e.g. stty min 1 time 0 < /dev/ttyS1
-+Try echoing again
-+
-+check serial line speed and set it to correct value if required
-+e.g. stty ispeed 115200 ospeed 115200 < /dev/ttyS1
-+
-+Final Items
-+===========
-+
-+I picked up this code from Dave Grothe and enhanced it.
-+
-+If you make some really cool modification to this stuff, or if you 
-+fix a bug, please let me know.
-+
-+Amit S. Kale
-+<akale at veritas.com>
-+
-+(First kgdb by David Grothe <dave at gcom.com>)
-+
-+(modified by Tigran Aivazian <tigran at sco.com>)
-+    Putting gdbstub into the kernel config menu.
-+
-+(modified by Scott Foehner <sfoehner at engr.sgi.com>)
-+    Hooks for entering gdbstub at boot time.
-+
-+(modified by Amit S. Kale <akale at veritas.com>)
-+    Threads, ia-32 hw debugging, mp support, console support,
-+    nmi watchdog handling.
-Index: linux-2.4.26-ct_sync/Documentation/Configure.help
-===================================================================
---- linux-2.4.26-ct_sync.orig/Documentation/Configure.help	2004-06-28 12:56:01.000000000 +0200
-+++ linux-2.4.26-ct_sync/Documentation/Configure.help	2004-06-28 12:56:07.000000000 +0200
-@@ -22146,6 +22146,31 @@
-   If you have a Western Digital WD93 SCSI controller on
-   an SGI MIPS system, say Y.  Otherwise, say N.
- 
-+KGDB: Remote (serial) kernel debugging with gdb
-+CONFIG_KGDB
-+  If you say Y here, it will be possible to remotely debug the
-+  kernel using gdb. This enlarges your kernel image disk size by
-+  several megabytes and requires a machine with more than 128 MB
-+  RAM to avoid excessive linking time. 
-+  To use this feature you need to perform some basic setup described
-+  briefly in Documentation/i386/gdb-serial.txt.
-+  More documentation of kernel debugger available at
-+  http://kgdb.sourceforge.net
-+  This is only useful for kernel hackers. If unsure, say N.
-+
-+KGDB: Thread analysis
-+CONFIG_KGDB_THREAD
-+  With thread analysis enabled, gdb can talk to kgdb stub to list
-+  threads and to get stack trace for a thread. This option also enables
-+  some code which helps gdb get exact status of thread. Thread analysis
-+  adds some overhead to schedule and down functions. You can disable this
-+  option if you do not want to compromise on speed.
-+
-+KGDB: Console messagegs through gdb
-+CONFIG_GDB_CONSOLE
-+  If you say Y here, console messages will appear through gdb.
-+  Other consoles such as tty or ttyS will continue to work as usual.
-+  
- Magic System Request Key support
- CONFIG_MAGIC_SYSRQ
-   If you say Y here, you will have some control over the system even
-

Deleted: branches/netfilter-ha/linux-2.6/patches/nfnetlink-ctnetlink.patch
===================================================================
--- branches/netfilter-ha/linux-2.6/patches/nfnetlink-ctnetlink.patch	2005-01-02 22:40:48 UTC (rev 3550)
+++ branches/netfilter-ha/linux-2.6/patches/nfnetlink-ctnetlink.patch	2005-01-02 23:13:27 UTC (rev 3551)
@@ -1,2953 +0,0 @@
-%patch
-Index: linux-2.4.26-ct_sync/include/linux/nfnetlink_conntrack.h
-===================================================================
---- linux-2.4.26-ct_sync.orig/include/linux/nfnetlink_conntrack.h	2004-06-16 09:19:51.000000000 +0200
-+++ linux-2.4.26-ct_sync/include/linux/nfnetlink_conntrack.h	2004-06-28 12:58:22.000000000 +0200
-@@ -0,0 +1,87 @@
-+#ifndef _NFNETLINK_CONNTRACK_H
-+#define _NFNETLINK_CONNTRACK_H
-+#include <linux/nfnetlink.h>
-+#include <linux/netfilter_ipv4/ip_conntrack.h>
-+
-+/* CTNETLINK for ip_conntrack */
-+
-+enum cntl_msg_types {
-+	CTNL_MSG_NEWCONNTRACK,
-+	CTNL_MSG_GETCONNTRACK,
-+	CTNL_MSG_DELCONNTRACK,
-+
-+	CTNL_MSG_NEWEXPECT,
-+	CTNL_MSG_GETEXPECT,
-+	CTNL_MSG_DELEXPECT,
-+
-+	CTNL_MSG_COUNT,
-+};
-+
-+/* ctnetlink attribute types.
-+ */
-+
-+enum ctattr_type_t
-+{
-+	CTA_UNSPEC,     /* [none] I don't know (unspecified). */
-+	CTA_ORIG,       /* [ip_conntrack_tuple] Original tuple. */
-+	CTA_RPLY,       /* [ip_conntrack_tuple] Reply tuple. */
-+	CTA_STATUS,     /* [unsigned long] Status of connection. */
-+	CTA_PROTOINFO,  /* [cta_proto] Protocol specific ct information. */
-+	CTA_HELPINFO,   /* [cta_help] Helper specific information. */
-+	CTA_NATINFO,    /* [cta_nat] Any NAT transformations. */
-+	CTA_TIMEOUT,    /* [unsigned long] timer */
-+	CTA_MARK,       /* [unsigned long] mark .*/
-+	
-+	CTA_EXP_TUPLE,	/* [ip_conntrack_tuple] Expected tuple */
-+	CTA_EXP_MASK,	/* [ip_conntrack_tuple] Mask for EXP_TUPLE */
-+	CTA_EXP_SEQNO,	/* [u_int32_t] sequence number */
-+	CTA_EXP_PROTO,	/* [cta_exp_proto] */
-+	CTA_EXP_HELP,	/* [cta_exp_help] */
-+	CTA_EXP_TIMEOUT,/* [unsigned long] timer */
-+
-+	CTA_MAX = CTA_EXP_TIMEOUT
-+};
-+
-+/* Attribute specific data structures.
-+ */
-+
-+#include <linux/netfilter_ipv4/ip_nat.h>
-+struct cta_nat {
-+	unsigned int num_manips;
-+	struct ip_nat_info_manip manips[IP_NAT_MAX_MANIPS];
-+};
-+
-+struct cta_proto {
-+	unsigned char num_proto;	/* Protocol number IPPROTO_X */
-+	union ip_conntrack_proto proto;
-+};
-+
-+#define CTA_HELP_MAXNAMESZ	31
-+
-+struct cta_help {
-+	char name[CTA_HELP_MAXNAMESZ];	/* name of conntrack helper */
-+	union ip_conntrack_help help;
-+};
-+
-+struct cta_exp_proto {
-+	union ip_conntrack_expect_proto proto;
-+};
-+
-+struct cta_exp_help {
-+	union ip_conntrack_expect_help help;
-+};
-+
-+/* ctnetlink multicast groups: reports any change of ctinfo,
-+ * ctstatus, or protocol state change.
-+ */
-+#define NFGRP_IPV4_CT_TCP	0x01
-+#define NFGRP_IPV4_CT_UDP	0x02
-+#define NFGRP_IPV4_CT_ICMP	0x04
-+#define NFGRP_IPV4_CT_OTHER 	0x08
-+
-+#define NFGRP_IPV6_CT_TCP       0x10
-+#define NFGRP_IPV6_CT_UDP       0x20
-+#define NFGRP_IPV6_CT_ICMP      0x40
-+#define NFGRP_IPV6_CT_OTHER 	0x80
-+
-+#endif /* _NFNETLINK_CONNTRACK_H */
-Index: linux-2.4.26-ct_sync/include/linux/nfnetlink.h
-===================================================================
---- linux-2.4.26-ct_sync.orig/include/linux/nfnetlink.h	2004-06-16 09:19:51.000000000 +0200
-+++ linux-2.4.26-ct_sync/include/linux/nfnetlink.h	2004-06-28 12:58:22.000000000 +0200
-@@ -0,0 +1,158 @@
-+#ifndef _NFNETLINK_H
-+#define _NFNETLINK_H
-+#include <linux/types.h>
-+
-+/* Generic structure for encapsulation optional netfilter information.
-+ * It is reminiscent of sockaddr, but with sa_family replaced
-+ * with attribute type. 
-+ * ! This should someday be put somewhere generic as now rtnetlink and
-+ * ! nfnetlink use the same attributes methods. - J. Schulist.
-+ */
-+
-+struct nfattr
-+{
-+	unsigned short  nfa_len;
-+	unsigned short  nfa_type;
-+};
-+
-+#define NFA_ALIGNTO     4
-+#define NFA_ALIGN(len)	(((len) + NFA_ALIGNTO - 1) & ~(NFA_ALIGNTO - 1))
-+#define NFA_OK(nfa,len)	((len) > 0 && (nfa)->nfa_len >= sizeof(struct nfattr) \
-+	&& (nfa)->nfa_len <= (len))
-+#define NFA_NEXT(nfa,attrlen)	((attrlen) -= NFA_ALIGN((nfa)->nfa_len), \
-+	(struct nfattr *)(((char *)(nfa)) + NFA_ALIGN((nfa)->nfa_len)))
-+#define NFA_LENGTH(len)	(NFA_ALIGN(sizeof(struct nfattr)) + (len))
-+#define NFA_SPACE(len)	NFA_ALIGN(NFA_LENGTH(len))
-+#define NFA_DATA(nfa)   ((void *)(((char *)(nfa)) + NFA_LENGTH(0)))
-+#define NFA_PAYLOAD(nfa) ((int)((nfa)->nfa_len) - NFA_LENGTH(0))
-+
-+/* General form of address family dependent message.
-+ */
-+struct nfgenmsg {
-+	unsigned char nfgen_family;
-+};
-+
-+#if 0
-+struct iptgenmsg {
-+	unsigned char 	iptgen_family;
-+	char 		iptgen_table[IPT_TABLE_MAXNAMELEN];
-+};
-+
-+struct iptmsg {
-+	unsigned char	iptm_family;
-+	char		iptm_table[IPT_TABLE_MAXNAMELEN];
-+	char		iptm_chain[IPT_FUNCTION_MAXNAMELEN];
-+	unsigned int	iptm_entry_num;
-+};
-+
-+enum iptattr_type_t
-+{
-+	IPTA_UNSPEC,	/* [none] I don't know (unspecified). */
-+	IPTA_IP,	/* [ipt_ip] */
-+	IPTA_NFCACHE,	/* [u_int] */
-+	IPTA_COUNTERS,	/* [ipt_counters] */
-+	IPTA_MATCH,	/* [ipt_info] */
-+	IPTA_TARGET,	/* [ipt_info] */
-+	IPTA_MAX = IPTA_TARGET
-+};
-+
-+struct ipta_info {
-+	u_int16_t 	size;
-+	char 		name[IPT_FUNCTION_MAXNAMELEN];
-+	unsigned char 	data[0];
-+};
-+
-+#define NFM_IPTA(n)	((struct nfattr *)(((char *)(n)) \
-+	+ NLMSG_ALIGN(sizeof(struct iptmsg))))
-+
-+#endif
-+
-+#define NFM_NFA(n)      ((struct nfattr *)(((char *)(n)) \
-+        + NLMSG_ALIGN(sizeof(struct nfgenmsg))))
-+#define NFM_PAYLOAD(n)  NLMSG_PAYLOAD(n, sizeof(struct nfgenmsg))
-+
-+
-+#ifndef NETLINK_NETFILTER
-+#define NETLINK_NETFILTER	6
-+#endif
-+
-+/* netfilter netlink message types are split in two pieces:
-+ * 8 bit subsystem, 8bit operation.
-+ */
-+
-+#define NFNL_SUBSYS_ID(x)	((x & 0xff00) >> 8)
-+#define NFNL_MSG_TYPE(x)	(x & 0x00ff)
-+
-+enum nfnl_subsys_id {
-+	NFNL_SUBSYS_NONE = 0,
-+	NFNL_SUBSYS_CTNETLINK,
-+	NFNL_SUBSYS_CTNETLINK_EXP,
-+	NFNL_SUBSYS_IPTNETLINK,
-+	NFNL_SUBSYS_QUEUE,
-+	NFNL_SUBSYS_ULOG,
-+	NFNL_SUBSYS_COUNT,
-+};
-+
-+#ifdef __KERNEL__
-+
-+#include <linux/capability.h>
-+
-+struct nfnl_callback
-+{
-+	kernel_cap_t cap_required; /* capabilities required for this msg */
-+	int (*call)(struct sock *nl, struct sk_buff *skb, 
-+		struct nlmsghdr *nlh, int *errp);
-+};
-+
-+struct nfnetlink_subsystem
-+{
-+	/* Internal use. */
-+	struct list_head list;
-+	
-+	const char *name;
-+	__u8 subsys_id;		/* nfnetlink subsystem ID */
-+	__u8 cb_count;		/* number of callbacks */
-+	u_int32_t attr_count;	/* number of nfattr's */
-+	struct nfnl_callback cb[0]; /* callback for individual types */
-+};
-+
-+extern void __nfa_fill(struct sk_buff *skb, int attrtype,
-+        int attrlen, const void *data);
-+#define NFA_PUT(skb, attrtype, attrlen, data) \
-+({ if (skb_tailroom(skb) < (int)NFA_SPACE(attrlen)) goto nfattr_failure; \
-+   __nfa_fill(skb, attrtype, attrlen, data); })
-+
-+extern struct semaphore nfnl_sem;
-+#define nfnl_exlock()		do { } while(0)
-+#define nfnl_exunlock()		do { } while(0)
-+#define nfnl_exlock_nowait()	(0)
-+
-+#define nfnl_shlock()		down(&nfnl_sem)
-+#define nfnl_shlock_nowait()	down_trylock(&nfnl_sem)
-+
-+#ifndef CONFIG_NF_NETLINK
-+#define nfnl_shunlock()		up(&nfnl_sem)
-+#else
-+#define nfnl_shunlock()		do { up(&nfnl_sem); \
-+                             		if(nfnl && nfnl->receive_queue.qlen) \
-+                                     		nfnl->data_ready(nfnl, 0); \
-+                        	} while(0)
-+#endif
-+
-+extern void nfnl_lock(void);
-+extern void nfnl_unlock(void);
-+
-+extern struct nfnetlink_subsystem *nfnetlink_subsys_alloc(int cb_count);
-+extern int nfnetlink_subsys_register(struct nfnetlink_subsystem *n);
-+extern int nfnetlink_subsys_unregister(struct nfnetlink_subsystem *n);
-+
-+extern int nfnetlink_check_attributes(struct nfnetlink_subsystem *subsys,
-+				      struct nlmsghdr *nlh, 
-+				      struct nfattr *cda[]);
-+extern int nfattr_parse(struct nfattr *tb[], int maxattr, 
-+			struct nfattr *nfa, int len);
-+extern int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, 
-+			  int echo);
-+
-+#endif	/* __KERNEL__ */
-+#endif	/* _NFNETLINK_H */
-Index: linux-2.4.26-ct_sync/include/linux/netfilter_ipv4/ip_conntrack_protocol.h
-===================================================================
---- linux-2.4.26-ct_sync.orig/include/linux/netfilter_ipv4/ip_conntrack_protocol.h	2002-11-29 00:53:15.000000000 +0100
-+++ linux-2.4.26-ct_sync/include/linux/netfilter_ipv4/ip_conntrack_protocol.h	2004-06-28 12:58:22.000000000 +0200
-@@ -42,6 +42,17 @@
- 	int (*new)(struct ip_conntrack *conntrack, struct iphdr *iph,
- 		   size_t len);
- 
-+	/* check if tuples are valid for a new connection */
-+	int (*ctnl_check_tuples)(struct ip_conntrack_tuple *orig,
-+	                         struct ip_conntrack_tuple *reply);
-+
-+	/* check protocol data is valid */
-+	int (*ctnl_check_private)(union ip_conntrack_proto *p);
-+
-+	/* change protocol info on behalf of ctnetlink */
-+	void (*ctnl_change)(struct ip_conntrack *ct,
-+                            union ip_conntrack_proto *p);
-+
- 	/* Called when a conntrack entry is destroyed */
- 	void (*destroy)(struct ip_conntrack *conntrack);
- 
-Index: linux-2.4.26-ct_sync/include/linux/netfilter_ipv4/ip_conntrack.h
-===================================================================
---- linux-2.4.26-ct_sync.orig/include/linux/netfilter_ipv4/ip_conntrack.h	2004-06-28 12:58:18.000000000 +0200
-+++ linux-2.4.26-ct_sync/include/linux/netfilter_ipv4/ip_conntrack.h	2004-06-28 12:58:22.000000000 +0200
-@@ -46,6 +46,10 @@
- 	/* Connection is confirmed: originating packet has left box */
- 	IPS_CONFIRMED_BIT = 3,
- 	IPS_CONFIRMED = (1 << IPS_CONFIRMED_BIT),
-+
-+	/* Connection is destroyed (removed from lists), can not be unset. */
-+	IPS_DESTROYED_BIT = 4,
-+	IPS_DESTROYED = (1 << IPS_DESTROYED_BIT),
- };
- 
- #include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
-@@ -123,6 +127,9 @@
- 
- 	/* reference count */
- 	atomic_t use;
-+ 
-+	/* unique increasing id */
-+	unsigned int id;
- 
- 	/* expectation list for this master */
- 	struct list_head expected_list;
-@@ -166,6 +173,14 @@
- 
- 	/* These are my tuples; original and reply */
- 	struct ip_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX];
-+ 
-+	/* ordered list member - for table dumping over netlink */
-+	struct list_head olist;
-+
-+	/* unique id (assigned when placing in hashtables) - for table dumping
-+	 * over netlink */
-+	unsigned int id;
-+
- 
- 	/* Have we seen traffic both ways yet? (bitset) */
- 	unsigned long status;
-@@ -241,6 +256,17 @@
- 
- /* decrement reference count on an expectation */
- void ip_conntrack_expect_put(struct ip_conntrack_expect *exp);
-+ 
-+/* remove all unconfirmed expectations */
-+extern void ip_conntrack_remove_expectations(struct ip_conntrack *ct, 
-+					     int drop_refcount);
-+
-+ 
-+struct ip_conntrack_protocol;
-+extern int invert_tuple(struct ip_conntrack_tuple *inverse,
-+			const struct ip_conntrack_tuple *orig,
-+			const struct ip_conntrack_protocol *protocol);
-+
- 
- extern int invert_tuplepr(struct ip_conntrack_tuple *inverse,
- 			  const struct ip_conntrack_tuple *orig);
-@@ -264,13 +290,95 @@
- extern void
- ip_ct_selective_cleanup(int (*kill)(const struct ip_conntrack *i, void *data),
- 			void *data);
-+ 
-+/* returns new ip_conntrack struct or NULL */
-+extern struct ip_conntrack *
-+ip_conntrack_alloc(const struct ip_conntrack_tuple *,
-+		   const struct ip_conntrack_tuple *);
-+
-+/* free conntrack structure */
-+extern void ip_conntrack_free(struct ip_conntrack *);
-+
-+/* place conntrack in hash and ordered list */
-+extern void ip_conntrack_place_in_lists(struct ip_conntrack *);
-+
- 
- /* It's confirmed if it is, or has been in the hash table. */
- static inline int is_confirmed(struct ip_conntrack *ct)
- {
- 	return test_bit(IPS_CONFIRMED_BIT, &ct->status);
- }
-+ 
-+/* It is destroyed after it has been removed from hash table. */
-+static inline int is_destroyed(struct ip_conntrack *ct)
-+{
-+	return test_bit(IPS_DESTROYED_BIT, &ct->status);
-+}
-+
- 
- extern unsigned int ip_conntrack_htable_size;
-+
-+enum ip_conntrack_events
-+{
-+	IPCT_NEW,
-+	IPCT_DESTROY,
-+	IPCT_STATUS,
-+	IPCT_REFRESH,
-+	IPCT_PROTOINFO,
-+	IPCT_HELPINFO,
-+	IPCT_NATINFO,
-+};
-+
-+#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
-+#include <linux/notifier.h>
-+
-+extern struct notifier_block *ip_conntrack_chain;
-+extern unsigned long ip_conntrack_event_cache[NR_CPUS];
-+
-+/* register notifier for conntrack events */
-+static inline int ip_conntrack_notify_register(struct notifier_block *nb)
-+{
-+	return notifier_chain_register(&ip_conntrack_chain, nb);
-+}
-+
-+static inline int ip_conntrack_notify_unregister(struct notifier_block *nb)
-+{
-+	return notifier_chain_unregister(&ip_conntrack_chain, nb);
-+}
-+
-+static inline void ip_conntrack_event(enum ip_conntrack_events event,
-+				      struct ip_conntrack *ct)
-+{
-+	if (is_confirmed(ct) && !is_destroyed(ct))
-+		notifier_call_chain(&ip_conntrack_chain, 1 << event, ct);
-+}
-+
-+static inline void ip_conntrack_event_cache_init(void)
-+{
-+	ip_conntrack_event_cache[smp_processor_id()] = 0UL;
-+}
-+
-+static inline void ip_conntrack_cache_event(enum ip_conntrack_events event)
-+{
-+	ip_conntrack_event_cache[smp_processor_id()] |= 1 << event;
-+}
-+
-+static inline void ip_conntrack_do_cached_events(struct ip_conntrack *ct)
-+{
-+	unsigned long events = ip_conntrack_event_cache[smp_processor_id()];
-+
-+	if (is_confirmed(ct) && !is_destroyed(ct) && events)
-+		notifier_call_chain(&ip_conntrack_chain, events, ct);
-+}
-+#else /* CONFIG_IP_NF_CONNTRACK_EVENTS */
-+static inline int ip_conntrack_notify_register(void *nb) { return 0; }
-+static inline int ip_conntrack_notify_unregister(void *nb) { return 0; }
-+static inline void ip_conntrack_event(enum ip_conntrack_events event,
-+				      struct ip_conntrack *ct) {}
-+static inline void ip_conntrack_event_cache_init(void) {}
-+static inline void ip_conntrack_cache_event(enum ip_conntrack_events event) {}
-+static inline void ip_conntrack_do_cached_events(struct ip_conntrack *ct) {}
-+#endif /* CONFIG_IP_NF_CONNTRACK_EVENTS */
-+
- #endif /* __KERNEL__ */
- #endif /* _IP_CONNTRACK_H */
-Index: linux-2.4.26-ct_sync/include/linux/netfilter_ipv4/ip_conntrack_helper.h
-===================================================================
---- linux-2.4.26-ct_sync.orig/include/linux/netfilter_ipv4/ip_conntrack_helper.h	2002-11-29 00:53:15.000000000 +0100
-+++ linux-2.4.26-ct_sync/include/linux/netfilter_ipv4/ip_conntrack_helper.h	2004-06-28 12:58:22.000000000 +0200
-@@ -28,6 +28,11 @@
- 	int (*help)(const struct iphdr *, size_t len,
- 		    struct ip_conntrack *ct,
- 		    enum ip_conntrack_info conntrackinfo);
-+
-+	void (*ctnl_change)(struct ip_conntrack *, union ip_conntrack_help *);
-+	void (*ctnl_new_expect)(struct ip_conntrack_expect *,
-+	                        union ip_conntrack_expect_proto *,
-+	                        union ip_conntrack_expect_help *);
- };
- 
- extern int ip_conntrack_helper_register(struct ip_conntrack_helper *);
-@@ -38,8 +43,15 @@
- /* Add an expected connection: can have more than one per connection */
- extern int ip_conntrack_expect_related(struct ip_conntrack *related_to,
- 				       struct ip_conntrack_expect *exp);
-+extern int __ip_conntrack_expect_related(struct ip_conntrack *related_to,
-+                                         struct ip_conntrack_expect *exp,
-+                                         struct ip_conntrack_expect **newp);
- extern int ip_conntrack_change_expect(struct ip_conntrack_expect *expect,
- 				      struct ip_conntrack_tuple *newtuple);
- extern void ip_conntrack_unexpect_related(struct ip_conntrack_expect *exp);
- 
-+extern struct ip_conntrack_expect *
-+__ip_ct_expect_find_tm(const struct ip_conntrack_tuple *tuple,
-+                       const struct ip_conntrack_tuple *mask);
-+
- #endif /*_IP_CONNTRACK_HELPER_H*/
-Index: linux-2.4.26-ct_sync/include/linux/netfilter_ipv4/ip_conntrack_core.h
-===================================================================
---- linux-2.4.26-ct_sync.orig/include/linux/netfilter_ipv4/ip_conntrack_core.h	2003-08-25 13:44:44.000000000 +0200
-+++ linux-2.4.26-ct_sync/include/linux/netfilter_ipv4/ip_conntrack_core.h	2004-06-28 12:58:22.000000000 +0200
-@@ -33,6 +33,11 @@
- struct ip_conntrack_tuple_hash *
- ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple,
- 		      const struct ip_conntrack *ignored_conntrack);
-+/* non-locked version */
-+struct ip_conntrack_tuple_hash *
-+__ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple,
-+                        const struct ip_conntrack *ignored_conntrack);
-+
- 
- extern int __ip_conntrack_confirm(struct nf_ct_info *nfct);
- 
-@@ -46,6 +51,7 @@
- }
- 
- extern struct list_head *ip_conntrack_hash;
-+extern struct list_head ip_conntrack_ordered_list;
- extern struct list_head ip_conntrack_expect_list;
- DECLARE_RWLOCK_EXTERN(ip_conntrack_lock);
- #endif /* _IP_CONNTRACK_CORE_H */
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	2003-11-28 19:26:21.000000000 +0100
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	2004-06-28 12:58:22.000000000 +0200
-@@ -186,13 +186,17 @@
- 	}
- 
- 	conntrack->proto.tcp.state = newconntrack;
-+	if (newconntrack != oldtcpstate)
-+		ip_conntrack_cache_event(IPCT_PROTOINFO);
- 
- 	/* Poor man's window tracking: record SYN/ACK for handshake check */
- 	if (oldtcpstate == TCP_CONNTRACK_SYN_SENT
- 	    && CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY
--	    && tcph->syn && tcph->ack)
-+	    && tcph->syn && tcph->ack) {
- 		conntrack->proto.tcp.handshake_ack
- 			= htonl(ntohl(tcph->seq) + 1);
-+		ip_conntrack_cache_event(IPCT_PROTOINFO);
-+	}
- 
- 	/* If only reply is a RST, we can consider ourselves not to
- 	   have an established connection: this is a fairly common
-@@ -207,8 +211,10 @@
- 		if (oldtcpstate == TCP_CONNTRACK_SYN_RECV
- 		    && CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL
- 		    && tcph->ack && !tcph->syn
--		    && tcph->ack_seq == conntrack->proto.tcp.handshake_ack)
-+		    && tcph->ack_seq == conntrack->proto.tcp.handshake_ack) {
- 			set_bit(IPS_ASSURED_BIT, &conntrack->status);
-+			ip_conntrack_cache_event(IPCT_STATUS);
-+		}
- 
- 		WRITE_UNLOCK(&tcp_lock);
- 		ip_ct_refresh(conntrack, *tcp_timeouts[newconntrack]);
-@@ -239,6 +245,22 @@
- 	return 1;
- }
- 
-+static int tcp_ctnl_check_private(union ip_conntrack_proto *p)
-+{
-+	struct ip_ct_tcp *tcp = (struct ip_ct_tcp *)p;
-+	if (tcp->state >= TCP_CONNTRACK_MAX)
-+		return -EINVAL;
-+	return 0;
-+}
-+
-+static void tcp_ctnl_change(struct ip_conntrack *conntrack,
-+                            union ip_conntrack_proto *p)
-+{
-+	WRITE_LOCK(&tcp_lock);
-+	memcpy(&conntrack->proto.tcp, p, sizeof(struct ip_ct_tcp));
-+	WRITE_UNLOCK(&tcp_lock);
-+}
-+
- static int tcp_exp_matches_pkt(struct ip_conntrack_expect *exp,
- 			       struct sk_buff **pskb)
- {
-@@ -254,4 +276,5 @@
- struct ip_conntrack_protocol ip_conntrack_protocol_tcp
- = { { NULL, NULL }, IPPROTO_TCP, "tcp",
-     tcp_pkt_to_tuple, tcp_invert_tuple, tcp_print_tuple, tcp_print_conntrack,
--    tcp_packet, tcp_new, NULL, tcp_exp_matches_pkt, NULL };
-+    tcp_packet, tcp_new, NULL, tcp_ctnl_check_private, tcp_ctnl_change, NULL,
-+    tcp_exp_matches_pkt, NULL };
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_ftp.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/ip_conntrack_ftp.c	2003-08-25 13:44:44.000000000 +0200
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_ftp.c	2004-06-28 12:58:22.000000000 +0200
-@@ -287,6 +287,7 @@
- 			ct_ftp_info->seq_aft_nl[dir] = 
- 						ntohl(tcph->seq) + datalen;
- 			ct_ftp_info->seq_aft_nl_set[dir] = 1;
-+			ip_conntrack_cache_event(IPCT_HELPINFO);
- 		}
- 	}
- 	UNLOCK_BH(&ip_ftp_lock);
-@@ -382,6 +383,13 @@
- 	return NF_ACCEPT;
- }
- 
-+static void ctnl_change(struct ip_conntrack *ct, union ip_conntrack_help *h)
-+{
-+	LOCK_BH(&ip_ftp_lock);
-+	memcpy(&ct->help, h, sizeof(ct->help));
-+	UNLOCK_BH(&ip_ftp_lock);
-+}
-+
- static struct ip_conntrack_helper ftp[MAX_PORTS];
- static char ftp_names[MAX_PORTS][10];
- 
-@@ -414,6 +422,7 @@
- 		ftp[i].flags = IP_CT_HELPER_F_REUSE_EXPECT;
- 		ftp[i].me = ip_conntrack_ftp;
- 		ftp[i].help = help;
-+		ftp[i].ctnl_change = ctnl_change;
- 
- 		tmpname = &ftp_names[i][0];
- 		if (ports[i] == FTP_PORT)
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_standalone.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/ip_conntrack_standalone.c	2004-06-28 12:58:18.000000000 +0200
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_standalone.c	2004-06-28 12:58:22.000000000 +0200
-@@ -503,7 +503,11 @@
- 
- EXPORT_SYMBOL(ip_conntrack_protocol_register);
- EXPORT_SYMBOL(ip_conntrack_protocol_unregister);
-+EXPORT_SYMBOL(invert_tuple);
- EXPORT_SYMBOL(invert_tuplepr);
-+EXPORT_SYMBOL(ip_conntrack_alloc);
-+EXPORT_SYMBOL(ip_conntrack_free);
-+EXPORT_SYMBOL(ip_conntrack_place_in_lists);
- EXPORT_SYMBOL(ip_conntrack_alter_reply);
- EXPORT_SYMBOL(ip_conntrack_destroyed);
- EXPORT_SYMBOL(ip_conntrack_get);
-@@ -515,16 +519,25 @@
- EXPORT_SYMBOL(__ip_ct_find_proto);
- EXPORT_SYMBOL(ip_ct_find_helper);
- EXPORT_SYMBOL(ip_conntrack_expect_related);
-+EXPORT_SYMBOL(__ip_conntrack_expect_related);
- EXPORT_SYMBOL(ip_conntrack_change_expect);
- EXPORT_SYMBOL(ip_conntrack_unexpect_related);
-+EXPORT_SYMBOL(ip_conntrack_remove_expectations);
-+EXPORT_SYMBOL(__ip_ct_expect_find_tm);
- EXPORT_SYMBOL_GPL(ip_conntrack_expect_find_get);
- EXPORT_SYMBOL_GPL(ip_conntrack_expect_put);
- EXPORT_SYMBOL(ip_conntrack_tuple_taken);
- EXPORT_SYMBOL(ip_ct_gather_frags);
- EXPORT_SYMBOL(ip_conntrack_htable_size);
- EXPORT_SYMBOL(ip_conntrack_expect_list);
-+EXPORT_SYMBOL(ip_conntrack_ordered_list);
- EXPORT_SYMBOL(ip_conntrack_lock);
- EXPORT_SYMBOL(ip_conntrack_hash);
- EXPORT_SYMBOL(ip_conntrack_untracked);
- EXPORT_SYMBOL_GPL(ip_conntrack_find_get);
-+EXPORT_SYMBOL_GPL(__ip_conntrack_find_get);
- EXPORT_SYMBOL_GPL(ip_conntrack_put);
-+#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
-+EXPORT_SYMBOL(ip_conntrack_chain);
-+EXPORT_SYMBOL(ip_conntrack_event_cache);
-+#endif /* CONFIG_IP_NF_CONNTRACK_EVENTS */
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_irc.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/ip_conntrack_irc.c	2003-11-28 19:26:21.000000000 +0100
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_irc.c	2004-06-28 12:58:22.000000000 +0200
-@@ -245,6 +245,24 @@
- 	return NF_ACCEPT;
- }
- 
-+static void ctnl_change(struct ip_conntrack *ct, union ip_conntrack_help *h)
-+{
-+	LOCK_BH(&ip_irc_lock);
-+	memcpy(&ct->help, h, sizeof(ct->help));
-+	UNLOCK_BH(&ip_irc_lock);
-+}
-+
-+static void ctnl_new_expect(struct ip_conntrack_expect *exp,
-+                            union ip_conntrack_expect_proto *p,
-+                            union ip_conntrack_expect_help *h)
-+{
-+	if (h == NULL)
-+		return;
-+	LOCK_BH(&ip_irc_lock);
-+	memcpy(&exp->help, h, sizeof(exp->help));
-+	UNLOCK_BH(&ip_irc_lock);
-+}
-+
- static struct ip_conntrack_helper irc_helpers[MAX_PORTS];
- static char irc_names[MAX_PORTS][10];
- 
-@@ -280,6 +298,8 @@
- 		hlpr->flags = IP_CT_HELPER_F_REUSE_EXPECT;
- 		hlpr->me = ip_conntrack_irc;
- 		hlpr->help = help;
-+		hlpr->ctnl_change = ctnl_change;
-+		hlpr->ctnl_new_expect = ctnl_new_expect;
- 
- 		tmpname = &irc_names[i][0];
- 		if (ports[i] == IRC_PORT)
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/Config.in
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/Config.in	2004-06-28 12:58:18.000000000 +0200
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/Config.in	2004-06-28 12:58:22.000000000 +0200
-@@ -4,8 +4,16 @@
- mainmenu_option next_comment
- comment '  IP: Netfilter Configuration'
- 
-+tristate 'Netfilter netlink interface' CONFIG_IP_NF_NETLINK
-+
- tristate 'Connection tracking (required for masq/NAT)' CONFIG_IP_NF_CONNTRACK
- if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then
-+  bool 'Connection tracking event notifications' CONFIG_IP_NF_CONNTRACK_EVENTS
-+  if [ "$CONFIG_IP_NF_CONNTRACK" = "y" ]; then
-+    dep_tristate '  Connection tracking netlink interface' CONFIG_IP_NF_NETLINK_CONNTRACK $CONFIG_IP_NF_NETLINK
-+  else
-+    dep_tristate '  Connection tracking netlink interface' CONFIG_IP_NF_NETLINK_CONNTRACK $CONFIG_IP_NF_CONNTRACK
-+  fi
-   dep_tristate '  FTP protocol support' CONFIG_IP_NF_FTP $CONFIG_IP_NF_CONNTRACK
-   bool '  Connection mark tracking support' CONFIG_IP_NF_CONNTRACK_MARK
-   dep_tristate '  Amanda protocol support' CONFIG_IP_NF_AMANDA $CONFIG_IP_NF_CONNTRACK
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/Makefile
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/Makefile	2004-06-28 12:58:18.000000000 +0200
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/Makefile	2004-07-08 13:42:53.000000000 +0200
-@@ -28,6 +28,15 @@
- ipfwadm-objs		:= $(ip_nf_compat-objs) ipfwadm_core.o
- ipchains-objs		:= $(ip_nf_compat-objs) ipchains_core.o
- 
-+# netfilter netlink interface
-+obj-$(CONFIG_IP_NF_NETLINK) += nfnetlink.o
-+ifdef CONFIG_IP_NF_NETLINK
-+	export-objs += nfnetlink.o
-+endif
-+
-+# nfnetlink modules
-+obj-$(CONFIG_IP_NF_NETLINK_CONNTRACK) += nfnetlink_conntrack.o
-+
- # connection tracking
- obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o
- 
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_proto_udp.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/ip_conntrack_proto_udp.c	2003-11-28 19:26:21.000000000 +0100
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_proto_udp.c	2004-06-28 12:58:22.000000000 +0200
-@@ -54,7 +54,10 @@
- 	if (test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) {
- 		ip_ct_refresh(conntrack, ip_ct_udp_timeout_stream);
- 		/* Also, more likely to be important, and not a probe */
--		set_bit(IPS_ASSURED_BIT, &conntrack->status);
-+		if (!test_bit(IPS_ASSURED_BIT, &conntrack->status)) {
-+			set_bit(IPS_ASSURED_BIT, &conntrack->status);
-+			ip_conntrack_cache_event(IPCT_STATUS);
-+		}
- 	} else
- 		ip_ct_refresh(conntrack, ip_ct_udp_timeout);
- 
-@@ -71,4 +74,4 @@
- struct ip_conntrack_protocol ip_conntrack_protocol_udp
- = { { NULL, NULL }, IPPROTO_UDP, "udp",
-     udp_pkt_to_tuple, udp_invert_tuple, udp_print_tuple, udp_print_conntrack,
--    udp_packet, udp_new, NULL, NULL, NULL };
-+    udp_packet, udp_new, NULL, NULL, NULL, NULL, NULL, NULL };
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/nfnetlink.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/nfnetlink.c	2004-06-16 09:19:51.000000000 +0200
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/nfnetlink.c	2004-06-28 12:58:22.000000000 +0200
-@@ -0,0 +1,354 @@
-+/* Netfilter messages via netlink socket. Allows for user space
-+ * protocol helpers and general trouble making from userspace.
-+ *
-+ * (C) 2001 by Jay Schulist <jschlst at samba.org>,
-+ * (C) 2002 by Harald Welte <laforge at gnumonks.org>
-+ *
-+ * Initial netfilter messages via netlink development funded and
-+ * generally made possible by Network Robots, Inc. (www.networkrobots.com)
-+ *
-+ * Further development of this code funded by Astaro AG (http://www.astaro.com)
-+ *
-+ * This software may be used and distributed according to the terms
-+ * of the GNU General Public License, incorporated herein by reference.
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/socket.h>
-+#include <linux/kernel.h>
-+#include <linux/major.h>
-+#include <linux/sched.h>
-+#include <linux/timer.h>
-+#include <linux/string.h>
-+#include <linux/sockios.h>
-+#include <linux/net.h>
-+#include <linux/fcntl.h>
-+#include <linux/skbuff.h>
-+#include <asm/uaccess.h>
-+#include <asm/system.h>
-+#include <net/sock.h>
-+#include <linux/init.h>
-+#include <linux/spinlock.h>
-+#include <linux/list.h>
-+
-+#include <linux/netfilter.h>
-+#include <linux/netlink.h>
-+#include <linux/nfnetlink.h>
-+
-+MODULE_LICENSE("GPL");
-+
-+static char __initdata nfversion[] = "0.12";
-+
-+#if 1
-+static int nf_debug_level = 1;
-+#define nf_debug(level, format, arg...)					\
-+do {									\
-+	if (nf_debug_level > level)					\
-+		printk(KERN_DEBUG "%s: " format, __FUNCTION__ , ## arg);	\
-+} while(0)
-+#else
-+#define nf_debug(level, format, arg...)
-+#endif
-+
-+static struct sock *nfnl = NULL;
-+static LIST_HEAD(subsys_list);
-+static struct nfnetlink_subsystem *subsys_table[NFNL_SUBSYS_COUNT];
-+DECLARE_MUTEX(nfnl_sem);
-+
-+void nfnl_lock(void)
-+{
-+	nfnl_shlock();
-+	nfnl_exlock();
-+}
-+
-+void nfnl_unlock(void)
-+{
-+	nfnl_exunlock();
-+	nfnl_shunlock();
-+}
-+
-+struct nfnetlink_subsystem *nfnetlink_subsys_alloc(int cb_count)
-+{
-+	int size;
-+	struct nfnetlink_subsystem *ss;
-+
-+	size = sizeof(struct nfnetlink_subsystem)
-+		+ (cb_count * sizeof(struct nfnl_callback));
-+
-+	ss = kmalloc(size, GFP_KERNEL);
-+	if (!ss)
-+		return NULL;
-+	memset(ss, 0, size);
-+
-+	return ss;
-+}
-+
-+int nfnetlink_subsys_register(struct nfnetlink_subsystem *n)
-+{
-+	MOD_INC_USE_COUNT;
-+
-+	nf_debug(0, "registering subsystem ID %u\n", n->subsys_id);
-+
-+	nfnl_lock();
-+	list_add(&n->list, &subsys_list);
-+	subsys_table[n->subsys_id] = n;
-+	nfnl_unlock();
-+
-+	return 0;
-+}
-+
-+int nfnetlink_subsys_unregister(struct nfnetlink_subsystem *n)
-+{
-+	nf_debug(0, "unregistering subsystem ID %u\n", n->subsys_id);
-+
-+	nfnl_lock();
-+	subsys_table[n->subsys_id] = NULL;
-+	list_del(&n->list);
-+	nfnl_unlock();
-+
-+	MOD_DEC_USE_COUNT;
-+
-+	return 0;
-+}
-+
-+struct nfnl_callback *nfnetlink_find_client(u_int16_t nlmsg_type)
-+{
-+	struct nfnetlink_subsystem *ss;
-+	u_int8_t subsys_id = NFNL_SUBSYS_ID(nlmsg_type);
-+	u_int8_t type = NFNL_MSG_TYPE(nlmsg_type);
-+
-+	if (subsys_id >= NFNL_SUBSYS_COUNT
-+	    || subsys_table[subsys_id] == NULL)
-+		return NULL;
-+
-+	ss = subsys_table[subsys_id];
-+
-+	if (type >= ss->cb_count) {
-+		nf_debug(0, "msgtype %u >= %u, returning\n", type, 
-+			 ss->cb_count);
-+		return NULL;
-+	}
-+
-+	return &ss->cb[type];
-+}
-+
-+void __nfa_fill(struct sk_buff *skb, int attrtype, int attrlen,
-+		const void *data)
-+{
-+	struct nfattr *nfa;
-+	int size = NFA_LENGTH(attrlen);
-+
-+	nfa = (struct nfattr *)skb_put(skb, NFA_ALIGN(size));
-+	nfa->nfa_type = attrtype;
-+	nfa->nfa_len  = size;
-+	memcpy(NFA_DATA(nfa), data, attrlen);
-+}
-+
-+int nfattr_parse(struct nfattr *tb[], int maxattr, struct nfattr *nfa, int len)
-+{
-+	memset(tb, 0, sizeof(struct nfattr *) * maxattr);
-+
-+	while (NFA_OK(nfa, len)) {
-+		unsigned flavor = nfa->nfa_type;
-+		if (flavor && flavor <= maxattr)
-+			tb[flavor-1] = nfa;
-+		nfa = NFA_NEXT(nfa, len);
-+	}
-+
-+	return 0;
-+}
-+
-+/**
-+ * nfnetlink_check_attributes - check and parse nfnetlink attributes
-+ *
-+ * subsys: nfnl subsystem for which this message is to be parsed
-+ * nlmsghdr: netlink message to be checked/parsed
-+ * cda: array of pointers, needs to be at least subsys->attr_count big
-+ *
-+ */
-+int
-+nfnetlink_check_attributes(struct nfnetlink_subsystem *subsys,
-+			   struct nlmsghdr *nlh, struct nfattr *cda[])
-+{
-+	int min_len;
-+
-+	memset(cda, 0, sizeof(struct nfattr *) * subsys->attr_count);
-+
-+	/* check attribute lengths. */
-+	min_len = sizeof(struct nfgenmsg);
-+	if (nlh->nlmsg_len < min_len)
-+		return -EINVAL;
-+
-+	if (nlh->nlmsg_len > min_len) {
-+		struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh));
-+		int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len);
-+
-+		while (NFA_OK(attr, attrlen)) {
-+			unsigned flavor = attr->nfa_type;
-+			if (flavor) {
-+				if (flavor > subsys->attr_count)
-+					return -EINVAL;
-+				cda[flavor - 1] = attr;
-+			}
-+			attr = NFA_NEXT(attr, attrlen);
-+		}
-+	} else
-+		return -EINVAL;
-+
-+        return 0;
-+}
-+
-+int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, int echo)
-+{
-+	int allocation = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
-+	int err = 0;
-+
-+	NETLINK_CB(skb).dst_groups = group;
-+	if (echo)
-+		atomic_inc(&skb->users);
-+	netlink_broadcast(nfnl, skb, pid, group, allocation);
-+	if (echo)
-+		err = netlink_unicast(nfnl, skb, pid, MSG_DONTWAIT);
-+
-+	return err;
-+}
-+
-+/* Process one complete nfnetlink message. */
-+static inline int nfnetlink_rcv_msg(struct sk_buff *skb,
-+				    struct nlmsghdr *nlh, int *errp)
-+{
-+	struct nfnl_callback *nc;
-+	int type, err = 0;
-+
-+	nf_debug(0, "entered; subsys=%u, msgtype=%u\n",
-+		 NFNL_SUBSYS_ID(nlh->nlmsg_type),
-+		 NFNL_MSG_TYPE(nlh->nlmsg_type));
-+
-+	/* Only requests are handled by kernel now. */
-+	if (!(nlh->nlmsg_flags & NLM_F_REQUEST)) {
-+		nf_debug(0, "received non-request message\n");
-+		return 0;
-+	}
-+
-+	/* Unknown message: reply with EINVAL */
-+	type = nlh->nlmsg_type;
-+	if (NFNL_SUBSYS_ID(type) > NFNL_SUBSYS_COUNT) {
-+		nf_debug(0, "subsys_id > subsys_count\n");
-+		goto err_inval;
-+	}
-+
-+	/* All the messages must have at least 1 byte length */
-+	if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct nfgenmsg))) {
-+		nf_debug(0, "received message was too short\n");
-+		return 0;
-+	}
-+
-+	nc = nfnetlink_find_client(type);
-+	if (!nc) {
-+		nf_debug(0, "unable to find client for type %d\n", type);
-+		goto err_inval;
-+	}
-+
-+	if (nc->cap_required && 
-+	    !cap_raised(NETLINK_CB(skb).eff_cap, nc->cap_required)) {
-+		nf_debug(0, "permission denied for type %d\n", type);
-+		*errp = -EPERM;
-+		return -1;
-+	}
-+
-+	err = nc->call(nfnl, skb, nlh, errp);
-+	*errp = err;
-+	return err;
-+
-+err_inval:
-+	*errp = -EINVAL;
-+	return -1;
-+}
-+
-+/* Process one packet of messages. */
-+static inline int nfnetlink_rcv_skb(struct sk_buff *skb)
-+{
-+	int err;
-+	struct nlmsghdr *nlh;
-+
-+	while (skb->len >= NLMSG_SPACE(0)) {
-+		u32 rlen;
-+
-+		nlh = (struct nlmsghdr *)skb->data;
-+		if (nlh->nlmsg_len < sizeof(struct nlmsghdr)
-+		    || skb->len < nlh->nlmsg_len)
-+			return 0;
-+		rlen = NLMSG_ALIGN(nlh->nlmsg_len);
-+		if (rlen > skb->len)
-+			rlen = skb->len;
-+		if (nfnetlink_rcv_msg(skb, nlh, &err)) {
-+			if (!err)
-+				return -1;
-+			netlink_ack(skb, nlh, err);
-+		} else
-+			if (nlh->nlmsg_flags & NLM_F_ACK)
-+				netlink_ack(skb, nlh, 0);
-+		skb_pull(skb, rlen);
-+	}
-+
-+	return 0;
-+}
-+
-+static void nfnetlink_rcv(struct sock *sk, int len)
-+{
-+	do {
-+		struct sk_buff *skb;
-+
-+		if (nfnl_shlock_nowait())
-+			return;
-+
-+		while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
-+			if (nfnetlink_rcv_skb(skb)) {
-+				if (skb->len)
-+					skb_queue_head(&sk->receive_queue, skb);
-+				else
-+					kfree_skb(skb);
-+				break;
-+			}
-+			kfree_skb(skb);
-+		}
-+
-+		up(&nfnl_sem);
-+	} while(nfnl && nfnl->receive_queue.qlen);
-+}
-+
-+void __exit nfnetlink_exit(void)
-+{
-+	printk("Netfilter removing netlink socket.\n");
-+	sock_release(nfnl->socket);
-+	return;
-+}
-+
-+int __init nfnetlink_init(void)
-+{
-+	int i;
-+	printk("Netfilter messages via NETLINK v%s.\n", nfversion);
-+
-+	for (i = 0; i < NFNL_SUBSYS_COUNT; i++)
-+		subsys_table[i] = NULL;
-+
-+	nfnl = netlink_kernel_create(NETLINK_NETFILTER, nfnetlink_rcv);
-+	if (!nfnl) {
-+		printk(KERN_ERR "cannot initialize nfnetlink!\n");
-+		return -1;
-+	}
-+
-+	return 0;
-+}
-+
-+module_init(nfnetlink_init);
-+module_exit(nfnetlink_exit);
-+
-+EXPORT_SYMBOL_GPL(nfnetlink_subsys_alloc);
-+EXPORT_SYMBOL_GPL(nfnetlink_subsys_register);
-+EXPORT_SYMBOL_GPL(nfnetlink_subsys_unregister);
-+EXPORT_SYMBOL_GPL(nfnetlink_check_attributes);
-+EXPORT_SYMBOL_GPL(nfnetlink_send);
-+EXPORT_SYMBOL_GPL(__nfa_fill);
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_nat_core.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/ip_nat_core.c	2004-06-14 14:52:11.000000000 +0200
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_nat_core.c	2004-06-28 12:58:22.000000000 +0200
-@@ -632,6 +632,8 @@
- 		IP_NF_ASSERT(info->num_manips <= IP_NAT_MAX_MANIPS);
- 	}
- 
-+	ip_conntrack_event(IPCT_NATINFO, conntrack);
-+
- 	/* If there's a helper, assign it; based on new tuple. */
- 	if (!conntrack->master)
- 		info->helper = LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_core.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/ip_conntrack_core.c	2004-06-28 12:58:18.000000000 +0200
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_core.c	2004-06-28 12:58:22.000000000 +0200
-@@ -11,6 +11,9 @@
-  * 16 Jul 2002: Harald Welte <laforge at gnumonks.org>
-  * 	- add usage/reference counts to ip_conntrack_expect
-  *	- export ip_conntrack[_expect]_{find_get,put} functions
-+ * 26 May 2003: Patrick McHardy <kaber at trash.net>
-+ *      - event notifications
-+ *      - restructured/exported some functions for ctnetlink
-  * */
- 
- #include <linux/version.h>
-@@ -30,6 +33,7 @@
- #include <linux/slab.h>
- #include <linux/random.h>
- #include <linux/jhash.h>
-+#include <linux/notifier.h>
- /* For ERR_PTR().  Yeah, I know... --RR */
- #include <linux/fs.h>
- 
-@@ -66,6 +70,15 @@
- static kmem_cache_t *ip_conntrack_cachep;
- struct ip_conntrack ip_conntrack_untracked;
- 
-+/* for ctnetlink */
-+LIST_HEAD(ip_conntrack_ordered_list);
-+static unsigned int ip_conntrack_next_id = 1;
-+static unsigned int ip_conntrack_exp_next_id = 1;
-+#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
-+struct notifier_block *ip_conntrack_chain = NULL;
-+unsigned long ip_conntrack_event_cache[NR_CPUS];
-+#endif /* CONFIG_IP_NF_CONNTRACK_EVENTS */
-+
- extern struct ip_conntrack_protocol ip_conntrack_generic_protocol;
- 
- static inline int proto_cmpfn(const struct ip_conntrack_protocol *curr,
-@@ -149,7 +162,7 @@
- 	return ret;
- }
- 
--static int
-+int
- invert_tuple(struct ip_conntrack_tuple *inverse,
- 	     const struct ip_conntrack_tuple *orig,
- 	     const struct ip_conntrack_protocol *protocol)
-@@ -172,6 +185,17 @@
- 	return ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask);
- }
- 
-+/* Compare expectation tuple/mask with given ones. */
-+static inline int expect_cmp_tm(const struct ip_conntrack_expect *i,
-+                                const struct ip_conntrack_tuple *tuple,
-+                                const struct ip_conntrack_tuple *mask)
-+{
-+//	this is wrong, a write locked ip_conntrack_lock is sufficent
-+//	MUST_BE_READ_LOCKED(&ip_conntrack_expect_tuple_lock);
-+	return ip_ct_tuple_equal(&i->tuple, tuple) &&
-+	       ip_ct_tuple_equal(&i->mask, mask);
-+}
-+
- static void
- destroy_expect(struct ip_conntrack_expect *exp)
- {
-@@ -202,6 +226,16 @@
- 			 struct ip_conntrack_expect *, tuple);
- }
- 
-+inline struct ip_conntrack_expect *
-+__ip_ct_expect_find_tm(const struct ip_conntrack_tuple *tuple,
-+                       const struct ip_conntrack_tuple *mask)
-+{
-+	MUST_BE_READ_LOCKED(&ip_conntrack_lock);
-+	MUST_BE_READ_LOCKED(&ip_conntrack_expect_tuple_lock);
-+	return LIST_FIND(&ip_conntrack_expect_list, expect_cmp_tm,
-+	                 struct ip_conntrack_expect *, tuple, mask);
-+}
-+
- /* Find a expectation corresponding to a tuple. */
- struct ip_conntrack_expect *
- ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple)
-@@ -258,12 +292,13 @@
- }
- 
- /* delete all unconfirmed expectations for this conntrack */
--static void remove_expectations(struct ip_conntrack *ct, int drop_refcount)
-+void
-+ip_conntrack_remove_expectations(struct ip_conntrack *ct, int drop_refcount)
- {
- 	struct list_head *exp_entry, *next;
- 	struct ip_conntrack_expect *exp;
- 
--	DEBUGP("remove_expectations(%p)\n", ct);
-+	DEBUGP("ip_conntrack_remove_expectations(%p,%d)\n", ct, drop_refcount);
- 
- 	list_for_each_safe(exp_entry, next, &ct->sibling_list) {
- 		exp = list_entry(exp_entry, struct ip_conntrack_expect,
-@@ -272,7 +307,7 @@
- 		/* we skip established expectations, as we want to delete
- 		 * the un-established ones only */
- 		if (exp->sibling) {
--			DEBUGP("remove_expectations: skipping established %p of %p\n", exp->sibling, ct);
-+			DEBUGP("ip_conntrack_remove_expectations: skipping established %p of %p\n", exp->sibling, ct);
- 			if (drop_refcount) {
- 				/* Indicate that this expectations parent is dead */
- 				ip_conntrack_put(exp->expectant);
-@@ -301,9 +336,17 @@
- 	hr = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
- 	LIST_DELETE(&ip_conntrack_hash[ho], &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
- 	LIST_DELETE(&ip_conntrack_hash[hr], &ct->tuplehash[IP_CT_DIR_REPLY]);
-+	LIST_DELETE(&ip_conntrack_ordered_list, &ct->olist);
- 
- 	/* Destroy all un-established, pending expectations */
--	remove_expectations(ct, 1);
-+	ip_conntrack_remove_expectations(ct, 1);
-+}
-+
-+inline void
-+ip_conntrack_free(struct ip_conntrack *conntrack)
-+{
-+	kmem_cache_free(ip_conntrack_cachep, conntrack);
-+	atomic_dec(&ip_conntrack_count);
- }
- 
- static void
-@@ -346,16 +389,17 @@
- 		ip_conntrack_put(master);
- 
- 	DEBUGP("destroy_conntrack: returning ct=%p to slab\n", ct);
--	kmem_cache_free(ip_conntrack_cachep, ct);
--	atomic_dec(&ip_conntrack_count);
-+	ip_conntrack_free(ct);
- }
- 
- static void death_by_timeout(unsigned long ul_conntrack)
- {
- 	struct ip_conntrack *ct = (void *)ul_conntrack;
- 
-+	ip_conntrack_event(IPCT_DESTROY, ct);
- 	WRITE_LOCK(&ip_conntrack_lock);
- 	clean_from_lists(ct);
-+	set_bit(IPS_DESTROYED_BIT, &ct->status);
- 	WRITE_UNLOCK(&ip_conntrack_lock);
- 	ip_conntrack_put(ct);
- }
-@@ -385,6 +429,17 @@
- 	return h;
- }
- 
-+inline struct ip_conntrack_tuple_hash *
-+__ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple,
-+                        const struct ip_conntrack *ignored_conntrack)
-+{
-+	struct ip_conntrack_tuple_hash *h;
-+	h = __ip_conntrack_find(tuple, ignored_conntrack);
-+	if (h)
-+		atomic_inc(&h->ctrack->ct_general.use);
-+	return h;
-+}
-+
- /* Find a connection corresponding to a tuple. */
- struct ip_conntrack_tuple_hash *
- ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple,
-@@ -393,9 +448,7 @@
- 	struct ip_conntrack_tuple_hash *h;
- 
- 	READ_LOCK(&ip_conntrack_lock);
--	h = __ip_conntrack_find(tuple, ignored_conntrack);
--	if (h)
--		atomic_inc(&h->ctrack->ct_general.use);
-+	h = __ip_conntrack_find_get(tuple, ignored_conntrack);
- 	READ_UNLOCK(&ip_conntrack_lock);
- 
- 	return h;
-@@ -422,6 +475,21 @@
- 	return NULL;
- }
- 
-+void inline
-+ip_conntrack_place_in_lists(struct ip_conntrack *conntrack)
-+{
-+	struct ip_conntrack_tuple_hash *h;
-+
-+	MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
-+
-+	conntrack->id = ip_conntrack_next_id++;
-+	list_add_tail(&conntrack->olist, &ip_conntrack_ordered_list);
-+	h = &conntrack->tuplehash[IP_CT_DIR_ORIGINAL];
-+	list_prepend(&ip_conntrack_hash[hash_conntrack(&h->tuple)], h);
-+	h = &conntrack->tuplehash[IP_CT_DIR_REPLY];
-+	list_prepend(&ip_conntrack_hash[hash_conntrack(&h->tuple)], h);
-+}
-+
- /* Confirm a connection given skb->nfct; places it in hash table */
- int
- __ip_conntrack_confirm(struct nf_ct_info *nfct)
-@@ -464,10 +532,7 @@
- 			  conntrack_tuple_cmp,
- 			  struct ip_conntrack_tuple_hash *,
- 			  &ct->tuplehash[IP_CT_DIR_REPLY].tuple, NULL)) {
--		list_prepend(&ip_conntrack_hash[hash],
--			     &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
--		list_prepend(&ip_conntrack_hash[repl_hash],
--			     &ct->tuplehash[IP_CT_DIR_REPLY]);
-+		ip_conntrack_place_in_lists(ct);
- 		/* Timer relative to confirmation time, not original
- 		   setting time, otherwise we'd get timer wrap in
- 		   weird delay cases. */
-@@ -476,6 +541,7 @@
- 		atomic_inc(&ct->ct_general.use);
- 		set_bit(IPS_CONFIRMED_BIT, &ct->status);
- 		WRITE_UNLOCK(&ip_conntrack_lock);
-+		ip_conntrack_event(IPCT_NEW, ct);
- 		return NF_ACCEPT;
- 	}
- 
-@@ -632,18 +698,12 @@
- 			 tuple);
- }
- 
--/* Allocate a new conntrack: we return -ENOMEM if classification
--   failed due to stress.  Otherwise it really is unclassifiable. */
--static struct ip_conntrack_tuple_hash *
--init_conntrack(const struct ip_conntrack_tuple *tuple,
--	       struct ip_conntrack_protocol *protocol,
--	       struct sk_buff *skb)
-+struct ip_conntrack *
-+ip_conntrack_alloc(const struct ip_conntrack_tuple *orig,
-+                   const struct ip_conntrack_tuple *reply)
- {
--	struct ip_conntrack *conntrack;
--	struct ip_conntrack_tuple repl_tuple;
--	size_t hash;
--	struct ip_conntrack_expect *expected;
--	int i;
-+	struct ip_conntrack *ct;
-+	unsigned int hash, i;
- 	static unsigned int drop_next = 0;
- 
- 	if (!ip_conntrack_hash_rnd_initted) {
-@@ -651,7 +711,7 @@
- 		ip_conntrack_hash_rnd_initted = 1;
- 	}
- 
--	hash = hash_conntrack(tuple);
-+	hash = hash_conntrack(orig);
- 
- 	if (ip_conntrack_max &&
- 	    atomic_read(&ip_conntrack_count) >= ip_conntrack_max) {
-@@ -664,43 +724,61 @@
- 		    && !early_drop(&ip_conntrack_hash[hash])) {
- 			if (net_ratelimit())
- 				printk(KERN_WARNING
--				       "ip_conntrack: table full, dropping"
--				       " packet.\n");
--			return ERR_PTR(-ENOMEM);
-+				       "ip_conntrack: table full.\n");
-+			return NULL;
- 		}
- 	}
- 
-+	ct = kmem_cache_alloc(ip_conntrack_cachep, GFP_ATOMIC);
-+	if (!ct)
-+		return NULL;
-+
-+	memset(ct, 0, sizeof(*ct));
-+	atomic_set(&ct->ct_general.use, 1);
-+	ct->ct_general.destroy = destroy_conntrack;
-+	ct->tuplehash[IP_CT_DIR_ORIGINAL].ctrack = ct;
-+	ct->tuplehash[IP_CT_DIR_REPLY].ctrack = ct;
-+	memcpy(&ct->tuplehash[IP_CT_DIR_REPLY].tuple, reply, sizeof(*reply));
-+	memcpy(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, orig, sizeof(*orig));
-+	for (i=0; i < IP_CT_NUMBER; i++)
-+		ct->infos[i].master = &ct->ct_general;
-+
-+	/* Don't set timer yet: wait for confirmation */
-+	init_timer(&ct->timeout);
-+	ct->timeout.data = (unsigned long)ct;
-+	ct->timeout.function = death_by_timeout;
-+
-+	INIT_LIST_HEAD(&ct->sibling_list);
-+	atomic_inc(&ip_conntrack_count);
-+	return ct;
-+}
-+
-+/* Allocate a new conntrack: we return -ENOMEM if classification
-+ * failed due to stress.  Otherwise it really is unclassifiable. */
-+static struct ip_conntrack_tuple_hash *
-+init_conntrack(const struct ip_conntrack_tuple *tuple,
-+		struct ip_conntrack_protocol *protocol,
-+		struct sk_buff *skb)
-+{
-+	struct ip_conntrack *conntrack;
-+	struct ip_conntrack_tuple repl_tuple;
-+	struct ip_conntrack_expect *expected;
-+
- 	if (!invert_tuple(&repl_tuple, tuple, protocol)) {
- 		DEBUGP("Can't invert tuple.\n");
- 		return NULL;
- 	}
- 
--	conntrack = kmem_cache_alloc(ip_conntrack_cachep, GFP_ATOMIC);
-+	conntrack = ip_conntrack_alloc(tuple, &repl_tuple);
- 	if (!conntrack) {
- 		DEBUGP("Can't allocate conntrack.\n");
- 		return ERR_PTR(-ENOMEM);
- 	}
--
--	memset(conntrack, 0, sizeof(*conntrack));
--	atomic_set(&conntrack->ct_general.use, 1);
--	conntrack->ct_general.destroy = destroy_conntrack;
--	conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *tuple;
--	conntrack->tuplehash[IP_CT_DIR_ORIGINAL].ctrack = conntrack;
--	conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = repl_tuple;
--	conntrack->tuplehash[IP_CT_DIR_REPLY].ctrack = conntrack;
--	for (i=0; i < IP_CT_NUMBER; i++)
--		conntrack->infos[i].master = &conntrack->ct_general;
--
-+	
- 	if (!protocol->new(conntrack, skb->nh.iph, skb->len)) {
--		kmem_cache_free(ip_conntrack_cachep, conntrack);
-+		ip_conntrack_free(conntrack);
- 		return NULL;
- 	}
--	/* Don't set timer yet: wait for confirmation */
--	init_timer(&conntrack->timeout);
--	conntrack->timeout.data = (unsigned long)conntrack;
--	conntrack->timeout.function = death_by_timeout;
--
--	INIT_LIST_HEAD(&conntrack->sibling_list);
- 
- 	WRITE_LOCK(&ip_conntrack_lock);
- 	/* Need finding and deleting of expected ONLY if we win race */
-@@ -742,7 +820,6 @@
- 		expected->expectant->expecting--;
- 		nf_conntrack_get(&master_ct(conntrack)->infos[0]);
- 	}
--	atomic_inc(&ip_conntrack_count);
- 	WRITE_UNLOCK(&ip_conntrack_lock);
- 
- 	if (expected && expected->expectfn)
-@@ -827,6 +904,8 @@
- 	/* FIXME: Do this right please. --RR */
- 	(*pskb)->nfcache |= NFC_UNKNOWN;
- 
-+	ip_conntrack_event_cache_init();
-+
- /* Doesn't cover locally-generated broadcast, so not worth it. */
- #if 0
- 	/* Ignore broadcast: no `connection'. */
-@@ -881,8 +960,12 @@
- 			return NF_ACCEPT;
- 		}
- 	}
--	if (set_reply)
-+	if (set_reply && !test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
- 		set_bit(IPS_SEEN_REPLY_BIT, &ct->status);
-+		ip_conntrack_cache_event(IPCT_STATUS);
-+	}
-+
-+	ip_conntrack_do_cached_events(ct);
- 
- 	return ret;
- }
-@@ -941,17 +1024,14 @@
- }
- 
- /* Add a related connection. */
--int ip_conntrack_expect_related(struct ip_conntrack *related_to,
--				struct ip_conntrack_expect *expect)
-+inline int __ip_conntrack_expect_related(struct ip_conntrack *related_to,
-+                                         struct ip_conntrack_expect *expect,
-+                                         struct ip_conntrack_expect **newp)
- {
- 	struct ip_conntrack_expect *old, *new;
- 	int ret = 0;
- 
--	WRITE_LOCK(&ip_conntrack_lock);
--	/* Because of the write lock, no reader can walk the lists,
--	 * so there is no need to use the tuple lock too */
--
--	DEBUGP("ip_conntrack_expect_related %p\n", related_to);
-+	DEBUGP("__ip_conntrack_expect_related %p\n", related_to);
- 	DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple);
- 	DEBUGP("mask:  "); DUMP_TUPLE(&expect->mask);
- 
-@@ -974,16 +1054,13 @@
- 			}
- 		}
- 
--		if (old) {
--			WRITE_UNLOCK(&ip_conntrack_lock);
-+		if (old)
- 			return -EEXIST;
--		}
- 	} else if (related_to->helper->max_expected && 
- 		   related_to->expecting >= related_to->helper->max_expected) {
- 		/* old == NULL */
- 		if (!(related_to->helper->flags & 
- 		      IP_CT_HELPER_F_REUSE_EXPECT)) {
--			WRITE_UNLOCK(&ip_conntrack_lock);
-  		    	if (net_ratelimit())
-  			    	printk(KERN_WARNING
- 				       "ip_conntrack: max number of expected "
-@@ -1023,7 +1100,6 @@
- 	} else if (LIST_FIND(&ip_conntrack_expect_list, expect_clash,
- 			     struct ip_conntrack_expect *, &expect->tuple, 
- 			     &expect->mask)) {
--		WRITE_UNLOCK(&ip_conntrack_lock);
- 		DEBUGP("expect_related: busy!\n");
- 		return -EBUSY;
- 	}
-@@ -1031,7 +1107,6 @@
- 	new = (struct ip_conntrack_expect *) 
- 	      kmalloc(sizeof(struct ip_conntrack_expect), GFP_ATOMIC);
- 	if (!new) {
--		WRITE_UNLOCK(&ip_conntrack_lock);
- 		DEBUGP("expect_relaed: OOM allocating expect\n");
- 		return -ENOMEM;
- 	}
-@@ -1046,17 +1121,38 @@
- 	list_add_tail(&new->expected_list, &related_to->sibling_list);
- 	/* add to global list of expectations */
- 	list_prepend(&ip_conntrack_expect_list, &new->list);
--	/* add and start timer if required */
-+	/* inititalize timer */
-+	init_timer(&new->timeout);
-+	new->timeout.data     = (unsigned long)new;
-+	new->timeout.function = expectation_timed_out;
-+
-+	related_to->expecting++;
-+
-+	*newp = new;
-+	return ret;
-+}
-+/* Add a related connection. */
-+int ip_conntrack_expect_related(struct ip_conntrack *related_to,
-+				struct ip_conntrack_expect *expect)
-+{
-+	struct ip_conntrack_expect *new;
-+	int ret = 0;
-+
-+	/* Because of the write lock, no reader can walk the lists,
-+	 * so there is no need to use the tuple lock too */
-+	WRITE_LOCK(&ip_conntrack_lock);
-+
-+	ret = __ip_conntrack_expect_related(related_to, expect, &new);
-+	if (ret < 0)
-+		goto out;
-+
- 	if (related_to->helper->timeout) {
--		init_timer(&new->timeout);
--		new->timeout.data = (unsigned long)new;
--		new->timeout.function = expectation_timed_out;
--		new->timeout.expires = jiffies + 
--					related_to->helper->timeout * HZ;
-+		new->timeout.expires = jiffies +
-+		                       related_to->helper->timeout * HZ;
- 		add_timer(&new->timeout);
- 	}
--	related_to->expecting++;
- 
-+out:
- 	WRITE_UNLOCK(&ip_conntrack_lock);
- 
- 	return ret;
-@@ -1145,9 +1241,10 @@
- {
- 	if (i->ctrack->helper == me) {
- 		/* Get rid of any expected. */
--		remove_expectations(i->ctrack, 0);
-+		ip_conntrack_remove_expectations(i->ctrack, 0);
- 		/* And *then* set helper to NULL */
- 		i->ctrack->helper = NULL;
-+		ip_conntrack_event(IPCT_HELPINFO, i->ctrack);
- 	}
- 	return 0;
- }
-@@ -1182,11 +1279,12 @@
- 	/* If not in hash table, timer will not be active yet */
- 	if (!is_confirmed(ct))
- 		ct->timeout.expires = extra_jiffies;
--	else {
-+	else if (abs(jiffies + extra_jiffies - ct->timeout.expires) >= HZ) {
- 		/* Need del_timer for race avoidance (may already be dying). */
- 		if (del_timer(&ct->timeout)) {
- 			ct->timeout.expires = jiffies + extra_jiffies;
- 			add_timer(&ct->timeout);
-+			ip_conntrack_cache_event(IPCT_REFRESH);
- 		}
- 	}
- 	WRITE_UNLOCK(&ip_conntrack_lock);
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/ip_conntrack_proto_icmp.c	2003-11-28 19:26:21.000000000 +0100
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_proto_icmp.c	2004-06-28 12:58:22.000000000 +0200
-@@ -14,6 +14,13 @@
- #define DEBUGP(format, args...)
- #endif
- 
-+static u_int8_t valid_new[] = {
-+	[ICMP_ECHO] = 1,
-+	[ICMP_TIMESTAMP] = 1,
-+	[ICMP_INFO_REQUEST] = 1,
-+	[ICMP_ADDRESS] = 1
-+};
-+
- static int icmp_pkt_to_tuple(const void *datah, size_t datalen,
- 			     struct ip_conntrack_tuple *tuple)
- {
-@@ -82,6 +89,7 @@
- 			ct->timeout.function((unsigned long)ct);
- 	} else {
- 		atomic_inc(&ct->proto.icmp.count);
-+		ip_conntrack_cache_event(IPCT_PROTOINFO);
- 		ip_ct_refresh(ct, ip_ct_icmp_timeout);
- 	}
- 
-@@ -92,12 +100,6 @@
- static int icmp_new(struct ip_conntrack *conntrack,
- 		    struct iphdr *iph, size_t len)
- {
--	static u_int8_t valid_new[]
--		= { [ICMP_ECHO] = 1,
--		    [ICMP_TIMESTAMP] = 1,
--		    [ICMP_INFO_REQUEST] = 1,
--		    [ICMP_ADDRESS] = 1 };
--
- 	if (conntrack->tuplehash[0].tuple.dst.u.icmp.type >= sizeof(valid_new)
- 	    || !valid_new[conntrack->tuplehash[0].tuple.dst.u.icmp.type]) {
- 		/* Can't create a new ICMP `conn' with this. */
-@@ -110,7 +112,25 @@
- 	return 1;
- }
- 
-+static int icmp_ctnl_check_tuples(struct ip_conntrack_tuple *orig,
-+                                  struct ip_conntrack_tuple *reply)
-+{
-+	unsigned int type = orig->dst.u.icmp.type;
-+
-+	if (type >= sizeof(valid_new) || !valid_new[type])
-+		return -EINVAL;
-+
-+	return 0;
-+}
-+
-+static void icmp_ctnl_change(struct ip_conntrack *conntrack,
-+                             union ip_conntrack_proto *p)
-+{
-+	memcpy(&conntrack->proto.icmp, p, sizeof(struct ip_ct_icmp));
-+}
-+
- struct ip_conntrack_protocol ip_conntrack_protocol_icmp
- = { { NULL, NULL }, IPPROTO_ICMP, "icmp",
-     icmp_pkt_to_tuple, icmp_invert_tuple, icmp_print_tuple,
--    icmp_print_conntrack, icmp_packet, icmp_new, NULL, NULL, NULL };
-+    icmp_print_conntrack, icmp_packet, icmp_new,
-+    icmp_ctnl_check_tuples, NULL, icmp_ctnl_change, NULL, NULL, NULL };
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_proto_generic.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/ip_conntrack_proto_generic.c	2003-11-28 19:26:21.000000000 +0100
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_proto_generic.c	2004-06-28 12:58:22.000000000 +0200
-@@ -57,5 +57,6 @@
- struct ip_conntrack_protocol ip_conntrack_generic_protocol
- = { { NULL, NULL }, 0, "unknown",
-     generic_pkt_to_tuple, generic_invert_tuple, generic_print_tuple,
--    generic_print_conntrack, established, new, NULL, NULL, NULL };
-+    generic_print_conntrack, established, new, NULL, NULL, NULL, NULL,
-+    NULL, NULL };
- 
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/nfnetlink_conntrack.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/nfnetlink_conntrack.c	2004-06-16 09:19:51.000000000 +0200
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/nfnetlink_conntrack.c	2004-06-28 12:58:22.000000000 +0200
-@@ -0,0 +1,1252 @@
-+/* Connection tracking via netlink socket. Allows for user space
-+ * protocol helpers and general trouble making from userspace.
-+ *
-+ * (C) 2001 by Jay Schulist <jschlst at samba.org>
-+ * (C) 2002 by Harald Welte <laforge at gnumonks.org>
-+ * (C) 2003 by Patrick Mchardy <kaber at trash.net>,
-+ *             Harald Welte <laforge at gnumonks.org>
-+ *
-+ * Initial connection tracking via netlink development funded and 
-+ * generally made possible by Network Robots, Inc. (www.networkrobots.com)
-+ *
-+ * Further development of this code funded by Astaro AG (http://www.astaro.com)
-+ *
-+ * This software may be used and distributed according to the terms
-+ * of the GNU General Public License, incorporated herein by reference.
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/socket.h>
-+#include <linux/kernel.h>
-+#include <linux/major.h>
-+#include <linux/sched.h>
-+#include <linux/timer.h>
-+#include <linux/string.h>
-+#include <linux/sockios.h>
-+#include <linux/net.h>
-+#include <linux/fcntl.h>
-+#include <linux/skbuff.h>
-+#include <asm/uaccess.h>
-+#include <asm/system.h>
-+#include <net/sock.h>
-+#include <linux/init.h>
-+#include <linux/netlink.h>
-+#include <linux/spinlock.h>
-+#include <linux/notifier.h>
-+#include <linux/rtnetlink.h>
-+
-+#include <linux/netfilter.h>
-+#include <linux/netfilter_ipv4.h>
-+#include <linux/netfilter_ipv4/ip_tables.h>
-+#include <linux/netfilter_ipv4/ip_conntrack.h>
-+#include <linux/netfilter_ipv4/ip_conntrack_core.h>
-+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
-+#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
-+
-+#include <linux/nfnetlink.h>
-+#include <linux/nfnetlink_conntrack.h>
-+
-+#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock)
-+#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_conntrack_lock)
-+#include <linux/netfilter_ipv4/listhelp.h>
-+
-+MODULE_LICENSE("GPL");
-+
-+static char __initdata ctversion[] = "0.12";
-+
-+#if 1
-+static int ct_debug_level = 1;
-+#define ct_debug(level, format, arg...)					\
-+do {									\
-+	if(ct_debug_level > level)					\
-+		printk(KERN_DEBUG "%s: " format, __FUNCTION__ , ## arg);	\
-+} while(0)
-+/* FIXME: this define is just needed for DUMP_TUPLE */
-+#define DEBUGP(format, args...)	ct_debug(0, format, ## args)
-+#else
-+#define ct_debug(level, format, arg...)
-+#define DEBUGP(format, args...)
-+#endif
-+
-+static struct nfnetlink_subsystem *ctnl_subsys;
-+
-+
-+static inline int
-+ctnetlink_dump_tuples(struct sk_buff *skb, const struct ip_conntrack *ct)
-+{
-+	NFA_PUT(skb, CTA_ORIG, sizeof(struct ip_conntrack_tuple),
-+	        &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
-+	NFA_PUT(skb, CTA_RPLY, sizeof(struct ip_conntrack_tuple),
-+	        &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
-+	return 0;
-+
-+nfattr_failure:
-+	return -1;
-+}
-+
-+static inline int
-+ctnetlink_dump_status(struct sk_buff *skb, const struct ip_conntrack *ct)
-+{
-+	NFA_PUT(skb, CTA_STATUS, sizeof(ct->status), &ct->status);
-+	return 0;
-+
-+nfattr_failure:
-+	return -1;
-+}
-+
-+static inline int
-+ctnetlink_dump_timeout(struct sk_buff *skb, const struct ip_conntrack *ct)
-+{
-+	unsigned long timeout = (ct->timeout.expires - jiffies) / HZ;
-+	
-+	NFA_PUT(skb, CTA_TIMEOUT, sizeof(timeout), &timeout);
-+	return 0;
-+
-+nfattr_failure:
-+	return -1;
-+}
-+
-+static inline int
-+ctnetlink_dump_protoinfo(struct sk_buff *skb, const struct ip_conntrack *ct)
-+{
-+	struct cta_proto cp;
-+
-+	cp.num_proto = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum;
-+	memcpy(&cp.proto, &ct->proto, sizeof(cp.proto));
-+	NFA_PUT(skb, CTA_PROTOINFO, sizeof(cp), &cp);
-+	return 0;
-+
-+nfattr_failure:
-+	return -1;
-+}
-+
-+static inline int
-+ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct ip_conntrack *ct)
-+{
-+	struct ip_conntrack_helper *h = ct->helper;
-+	struct cta_help ch;
-+
-+	if (h == NULL)
-+		memset(&ch, 0, sizeof(struct cta_help));
-+	else {
-+		strncpy((char *)&ch.name, h->name, sizeof(ch.name));
-+		memcpy(&ch.help, &ct->help, sizeof(ch.help));
-+	}
-+	NFA_PUT(skb, CTA_HELPINFO, sizeof(ch), &ch);
-+	return 0;
-+
-+nfattr_failure:
-+	return -1;
-+}
-+
-+static inline int
-+ctnetlink_dump_natinfo(struct sk_buff *skb, const struct ip_conntrack *ct)
-+{
-+#ifdef CONFIG_IP_NF_NAT_NEEDED
-+	const struct ip_nat_info *info = &ct->nat.info;
-+	struct cta_nat cn;
-+
-+	if (!info->initialized || !info->num_manips)
-+		return 0;
-+
-+	cn.num_manips = info->num_manips;
-+	memcpy(&cn.manips, &info->manips,
-+	       info->num_manips * sizeof(struct ip_nat_info_manip));
-+	NFA_PUT(skb, CTA_NATINFO, sizeof(struct cta_nat), &cn);
-+	return 0;
-+
-+nfattr_failure:
-+	return -1;
-+#else
-+	return 0;
-+#endif
-+}
-+
-+static inline int
-+ctnetlink_dump_mark(struct sk_buff *skb, const struct ip_conntrack *ct)
-+{
-+	return 0;
-+}
-+
-+static int
-+ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq,
-+		    int event, int nowait, 
-+		    const struct ip_conntrack *ct)
-+{
-+	struct nlmsghdr *nlh;
-+	struct nfgenmsg *nfmsg;
-+	unsigned char *b;
-+
-+	b = skb->tail;
-+
-+	event |= NFNL_SUBSYS_CTNETLINK << 8;
-+	nlh    = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg));
-+	nfmsg  = NLMSG_DATA(nlh);
-+
-+	nlh->nlmsg_flags    = (nowait && pid) ? NLM_F_MULTI : 0;
-+	nfmsg->nfgen_family = AF_INET;
-+
-+	if (ctnetlink_dump_tuples(skb, ct) < 0 ||
-+	    ctnetlink_dump_status(skb, ct) < 0 ||
-+	    ctnetlink_dump_timeout(skb, ct) < 0 ||
-+	    ctnetlink_dump_protoinfo(skb, ct) < 0 ||
-+	    ctnetlink_dump_helpinfo(skb, ct) < 0 ||
-+	    ctnetlink_dump_natinfo(skb, ct) < 0 ||
-+	    ctnetlink_dump_mark(skb, ct) < 0)
-+		goto nfattr_failure;
-+
-+	nlh->nlmsg_len = skb->tail - b;
-+	return skb->len;
-+
-+nlmsg_failure:
-+nfattr_failure:
-+	skb_trim(skb, b - skb->data);
-+	return -1;
-+}
-+
-+static inline unsigned int
-+ctnetlink_get_mcgroups(struct ip_conntrack *ct)
-+{
-+	unsigned int groups;
-+	int proto = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum;
-+
-+	switch (proto) {
-+	case IPPROTO_TCP:
-+		groups = NFGRP_IPV4_CT_TCP;
-+		break;
-+	case IPPROTO_UDP:
-+		groups = NFGRP_IPV4_CT_UDP;
-+		break;
-+	case IPPROTO_ICMP:
-+		groups = NFGRP_IPV4_CT_ICMP;
-+		break;
-+	default:
-+		groups = NFGRP_IPV4_CT_OTHER;
-+		break;
-+	}
-+
-+	return groups;
-+}
-+
-+#define EVENT(m,e) ((m) & (1 << (e)))
-+
-+static int ctnetlink_conntrack_event(struct notifier_block *this,
-+                                     unsigned long events, void *ptr)
-+{
-+	struct nlmsghdr *nlh;
-+	struct nfgenmsg *nfmsg;
-+	struct ip_conntrack *ct = (struct ip_conntrack *)ptr;
-+	struct sk_buff *skb;
-+	unsigned int type;
-+	unsigned char *b;
-+	int flags = 0;
-+
-+	/* FIXME: much too big, costs lots of socket buffer space */
-+	skb = alloc_skb(400 /* NLMSG_GOODSIZE */, GFP_ATOMIC);
-+	if (!skb)
-+		return NOTIFY_DONE;
-+
-+	if (EVENT(events, IPCT_DESTROY))
-+		type = CTNL_MSG_DELCONNTRACK;
-+	else {
-+		type = CTNL_MSG_NEWCONNTRACK;
-+		if (EVENT(events, IPCT_NEW)) {
-+			flags = NLM_F_CREATE|NLM_F_EXCL;
-+			/* dump everything */
-+			events = ~0UL;
-+		}
-+	}
-+
-+	b = skb->tail;
-+
-+	type |= NFNL_SUBSYS_CTNETLINK << 8;
-+	nlh   = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg));
-+	nfmsg = NLMSG_DATA(nlh);
-+
-+	nlh->nlmsg_flags    = flags;
-+	nfmsg->nfgen_family = AF_INET;
-+
-+	if (ctnetlink_dump_tuples(skb, ct) < 0)
-+		goto nfattr_failure;
-+
-+	if (EVENT(events, IPCT_STATUS)
-+	    && ctnetlink_dump_status(skb, ct) < 0)
-+		goto nfattr_failure;
-+	if (EVENT(events, IPCT_REFRESH)
-+	    && ctnetlink_dump_timeout(skb, ct) < 0)
-+		goto nfattr_failure;
-+	if (EVENT(events, IPCT_PROTOINFO)
-+	    && ctnetlink_dump_protoinfo(skb, ct) < 0)
-+		goto nfattr_failure;
-+	if (EVENT(events, IPCT_HELPINFO)
-+	    && ctnetlink_dump_helpinfo(skb, ct) < 0)
-+		goto nfattr_failure;
-+	if (EVENT(events, IPCT_NATINFO)
-+	    && ctnetlink_dump_natinfo(skb, ct) < 0)
-+		goto nfattr_failure;
-+
-+	nlh->nlmsg_len = skb->tail - b;
-+	nfnetlink_send(skb, 0, ctnetlink_get_mcgroups(ct), 0);
-+	return NOTIFY_DONE;
-+
-+nlmsg_failure:
-+nfattr_failure:
-+	kfree_skb(skb);
-+	return NOTIFY_DONE;
-+}
-+
-+static const int cta_min[CTA_MAX] = {
-+	[CTA_ORIG-1]		= sizeof(struct ip_conntrack_tuple),
-+	[CTA_RPLY-1]		= sizeof(struct ip_conntrack_tuple),
-+	[CTA_STATUS-1]		= sizeof(unsigned long),
-+	[CTA_PROTOINFO-1]	= sizeof(struct cta_proto),
-+	[CTA_HELPINFO-1]	= sizeof(struct cta_help),
-+	[CTA_NATINFO-1]		= sizeof(struct cta_nat),
-+	[CTA_TIMEOUT-1]		= sizeof(unsigned long),
-+
-+	[CTA_EXP_TUPLE-1]	= sizeof(struct ip_conntrack_tuple),
-+	[CTA_EXP_MASK-1]	= sizeof(struct ip_conntrack_tuple),
-+	[CTA_EXP_SEQNO-1]	= sizeof(u_int32_t),
-+	[CTA_EXP_PROTO-1]	= sizeof(struct cta_exp_proto),
-+	[CTA_EXP_HELP-1]	= sizeof(struct cta_exp_help),
-+	[CTA_EXP_TIMEOUT-1]	= sizeof(unsigned long)
-+};
-+
-+static inline int ctnetlink_kill(const struct ip_conntrack *i, void *data)
-+{
-+	struct ip_conntrack *t = (struct ip_conntrack *)data;
-+
-+	if (!memcmp(&i->tuplehash[IP_CT_DIR_ORIGINAL], 
-+	            &t->tuplehash[IP_CT_DIR_ORIGINAL], 
-+	            sizeof(struct ip_conntrack_tuple_hash))) {
-+		ip_conntrack_put(t);
-+		return 1;
-+	}
-+
-+	return 0;
-+}
-+
-+static int
-+ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, 
-+			struct nlmsghdr *nlh, int *errp)
-+{
-+	struct ip_conntrack_tuple_hash *h;
-+	struct ip_conntrack_tuple *tuple;
-+	struct nfattr *cda[CTA_MAX];
-+
-+	ct_debug(0, "entered\n");
-+
-+	if (nfnetlink_check_attributes(ctnl_subsys, nlh, cda) < 0)
-+		return -EINVAL;
-+
-+	if (cda[CTA_ORIG-1] &&
-+	    NFA_PAYLOAD(cda[CTA_ORIG-1]) < cta_min[CTA_ORIG-1])
-+		return -EINVAL;
-+
-+	if (cda[CTA_RPLY-1] &&
-+	    NFA_PAYLOAD(cda[CTA_RPLY-1]) < cta_min[CTA_RPLY-1])
-+		return -EINVAL;
-+	
-+	if (cda[CTA_ORIG-1])
-+		tuple = NFA_DATA(cda[CTA_ORIG-1]);
-+	else {
-+		if (cda[CTA_RPLY-1])
-+			tuple = NFA_DATA(cda[CTA_RPLY-1]);
-+		else {
-+			ct_debug(0, "no tuple found in request\n");
-+			return -EINVAL;
-+		}
-+	}
-+
-+	h = ip_conntrack_find_get(tuple, NULL);
-+	if (!h) {
-+		ct_debug(0, "tuple not found in conntrack hash:");
-+		DUMP_TUPLE(tuple);
-+		return -ENOENT;
-+	}
-+
-+	ct_debug(0, "calling selective_cleanup\n");
-+	ip_ct_selective_cleanup(ctnetlink_kill, h->ctrack);
-+
-+	return 0;
-+}
-+
-+static int ctnetlink_done(struct netlink_callback *cb)
-+{
-+	ct_debug(0, "entering\n");
-+	return 0;
-+}
-+
-+static int
-+ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
-+{
-+	struct ip_conntrack *ct;
-+
-+	ct_debug(0, "entered, last=%lu\n", cb->args[0]);
-+
-+	/* Traverse ordered list; send originals then reply. */
-+	READ_LOCK(&ip_conntrack_lock);
-+	list_for_each_entry(ct, &ip_conntrack_ordered_list, olist) {
-+		if (ct->id <= cb->args[0])
-+			continue;
-+		if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid,
-+		                        cb->nlh->nlmsg_seq,
-+					CTNL_MSG_NEWCONNTRACK, 1, ct) < 0)
-+			break;
-+		cb->args[0] = ct->id;
-+	}
-+	READ_UNLOCK(&ip_conntrack_lock);
-+	
-+	ct_debug(0, "leaving, last=%lu\n", cb->args[0]);
-+
-+	return skb->len;
-+}
-+
-+static int
-+ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, 
-+			struct nlmsghdr *nlh, int *errp)
-+{
-+	struct ip_conntrack_tuple_hash *h;
-+	struct ip_conntrack_tuple *tuple;
-+	struct nfattr *cda[CTA_MAX];
-+	struct ip_conntrack *ct;
-+	struct sk_buff *skb2 = NULL;
-+	int err;
-+
-+	ct_debug(0, "entered\n");
-+
-+	if (nlh->nlmsg_flags & NLM_F_DUMP) {
-+		struct nfgenmsg *msg = NLMSG_DATA(nlh);
-+		u32 rlen;
-+
-+		if (msg->nfgen_family != AF_INET)
-+			return -EAFNOSUPPORT;
-+
-+		if ((*errp = netlink_dump_start(ctnl, skb, nlh,
-+		                                ctnetlink_dump_table,
-+		                                ctnetlink_done)) != 0)
-+			return -EINVAL;
-+
-+		rlen = NLMSG_ALIGN(nlh->nlmsg_len);
-+		if (rlen > skb->len)
-+			rlen = skb->len;
-+		skb_pull(skb, rlen);
-+		return 0;
-+	}
-+
-+	if (nfnetlink_check_attributes(ctnl_subsys, nlh, cda) < 0)
-+		return -EINVAL;
-+
-+	if (cda[CTA_ORIG-1] &&
-+	    NFA_PAYLOAD(cda[CTA_ORIG-1]) < cta_min[CTA_ORIG-1])
-+		return -EINVAL;
-+
-+	if (cda[CTA_RPLY-1] &&
-+	    NFA_PAYLOAD(cda[CTA_RPLY-1]) < cta_min[CTA_RPLY-1])
-+		return -EINVAL;
-+	
-+	if (cda[CTA_ORIG-1])
-+		tuple = NFA_DATA(cda[CTA_ORIG-1]);
-+	else {
-+		if (cda[CTA_RPLY-1])
-+			tuple = NFA_DATA(cda[CTA_RPLY-1]);
-+		else
-+			return -EINVAL;
-+	}
-+
-+	h = ip_conntrack_find_get(tuple, NULL);
-+	if (!h) {
-+		ct_debug(0, "tuple not found in conntrack hash:");
-+		DUMP_TUPLE(tuple);
-+		return -ENOENT;
-+	}
-+	ct = h->ctrack;
-+
-+	skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC);
-+	if (!skb2) {
-+		ip_conntrack_put(ct);
-+		return -ENOMEM;
-+	}
-+	NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid;
-+
-+	err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, 
-+				  CTNL_MSG_NEWCONNTRACK, 1, ct);
-+	ip_conntrack_put(ct);
-+	if (err <= 0)
-+		goto nlmsg_failure;
-+
-+	err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT);
-+	if (err < 0)
-+		return err;
-+	return 0;
-+
-+nlmsg_failure:
-+	if (skb2)
-+		kfree_skb(skb2);
-+	return -1;
-+}
-+
-+static inline int
-+ctnetlink_change_status(struct ip_conntrack *ct, unsigned long *status)
-+{
-+	unsigned long d = ct->status ^ *status;
-+
-+	if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DESTROYED))
-+		/* unchangeable */
-+		return -EINVAL;
-+	
-+	if (d & IPS_SEEN_REPLY && !(*status & IPS_SEEN_REPLY))
-+		/* SEEN_REPLY bit can only be set */
-+		return -EINVAL;
-+
-+	if (d & IPS_ASSURED && !(*status & IPS_ASSURED))
-+		/* ASSURED bit can only be set */
-+		return -EINVAL;
-+
-+	ct->status = *status;
-+	return 0;
-+}
-+
-+static inline int
-+ctnetlink_change_protoinfo(struct ip_conntrack *ct, struct cta_proto *cp)
-+{
-+	struct ip_conntrack_protocol *icp;
-+	int proto = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum;
-+	
-+	if (cp->num_proto != proto)
-+		return -EINVAL;
-+
-+	icp = __ip_ct_find_proto(cp->num_proto);
-+	if (icp->ctnl_check_private
-+	    && icp->ctnl_check_private(&cp->proto) < 0)
-+		return -EINVAL;
-+
-+	if (icp->ctnl_change)
-+		icp->ctnl_change(ct, &cp->proto);
-+
-+	return 0;
-+}
-+
-+static inline int
-+ctnetlink_change_helpinfo(struct ip_conntrack *ct, struct cta_help *h)
-+{
-+	struct ip_conntrack_helper *helper = ct->helper;
-+	struct ip_conntrack_tuple *reply;
-+
-+	if (helper == NULL) {
-+		if (*h->name == '\0')
-+			return 0;
-+		if (ct->master)
-+			return -EINVAL;
-+		reply = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;
-+		helper = ip_ct_find_helper(reply);
-+		if (helper == NULL)
-+			return -ENOENT;
-+	} else if (*h->name == '\0') {
-+		ip_conntrack_remove_expectations(ct, 1);
-+		ct->helper = NULL;
-+		return 0;
-+	}
-+
-+	h->name[CTA_HELP_MAXNAMESZ - 1] = '\0';
-+	if (strcmp(helper->name, h->name))
-+		return -EINVAL;
-+
-+	ct->helper = helper;
-+	if (helper->ctnl_change)
-+		helper->ctnl_change(ct, &h->help);
-+
-+	return 0;
-+}
-+
-+static inline int
-+ctnetlink_change_natinfo(struct ip_conntrack *ct, struct cta_nat *n)
-+{
-+#ifdef CONFIG_IP_NF_NAT_NEEDED
-+	struct ip_nat_info *info = &ct->nat.info;
-+	int i;
-+
-+	if (n->num_manips > IP_NAT_MAX_MANIPS)
-+		return -EINVAL;
-+
-+	if (info->initialized && n->num_manips < info->num_manips)
-+		return -EINVAL;
-+
-+	for (i = 0; i < n->num_manips; i++) {
-+		if (n->manips[i].direction > IP_CT_DIR_MAX)
-+			return -EINVAL;
-+		if (n->manips[i].hooknum > NF_IP_NUMHOOKS)
-+			return -EINVAL;
-+		if (n->manips[i].hooknum == NF_IP_FORWARD)
-+			return -EINVAL;
-+		if (n->manips[i].maniptype > IP_NAT_MANIP_DST)
-+			return -EINVAL;
-+	}
-+
-+	return 0;
-+#else
-+	return -EOPNOTSUPP;
-+#endif
-+}
-+
-+static inline int
-+ctnetlink_change_timeout(struct ip_conntrack *ct, unsigned long *timeout)
-+{
-+	if (!del_timer(&ct->timeout))
-+		return -ETIME;
-+	ct->timeout.expires = jiffies + *timeout * HZ;
-+	add_timer(&ct->timeout);
-+
-+	return 0;
-+}
-+
-+static int
-+ctnetlink_change_conntrack(struct ip_conntrack *ct, struct nfattr *cda[])
-+{
-+	void *data;
-+	int err;
-+	
-+	ct_debug(0, "entered\n");
-+
-+	if (cda[CTA_STATUS-1]) {
-+		data = NFA_DATA(cda[CTA_STATUS-1]);
-+		if ((err = ctnetlink_change_status(ct, data)) < 0)
-+			return err;
-+	}
-+	if (cda[CTA_PROTOINFO-1]) {
-+		data = NFA_DATA(cda[CTA_PROTOINFO-1]);
-+		if ((err = ctnetlink_change_protoinfo(ct, data)) < 0)
-+			return err;
-+	}
-+	if (cda[CTA_HELPINFO-1]) {
-+		data = NFA_DATA(cda[CTA_HELPINFO-1]);
-+		if ((err = ctnetlink_change_helpinfo(ct, data)) < 0)
-+			return err;
-+	}
-+	if (cda[CTA_NATINFO-1]) {
-+		data = NFA_DATA(cda[CTA_NATINFO-1]);
-+		if ((err = ctnetlink_change_natinfo(ct, data)) < 0)
-+			return err;
-+	}
-+	if (cda[CTA_TIMEOUT-1]) {
-+		data = NFA_DATA(cda[CTA_TIMEOUT-1]);
-+		if ((err = ctnetlink_change_timeout(ct, data)) < 0)
-+			return err;
-+	}
-+
-+	ct_debug(0, "all done\n");
-+	return 0;
-+}
-+
-+static int
-+ctnetlink_create_conntrack(struct nfattr *cda[])
-+{
-+	struct ip_conntrack *ct;
-+	struct ip_conntrack_tuple *otuple, *rtuple, t;
-+	struct ip_conntrack_protocol *icp;
-+	struct cta_proto *proto;
-+	unsigned long *status;
-+	unsigned long *timeout;
-+	int err;
-+
-+	ct_debug(0, "entered\n");
-+
-+	if (!(cda[CTA_ORIG-1] && cda[CTA_RPLY-1] && cda[CTA_STATUS-1] &&
-+	      cda[CTA_PROTOINFO-1] && cda[CTA_TIMEOUT-1])) {
-+		ct_debug(0, "required attribute(s) missing\n");
-+		return -EINVAL;
-+	}
-+
-+	otuple  = NFA_DATA(cda[CTA_ORIG-1]);
-+	rtuple  = NFA_DATA(cda[CTA_RPLY-1]);
-+	timeout = NFA_DATA(cda[CTA_TIMEOUT-1]);
-+
-+	status  = NFA_DATA(cda[CTA_STATUS-1]);
-+	if (!(*status & IPS_CONFIRMED))
-+		return -EINVAL;	/* cannot create unconfirmed connections */
-+
-+	proto = NFA_DATA(cda[CTA_PROTOINFO-1]);
-+	icp   = __ip_ct_find_proto(proto->num_proto);
-+
-+	if (!invert_tuple(&t, otuple, icp) || !ip_ct_tuple_equal(&t, rtuple))
-+		; // FIXME: nat changes reply tuples // return -EINVAL;
-+
-+	if (icp->ctnl_check_tuples
-+	    && icp->ctnl_check_tuples(otuple, rtuple) < 0)
-+		return -EINVAL;
-+	
-+	if (icp->ctnl_check_private
-+	    && icp->ctnl_check_private(&proto->proto) < 0)
-+		return -EINVAL;
-+
-+	ct = ip_conntrack_alloc(otuple, rtuple);
-+	if (ct == NULL)
-+		return -ENOMEM;
-+
-+	ct->status = *status;
-+	ct->timeout.expires = jiffies + *timeout * HZ;
-+
-+	if (icp->ctnl_change)
-+		icp->ctnl_change(ct, &proto->proto);
-+
-+	cda[CTA_ORIG-1] = cda[CTA_RPLY-1] = cda[CTA_PROTOINFO-1] = 
-+		cda[CTA_STATUS-1] = cda[CTA_TIMEOUT-1] = NULL;
-+
-+	err = ctnetlink_change_conntrack(ct, cda);
-+	if (err < 0) {
-+		ip_conntrack_free(ct);
-+		return err;
-+	}
-+
-+	ip_conntrack_place_in_lists(ct);
-+	add_timer(&ct->timeout);
-+
-+	ct_debug(0, "all done\n");
-+	return 0;
-+}
-+
-+static int 
-+ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, 
-+			struct nlmsghdr *nlh, int *errp)
-+{
-+	struct nfattr *cda[CTA_MAX];
-+	struct ip_conntrack_tuple *otuple = NULL, *rtuple = NULL;
-+	struct ip_conntrack_tuple_hash *h = NULL;
-+	int i, err = 0;
-+
-+	ct_debug(0, "entered\n");
-+
-+	if (nfnetlink_check_attributes(ctnl_subsys, nlh, cda) < 0)
-+		return -EINVAL;
-+
-+	for (i = 0; i < CTA_MAX; i++)
-+		if (cda[i] && NFA_PAYLOAD(cda[i]) < cta_min[i])
-+			return -EINVAL;
-+
-+	ct_debug(0, "all attribute sizes ok\n");
-+
-+	if (cda[CTA_ORIG-1])
-+		otuple = NFA_DATA(cda[CTA_ORIG-1]);
-+	
-+	if (cda[CTA_RPLY-1])
-+		rtuple = NFA_DATA(cda[CTA_RPLY-1]);
-+
-+	if (otuple == NULL && rtuple == NULL) {
-+		ct_debug(0, "no tuple found in request\n");
-+		return -EINVAL;
-+	}
-+
-+	WRITE_LOCK(&ip_conntrack_lock);
-+	if (otuple)
-+		h = __ip_conntrack_find_get(otuple, NULL);
-+	if (h == NULL && rtuple)
-+		h = __ip_conntrack_find_get(rtuple, NULL);
-+
-+	if (h == NULL) {
-+		ct_debug(0, "no such conntrack, create new\n");
-+		err = -ENOENT;
-+		if (!(nlh->nlmsg_flags & NLM_F_CREATE))
-+			goto out_unlock;
-+		err = ctnetlink_create_conntrack(cda);
-+		goto out_unlock;
-+	} else {
-+		ct_debug(0, "conntrack found, change\n");
-+		err = -EEXIST;
-+		if (nlh->nlmsg_flags & NLM_F_EXCL)
-+			goto out_put;
-+		err = ctnetlink_change_conntrack(h->ctrack, cda);
-+	}
-+
-+out_put:
-+	ip_conntrack_put(h->ctrack);
-+out_unlock:
-+	WRITE_UNLOCK(&ip_conntrack_lock);
-+	return err;
-+}
-+
-+/* EXPECT */
-+
-+static inline int
-+ctnetlink_exp_dump_tuples(struct sk_buff *skb,
-+                          const struct ip_conntrack_expect *exp)
-+{
-+	NFA_PUT(skb, CTA_EXP_TUPLE, sizeof(struct ip_conntrack_tuple),
-+	        &exp->tuple);
-+	NFA_PUT(skb, CTA_EXP_MASK, sizeof(struct ip_conntrack_tuple),
-+		&exp->mask);
-+	return 0;
-+	
-+nfattr_failure:
-+	return -1;
-+}
-+
-+static inline int
-+ctnetlink_exp_dump_seqno(struct sk_buff *skb,
-+                         const struct ip_conntrack_expect *exp)
-+{
-+	NFA_PUT(skb, CTA_EXP_SEQNO, sizeof(u_int32_t), &exp->seq);
-+	return 0;
-+	
-+nfattr_failure:
-+	return -1;
-+}
-+
-+static inline int
-+ctnetlink_exp_dump_proto(struct sk_buff *skb,
-+                         const struct ip_conntrack_expect *exp)
-+{
-+	return 0;
-+}
-+
-+static inline int
-+ctnetlink_exp_dump_help(struct sk_buff *skb,
-+                        const struct ip_conntrack_expect *exp)
-+{
-+	struct cta_exp_help ch;
-+
-+	memcpy(&ch.help, &exp->help, sizeof(ch.help));
-+	NFA_PUT(skb, CTA_EXP_HELP, sizeof(union ip_conntrack_expect_help),
-+	        &exp->help);
-+	return 0;
-+	
-+nfattr_failure:
-+	return -1;
-+}
-+
-+static int
-+ctnetlink_exp_fill_info(struct sk_buff *skb, u32 pid, u32 seq,
-+		    int event, 
-+		    int nowait, 
-+		    const struct ip_conntrack_expect *exp)
-+{
-+	struct nlmsghdr *nlh;
-+	struct nfgenmsg *nfmsg;
-+	unsigned char *b;
-+
-+	b = skb->tail;
-+
-+	event |= NFNL_SUBSYS_CTNETLINK << 8;
-+	nlh    = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg));
-+	nfmsg  = NLMSG_DATA(nlh);
-+
-+	nlh->nlmsg_flags    = (nowait && pid) ? NLM_F_MULTI : 0;
-+	nfmsg->nfgen_family = AF_INET;
-+
-+	if (ctnetlink_exp_dump_tuples(skb, exp) < 0 ||
-+	    ctnetlink_exp_dump_seqno(skb, exp) < 0 ||
-+	    ctnetlink_exp_dump_proto(skb, exp) < 0 ||
-+	    ctnetlink_exp_dump_help(skb, exp) < 0)
-+		goto nfattr_failure;
-+
-+	nlh->nlmsg_len = skb->tail - b;
-+	return skb->len;
-+
-+nlmsg_failure:
-+nfattr_failure:
-+	skb_trim(skb, b - skb->data);
-+	return -1;
-+}
-+
-+static inline struct sk_buff *
-+ctnetlink_exp_event_build_msg(const struct ip_conntrack_expect *exp)
-+{
-+	struct sk_buff *skb;
-+	int err;
-+
-+	skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC);
-+	if (!skb)
-+		return NULL;
-+
-+	err = ctnetlink_exp_fill_info(skb, 0, 0, CTNL_MSG_NEWEXPECT, 1, exp);
-+	if (err <= 0)
-+		goto nlmsg_failure;
-+	return skb;
-+
-+nlmsg_failure:
-+	if (skb)
-+		kfree_skb(skb);
-+	return NULL;
-+}
-+
-+static void
-+ctnetlink_exp_create(struct ip_conntrack_expect *exp)
-+{
-+	u16 proto = exp->tuple.dst.protonum;
-+	struct sk_buff *skb;
-+
-+	skb = ctnetlink_exp_event_build_msg(exp);
-+	if (!skb)
-+		return;
-+
-+	if (proto == IPPROTO_TCP) {
-+		nfnetlink_send(skb, 0, NFGRP_IPV4_CT_TCP, 0);
-+		return;
-+	} else if (proto == IPPROTO_UDP) {
-+		nfnetlink_send(skb, 0, NFGRP_IPV4_CT_UDP, 0);
-+		return;
-+	} else if (proto == IPPROTO_ICMP) {
-+		nfnetlink_send(skb, 0, NFGRP_IPV4_CT_ICMP, 0);
-+		return;
-+	} else {
-+		nfnetlink_send(skb, 0, NFGRP_IPV4_CT_OTHER, 0);
-+		return;
-+	}
-+	kfree_skb(skb);
-+	return;
-+}
-+
-+static int
-+ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, 
-+		     struct nlmsghdr *nlh, int *errp)
-+{
-+	struct ip_conntrack_expect *exp;
-+	struct ip_conntrack_tuple *tuple;
-+	struct nfattr *cda[CTA_MAX];
-+
-+	if (nfnetlink_check_attributes(ctnl_subsys, nlh, cda) < 0)
-+		return -EINVAL;
-+
-+	if (cda[CTA_ORIG-1] &&
-+	    NFA_PAYLOAD(cda[CTA_ORIG-1]) < cta_min[CTA_ORIG-1])
-+		return -EINVAL;
-+
-+	if (cda[CTA_RPLY-1] &&
-+	    NFA_PAYLOAD(cda[CTA_RPLY-1]) < cta_min[CTA_RPLY-1])
-+		return -EINVAL;
-+
-+	if (cda[CTA_ORIG-1])
-+		tuple = NFA_DATA(cda[CTA_ORIG-1]);
-+	else {
-+		if (cda[CTA_RPLY-1])
-+			tuple = NFA_DATA(cda[CTA_RPLY-1]);
-+		else
-+			return -EINVAL;
-+	}
-+
-+	/* bump usage count to 2 */
-+	exp = ip_conntrack_expect_find_get(tuple);
-+	if (!exp)
-+		return -ENOENT;
-+
-+	/* after list removal, usage count == 1 */
-+	ip_conntrack_unexpect_related(exp);
-+	/* we have put what we 'get' above. after this line usage count == 0 */
-+	ip_conntrack_expect_put(exp);
-+
-+	return 0;
-+}
-+
-+static int
-+ctnetlink_exp_dump_build_msg(const struct ip_conntrack_expect *exp,
-+			 struct sk_buff *skb, u32 pid, u32 seq)
-+{
-+	int err, proto;
-+
-+	proto = exp->tuple.dst.protonum;
-+	err = ctnetlink_exp_fill_info(skb, pid, seq, CTNL_MSG_NEWEXPECT, 1, 
-+				      exp);
-+	if (err <= 0)
-+		goto nlmsg_failure;
-+	return 0;
-+
-+nlmsg_failure:
-+	if (skb)
-+		kfree_skb(skb);
-+	return -1;
-+}
-+
-+static int
-+ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
-+{
-+	ct_debug(0, "entered\n");
-+	if (cb->args[0] == 0) {
-+		READ_LOCK(&ip_conntrack_lock);
-+		LIST_FIND(&ip_conntrack_expect_list, 
-+			  ctnetlink_exp_dump_build_msg,
-+			  struct ip_conntrack_expect *, skb,
-+			  NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq);
-+		READ_UNLOCK(&ip_conntrack_lock);
-+		cb->args[0] = 1;
-+	}
-+	ct_debug(0, "returning\n");
-+
-+	return skb->len;
-+}
-+
-+
-+static int
-+ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, 
-+		     struct nlmsghdr *nlh, int *errp)
-+{
-+	struct ip_conntrack_expect *exp;
-+	struct ip_conntrack_tuple *tuple;
-+	struct nfattr *cda[CTA_MAX];
-+	struct sk_buff *skb2 = NULL;
-+	int err, proto;
-+
-+	ct_debug(0, "entered\n");
-+
-+	if (nlh->nlmsg_flags & NLM_F_DUMP) {
-+		struct nfgenmsg *msg = NLMSG_DATA(nlh);
-+		u32 rlen;
-+
-+		if (msg->nfgen_family != AF_INET)
-+			return -EAFNOSUPPORT;
-+
-+		ct_debug(0, "starting dump\n");
-+			if ((*errp = netlink_dump_start(ctnl, skb, nlh,
-+		    				ctnetlink_exp_dump_table,
-+						ctnetlink_done)) != 0)
-+			return -EINVAL;
-+		rlen = NLMSG_ALIGN(nlh->nlmsg_len);
-+		if (rlen > skb->len)
-+			rlen = skb->len;
-+		skb_pull(skb, rlen);
-+		return 0;
-+	}
-+
-+	if (nfnetlink_check_attributes(ctnl_subsys, nlh, cda) < 0)
-+		return -EINVAL;
-+
-+	if (cda[CTA_ORIG-1]
-+	    && NFA_PAYLOAD(cda[CTA_ORIG-1]) < sizeof(struct ip_conntrack_tuple))
-+		return -EINVAL;
-+
-+	if (cda[CTA_RPLY-1]
-+	    && NFA_PAYLOAD(cda[CTA_RPLY-1]) < sizeof(struct ip_conntrack_tuple))
-+		return -EINVAL;
-+
-+	if (cda[CTA_ORIG-1])
-+		tuple = NFA_DATA(cda[CTA_ORIG-1]);
-+	else {
-+		if (cda[CTA_RPLY-1])
-+			tuple = NFA_DATA(cda[CTA_RPLY-1]);
-+		else
-+			return -EINVAL;
-+	}
-+
-+	exp = ip_conntrack_expect_find_get(tuple);
-+	if (!exp)
-+		return -ENOENT;
-+
-+	skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC);
-+	if (!skb2)
-+		return -ENOMEM;
-+	NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid;
-+	proto = exp->tuple.dst.protonum;
-+	
-+	err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).pid, 
-+				      nlh->nlmsg_seq, CTNL_MSG_NEWEXPECT,
-+				      1, exp);
-+	if (err <= 0)
-+		goto nlmsg_failure;
-+
-+	err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT);
-+	if (err < 0)
-+		return err;
-+	return 0;
-+
-+nlmsg_failure:
-+	if (skb2)
-+		kfree_skb(skb2);
-+	return -1;
-+}
-+
-+static int
-+ctnetlink_change_expect(struct ip_conntrack_expect *x, struct nfattr *cda[])
-+{
-+
-+	return -EOPNOTSUPP;
-+}
-+
-+static int
-+ctnetlink_create_expect(struct nfattr *cda[])
-+{
-+	struct ip_conntrack_tuple *tuple, *mask;
-+	struct ip_conntrack_tuple *orig, *reply;
-+	struct ip_conntrack_tuple_hash *h = NULL;
-+	struct ip_conntrack_expect exp, *new;
-+	struct ip_conntrack_helper *helper;
-+	unsigned long timeout;
-+	int err;
-+
-+	ct_debug(0, "entered\n");
-+
-+	if (!(cda[CTA_ORIG-1] || cda[CTA_RPLY-1])) {
-+		ct_debug(0, "required attributes missing\n");
-+		return -EINVAL;
-+	}
-+
-+	tuple = NFA_DATA(cda[CTA_EXP_TUPLE-1]);
-+	mask  = NFA_DATA(cda[CTA_EXP_MASK-1]);
-+	orig  = NFA_DATA(cda[CTA_ORIG-1]);
-+	reply = NFA_DATA(cda[CTA_RPLY-1]);
-+
-+	memcpy(&exp.tuple, tuple, sizeof(struct ip_conntrack_tuple));
-+	memcpy(&exp.mask, mask, sizeof(struct ip_conntrack_tuple));
-+
-+	exp.expectfn = NULL;
-+
-+	if (cda[CTA_EXP_SEQNO-1])
-+		exp.seq = *(u_int32_t *)NFA_DATA(cda[CTA_EXP_SEQNO-1]);
-+
-+	h = __ip_conntrack_find_get(orig, NULL);
-+	if (h == NULL)
-+		h = __ip_conntrack_find_get(reply, NULL);
-+	if (h == NULL)
-+		return -ENOENT;
-+
-+	helper = h->ctrack->helper;
-+
-+	if (cda[CTA_EXP_TIMEOUT-1])
-+		timeout = *(unsigned long *)NFA_DATA(cda[CTA_EXP_TIMEOUT-1]);
-+	else if (helper && helper->timeout)
-+		timeout = helper->timeout;
-+	else
-+		return -EINVAL;
-+
-+	if (helper && helper->ctnl_new_expect) {
-+		struct cta_exp_proto *cp = NULL;
-+		struct cta_exp_help *ch = NULL;
-+
-+		if (cda[CTA_EXP_PROTO-1])
-+			cp = NFA_DATA(cda[CTA_EXP_PROTO-1]);
-+		if (cda[CTA_EXP_HELP-1])
-+			ch = NFA_DATA(cda[CTA_EXP_HELP-1]);
-+		
-+		helper->ctnl_new_expect(&exp, &cp->proto, &ch->help);
-+	}
-+
-+	err = __ip_conntrack_expect_related(h->ctrack, &exp, &new);
-+	if (err < 0)
-+		return err;
-+	
-+	new->timeout.expires = jiffies + timeout * HZ;
-+	add_timer(&new->timeout);
-+	return 0;
-+}
-+
-+static int
-+ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
-+		     struct nlmsghdr *nlh, int *errp)
-+{
-+	struct nfattr *cda[CTA_MAX];
-+	struct ip_conntrack_tuple *tuple, *mask;
-+	struct ip_conntrack_expect *exp;
-+	int i, err = 0;
-+
-+	if (nfnetlink_check_attributes(ctnl_subsys, nlh, cda) < 0)
-+		return -EINVAL;
-+
-+	for (i = 0; i < CTA_MAX; i++)
-+		if (cda[i] && NFA_PAYLOAD(cda[i]) < cta_min[i])
-+			return -EINVAL;
-+
-+	if (!cda[CTA_EXP_TUPLE-1] || !cda[CTA_EXP_MASK-1])
-+		return -EINVAL;
-+
-+	tuple = NFA_DATA(cda[CTA_EXP_TUPLE-1]);
-+	mask  = NFA_DATA(cda[CTA_EXP_MASK-1]);
-+
-+	WRITE_LOCK(&ip_conntrack_lock);
-+	exp = __ip_ct_expect_find_tm(tuple, mask);
-+
-+	if (exp == NULL) {
-+		err = -ENOENT;
-+		if (!(nlh->nlmsg_flags & NLM_F_CREATE))
-+			goto out_unlock;
-+		err = ctnetlink_create_expect(cda);
-+	} else {
-+		err = -EEXIST;
-+		if (nlh->nlmsg_flags & NLM_F_EXCL)
-+			goto out_unlock;
-+		err = ctnetlink_change_expect(exp, cda);
-+	}
-+
-+out_unlock:
-+	WRITE_UNLOCK(&ip_conntrack_lock);
-+	return err;
-+}
-+
-+/* struct conntrack_expect stuff */
-+
-+static struct notifier_block ctnl_notifier = {
-+	ctnetlink_conntrack_event,
-+	NULL,
-+	0
-+};
-+
-+static void __exit ctnetlink_exit(void)
-+{
-+	printk("ctnetlink: unregistering with nfnetlink.\n");
-+//	ip_conntrack_notify_unregister(&ctnl_exp_notify);
-+	ip_conntrack_notify_unregister(&ctnl_notifier);
-+	nfnetlink_subsys_unregister(ctnl_subsys);
-+	kfree(ctnl_subsys);
-+	return;
-+}
-+
-+static int __init ctnetlink_init(void)
-+{
-+	int ret;
-+
-+	ctnl_subsys = nfnetlink_subsys_alloc(CTNL_MSG_COUNT);
-+	if (!ctnl_subsys) {
-+		ret = -ENOMEM;
-+		goto err_out; 
-+	}
-+
-+	ctnl_subsys->name = "conntrack";
-+	ctnl_subsys->subsys_id = NFNL_SUBSYS_CTNETLINK;
-+	ctnl_subsys->cb_count = CTNL_MSG_COUNT;
-+	ctnl_subsys->attr_count = CTA_MAX;
-+	ctnl_subsys->cb[CTNL_MSG_NEWCONNTRACK].call = ctnetlink_new_conntrack;
-+	ctnl_subsys->cb[CTNL_MSG_NEWCONNTRACK].cap_required = CAP_NET_ADMIN;
-+	ctnl_subsys->cb[CTNL_MSG_DELCONNTRACK].call = ctnetlink_del_conntrack;
-+	ctnl_subsys->cb[CTNL_MSG_DELCONNTRACK].cap_required = CAP_NET_ADMIN;
-+	ctnl_subsys->cb[CTNL_MSG_GETCONNTRACK].call = ctnetlink_get_conntrack;
-+	ctnl_subsys->cb[CTNL_MSG_GETCONNTRACK].cap_required = 0;
-+	ctnl_subsys->cb[CTNL_MSG_NEWEXPECT].call = ctnetlink_new_expect;
-+	ctnl_subsys->cb[CTNL_MSG_NEWEXPECT].cap_required = CAP_NET_ADMIN;
-+	ctnl_subsys->cb[CTNL_MSG_DELEXPECT].call = ctnetlink_del_expect;
-+	ctnl_subsys->cb[CTNL_MSG_DELEXPECT].cap_required = CAP_NET_ADMIN;
-+	ctnl_subsys->cb[CTNL_MSG_GETEXPECT].call = ctnetlink_get_expect;
-+	ctnl_subsys->cb[CTNL_MSG_GETEXPECT].cap_required = 0;
-+
-+	printk("ctnetlink v%s: registering with nfnetlink.\n", ctversion);
-+	if ((ret = nfnetlink_subsys_register(ctnl_subsys) < 0)) {
-+		printk("ctnetlink_init: cannot register with nfnetlink.\n");
-+		goto err_free_subsys;
-+	}
-+
-+	if ((ret = ip_conntrack_notify_register(&ctnl_notifier)) < 0) {
-+		printk("ctnetlink_init: cannot register notifier.\n");
-+		goto err_unreg_subsys;
-+	}
-+
-+#if 0
-+	if ((ret = ip_conntrack_notify_register(&ctnl_exp_notify)) < 0) {
-+		printk("ctnetlink_init: cannot register exp notifier\n");
-+		goto err_unreg_notify;
-+	}
-+#endif
-+
-+
-+	return 0;
-+	
-+#if 0
-+err_unreg_notify:
-+	ip_conntrack_notify_unregister(&ctnl_notify);
-+#endif 
-+err_unreg_subsys:
-+	nfnetlink_subsys_unregister(ctnl_subsys);
-+err_free_subsys:
-+	kfree(ctnl_subsys);
-+err_out:
-+	return ret;
-+}
-+
-+module_init(ctnetlink_init);
-+module_exit(ctnetlink_exit);
-
-%diffstat
- include/linux/netfilter_ipv4/ip_conntrack.h          |  109 +
- include/linux/netfilter_ipv4/ip_conntrack_core.h     |    6 
- include/linux/netfilter_ipv4/ip_conntrack_helper.h   |   12 
- include/linux/netfilter_ipv4/ip_conntrack_protocol.h |   11 
- include/linux/nfnetlink.h                            |  158 ++
- include/linux/nfnetlink_conntrack.h                  |   87 +
- net/ipv4/netfilter/Config.in                         |    8 
- net/ipv4/netfilter/Makefile                          |    9 
- net/ipv4/netfilter/ip_conntrack_core.c               |  242 ++-
- net/ipv4/netfilter/ip_conntrack_ftp.c                |    9 
- net/ipv4/netfilter/ip_conntrack_irc.c                |   20 
- net/ipv4/netfilter/ip_conntrack_proto_generic.c      |    3 
- net/ipv4/netfilter/ip_conntrack_proto_icmp.c         |   34 
- net/ipv4/netfilter/ip_conntrack_proto_tcp.c          |   29 
- net/ipv4/netfilter/ip_conntrack_proto_udp.c          |    7 
- net/ipv4/netfilter/ip_conntrack_standalone.c         |   13 
- net/ipv4/netfilter/ip_nat_core.c                     |    2 
- net/ipv4/netfilter/nfnetlink.c                       |  354 +++++
- net/ipv4/netfilter/nfnetlink_conntrack.c             | 1252 +++++++++++++++++++
- 19 files changed, 2280 insertions(+), 85 deletions(-)
-

Modified: branches/netfilter-ha/linux-2.6/patches/pf_packet.patch
===================================================================
--- branches/netfilter-ha/linux-2.6/patches/pf_packet.patch	2005-01-02 22:40:48 UTC (rev 3550)
+++ branches/netfilter-ha/linux-2.6/patches/pf_packet.patch	2005-01-02 23:13:27 UTC (rev 3551)
@@ -1,8 +1,8 @@
 %patch
-Index: linux-2.4.26-ct_sync/include/linux/netfilter_packet.h
+Index: linux-2.6.9/include/linux/netfilter_packet.h
 ===================================================================
---- linux-2.4.26-ct_sync.orig/include/linux/netfilter_packet.h	Fri Dec 19 09:26:33 2003
-+++ linux-2.4.26-ct_sync/include/linux/netfilter_packet.h	Mon Jun 14 14:52:20 2004
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.9/include/linux/netfilter_packet.h	2004-12-15 21:06:07.525658800 +0100
 @@ -0,0 +1,17 @@
 +#ifndef __LINUX_NETFILTER_PACKET_H
 +#define __LINUX_NETFILTER_PACKET_H
@@ -21,19 +21,19 @@
 +#define NF_PACKET_OUTPUT       1
 +
 +#endif /* __LINUX_NETFILTER_PACKET_H */
-Index: linux-2.4.26-ct_sync/net/core/dev.c
+Index: linux-2.6.9/net/core/dev.c
 ===================================================================
---- linux-2.4.26-ct_sync.orig/net/core/dev.c	Wed Apr 14 15:05:41 2004
-+++ linux-2.4.26-ct_sync/net/core/dev.c	Mon Jun 14 14:55:01 2004
-@@ -100,6 +100,7 @@
- #include <linux/init.h>
- #include <linux/kmod.h>
- #include <linux/module.h>
-+#include <linux/netfilter_packet.h>
- #if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO)
+--- linux-2.6.9.orig/net/core/dev.c	2004-11-27 00:25:43.000000000 +0100
++++ linux-2.6.9/net/core/dev.c	2004-12-15 21:24:52.782593744 +0100
+@@ -112,6 +112,7 @@
  #include <linux/wireless.h>		/* Note : will define WIRELESS_EXT */
  #include <net/iw_handler.h>
-@@ -1032,40 +1033,11 @@
+ #endif	/* CONFIG_NET_RADIO */
++#include <linux/netfilter_packet.h>
+ #include <asm/current.h>
+ 
+ /* This define, if set, will randomly drop a packet when congestion
+@@ -1255,37 +1256,12 @@
   *	to congestion or traffic shaping.
   */
  
@@ -41,136 +41,143 @@
 +static inline int dev_queue_xmit_finish(struct sk_buff *skb)
  {
  	struct net_device *dev = skb->dev;
- 	struct Qdisc  *q;
+ 	struct Qdisc *q;
+ 	int rc = -ENOMEM;
  
 -	if (skb_shinfo(skb)->frag_list &&
--	    !(dev->features&NETIF_F_FRAGLIST) &&
--	    skb_linearize(skb, GFP_ATOMIC) != 0) {
--		kfree_skb(skb);
--		return -ENOMEM;
--	}
+-	    !(dev->features & NETIF_F_FRAGLIST) &&
+-	    __skb_linearize(skb, GFP_ATOMIC))
+-		goto out_kfree_skb;
 -
 -	/* Fragmented skb is linearized if device does not support SG,
 -	 * or if at least one of fragments is in highmem and device
 -	 * does not support DMA from it.
 -	 */
 -	if (skb_shinfo(skb)->nr_frags &&
--	    (!(dev->features&NETIF_F_SG) || illegal_highdma(dev, skb)) &&
--	    skb_linearize(skb, GFP_ATOMIC) != 0) {
--		kfree_skb(skb);
--		return -ENOMEM;
--	}
+-	    (!(dev->features & NETIF_F_SG) || illegal_highdma(dev, skb)) &&
+-	    __skb_linearize(skb, GFP_ATOMIC))
+-		goto out_kfree_skb;
 -
 -	/* If packet is not checksummed and device does not support
 -	 * checksumming for this protocol, complete checksumming here.
 -	 */
 -	if (skb->ip_summed == CHECKSUM_HW &&
--	    (!(dev->features&(NETIF_F_HW_CSUM|NETIF_F_NO_CSUM)) &&
--	     (!(dev->features&NETIF_F_IP_CSUM) ||
--	      skb->protocol != htons(ETH_P_IP)))) {
--		if ((skb = skb_checksum_help(skb)) == NULL)
--			return -ENOMEM;
--	}
+-	    (!(dev->features & (NETIF_F_HW_CSUM | NETIF_F_NO_CSUM)) &&
+-	     (!(dev->features & NETIF_F_IP_CSUM) ||
+-	      skb->protocol != htons(ETH_P_IP))))
+-	      	if (skb_checksum_help(&skb, 0))
+-	      		goto out_kfree_skb;
 -
- 	/* Grab device queue */
- 	spin_lock_bh(&dev->queue_lock);
- 	q = dev->qdisc;
-@@ -1125,6 +1097,43 @@
- 	return -ENETDOWN;
+-
+ 	/* Disable soft irqs for various locks below. Also 
+ 	 * stops preemption for RCU. 
+ 	 */
+@@ -1364,13 +1340,50 @@
+ 	}
+ out_enetdown:
+ 	rc = -ENETDOWN;
+-out_kfree_skb:
+ 	kfree_skb(skb);
+ out:
+ 	local_bh_enable();
+ 	return rc;
  }
  
 +int dev_queue_xmit(struct sk_buff *skb)
 +{
-+       struct net_device *dev = skb->dev;
++	struct net_device *dev = skb->dev;
 +
-+       if (skb_shinfo(skb)->frag_list &&
-+           !(dev->features&NETIF_F_FRAGLIST) &&
-+           skb_linearize(skb, GFP_ATOMIC) != 0) {
-+               kfree_skb(skb);
-+               return -ENOMEM;
-+       }
++	if (skb_shinfo(skb)->frag_list &&
++	    !(dev->features & NETIF_F_FRAGLIST) &&
++	    __skb_linearize(skb, GFP_ATOMIC)) {
++		kfree_skb(skb);
++		return -ENOMEM;
++	}
 +
-+       /* Fragmented skb is linearized if device does not support SG,
-+        * or if at least one of fragments is in highmem and device
-+        * does not support DMA from it.
-+        */
-+       if (skb_shinfo(skb)->nr_frags &&
-+           (!(dev->features&NETIF_F_SG) || illegal_highdma(dev, skb)) &&
-+           skb_linearize(skb, GFP_ATOMIC) != 0) {
-+               kfree_skb(skb);
-+               return -ENOMEM;
-+       }
++	/* Fragmented skb is linearized if device does not support SG,
++	 * or if at least one of fragments is in highmem and device
++	 * does not support DMA from it.
++	 */
++	if (skb_shinfo(skb)->nr_frags &&
++	    (!(dev->features & NETIF_F_SG) || illegal_highdma(dev, skb)) &&
++	    __skb_linearize(skb, GFP_ATOMIC)) {
++		kfree_skb(skb);
++		return -ENOMEM;
++	}
 +
-+       /* If packet is not checksummed and device does not support
-+        * checksumming for this protocol, complete checksumming here.
-+        */
-+       if (skb->ip_summed == CHECKSUM_HW &&
-+           (!(dev->features&(NETIF_F_HW_CSUM|NETIF_F_NO_CSUM)) &&
-+            (!(dev->features&NETIF_F_IP_CSUM) ||
-+             skb->protocol != htons(ETH_P_IP)))) {
-+               if ((skb = skb_checksum_help(skb)) == NULL)
-+                       return -ENOMEM;
-+       }
++	/* If packet is not checksummed and device does not support
++	 * checksumming for this protocol, complete checksumming here.
++	 */
++	if (skb->ip_summed == CHECKSUM_HW &&
++	    (!(dev->features & (NETIF_F_HW_CSUM | NETIF_F_NO_CSUM)) &&
++	     (!(dev->features & NETIF_F_IP_CSUM) ||
++	      skb->protocol != htons(ETH_P_IP))))
++	      	if (skb_checksum_help(&skb, 0)) {
++			kfree_skb(skb);
++			return -ENOMEM;
++		}
 +
-+       return NF_HOOK(PF_PACKET, NF_PACKET_OUTPUT, skb, NULL, dev,
-+                      dev_queue_xmit_finish);
++	return NF_HOOK(PF_PACKET, NF_PACKET_OUTPUT, skb, NULL, dev,
++			dev_queue_xmit_finish);
 +}
 +
  
  /*=======================================================================
  			Receiver routines
-@@ -1458,28 +1467,12 @@
+@@ -1714,29 +1727,12 @@
  }
- #endif   /* CONFIG_NET_DIVERT */
+ #endif
  
 -int netif_receive_skb(struct sk_buff *skb)
-+static inline int netif_receive_skb_finish(struct sk_buff *skb)
++static int netif_receive_skb_finish(struct sk_buff *skb)
  {
  	struct packet_type *ptype, *pt_prev;
  	int ret = NET_RX_DROP;
  	unsigned short type;
  
--	if (skb->stamp.tv_sec == 0)
--		do_gettimeofday(&skb->stamp);
+-#ifdef CONFIG_NETPOLL
+-	if (skb->dev->netpoll_rx && skb->dev->poll && netpoll_rx(skb)) {
+-		kfree_skb(skb);
+-		return NET_RX_DROP;
+-	}
+-#endif
 -
+-	if (!skb->stamp.tv_sec)
+-		net_timestamp(&skb->stamp);
+-
 -	skb_bond(skb);
 -
--	netdev_rx_stat[smp_processor_id()].total++;
+-	__get_cpu_var(netdev_rx_stat).total++;
 -
--#ifdef CONFIG_NET_FASTROUTE
--	if (skb->pkt_type == PACKET_FASTROUTE) {
--		netdev_rx_stat[smp_processor_id()].fastroute_deferred_out++;
--		return dev_queue_xmit(skb);
--	}
--#endif
--
 -	skb->h.raw = skb->nh.raw = skb->data;
+-	skb->mac_len = skb->nh.raw - skb->mac.raw;
 -
  	pt_prev = NULL;
- 	for (ptype = ptype_all; ptype; ptype = ptype->next) {
- 		if (!ptype->dev || ptype->dev == skb->dev) {
-@@ -1540,7 +1533,29 @@
+ 
+ 	rcu_read_lock();
+@@ -1805,7 +1801,30 @@
  	return ret;
  }
  
 -static int process_backlog(struct net_device *backlog_dev, int *budget)
 +int netif_receive_skb(struct sk_buff *skb)
 +{
-+	if (skb->stamp.tv_sec == 0)
-+	do_gettimeofday(&skb->stamp);
++#ifdef CONFIG_NETPOLL
++	if (skb->dev->netpoll_rx && skb->dev->poll && netpoll_rx(skb)) {
++		kfree_skb(skb);
++		return NET_RX_DROP;
++	}
++#endif
 +
++	if (!skb->stamp.tv_sec)
++		net_timestamp(&skb->stamp);
++
 +	skb_bond(skb);
 +
-+	netdev_rx_stat[smp_processor_id()].total++;
++	__get_cpu_var(netdev_rx_stat).total++;
 +
-+#ifdef CONFIG_NET_FASTROUTE
-+	if (skb->pkt_type == PACKET_FASTROUTE) {
-+		netdev_rx_stat[smp_processor_id()].fastroute_deferred_out++;
-+		return dev_queue_xmit(skb);
-+	}
-+#endif
-+
 +	skb->h.raw = skb->nh.raw = skb->data;
++	skb->mac_len = skb->nh.raw - skb->mac.raw;
 +
 +	return NF_HOOK(PF_PACKET, NF_PACKET_INPUT, skb, skb->dev, NULL,
 +		       netif_receive_skb_finish);
@@ -180,9 +187,3 @@
  {
  	int work = 0;
  	int quota = min(backlog_dev->quota, *budget);
-
-%diffstat
- include/linux/netfilter_packet.h |   17 +++++
- net/core/dev.c                   |  111 ++++++++++++++++++++++-----------------
- 2 files changed, 80 insertions(+), 48 deletions(-)
-

Modified: branches/netfilter-ha/linux-2.6/patches/pf_packet_remove_warning.patch
===================================================================
--- branches/netfilter-ha/linux-2.6/patches/pf_packet_remove_warning.patch	2005-01-02 22:40:48 UTC (rev 3550)
+++ branches/netfilter-ha/linux-2.6/patches/pf_packet_remove_warning.patch	2005-01-02 23:13:27 UTC (rev 3551)
@@ -1,9 +1,9 @@
-Index: linux-2.4.26-ct_sync/net/core/netfilter.c
+Index: linux-2.6.9/net/core/netfilter.c
 ===================================================================
---- linux-2.4.26-ct_sync.orig/net/core/netfilter.c	2003-08-25 13:44:44.000000000 +0200
-+++ linux-2.4.26-ct_sync/net/core/netfilter.c	2004-06-24 15:35:12.000000000 +0200
-@@ -472,10 +472,12 @@
- 	br_read_lock_bh(BR_NETPROTO_LOCK);
+--- linux-2.6.9.orig/net/core/netfilter.c	2004-11-27 00:25:43.000000000 +0100
++++ linux-2.6.9/net/core/netfilter.c	2004-12-15 21:19:44.270494712 +0100
+@@ -508,10 +508,12 @@
+ 	rcu_read_lock();
  
  #ifdef CONFIG_NETFILTER_DEBUG
 +#if 0

Deleted: branches/netfilter-ha/linux-2.6/patches/proc_net_stat.patch
===================================================================
--- branches/netfilter-ha/linux-2.6/patches/proc_net_stat.patch	2005-01-02 22:40:48 UTC (rev 3550)
+++ branches/netfilter-ha/linux-2.6/patches/proc_net_stat.patch	2005-01-02 23:13:27 UTC (rev 3551)
@@ -1,40 +0,0 @@
-diff -Nru linux-2.4.21-24105-cts-plain/fs/proc/root.c linux-2.4.21-24105-cts-debug/fs/proc/root.c
---- linux-2.4.21-24105-cts-plain/fs/proc/root.c	2004-10-06 15:30:02.000000000 +0200
-+++ linux-2.4.21-24105-cts-debug/fs/proc/root.c	2004-10-13 12:04:56.000000000 +0200
-@@ -17,7 +17,7 @@
- #include <linux/module.h>
- #include <asm/bitops.h>
- 
--struct proc_dir_entry *proc_net, *proc_bus, *proc_root_fs, *proc_root_driver;
-+struct proc_dir_entry *proc_net, *proc_net_stat, *proc_bus, *proc_root_fs, *proc_root_driver;
- 
- #ifdef CONFIG_SYSCTL
- struct proc_dir_entry *proc_sys_root;
-@@ -38,6 +38,7 @@
- 	}
- 	proc_misc_init();
- 	proc_net = proc_mkdir("net", 0);
-+	proc_net_stat = proc_mkdir("net/stat", 0);
- #ifdef CONFIG_SYSVIPC
- 	proc_mkdir("sysvipc", 0);
- #endif
-@@ -143,6 +144,7 @@
- EXPORT_SYMBOL(proc_root);
- EXPORT_SYMBOL(proc_root_fs);
- EXPORT_SYMBOL(proc_net);
-+EXPORT_SYMBOL(proc_net_stat);
- EXPORT_SYMBOL(proc_bus);
- EXPORT_SYMBOL(proc_root_driver);
- EXPORT_SYMBOL(proc_get_inode);
-diff -Nru linux-2.4.21-24105-cts-plain/include/linux/proc_fs.h linux-2.4.21-24105-cts-debug/include/linux/proc_fs.h
---- linux-2.4.21-24105-cts-plain/include/linux/proc_fs.h	2004-10-13 10:39:10.000000000 +0200
-+++ linux-2.4.21-24105-cts-debug/include/linux/proc_fs.h	2004-10-15 11:54:32.000000000 +0200
-@@ -79,6 +79,7 @@
- extern struct proc_dir_entry proc_root;
- extern struct proc_dir_entry *proc_root_fs;
- extern struct proc_dir_entry *proc_net;
-+extern struct proc_dir_entry *proc_net_stat;
- extern struct proc_dir_entry *proc_bus;
- extern struct proc_dir_entry *proc_root_driver;
- extern struct proc_dir_entry *proc_root_kcore;
-

Deleted: branches/netfilter-ha/linux-2.6/patches/raw.patch
===================================================================
--- branches/netfilter-ha/linux-2.6/patches/raw.patch	2005-01-02 22:40:48 UTC (rev 3550)
+++ branches/netfilter-ha/linux-2.6/patches/raw.patch	2005-01-02 23:13:27 UTC (rev 3551)
@@ -1,760 +0,0 @@
-%patch
-Index: linux-2.4.26-ct_sync/Documentation/Configure.help
-===================================================================
---- linux-2.4.26-ct_sync.orig/Documentation/Configure.help	Wed Apr 14 15:05:24 2004
-+++ linux-2.4.26-ct_sync/Documentation/Configure.help	Mon Jun 14 14:52:11 2004
-@@ -2978,6 +2978,34 @@
-   If you want to compile it as a module, say M here and read
-   <file:Documentation/modules.txt>.  If unsure, say `N'.
- 
-+raw table support (required for NOTRACK/TRACE)
-+CONFIG_IP_NF_RAW
-+  This option adds a `raw' table to iptables. This table is the very
-+  first in the netfilter framework and hooks in at the PREROUTING
-+  and OUTPUT chains.
-+
-+  If you want to compile it as a module, say M here and read
-+  <file:Documentation/modules.txt>.  If unsure, say `N'.
-+
-+NOTRACK target support
-+CONFIG_IP_NF_TARGET_NOTRACK
-+  The NOTRACK target allows a select rule to specify
-+  which packets *not* to enter the conntrack/NAT
-+  subsystem with all the consequences (no ICMP error tracking,
-+  no protocol helpers for the selected packets).
-+
-+  If you want to compile it as a module, say M here and read
-+  <file:Documentation/modules.txt>.  If unsure, say `N'.
-+
-+raw table support (required for TRACE)
-+CONFIG_IP6_NF_RAW
-+  This option adds a `raw' table to ip6tables. This table is the very
-+  first in the netfilter framework and hooks in at the PREROUTING
-+  and OUTPUT chains.
-+
-+  If you want to compile it as a module, say M here and read
-+  <file:Documentation/modules.txt>.  If unsure, say `N'.
-+
- REJECT target support
- CONFIG_IP_NF_TARGET_REJECT
-   The REJECT target allows a filtering rule to specify that an ICMP
-Index: linux-2.4.26-ct_sync/include/linux/netfilter_ipv4/ip_conntrack.h
-===================================================================
---- linux-2.4.26-ct_sync.orig/include/linux/netfilter_ipv4/ip_conntrack.h	Wed Apr 14 15:05:40 2004
-+++ linux-2.4.26-ct_sync/include/linux/netfilter_ipv4/ip_conntrack.h	Mon Jun 14 14:52:11 2004
-@@ -249,6 +249,9 @@
- /* Call me when a conntrack is destroyed. */
- extern void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack);
- 
-+/* Fake conntrack entry for untracked connections */
-+extern struct ip_conntrack ip_conntrack_untracked;
-+
- /* Returns new sk_buff, or NULL */
- struct sk_buff *
- ip_ct_gather_frags(struct sk_buff *skb);
-Index: linux-2.4.26-ct_sync/include/linux/netfilter_ipv4/ipt_conntrack.h
-===================================================================
---- linux-2.4.26-ct_sync.orig/include/linux/netfilter_ipv4/ipt_conntrack.h	Fri Nov 29 00:53:15 2002
-+++ linux-2.4.26-ct_sync/include/linux/netfilter_ipv4/ipt_conntrack.h	Mon Jun 14 14:52:11 2004
-@@ -10,6 +10,7 @@
- 
- #define IPT_CONNTRACK_STATE_SNAT (1 << (IP_CT_NUMBER + 1))
- #define IPT_CONNTRACK_STATE_DNAT (1 << (IP_CT_NUMBER + 2))
-+#define IPT_CONNTRACK_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 3))
- 
- /* flags, invflags: */
- #define IPT_CONNTRACK_STATE	0x01
-Index: linux-2.4.26-ct_sync/include/linux/netfilter_ipv4/ipt_state.h
-===================================================================
---- linux-2.4.26-ct_sync.orig/include/linux/netfilter_ipv4/ipt_state.h	Fri Apr 14 18:37:20 2000
-+++ linux-2.4.26-ct_sync/include/linux/netfilter_ipv4/ipt_state.h	Mon Jun 14 14:52:11 2004
-@@ -4,6 +4,8 @@
- #define IPT_STATE_BIT(ctinfo) (1 << ((ctinfo)%IP_CT_IS_REPLY+1))
- #define IPT_STATE_INVALID (1 << 0)
- 
-+#define IPT_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 1))
-+
- struct ipt_state_info
- {
- 	unsigned int statemask;
-Index: linux-2.4.26-ct_sync/include/linux/netfilter_ipv4.h
-===================================================================
---- linux-2.4.26-ct_sync.orig/include/linux/netfilter_ipv4.h	Mon Feb 25 20:38:13 2002
-+++ linux-2.4.26-ct_sync/include/linux/netfilter_ipv4.h	Mon Jun 14 14:52:11 2004
-@@ -51,6 +51,8 @@
- 
- enum nf_ip_hook_priorities {
- 	NF_IP_PRI_FIRST = INT_MIN,
-+	NF_IP_PRI_CONNTRACK_DEFRAG = -400,
-+	NF_IP_PRI_RAW = -300,
- 	NF_IP_PRI_CONNTRACK = -200,
- 	NF_IP_PRI_MANGLE = -150,
- 	NF_IP_PRI_NAT_DST = -100,
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/Config.in
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/Config.in	Mon Aug 25 13:44:44 2003
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/Config.in	Mon Jun 14 14:52:11 2004
-@@ -108,6 +108,15 @@
-   dep_tristate '  LOG target support' CONFIG_IP_NF_TARGET_LOG $CONFIG_IP_NF_IPTABLES
-   dep_tristate '  ULOG target support' CONFIG_IP_NF_TARGET_ULOG $CONFIG_IP_NF_IPTABLES
-   dep_tristate '  TCPMSS target support' CONFIG_IP_NF_TARGET_TCPMSS $CONFIG_IP_NF_IPTABLES
-+  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-+    tristate '  raw table support (required for NOTRACK/TRACE)' CONFIG_IP_NF_RAW $CONFIG_IP_NF_IPTABLES
-+  fi
-+  if [ "$CONFIG_IP_NF_RAW" != "n" ]; then
-+    if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then
-+      dep_tristate '    NOTRACK target support' CONFIG_IP_NF_TARGET_NOTRACK $CONFIG_IP_NF_RAW
-+    fi
-+  # Marker for TRACE target
-+  fi
- fi
- 
- tristate 'ARP tables support' CONFIG_IP_NF_ARPTABLES
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/Makefile
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/Makefile	Mon Aug 25 13:44:44 2003
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/Makefile	Mon Jun 14 14:52:11 2004
-@@ -61,6 +61,7 @@
- obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o
- obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o
- obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o
-+obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o
- 
- # matches
- obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o
-@@ -100,6 +101,7 @@
- obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
- obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
- obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o
-+obj-$(CONFIG_IP_NF_TARGET_NOTRACK) += ipt_NOTRACK.o
- 
- # generic ARP tables
- obj-$(CONFIG_IP_NF_ARPTABLES) += arp_tables.o
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_core.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/ip_conntrack_core.c	Wed Feb 18 14:36:32 2004
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_core.c	Mon Jun 14 14:52:11 2004
-@@ -64,6 +64,7 @@
- static atomic_t ip_conntrack_count = ATOMIC_INIT(0);
- struct list_head *ip_conntrack_hash;
- static kmem_cache_t *ip_conntrack_cachep;
-+struct ip_conntrack ip_conntrack_untracked;
- 
- extern struct ip_conntrack_protocol ip_conntrack_generic_protocol;
- 
-@@ -811,6 +812,15 @@
- 	int set_reply;
- 	int ret;
- 
-+	/* Never happen */
-+	if ((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) {
-+		if (net_ratelimit()) {
-+		printk(KERN_ERR "ip_conntrack_in: Frag of proto %u (hook=%u)\n",
-+		       (*pskb)->nh.iph->protocol, hooknum);
-+		}
-+		return NF_DROP;
-+	}
-+
- 	/* FIXME: Do this right please. --RR */
- 	(*pskb)->nfcache |= NFC_UNKNOWN;
- 
-@@ -829,18 +839,10 @@
- 	}
- #endif
- 
--	/* Previously seen (loopback)?  Ignore.  Do this before
--           fragment check. */
-+	/* Previously seen (loopback or untracked)?  Ignore. */
- 	if ((*pskb)->nfct)
- 		return NF_ACCEPT;
- 
--	/* Gather fragments. */
--	if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
--		*pskb = ip_ct_gather_frags(*pskb);
--		if (!*pskb)
--			return NF_STOLEN;
--	}
--
- 	proto = ip_ct_find_proto((*pskb)->nh.iph->protocol);
- 
- 	/* It may be an icmp error... */
-@@ -1439,6 +1441,18 @@
- 
- 	/* For use by ipt_REJECT */
- 	ip_ct_attach = ip_conntrack_attach;
-+
-+	/* Set up fake conntrack:
-+	    - to never be deleted, not in any hashes */
-+	atomic_set(&ip_conntrack_untracked.ct_general.use, 1);
-+	/*  - and look it like as a confirmed connection */
-+	set_bit(IPS_CONFIRMED_BIT, &ip_conntrack_untracked.status);
-+	/*  - and prepare the ctinfo field for REJECT/NAT. */
-+	ip_conntrack_untracked.infos[IP_CT_NEW].master = 
-+	ip_conntrack_untracked.infos[IP_CT_RELATED].master = 
-+	ip_conntrack_untracked.infos[IP_CT_RELATED + IP_CT_IS_REPLY].master = 
-+		&ip_conntrack_untracked.ct_general;
-+
- 	return ret;
- 
- err_free_hash:
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_standalone.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/ip_conntrack_standalone.c	Wed Feb 18 14:36:32 2004
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_conntrack_standalone.c	Mon Jun 14 14:52:11 2004
-@@ -189,6 +189,26 @@
- 	return ip_conntrack_confirm(*pskb);
- }
- 
-+static unsigned int ip_conntrack_defrag(unsigned int hooknum,
-+				        struct sk_buff **pskb,
-+				        const struct net_device *in,
-+				        const struct net_device *out,
-+				        int (*okfn)(struct sk_buff *))
-+{
-+	/* Previously seen (loopback)?  Ignore.  Do this before
-+           fragment check. */
-+	if ((*pskb)->nfct)
-+		return NF_ACCEPT;
-+
-+	/* Gather fragments. */
-+	if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
-+		*pskb = ip_ct_gather_frags(*pskb);
-+		if (!*pskb)
-+			return NF_STOLEN;
-+	}
-+	return NF_ACCEPT;
-+}
-+
- static unsigned int ip_refrag(unsigned int hooknum,
- 			      struct sk_buff **pskb,
- 			      const struct net_device *in,
-@@ -230,9 +250,15 @@
- 
- /* Connection tracking may drop packets, but never alters them, so
-    make it the first hook. */
-+static struct nf_hook_ops ip_conntrack_defrag_ops
-+= { { NULL, NULL }, ip_conntrack_defrag, PF_INET, NF_IP_PRE_ROUTING,
-+	NF_IP_PRI_CONNTRACK_DEFRAG };
- static struct nf_hook_ops ip_conntrack_in_ops
- = { { NULL, NULL }, ip_conntrack_in, PF_INET, NF_IP_PRE_ROUTING,
- 	NF_IP_PRI_CONNTRACK };
-+static struct nf_hook_ops ip_conntrack_defrag_local_out_ops
-+= { { NULL, NULL }, ip_conntrack_defrag, PF_INET, NF_IP_LOCAL_OUT,
-+	NF_IP_PRI_CONNTRACK_DEFRAG };
- static struct nf_hook_ops ip_conntrack_local_out_ops
- = { { NULL, NULL }, ip_conntrack_local, PF_INET, NF_IP_LOCAL_OUT,
- 	NF_IP_PRI_CONNTRACK };
-@@ -353,10 +379,20 @@
- 	if (!proc) goto cleanup_init;
- 	proc->owner = THIS_MODULE;
- 
-+	ret = nf_register_hook(&ip_conntrack_defrag_ops);
-+	if (ret < 0) {
-+		printk("ip_conntrack: can't register pre-routing defrag hook.\n");
-+		goto cleanup_proc;
-+	}
-+	ret = nf_register_hook(&ip_conntrack_defrag_local_out_ops);
-+	if (ret < 0) {
-+		printk("ip_conntrack: can't register local_out defrag hook.\n");
-+		goto cleanup_defragops;
-+	}
- 	ret = nf_register_hook(&ip_conntrack_in_ops);
- 	if (ret < 0) {
- 		printk("ip_conntrack: can't register pre-routing hook.\n");
--		goto cleanup_proc;
-+		goto cleanup_defraglocalops;
- 	}
- 	ret = nf_register_hook(&ip_conntrack_local_out_ops);
- 	if (ret < 0) {
-@@ -394,6 +430,10 @@
- 	nf_unregister_hook(&ip_conntrack_local_out_ops);
-  cleanup_inops:
- 	nf_unregister_hook(&ip_conntrack_in_ops);
-+ cleanup_defraglocalops:
-+	nf_unregister_hook(&ip_conntrack_defrag_local_out_ops);
-+ cleanup_defragops:
-+	nf_unregister_hook(&ip_conntrack_defrag_ops);
-  cleanup_proc:
- 	proc_net_remove("ip_conntrack");
-  cleanup_init:
-@@ -482,5 +522,6 @@
- EXPORT_SYMBOL(ip_conntrack_expect_list);
- EXPORT_SYMBOL(ip_conntrack_lock);
- EXPORT_SYMBOL(ip_conntrack_hash);
-+EXPORT_SYMBOL(ip_conntrack_untracked);
- EXPORT_SYMBOL_GPL(ip_conntrack_find_get);
- EXPORT_SYMBOL_GPL(ip_conntrack_put);
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_nat_core.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/ip_nat_core.c	Wed Feb 18 14:36:32 2004
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/ip_nat_core.c	Mon Jun 14 14:52:11 2004
-@@ -991,6 +991,10 @@
- 	/* FIXME: Man, this is a hack.  <SIGH> */
- 	IP_NF_ASSERT(ip_conntrack_destroyed == NULL);
- 	ip_conntrack_destroyed = &ip_nat_cleanup_conntrack;
-+	
-+	/* Initialize fake conntrack so that NAT will skip it */
-+	ip_conntrack_untracked.nat.info.initialized |= 
-+		(1 << IP_NAT_MANIP_SRC) | (1 << IP_NAT_MANIP_DST);
- 
- 	return 0;
- }
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/ipt_NOTRACK.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/ipt_NOTRACK.c	Fri Dec 19 09:26:33 2003
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/ipt_NOTRACK.c	Mon Jun 14 14:52:11 2004
-@@ -0,0 +1,75 @@
-+/* This is a module which is used for setting up fake conntracks
-+ * on packets so that they are not seen by the conntrack/NAT code.
-+ */
-+#include <linux/module.h>
-+#include <linux/skbuff.h>
-+
-+#include <linux/netfilter_ipv4/ip_tables.h>
-+#include <linux/netfilter_ipv4/ip_conntrack.h>
-+
-+static unsigned int
-+target(struct sk_buff **pskb,
-+       unsigned int hooknum,
-+       const struct net_device *in,
-+       const struct net_device *out,
-+       const void *targinfo,
-+       void *userinfo)
-+{
-+	/* Previously seen (loopback)? Ignore. */
-+	if ((*pskb)->nfct != NULL)
-+		return IPT_CONTINUE;
-+
-+	/* Attach fake conntrack entry. 
-+	   If there is a real ct entry correspondig to this packet, 
-+	   it'll hang aroun till timing out. We don't deal with it
-+	   for performance reasons. JK */
-+	(*pskb)->nfct = &ip_conntrack_untracked.infos[IP_CT_NEW];
-+	nf_conntrack_get((*pskb)->nfct);
-+
-+	return IPT_CONTINUE;
-+}
-+
-+static int
-+checkentry(const char *tablename,
-+	   const struct ipt_entry *e,
-+           void *targinfo,
-+           unsigned int targinfosize,
-+           unsigned int hook_mask)
-+{
-+	if (targinfosize != 0) {
-+		printk(KERN_WARNING "NOTRACK: targinfosize %u != 0\n",
-+		       targinfosize);
-+		return 0;
-+	}
-+
-+	if (strcmp(tablename, "raw") != 0) {
-+		printk(KERN_WARNING "NOTRACK: can only be called from \"raw\" table, not \"%s\"\n", tablename);
-+		return 0;
-+	}
-+
-+	return 1;
-+}
-+
-+static struct ipt_target ipt_notrack_reg = { 
-+	.name = "NOTRACK", 
-+	.target = target, 
-+	.checkentry = checkentry, 
-+	.me = THIS_MODULE 
-+};
-+
-+static int __init init(void)
-+{
-+	if (ipt_register_target(&ipt_notrack_reg))
-+		return -EINVAL;
-+
-+	return 0;
-+}
-+
-+static void __exit fini(void)
-+{
-+	ipt_unregister_target(&ipt_notrack_reg);
-+}
-+
-+module_init(init);
-+module_exit(fini);
-+MODULE_LICENSE("GPL");
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/ipt_conntrack.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/ipt_conntrack.c	Wed Feb 18 14:36:32 2004
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/ipt_conntrack.c	Mon Jun 14 14:52:11 2004
-@@ -27,11 +27,13 @@
- 
- #define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
- 
--	if (ct)
--		statebit = IPT_CONNTRACK_STATE_BIT(ctinfo);
--	else
--		statebit = IPT_CONNTRACK_STATE_INVALID;
--
-+	if (skb->nfct == &ip_conntrack_untracked.infos[IP_CT_NEW])
-+		statebit = IPT_CONNTRACK_STATE_UNTRACKED;
-+	else if (ct)
-+ 		statebit = IPT_CONNTRACK_STATE_BIT(ctinfo);
-+ 	else
-+ 		statebit = IPT_CONNTRACK_STATE_INVALID;
-+ 
- 	if(sinfo->flags & IPT_CONNTRACK_STATE) {
- 		if (ct) {
- 			if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip !=
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/ipt_state.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/ipt_state.c	Wed Feb 18 14:36:32 2004
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/ipt_state.c	Mon Jun 14 14:52:11 2004
-@@ -21,7 +21,9 @@
- 	enum ip_conntrack_info ctinfo;
- 	unsigned int statebit;
- 
--	if (!ip_conntrack_get((struct sk_buff *)skb, &ctinfo))
-+	if (skb->nfct == &ip_conntrack_untracked.infos[IP_CT_NEW])
-+		statebit = IPT_STATE_UNTRACKED;
-+	else if (!ip_conntrack_get((struct sk_buff *)skb, &ctinfo))
- 		statebit = IPT_STATE_INVALID;
- 	else
- 		statebit = IPT_STATE_BIT(ctinfo);
-Index: linux-2.4.26-ct_sync/net/ipv4/netfilter/iptable_raw.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv4/netfilter/iptable_raw.c	Fri Dec 19 09:26:33 2003
-+++ linux-2.4.26-ct_sync/net/ipv4/netfilter/iptable_raw.c	Mon Jun 14 14:52:11 2004
-@@ -0,0 +1,149 @@
-+/* 
-+ * 'raw' table, which is the very first hooked in at PRE_ROUTING and LOCAL_OUT .
-+ *
-+ * Copyright (C) 2003 Jozsef Kadlecsik <kadlec at blackhole.kfki.hu>
-+ */
-+#include <linux/module.h>
-+#include <linux/netfilter_ipv4/ip_tables.h>
-+
-+#define RAW_VALID_HOOKS ((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT))
-+
-+/* Standard entry. */
-+struct ipt_standard
-+{
-+	struct ipt_entry entry;
-+	struct ipt_standard_target target;
-+};
-+
-+struct ipt_error_target
-+{
-+	struct ipt_entry_target target;
-+	char errorname[IPT_FUNCTION_MAXNAMELEN];
-+};
-+
-+struct ipt_error
-+{
-+	struct ipt_entry entry;
-+	struct ipt_error_target target;
-+};
-+
-+static struct
-+{
-+	struct ipt_replace repl;
-+	struct ipt_standard entries[2];
-+	struct ipt_error term;
-+} initial_table __initdata
-+= { { "raw", RAW_VALID_HOOKS, 3,
-+      sizeof(struct ipt_standard) * 2 + sizeof(struct ipt_error),
-+      { [NF_IP_PRE_ROUTING] 0,
-+	[NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) },
-+      { [NF_IP_PRE_ROUTING] 0,
-+	[NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) },
-+      0, NULL, { } },
-+    {
-+	    /* PRE_ROUTING */
-+	    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-+		0,
-+		sizeof(struct ipt_entry),
-+		sizeof(struct ipt_standard),
-+		0, { 0, 0 }, { } },
-+	      { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
-+		-NF_ACCEPT - 1 } },
-+	    /* LOCAL_OUT */
-+	    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-+		0,
-+		sizeof(struct ipt_entry),
-+		sizeof(struct ipt_standard),
-+		0, { 0, 0 }, { } },
-+	      { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
-+		-NF_ACCEPT - 1 } }
-+    },
-+    /* ERROR */
-+    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-+	0,
-+	sizeof(struct ipt_entry),
-+	sizeof(struct ipt_error),
-+	0, { 0, 0 }, { } },
-+      { { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } },
-+	  { } },
-+	"ERROR"
-+      }
-+    }
-+};
-+
-+static struct ipt_table packet_raw = { 
-+	.name = "raw", 
-+	.table = &initial_table.repl,
-+	.valid_hooks =  RAW_VALID_HOOKS, 
-+	.lock = RW_LOCK_UNLOCKED, 
-+	.me = THIS_MODULE
-+};
-+
-+/* The work comes in here from netfilter.c. */
-+static unsigned int
-+ipt_hook(unsigned int hook,
-+	 struct sk_buff **pskb,
-+	 const struct net_device *in,
-+	 const struct net_device *out,
-+	 int (*okfn)(struct sk_buff *))
-+{
-+	return ipt_do_table(pskb, hook, in, out, &packet_raw, NULL);
-+}
-+
-+/* 'raw' is the very first table. */
-+static struct nf_hook_ops ipt_ops[] = {
-+	{
-+	  .hook = ipt_hook, 
-+	  .pf = PF_INET, 
-+	  .hooknum = NF_IP_PRE_ROUTING, 
-+	  .priority = NF_IP_PRI_RAW
-+	},
-+	{
-+	  .hook = ipt_hook, 
-+	  .pf = PF_INET, 
-+	  .hooknum = NF_IP_LOCAL_OUT, 
-+	  .priority = NF_IP_PRI_RAW
-+	},
-+};
-+
-+static int __init init(void)
-+{
-+	int ret;
-+
-+	/* Register table */
-+	ret = ipt_register_table(&packet_raw);
-+	if (ret < 0)
-+		return ret;
-+
-+	/* Register hooks */
-+	ret = nf_register_hook(&ipt_ops[0]);
-+	if (ret < 0)
-+		goto cleanup_table;
-+
-+	ret = nf_register_hook(&ipt_ops[1]);
-+	if (ret < 0)
-+		goto cleanup_hook0;
-+
-+	return ret;
-+
-+ cleanup_hook0:
-+	nf_unregister_hook(&ipt_ops[0]);
-+ cleanup_table:
-+	ipt_unregister_table(&packet_raw);
-+
-+	return ret;
-+}
-+
-+static void __exit fini(void)
-+{
-+	unsigned int i;
-+
-+	for (i = 0; i < sizeof(ipt_ops)/sizeof(struct nf_hook_ops); i++)
-+		nf_unregister_hook(&ipt_ops[i]);
-+
-+	ipt_unregister_table(&packet_raw);
-+}
-+
-+module_init(init);
-+module_exit(fini);
-+MODULE_LICENSE("GPL");
-Index: linux-2.4.26-ct_sync/net/ipv6/netfilter/Config.in
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv6/netfilter/Config.in	Fri Jun 13 16:51:39 2003
-+++ linux-2.4.26-ct_sync/net/ipv6/netfilter/Config.in	Mon Jun 14 14:52:11 2004
-@@ -73,6 +73,10 @@
-     dep_tristate '    MARK target support' CONFIG_IP6_NF_TARGET_MARK $CONFIG_IP6_NF_MANGLE
-   fi
-   #dep_tristate '  LOG target support' CONFIG_IP6_NF_TARGET_LOG $CONFIG_IP6_NF_IPTABLES
-+  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-+    tristate '  raw table support (required for TRACE)' CONFIG_IP6_NF_RAW $CONFIG_IP6_NF_IPTABLES
-+  fi
-+  # Marker for TRACE target
- fi
- 
- endmenu
-Index: linux-2.4.26-ct_sync/net/ipv6/netfilter/Makefile
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv6/netfilter/Makefile	Fri Jun 13 16:51:39 2003
-+++ linux-2.4.26-ct_sync/net/ipv6/netfilter/Makefile	Mon Jun 14 14:52:11 2004
-@@ -30,6 +30,7 @@
- obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o
- obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o
- obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
-+obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
- obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o
- 
- include $(TOPDIR)/Rules.make
-Index: linux-2.4.26-ct_sync/net/ipv6/netfilter/ip6table_raw.c
-===================================================================
---- linux-2.4.26-ct_sync.orig/net/ipv6/netfilter/ip6table_raw.c	Fri Dec 19 09:26:33 2003
-+++ linux-2.4.26-ct_sync/net/ipv6/netfilter/ip6table_raw.c	Mon Jun 14 14:52:11 2004
-@@ -0,0 +1,154 @@
-+/*
-+ * IPv6 raw table, a port of the IPv4 raw table to IPv6
-+ *
-+ * Copyright (C) 2003 Jozsef Kadlecsik <kadlec at blackhole.kfki.hu>
-+ */
-+#include <linux/module.h>
-+#include <linux/netfilter_ipv6/ip6_tables.h>
-+
-+#define RAW_VALID_HOOKS ((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_OUT))
-+
-+#if 0
-+#define DEBUGP(x, args...)	printk(KERN_DEBUG x, ## args)
-+#else
-+#define DEBUGP(x, args...)
-+#endif
-+
-+/* Standard entry. */
-+struct ip6t_standard
-+{
-+	struct ip6t_entry entry;
-+	struct ip6t_standard_target target;
-+};
-+
-+struct ip6t_error_target
-+{
-+	struct ip6t_entry_target target;
-+	char errorname[IP6T_FUNCTION_MAXNAMELEN];
-+};
-+
-+struct ip6t_error
-+{
-+	struct ip6t_entry entry;
-+	struct ip6t_error_target target;
-+};
-+
-+static struct
-+{
-+	struct ip6t_replace repl;
-+	struct ip6t_standard entries[2];
-+	struct ip6t_error term;
-+} initial_table __initdata 
-+= { { "raw", RAW_VALID_HOOKS, 3,
-+      sizeof(struct ip6t_standard) * 2 + sizeof(struct ip6t_error),
-+      { [NF_IP6_PRE_ROUTING] 	0,
-+	[NF_IP6_LOCAL_OUT]	sizeof(struct ip6t_standard) },
-+      { [NF_IP6_PRE_ROUTING] 	0,
-+	[NF_IP6_LOCAL_OUT]	sizeof(struct ip6t_standard) },
-+      0, NULL, { } },
-+    {
-+	    /* PRE_ROUTING */
-+            { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-+		0,
-+		sizeof(struct ip6t_entry),
-+		sizeof(struct ip6t_standard),
-+		0, { 0, 0 }, { } },
-+	      { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
-+		-NF_ACCEPT - 1 } },
-+	    /* LOCAL_OUT */
-+            { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-+		0,
-+		sizeof(struct ip6t_entry),
-+		sizeof(struct ip6t_standard),
-+		0, { 0, 0 }, { } },
-+	      { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
-+		-NF_ACCEPT - 1 } },
-+    },
-+    /* ERROR */
-+    { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-+	0,
-+	sizeof(struct ip6t_entry),
-+	sizeof(struct ip6t_error),
-+	0, { 0, 0 }, { } },
-+      { { { { IP6T_ALIGN(sizeof(struct ip6t_error_target)), IP6T_ERROR_TARGET } },
-+	  { } },
-+	"ERROR"
-+      }
-+    }
-+};
-+
-+static struct ip6t_table packet_raw = { 
-+	.name = "raw", 
-+	.table = &initial_table.repl,
-+	.valid_hooks = RAW_VALID_HOOKS, 
-+	.lock = RW_LOCK_UNLOCKED, 
-+	.me = THIS_MODULE
-+};
-+
-+/* The work comes in here from netfilter.c. */
-+static unsigned int
-+ip6t_hook(unsigned int hook,
-+	 struct sk_buff **pskb,
-+	 const struct net_device *in,
-+	 const struct net_device *out,
-+	 int (*okfn)(struct sk_buff *))
-+{
-+	return ip6t_do_table(pskb, hook, in, out, &packet_raw, NULL);
-+}
-+
-+static struct nf_hook_ops ip6t_ops[] = { 
-+	{
-+	  .hook = ip6t_hook, 
-+	  .pf = PF_INET6,
-+	  .hooknum = NF_IP6_PRE_ROUTING,
-+	  .priority = NF_IP6_PRI_FIRST
-+	},
-+	{
-+	  .hook = ip6t_hook, 
-+	  .pf = PF_INET6, 
-+	  .hooknum = NF_IP6_LOCAL_OUT,
-+	  .priority = NF_IP6_PRI_FIRST
-+	},
-+};
-+
-+static int __init init(void)
-+{
-+	int ret;
-+
-+	/* Register table */
-+	ret = ip6t_register_table(&packet_raw);
-+	if (ret < 0)
-+		return ret;
-+
-+	/* Register hooks */
-+	ret = nf_register_hook(&ip6t_ops[0]);
-+	if (ret < 0)
-+		goto cleanup_table;
-+
-+	ret = nf_register_hook(&ip6t_ops[1]);
-+	if (ret < 0)
-+		goto cleanup_hook0;
-+
-+	return ret;
-+
-+ cleanup_hook0:
-+	nf_unregister_hook(&ip6t_ops[0]);
-+ cleanup_table:
-+	ip6t_unregister_table(&packet_raw);
-+
-+	return ret;
-+}
-+
-+static void __exit fini(void)
-+{
-+	unsigned int i;
-+
-+	for (i = 0; i < sizeof(ip6t_ops)/sizeof(struct nf_hook_ops); i++)
-+		nf_unregister_hook(&ip6t_ops[i]);
-+
-+	ip6t_unregister_table(&packet_raw);
-+}
-+
-+module_init(init);
-+module_exit(fini);
-+MODULE_LICENSE("GPL");
-

Deleted: branches/netfilter-ha/linux-2.6/patches/seq_file-seq_start_token.patch
===================================================================
--- branches/netfilter-ha/linux-2.6/patches/seq_file-seq_start_token.patch	2005-01-02 22:40:48 UTC (rev 3550)
+++ branches/netfilter-ha/linux-2.6/patches/seq_file-seq_start_token.patch	2005-01-02 23:13:27 UTC (rev 3551)
@@ -1,13 +0,0 @@
-diff -Nru linux-2.4.21-24105-cts-plain/include/linux/seq_file.h linux-2.4.21-24105-cts-debug/include/linux/seq_file.h
---- linux-2.4.21-24105-cts-plain/include/linux/seq_file.h	2004-10-06 15:30:06.000000000 +0200
-+++ linux-2.4.21-24105-cts-debug/include/linux/seq_file.h	2004-10-13 10:47:25.000000000 +0200
-@@ -2,6 +2,8 @@
- #define _LINUX_SEQ_FILE_H
- #ifdef __KERNEL__
- 
-+#define SEQ_START_TOKEN ((void *)1)
-+
- struct seq_operations;
- 
- struct seq_file {
-

Modified: branches/netfilter-ha/linux-2.6/patches/series
===================================================================
--- branches/netfilter-ha/linux-2.6/patches/series	2005-01-02 22:40:48 UTC (rev 3550)
+++ branches/netfilter-ha/linux-2.6/patches/series	2005-01-02 23:13:27 UTC (rev 3551)
@@ -1,16 +1,12 @@
-raw.patch 
+ct_notifier_pkt.patch 
+connmark.patch 
 pf_packet.patch 
 pf_packet_remove_warning.patch 
-connmark.patch 
-nfnetlink-ctnetlink.patch 
-kgdb-1.9.patch 
 export_ip_conntrack_helpers.patch 
 export_ip_nat_helpers.patch 
 export_ip_conntrack_find.patch 
-export_hash_conntrack.patch 
-export_ct_id.patch 
-export_ip_nat_lock.patch 
-export_ip_nat_hash.patch 
+export_ip_nat_lock_and_hash.patch 
+export_ip_conntrack_clean_from_lists.patch 
+conntrack_hash_manip.patch 
+conntrack_alloc.patch 
 ct_sync_config_and_makefile.patch
-proc_net_stat.patch
-seq_file-seq_start_token.patch




More information about the netfilter-cvslog mailing list