diff -Nru linux-2.4.20/Documentation/Configure.help linux-2.4.20-pom2patch/Documentation/Configure.help
--- linux-2.4.20/Documentation/Configure.help	2003-05-02 12:57:17.000000000 -0500
+++ linux-2.4.20-pom2patch/Documentation/Configure.help	2003-05-02 12:57:19.000000000 -0500
@@ -2564,6 +2564,16 @@
   If you want to compile it as a module, say M here and read
   Documentation/modules.txt.  If unsure, say `N'.
 
+H.323 (netmeeting) support
+CONFIG_IP_NF_H323
+  H.323 is a standard signalling protocol used by teleconferencing
+  softwares like netmeeting. With the ip_conntrack_h323 and
+  the ip_nat_h323 modules you can support the protocol on a connection
+  tracking/NATing firewall.
+
+  If you want to compile it as a module, say 'M' here and read
+  Documentation/modules.txt.  If unsure, say 'N'.
+
 FTP protocol support
 CONFIG_IP_NF_FTP
   Tracking FTP connections is problematic: special helpers are
diff -Nru linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.20-pom2patch/include/linux/netfilter_ipv4/ip_conntrack.h
--- linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack.h	2003-05-02 12:56:58.000000000 -0500
+++ linux-2.4.20-pom2patch/include/linux/netfilter_ipv4/ip_conntrack.h	2003-05-02 12:57:19.000000000 -0500
@@ -58,12 +58,15 @@
 };
 
 /* Add protocol helper include file here */
+#include <linux/netfilter_ipv4/ip_conntrack_h323.h>
+
 #include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
 #include <linux/netfilter_ipv4/ip_conntrack_irc.h>
 
 /* per expectation: application helper private data */
 union ip_conntrack_expect_help {
 	/* insert conntrack helper private data (expect) here */
+	struct ip_ct_h225_expect exp_h225_info;
 	struct ip_ct_ftp_expect exp_ftp_info;
 	struct ip_ct_irc_expect exp_irc_info;
 
@@ -77,6 +80,7 @@
 /* per conntrack: application helper private data */
 union ip_conntrack_help {
 	/* insert conntrack helper private data (master) here */
+	struct ip_ct_h225_master ct_h225_info;
 	struct ip_ct_ftp_master ct_ftp_info;
 	struct ip_ct_irc_master ct_irc_info;
 };
diff -Nru linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_h323.h linux-2.4.20-pom2patch/include/linux/netfilter_ipv4/ip_conntrack_h323.h
--- linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack_h323.h	1969-12-31 18:00:00.000000000 -0600
+++ linux-2.4.20-pom2patch/include/linux/netfilter_ipv4/ip_conntrack_h323.h	2003-05-02 12:57:19.000000000 -0500
@@ -0,0 +1,30 @@
+#ifndef _IP_CONNTRACK_H323_H
+#define _IP_CONNTRACK_H323_H
+/* H.323 connection tracking. */
+
+#ifdef __KERNEL__
+/* Protects H.323 related data */
+DECLARE_LOCK_EXTERN(ip_h323_lock);
+#endif
+
+/* Default H.225 port */
+#define H225_PORT	1720
+
+/* This structure is per expected connection */
+struct ip_ct_h225_expect {
+	u_int16_t port;			/* Port of the H.225 helper/RTCP/RTP channel */
+	enum ip_conntrack_dir dir;	/* Direction of the original connection */
+	unsigned int offset;		/* offset of the address in the payload */
+};
+
+/* This structure exists only once per master */
+struct ip_ct_h225_master {
+	int is_h225;				/* H.225 or H.245 connection */
+#ifdef CONFIG_IP_NF_NAT_NEEDED
+	enum ip_conntrack_dir dir;		/* Direction of the original connection */
+	u_int32_t seq[IP_CT_DIR_MAX];		/* Exceptional packet mangling for signal addressess... */
+	unsigned int offset[IP_CT_DIR_MAX];	/* ...and the offset of the addresses in the payload */
+#endif
+};
+
+#endif /* _IP_CONNTRACK_H323_H */
diff -Nru linux-2.4.20/net/ipv4/netfilter/Config.in linux-2.4.20-pom2patch/net/ipv4/netfilter/Config.in
--- linux-2.4.20/net/ipv4/netfilter/Config.in	2003-05-02 12:57:17.000000000 -0500
+++ linux-2.4.20-pom2patch/net/ipv4/netfilter/Config.in	2003-05-02 12:57:19.000000000 -0500
@@ -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
+  dep_tristate '  H.323 (netmeeting) support' CONFIG_IP_NF_H323 $CONFIG_IP_NF_CONNTRACK
   dep_tristate '  Eggdrop bot support' CONFIG_IP_NF_EGG $CONFIG_IP_NF_CONNTRACK
   bool '  Connection mark tracking support' CONFIG_IP_NF_CONNTRACK_MARK
   dep_tristate '  IRC protocol support' CONFIG_IP_NF_IRC $CONFIG_IP_NF_CONNTRACK
@@ -82,6 +83,13 @@
       define_bool CONFIG_IP_NF_NAT_NEEDED y
       dep_tristate '    MASQUERADE target support' CONFIG_IP_NF_TARGET_MASQUERADE $CONFIG_IP_NF_NAT
       dep_tristate '    REDIRECT target support' CONFIG_IP_NF_TARGET_REDIRECT $CONFIG_IP_NF_NAT
+      if [ "$CONFIG_IP_NF_H323" = "m" ]; then
+       define_tristate CONFIG_IP_NF_NAT_H323 m
+      else
+        if [ "$CONFIG_IP_NF_H323" = "y" ]; then
+          define_tristate CONFIG_IP_NF_NAT_H323 $CONFIG_IP_NF_NAT
+        fi
+      fi
       dep_tristate '    SAME target support' CONFIG_IP_NF_TARGET_SAME $CONFIG_IP_NF_NAT
       dep_tristate '    NETMAP target support' CONFIG_IP_NF_TARGET_NETMAP $CONFIG_IP_NF_NAT
       bool '    NAT of local connections (READ HELP)' CONFIG_IP_NF_NAT_LOCAL
diff -Nru linux-2.4.20/net/ipv4/netfilter/Makefile linux-2.4.20-pom2patch/net/ipv4/netfilter/Makefile
--- linux-2.4.20/net/ipv4/netfilter/Makefile	2003-05-02 12:57:17.000000000 -0500
+++ linux-2.4.20-pom2patch/net/ipv4/netfilter/Makefile	2003-05-02 12:57:19.000000000 -0500
@@ -30,6 +30,14 @@
 
 # connection tracking
 obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o
+ 
+# H.323 support
+obj-$(CONFIG_IP_NF_H323) += ip_conntrack_h323.o
+ifdef CONFIG_IP_NF_H323
+	export-objs += ip_conntrack_h323.o
+endif
+obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o
+
 
 # connection tracking helpers
 obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o
diff -Nru linux-2.4.20/net/ipv4/netfilter/ip_conntrack_h323.c linux-2.4.20-pom2patch/net/ipv4/netfilter/ip_conntrack_h323.c
--- linux-2.4.20/net/ipv4/netfilter/ip_conntrack_h323.c	1969-12-31 18:00:00.000000000 -0600
+++ linux-2.4.20-pom2patch/net/ipv4/netfilter/ip_conntrack_h323.c	2003-05-02 12:57:19.000000000 -0500
@@ -0,0 +1,308 @@
+/* 
+ * H.323 'brute force' extension for H.323 connection tracking. 
+ * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ *
+ * Based on ip_masq_h323.c for 2.2 kernels from CoRiTel, Sofia project.
+ * (http://www.coritel.it/projects/sofia/nat/)
+ * Uses Sampsa Ranta's excellent idea on using expectfn to 'bind'
+ * the unregistered helpers to the conntrack entries.
+ */
+
+
+#include <linux/module.h>
+#include <linux/netfilter.h>
+#include <linux/ip.h>
+#include <net/checksum.h>
+#include <net/tcp.h>
+
+#include <linux/netfilter_ipv4/lockhelp.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_tuple.h>
+#include <linux/netfilter_ipv4/ip_conntrack_h323.h>
+
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_DESCRIPTION("H.323 'brute force' connection tracking module");
+MODULE_LICENSE("GPL");
+
+DECLARE_LOCK(ip_h323_lock);
+struct module *ip_conntrack_h323 = THIS_MODULE;
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+/* FIXME: This should be in userspace.  Later. */
+static int h245_help(const struct iphdr *iph, size_t len,
+		     struct ip_conntrack *ct,
+		     enum ip_conntrack_info ctinfo)
+{
+	struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
+	unsigned char *data = (unsigned char *) tcph + tcph->doff * 4;
+	unsigned char *data_limit;
+	u_int32_t tcplen = len - iph->ihl * 4;
+	u_int32_t datalen = tcplen - tcph->doff * 4;
+	int dir = CTINFO2DIR(ctinfo);
+	struct ip_ct_h225_master *info = &ct->help.ct_h225_info;
+	struct ip_conntrack_expect expect, *exp = &expect;
+	struct ip_ct_h225_expect *exp_info = &exp->help.exp_h225_info;
+	u_int16_t data_port;
+	u_int32_t data_ip;
+	unsigned int i;
+
+	DEBUGP("ct_h245_help: help entered %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
+		NIPQUAD(iph->saddr), ntohs(tcph->source),
+		NIPQUAD(iph->daddr), ntohs(tcph->dest));
+
+	/* Can't track connections formed before we registered */
+	if (!info)
+		return NF_ACCEPT;
+		
+	/* Until there's been traffic both ways, don't look in packets. */
+	if (ctinfo != IP_CT_ESTABLISHED
+	    && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
+		DEBUGP("ct_h245_help: Conntrackinfo = %u\n", ctinfo);
+		return NF_ACCEPT;
+	}
+
+	/* Not whole TCP header or too short packet? */
+	if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4 + 5) {
+		DEBUGP("ct_h245_help: tcplen = %u\n", (unsigned)tcplen);
+		return NF_ACCEPT;
+	}
+
+	/* Checksum invalid?  Ignore. */
+	/* FIXME: Source route IP option packets --RR */
+	if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
+			      csum_partial((char *)tcph, tcplen, 0))) {
+		DEBUGP("ct_h245_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
+		       tcph, tcplen, NIPQUAD(iph->saddr),
+		       NIPQUAD(iph->daddr));
+		return NF_ACCEPT;
+	}
+
+	data_limit = (unsigned char *) data + datalen;
+	/* bytes: 0123   45
+	          ipadrr port */
+	for (i = 0; data < (data_limit - 5); data++, i++) {
+		data_ip = *((u_int32_t *)data);
+		if (data_ip == iph->saddr) {
+			data_port = *((u_int16_t *)(data + 4));
+			memset(&expect, 0, sizeof(expect));
+			/* update the H.225 info */
+			DEBUGP("ct_h245_help: new RTCP/RTP requested %u.%u.%u.%u:->%u.%u.%u.%u:%u\n",
+				NIPQUAD(ct->tuplehash[!dir].tuple.src.ip),
+				NIPQUAD(iph->saddr), ntohs(data_port));
+			LOCK_BH(&ip_h323_lock);
+			info->is_h225 = H225_PORT + 1;
+			exp_info->port = data_port;
+			exp_info->dir = dir;
+			exp_info->offset = i;
+
+			exp->seq = ntohl(tcph->seq) + i;
+		    
+			exp->tuple = ((struct ip_conntrack_tuple)
+				{ { ct->tuplehash[!dir].tuple.src.ip,
+				    { 0 } },
+				  { data_ip,
+				    { data_port },
+				    IPPROTO_UDP }});
+			exp->mask = ((struct ip_conntrack_tuple)
+				{ { 0xFFFFFFFF, { 0 } },
+				  { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
+	
+			exp->expectfn = NULL;
+			
+			/* Ignore failure; should only happen with NAT */
+			ip_conntrack_expect_related(ct, exp);
+
+			UNLOCK_BH(&ip_h323_lock);
+		}
+	}
+
+	return NF_ACCEPT;
+
+}
+
+/* H.245 helper is not registered! */
+static struct ip_conntrack_helper h245 = 
+	{ { NULL, NULL },
+          "H.245",				/* name */
+          IP_CT_HELPER_F_REUSE_EXPECT,		/* flags */
+          NULL,					/* module */
+          8,					/* max_ expected */
+          240,					/* timeout */
+          { { 0, { 0 } },			/* tuple */
+            { 0, { 0 }, IPPROTO_TCP } },
+          { { 0, { 0xFFFF } },			/* mask */
+            { 0, { 0 }, 0xFFFF } },
+          h245_help				/* helper */
+	};
+
+static int h225_expect(struct ip_conntrack *ct)
+{
+	WRITE_LOCK(&ip_conntrack_lock);
+	ct->helper = &h245;
+	DEBUGP("h225_expect: helper for %p added\n", ct);
+	WRITE_UNLOCK(&ip_conntrack_lock);
+	
+	return NF_ACCEPT;	/* unused */
+}
+
+/* FIXME: This should be in userspace.  Later. */
+static int h225_help(const struct iphdr *iph, size_t len,
+		     struct ip_conntrack *ct,
+		     enum ip_conntrack_info ctinfo)
+{
+	struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
+	unsigned char *data = (unsigned char *) tcph + tcph->doff * 4;
+	unsigned char *data_limit;
+	u_int32_t tcplen = len - iph->ihl * 4;
+	u_int32_t datalen = tcplen - tcph->doff * 4;
+	int dir = CTINFO2DIR(ctinfo);
+	struct ip_ct_h225_master *info = &ct->help.ct_h225_info;
+	struct ip_conntrack_expect expect, *exp = &expect;
+	struct ip_ct_h225_expect *exp_info = &exp->help.exp_h225_info;
+	u_int16_t data_port;
+	u_int32_t data_ip;
+	unsigned int i;
+	
+	DEBUGP("ct_h225_help: help entered %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
+		NIPQUAD(iph->saddr), ntohs(tcph->source),
+		NIPQUAD(iph->daddr), ntohs(tcph->dest));
+
+	/* Can't track connections formed before we registered */
+	if (!info)
+		return NF_ACCEPT;
+
+	/* Until there's been traffic both ways, don't look in packets. */
+	if (ctinfo != IP_CT_ESTABLISHED
+	    && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
+		DEBUGP("ct_h225_help: Conntrackinfo = %u\n", ctinfo);
+		return NF_ACCEPT;
+	}
+
+	/* Not whole TCP header or too short packet? */
+	if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4 + 5) {
+		DEBUGP("ct_h225_help: tcplen = %u\n", (unsigned)tcplen);
+		return NF_ACCEPT;
+	}
+
+	/* Checksum invalid?  Ignore. */
+	/* FIXME: Source route IP option packets --RR */
+	if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
+			      csum_partial((char *)tcph, tcplen, 0))) {
+		DEBUGP("ct_h225_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
+		       tcph, tcplen, NIPQUAD(iph->saddr),
+		       NIPQUAD(iph->daddr));
+		return NF_ACCEPT;
+	}
+	
+	data_limit = (unsigned char *) data + datalen;
+	/* bytes: 0123   45
+	          ipadrr port */
+	for (i = 0; data < (data_limit - 5); data++, i++) {
+		data_ip = *((u_int32_t *)data);
+		if (data_ip == iph->saddr) {
+			data_port = *((u_int16_t *)(data + 4));
+			if (data_port == tcph->source) {
+				/* Signal address */
+				DEBUGP("ct_h225_help: sourceCallSignalAddress from %u.%u.%u.%u\n",
+					NIPQUAD(iph->saddr));
+				/* Update the H.225 info so that NAT can mangle the address/port
+				   even when we have no expected connection! */
+#ifdef CONFIG_IP_NF_NAT_NEEDED
+				LOCK_BH(&ip_h323_lock);
+				info->dir = dir;
+				info->seq[IP_CT_DIR_ORIGINAL] = ntohl(tcph->seq) + i;
+				info->offset[IP_CT_DIR_ORIGINAL] = i;
+				UNLOCK_BH(&ip_h323_lock);
+#endif
+			} else {
+				memset(&expect, 0, sizeof(expect));
+
+				/* update the H.225 info */
+				LOCK_BH(&ip_h323_lock);
+				info->is_h225 = H225_PORT;
+				exp_info->port = data_port;
+				exp_info->dir = dir;
+				exp_info->offset = i;
+
+				exp->seq = ntohl(tcph->seq) + i;
+
+				exp->tuple = ((struct ip_conntrack_tuple)
+					{ { ct->tuplehash[!dir].tuple.src.ip,
+					    { 0 } },
+					  { data_ip,
+					    { data_port },
+					    IPPROTO_TCP }});
+				exp->mask = ((struct ip_conntrack_tuple)
+					{ { 0xFFFFFFFF, { 0 } },
+					  { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
+	
+				exp->expectfn = h225_expect;
+				
+				/* Ignore failure */
+				ip_conntrack_expect_related(ct, exp);
+
+				DEBUGP("ct_h225_help: new H.245 requested %u.%u.%u.%u->%u.%u.%u.%u:%u\n",
+					NIPQUAD(ct->tuplehash[!dir].tuple.src.ip),
+					NIPQUAD(iph->saddr), ntohs(data_port));
+
+				UNLOCK_BH(&ip_h323_lock);
+                	}  
+#ifdef CONFIG_IP_NF_NAT_NEEDED
+		} else if (data_ip == iph->daddr) {
+			data_port = *((u_int16_t *)(data + 4));
+			if (data_port == tcph->dest) {
+				/* Signal address */
+				DEBUGP("ct_h225_help: destCallSignalAddress %u.%u.%u.%u\n",
+					NIPQUAD(iph->daddr));
+				/* Update the H.225 info so that NAT can mangle the address/port
+				   even when we have no expected connection! */
+				LOCK_BH(&ip_h323_lock);
+				info->dir = dir;
+				info->seq[IP_CT_DIR_REPLY] = ntohl(tcph->seq) + i;
+				info->offset[IP_CT_DIR_REPLY] = i;
+				UNLOCK_BH(&ip_h323_lock);
+			}
+#endif
+		}
+	}
+
+	return NF_ACCEPT;
+
+}
+
+static struct ip_conntrack_helper h225 = 
+	{ { NULL, NULL },
+	  "H.225",					/* name */
+	  IP_CT_HELPER_F_REUSE_EXPECT,			/* flags */
+	  THIS_MODULE,					/* module */
+	  2,						/* max_expected */
+	  240,						/* timeout */
+	  { { 0, { __constant_htons(H225_PORT) } },	/* tuple */
+	    { 0, { 0 }, IPPROTO_TCP } },
+	  { { 0, { 0xFFFF } },				/* mask */
+	    { 0, { 0 }, 0xFFFF } },
+	  h225_help					/* helper */
+	};
+
+static int __init init(void)
+{
+	return ip_conntrack_helper_register(&h225);
+}
+
+static void __exit fini(void)
+{
+	/* Unregister H.225 helper */	
+	ip_conntrack_helper_unregister(&h225);
+}
+
+EXPORT_SYMBOL(ip_h323_lock);
+
+module_init(init);
+module_exit(fini);
diff -Nru linux-2.4.20/net/ipv4/netfilter/ip_nat_h323.c linux-2.4.20-pom2patch/net/ipv4/netfilter/ip_nat_h323.c
--- linux-2.4.20/net/ipv4/netfilter/ip_nat_h323.c	1969-12-31 18:00:00.000000000 -0600
+++ linux-2.4.20-pom2patch/net/ipv4/netfilter/ip_nat_h323.c	2003-05-02 12:57:19.000000000 -0500
@@ -0,0 +1,419 @@
+/* 
+ * H.323 'brute force' extension for NAT alteration. 
+ * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ *
+ * Based on ip_masq_h323.c for 2.2 kernels from CoRiTel, Sofia project.
+ * (http://www.coritel.it/projects/sofia/nat.html)
+ * Uses Sampsa Ranta's excellent idea on using expectfn to 'bind'
+ * the unregistered helpers to the conntrack entries.
+ */
+
+
+#include <linux/module.h>
+#include <linux/netfilter.h>
+#include <linux/ip.h>
+#include <net/checksum.h>
+#include <net/tcp.h>
+
+#include <linux/netfilter_ipv4/lockhelp.h>
+#include <linux/netfilter_ipv4/ip_nat.h>
+#include <linux/netfilter_ipv4/ip_nat_helper.h>
+#include <linux/netfilter_ipv4/ip_nat_rule.h>
+#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+#include <linux/netfilter_ipv4/ip_conntrack_h323.h>
+
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_DESCRIPTION("H.323 'brute force' connection tracking module");
+MODULE_LICENSE("GPL");
+
+DECLARE_LOCK_EXTERN(ip_h323_lock);
+struct module *ip_nat_h323 = THIS_MODULE;
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+/* FIXME: Time out? --RR */
+
+static unsigned int 
+h225_nat_expected(struct sk_buff **pskb,
+		  unsigned int hooknum,
+		  struct ip_conntrack *ct,
+		  struct ip_nat_info *info);
+
+static unsigned int h225_nat_help(struct ip_conntrack *ct,
+				  struct ip_conntrack_expect *exp,
+			 	  struct ip_nat_info *info,
+			 	  enum ip_conntrack_info ctinfo,
+			 	  unsigned int hooknum,
+			 	  struct sk_buff **pskb);
+		  
+static struct ip_nat_helper h245 = 
+	{ { NULL, NULL },
+          "H.245",				/* name */
+	  0,					/* flags */
+	  NULL,					/* module */
+	  { { 0, { 0 } },			/* tuple */
+	    { 0, { 0 }, IPPROTO_TCP } },
+	  { { 0, { 0xFFFF } },			/* mask */
+	    { 0, { 0 }, 0xFFFF } },
+	  h225_nat_help,			/* helper */
+	  h225_nat_expected			/* expectfn */
+	};
+
+static unsigned int
+h225_nat_expected(struct sk_buff **pskb,
+		  unsigned int hooknum,
+		  struct ip_conntrack *ct,
+		  struct ip_nat_info *info)
+{
+	struct ip_nat_multi_range mr;
+	u_int32_t newdstip, newsrcip, newip;
+	u_int16_t port;
+	struct ip_ct_h225_expect *exp_info;
+	struct ip_ct_h225_master *master_info;
+	struct ip_conntrack *master = master_ct(ct);
+	unsigned int is_h225, ret;
+	
+	IP_NF_ASSERT(info);
+	IP_NF_ASSERT(master);
+
+	IP_NF_ASSERT(!(info->initialized & (1<<HOOK2MANIP(hooknum))));
+
+	DEBUGP("h225_nat_expected: We have a connection!\n");
+	master_info = &ct->master->expectant->help.ct_h225_info;
+	exp_info = &ct->master->help.exp_h225_info;
+
+	LOCK_BH(&ip_h323_lock);
+
+	DEBUGP("master: ");
+	DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+	DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_REPLY].tuple);
+	DEBUGP("conntrack: ");
+	DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+	if (exp_info->dir == IP_CT_DIR_ORIGINAL) {
+		/* Make connection go to the client. */
+		newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
+		newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
+		DEBUGP("h225_nat_expected: %u.%u.%u.%u->%u.%u.%u.%u (to client)\n",
+		       NIPQUAD(newsrcip), NIPQUAD(newdstip));
+	} else {
+		/* Make the connection go to the server */
+		newdstip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
+		newsrcip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
+		DEBUGP("h225_nat_expected: %u.%u.%u.%u->%u.%u.%u.%u (to server)\n",
+		       NIPQUAD(newsrcip), NIPQUAD(newdstip));
+	}
+	port = exp_info->port;
+	is_h225 = master_info->is_h225 == H225_PORT;
+	UNLOCK_BH(&ip_h323_lock);
+	
+	if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
+		newip = newsrcip;
+	else
+		newip = newdstip;
+
+	DEBUGP("h225_nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip));
+
+	mr.rangesize = 1;
+	/* We don't want to manip the per-protocol, just the IPs... */
+	mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
+	mr.range[0].min_ip = mr.range[0].max_ip = newip;
+
+	/* ... unless we're doing a MANIP_DST, in which case, make
+	   sure we map to the correct port */
+	if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
+		mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
+		mr.range[0].min = mr.range[0].max
+			= ((union ip_conntrack_manip_proto)
+				{ port });
+	}
+
+	ret = ip_nat_setup_info(ct, &mr, hooknum);
+	
+	if (is_h225) {
+		DEBUGP("h225_nat_expected: H.225, setting NAT helper for %p\n", ct);
+		/* NAT expectfn called with ip_nat_lock write-locked */
+		info->helper = &h245;
+	}
+	return ret;
+}
+
+static int h323_signal_address_fixup(struct ip_conntrack *ct,
+			      	     struct sk_buff **pskb,
+			      	     enum ip_conntrack_info ctinfo)
+{
+	struct iphdr *iph = (*pskb)->nh.iph;
+	struct tcphdr *tcph = (void *)iph + iph->ihl*4;
+	char *data = (char *) tcph + tcph->doff * 4;
+	u_int32_t tcplen = (*pskb)->len - iph->ihl*4;
+	u_int32_t datalen = tcplen - tcph->doff*4;
+	struct ip_ct_h225_master *info = &ct->help.ct_h225_info; 
+	u_int32_t newip;
+	u_int16_t port;
+	int i;
+
+	MUST_BE_LOCKED(&ip_h323_lock);
+
+	DEBUGP("h323_signal_address_fixup: %s %s\n",
+		between(info->seq[IP_CT_DIR_ORIGINAL], ntohl(tcph->seq), ntohl(tcph->seq) + datalen)
+			? "yes" : "no",
+		between(info->seq[IP_CT_DIR_REPLY], ntohl(tcph->seq), ntohl(tcph->seq) + datalen)
+			? "yes" : "no");
+	if (!(between(info->seq[IP_CT_DIR_ORIGINAL], ntohl(tcph->seq), ntohl(tcph->seq) + datalen)
+		|| between(info->seq[IP_CT_DIR_REPLY], ntohl(tcph->seq), ntohl(tcph->seq) + datalen)))
+		return 1;
+
+	DEBUGP("h323_signal_address_fixup: offsets %u + 6  and %u + 6 in %u\n", 
+		info->offset[IP_CT_DIR_ORIGINAL], 
+		info->offset[IP_CT_DIR_REPLY],
+		tcplen);
+	DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+	DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
+
+	for (i = 0; i < IP_CT_DIR_MAX; i++) {
+		DEBUGP("h323_signal_address_fixup: %s %s\n",
+			info->dir == IP_CT_DIR_ORIGINAL ? "original" : "reply",
+			i == IP_CT_DIR_ORIGINAL ? "caller" : "callee");
+		if (!between(info->seq[i], ntohl(tcph->seq), 
+			     ntohl(tcph->seq) + datalen))
+			continue;
+		if (!between(info->seq[i] + 6, ntohl(tcph->seq),
+			     ntohl(tcph->seq) + datalen)) {
+			/* Partial retransmisison. It's a cracker being funky. */
+			if (net_ratelimit()) {
+				printk("H.323_NAT: partial packet %u/6 in %u/%u\n",
+				     info->seq[i],
+				     ntohl(tcph->seq),
+				     ntohl(tcph->seq) + datalen);
+			}
+			return 0;
+		}
+
+		/* Change address inside packet to match way we're mapping
+		   this connection. */
+		if (i == IP_CT_DIR_ORIGINAL) {
+			newip = ct->tuplehash[!info->dir].tuple.dst.ip;
+			port = ct->tuplehash[!info->dir].tuple.dst.u.tcp.port;
+		} else {
+			newip = ct->tuplehash[!info->dir].tuple.src.ip;
+			port = ct->tuplehash[!info->dir].tuple.src.u.tcp.port;
+		}
+
+		DEBUGP("h323_signal_address_fixup: orig %s IP:port %u.%u.%u.%u:%u\n", 
+			i == IP_CT_DIR_ORIGINAL ? "source" : "dest  ", 
+			NIPQUAD(*((u_int32_t *)(data + info->offset[i]))), 
+			ntohs(*((u_int16_t *)(data + info->offset[i] + 4))));
+
+		/* Modify the packet */
+		*(u_int32_t *)(data + info->offset[i]) = newip;
+		*(u_int16_t *)(data + info->offset[i] + 4) = port;
+	
+		DEBUGP("h323_signal_address_fixup:  new %s IP:port %u.%u.%u.%u:%u\n", 
+			i == IP_CT_DIR_ORIGINAL ? "source" : "dest  ", 
+			NIPQUAD(*((u_int32_t *)(data + info->offset[i]))), 
+			ntohs(*((u_int16_t *)(data + info->offset[i] + 4))));
+	}
+
+	/* fix checksum information */
+
+	(*pskb)->csum = csum_partial((char *)tcph + tcph->doff*4,
+				     datalen, 0);
+
+	tcph->check = 0;
+	tcph->check = tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
+				   csum_partial((char *)tcph, tcph->doff*4,
+					   (*pskb)->csum));
+	ip_send_check(iph);
+
+	return 1;
+}
+
+static int h323_data_fixup(struct ip_ct_h225_expect *info,
+			   struct ip_conntrack *ct,
+			   struct sk_buff **pskb,
+			   enum ip_conntrack_info ctinfo,
+			   struct ip_conntrack_expect *expect)
+{
+	u_int32_t newip;
+	u_int16_t port;
+	struct ip_conntrack_tuple newtuple;
+	struct iphdr *iph = (*pskb)->nh.iph;
+	struct tcphdr *tcph = (void *)iph + iph->ihl*4;
+	char *data = (char *) tcph + tcph->doff * 4;
+	u_int32_t tcplen = (*pskb)->len - iph->ihl*4;
+	struct ip_ct_h225_master *master_info = &ct->help.ct_h225_info;
+	int is_h225;
+
+	MUST_BE_LOCKED(&ip_h323_lock);
+	DEBUGP("h323_data_fixup: offset %u + 6 in %u\n", info->offset, tcplen);
+	DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+	DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
+
+	if (!between(expect->seq + 6, ntohl(tcph->seq),
+		    ntohl(tcph->seq) + tcplen - tcph->doff * 4)) {
+		/* Partial retransmisison. It's a cracker being funky. */
+		if (net_ratelimit()) {
+			printk("H.323_NAT: partial packet %u/6 in %u/%u\n",
+			     expect->seq,
+			     ntohl(tcph->seq),
+			     ntohl(tcph->seq) + tcplen - tcph->doff * 4);
+		}
+		return 0;
+	}
+
+	/* Change address inside packet to match way we're mapping
+	   this connection. */
+	if (info->dir == IP_CT_DIR_REPLY) {
+		/* Must be where client thinks server is */
+		newip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
+		/* Expect something from client->server */
+		newtuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
+		newtuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
+	} else {
+		/* Must be where server thinks client is */
+		newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
+		/* Expect something from server->client */
+		newtuple.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
+		newtuple.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
+	}
+
+	is_h225 = (master_info->is_h225 == H225_PORT);
+
+	if (is_h225) {
+		newtuple.dst.protonum = IPPROTO_TCP;
+		newtuple.src.u.tcp.port = expect->tuple.src.u.tcp.port;
+	} else {
+		newtuple.dst.protonum = IPPROTO_UDP;
+		newtuple.src.u.udp.port = expect->tuple.src.u.udp.port;
+	}
+	
+	/* Try to get same port: if not, try to change it. */
+	for (port = ntohs(info->port); port != 0; port++) {
+		if (is_h225)
+			newtuple.dst.u.tcp.port = htons(port);
+		else
+			newtuple.dst.u.udp.port = htons(port);
+
+		if (ip_conntrack_change_expect(expect, &newtuple) == 0)
+			break;
+	}
+	if (port == 0) {
+		DEBUGP("h323_data_fixup: no free port found!\n");
+		return 0;
+	}
+
+	port = htons(port);
+
+	DEBUGP("h323_data_fixup: orig IP:port %u.%u.%u.%u:%u\n", 
+		NIPQUAD(*((u_int32_t *)(data + info->offset))), 
+		ntohs(*((u_int16_t *)(data + info->offset + 4))));
+
+	/* Modify the packet */
+	*(u_int32_t *)(data + info->offset) = newip;
+	*(u_int16_t *)(data + info->offset + 4) = port;
+	
+	DEBUGP("h323_data_fixup: new IP:port %u.%u.%u.%u:%u\n", 
+		NIPQUAD(*((u_int32_t *)(data + info->offset))), 
+		ntohs(*((u_int16_t *)(data + info->offset + 4))));
+
+	/* fix checksum information  */
+	/* FIXME: usually repeated multiple times in the case of H.245! */
+
+	(*pskb)->csum = csum_partial((char *)tcph + tcph->doff*4,
+				     tcplen - tcph->doff*4, 0);
+
+	tcph->check = 0;
+	tcph->check = tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
+				   csum_partial((char *)tcph, tcph->doff*4,
+					   (*pskb)->csum));
+	ip_send_check(iph);
+
+	return 1;
+}
+
+static unsigned int h225_nat_help(struct ip_conntrack *ct,
+				  struct ip_conntrack_expect *exp,
+			 	  struct ip_nat_info *info,
+			 	  enum ip_conntrack_info ctinfo,
+			 	  unsigned int hooknum,
+			 	  struct sk_buff **pskb)
+{
+	int dir;
+	struct ip_ct_h225_expect *exp_info;
+	
+	/* Only mangle things once: original direction in POST_ROUTING
+	   and reply direction on PRE_ROUTING. */
+	dir = CTINFO2DIR(ctinfo);
+	DEBUGP("nat_h323: dir %s at hook %s\n",
+	       dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
+	       hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
+	       : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
+	       : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");
+	if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)
+	      || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) {
+		DEBUGP("nat_h323: Not touching dir %s at hook %s\n",
+		       dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
+		       hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
+		       : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
+		       : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");
+		return NF_ACCEPT;
+	}
+
+	if (!exp) {
+		LOCK_BH(&ip_h323_lock);
+		if (!h323_signal_address_fixup(ct, pskb, ctinfo)) {
+			UNLOCK_BH(&ip_h323_lock);
+			return NF_DROP;
+		}
+		UNLOCK_BH(&ip_h323_lock);
+		return NF_ACCEPT;
+	}
+		
+	exp_info = &exp->help.exp_h225_info;
+
+	LOCK_BH(&ip_h323_lock);
+	if (!h323_data_fixup(exp_info, ct, pskb, ctinfo, exp)) {
+		UNLOCK_BH(&ip_h323_lock);
+		return NF_DROP;
+	}
+	UNLOCK_BH(&ip_h323_lock);
+
+	return NF_ACCEPT;
+}
+
+static struct ip_nat_helper h225 = 
+	{ { NULL, NULL },
+	  "H.225",					/* name */
+	  IP_NAT_HELPER_F_ALWAYS, 			/* flags */
+	  THIS_MODULE,					/* module */
+	  { { 0, { __constant_htons(H225_PORT) } },	/* tuple */
+	    { 0, { 0 }, IPPROTO_TCP } },
+	  { { 0, { 0xFFFF } },				/* mask */
+	    { 0, { 0 }, 0xFFFF } },
+	  h225_nat_help,				/* helper */
+	  h225_nat_expected				/* expectfn */
+	};
+
+static int __init init(void)
+{
+	int ret;
+	
+	ret = ip_nat_helper_register(&h225);
+
+	if (ret != 0)
+		printk("ip_nat_h323: cannot initialize the module!\n");
+
+	return ret;
+}
+
+static void __exit fini(void)
+{
+	ip_nat_helper_unregister(&h225);
+}
+
+module_init(init);
+module_exit(fini);
