1diff -urN -X dontdiff linux-2.4.20-pre7/include/linux/netfilter_ipv4/ip_conntrack_mms.h linux-2.4.20-pre7-mms/include/linux/netfilter_ipv4/ip_conntrack_mms.h
2--- linux-2.4.20-pre7/include/linux/netfilter_ipv4/ip_conntrack_mms.h	1970-01-01 01:00:00.000000000 +0100
3+++ linux-2.4.20-pre7-mms/include/linux/netfilter_ipv4/ip_conntrack_mms.h	2002-09-17 04:08:25.000000000 +0200
4@@ -0,0 +1,31 @@
5+#ifndef _IP_CONNTRACK_MMS_H
6+#define _IP_CONNTRACK_MMS_H
7+/* MMS tracking. */
8+
9+#ifdef __KERNEL__
10+#include <linux/netfilter_ipv4/lockhelp.h>
11+
12+DECLARE_LOCK_EXTERN(ip_mms_lock);
13+
14+#define MMS_PORT                         1755
15+#define MMS_SRV_MSG_ID                   196610
16+
17+#define MMS_SRV_MSG_OFFSET               36
18+#define MMS_SRV_UNICODE_STRING_OFFSET    60
19+#define MMS_SRV_CHUNKLENLV_OFFSET        16
20+#define MMS_SRV_CHUNKLENLM_OFFSET        32
21+#define MMS_SRV_MESSAGELENGTH_OFFSET     8
22+#endif
23+
24+/* This structure is per expected connection */
25+struct ip_ct_mms_expect {
26+	u_int32_t len;
27+	u_int32_t padding;
28+	u_int16_t port;
29+};
30+
31+/* This structure exists only once per master */
32+struct ip_ct_mms_master {
33+};
34+
35+#endif /* _IP_CONNTRACK_MMS_H */
36diff -urN -X dontdiff linux-2.4.20-pre7/net/ipv4/netfilter/ip_conntrack_mms.c linux-2.4.20-pre7-mms/net/ipv4/netfilter/ip_conntrack_mms.c
37--- linux-2.4.20-pre7/net/ipv4/netfilter/ip_conntrack_mms.c	1970-01-01 01:00:00.000000000 +0100
38+++ linux-2.4.20-pre7-mms/net/ipv4/netfilter/ip_conntrack_mms.c	2002-09-17 01:29:20.000000000 +0200
39@@ -0,0 +1,310 @@
40+/* MMS extension for IP connection tracking
41+ * (C) 2002 by Filip Sneppe <filip.sneppe@cronos.be>
42+ * based on ip_conntrack_ftp.c and ip_conntrack_irc.c
43+ *
44+ * ip_conntrack_mms.c v0.3 2002-09-22
45+ *
46+ *      This program is free software; you can redistribute it and/or
47+ *      modify it under the terms of the GNU General Public License
48+ *      as published by the Free Software Foundation; either version
49+ *      2 of the License, or (at your option) any later version.
50+ *
51+ *      Module load syntax:
52+ *      insmod ip_conntrack_mms.o ports=port1,port2,...port<MAX_PORTS>
53+ *
54+ *      Please give the ports of all MMS servers You wish to connect to.
55+ *      If you don't specify ports, the default will be TCP port 1755.
56+ *
57+ *      More info on MMS protocol, firewalls and NAT:
58+ *      http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwmt/html/MMSFirewall.asp
59+ *      http://www.microsoft.com/windows/windowsmedia/serve/firewall.asp
60+ *
61+ *      The SDP project people are reverse-engineering MMS:
62+ *      http://get.to/sdp
63+ */
64+
65+#include <linux/config.h>
66+#include <linux/module.h>
67+#include <linux/netfilter.h>
68+#include <linux/ip.h>
69+#include <linux/ctype.h>
70+#include <net/checksum.h>
71+#include <net/tcp.h>
72+
73+#include <linux/netfilter_ipv4/lockhelp.h>
74+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
75+#include <linux/netfilter_ipv4/ip_conntrack_mms.h>
76+
77+DECLARE_LOCK(ip_mms_lock);
78+struct module *ip_conntrack_mms = THIS_MODULE;
79+
80+#define MAX_PORTS 8
81+static int ports[MAX_PORTS];
82+static int ports_c;
83+#ifdef MODULE_PARM
84+MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
85+#endif
86+
87+#if 0 
88+#define DEBUGP printk
89+#else
90+#define DEBUGP(format, args...)
91+#endif
92+
93+#ifdef CONFIG_IP_NF_NAT_NEEDED
94+EXPORT_SYMBOL(ip_mms_lock);
95+#endif
96+
97+MODULE_AUTHOR("Filip Sneppe <filip.sneppe@cronos.be>");
98+MODULE_DESCRIPTION("Microsoft Windows Media Services (MMS) connection tracking module");
99+MODULE_LICENSE("GPL");
100+
101+/* #define isdigit(c) (c >= '0' && c <= '9') */
102+
103+/* copied from drivers/usb/serial/io_edgeport.c - not perfect but will do the trick */
104+static void unicode_to_ascii (char *string, short *unicode, int unicode_size)
105+{
106+	int i;
107+	for (i = 0; i < unicode_size; ++i) {
108+		string[i] = (char)(unicode[i]);
109+	}
110+	string[unicode_size] = 0x00;
111+}
112+
113+__inline static int atoi(char *s) 
114+{
115+	int i=0;
116+	while (isdigit(*s)) {
117+		i = i*10 + *(s++) - '0';
118+	}
119+	return i;
120+}
121+
122+/* convert ip address string like "192.168.0.10" to unsigned int */
123+__inline static u_int32_t asciiiptoi(char *s)
124+{
125+	unsigned int i, j, k;
126+
127+	for(i=k=0; k<3; ++k, ++s, i<<=8) {
128+		i+=atoi(s);
129+		for(j=0; (*(++s) != '.') && (j<3); ++j)
130+			;
131+	}
132+	i+=atoi(s);
133+	return ntohl(i);
134+}
135+
136+int parse_mms(const char *data, 
137+	      const unsigned int datalen,
138+	      u_int32_t *mms_ip,
139+	      u_int16_t *mms_proto,
140+	      u_int16_t *mms_port,
141+	      char **mms_string_b,
142+	      char **mms_string_e,
143+	      char **mms_padding_e)
144+{
145+	int unicode_size, i;
146+	char tempstring[28];       /* "\\255.255.255.255\UDP\65535" */
147+	char getlengthstring[28];
148+	
149+	for(unicode_size=0; 
150+	    (char) *(data+(MMS_SRV_UNICODE_STRING_OFFSET+unicode_size*2)) != (char)0;
151+	    unicode_size++)
152+		if ((unicode_size == 28) || (MMS_SRV_UNICODE_STRING_OFFSET+unicode_size*2 >= datalen)) 
153+			return -1; /* out of bounds - incomplete packet */
154+	
155+	unicode_to_ascii(tempstring, (short *)(data+MMS_SRV_UNICODE_STRING_OFFSET), unicode_size);
156+	DEBUGP("ip_conntrack_mms: offset 60: %s\n", (const char *)(tempstring));
157+	
158+	/* IP address ? */
159+	*mms_ip = asciiiptoi(tempstring+2);
160+	
161+	i=sprintf(getlengthstring, "%u.%u.%u.%u", HIPQUAD(*mms_ip));
162+		
163+	/* protocol ? */
164+	if(strncmp(tempstring+3+i, "TCP", 3)==0)
165+		*mms_proto = IPPROTO_TCP;
166+	else if(strncmp(tempstring+3+i, "UDP", 3)==0)
167+		*mms_proto = IPPROTO_UDP;
168+
169+	/* port ? */
170+	*mms_port = atoi(tempstring+7+i);
171+
172+	/* we store a pointer to the beginning of the "\\a.b.c.d\proto\port" 
173+	   unicode string, one to the end of the string, and one to the end 
174+	   of the packet, since we must keep track of the number of bytes 
175+	   between end of the unicode string and the end of packet (padding) */
176+	*mms_string_b  = (char *)(data + MMS_SRV_UNICODE_STRING_OFFSET);
177+	*mms_string_e  = (char *)(data + MMS_SRV_UNICODE_STRING_OFFSET + unicode_size * 2);
178+	*mms_padding_e = (char *)(data + datalen); /* looks funny, doesn't it */
179+	return 0;
180+}
181+
182+
183+
184+static int help(const struct iphdr *iph, size_t len,
185+		struct ip_conntrack *ct,
186+		enum ip_conntrack_info ctinfo)
187+{
188+	/* tcplen not negative guaranteed by ip_conntrack_tcp.c */
189+	struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
190+	const char *data = (const char *)tcph + tcph->doff * 4;
191+	unsigned int tcplen = len - iph->ihl * 4;
192+	unsigned int datalen = tcplen - tcph->doff * 4;
193+	int dir = CTINFO2DIR(ctinfo);
194+	struct ip_conntrack_expect expect, *exp = &expect; 
195+	struct ip_ct_mms_expect *exp_mms_info = &exp->help.exp_mms_info;
196+	
197+	u_int32_t mms_ip;
198+	u_int16_t mms_proto;
199+	char mms_proto_string[8];
200+	u_int16_t mms_port;
201+	char *mms_string_b, *mms_string_e, *mms_padding_e;
202+	     
203+	/* Until there's been traffic both ways, don't look in packets. */
204+	if (ctinfo != IP_CT_ESTABLISHED
205+	    && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) {
206+		DEBUGP("ip_conntrack_mms: Conntrackinfo = %u\n", ctinfo);
207+		return NF_ACCEPT;
208+	}
209+
210+	/* Not whole TCP header? */
211+	if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff*4) {
212+		DEBUGP("ip_conntrack_mms: tcplen = %u\n", (unsigned)tcplen);
213+		return NF_ACCEPT;
214+	}
215+
216+	/* Checksum invalid?  Ignore. */
217+	
218+	if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
219+	    csum_partial((char *)tcph, tcplen, 0))) {
220+		DEBUGP("mms_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
221+		       tcph, tcplen, NIPQUAD(iph->saddr),
222+		       NIPQUAD(iph->daddr));
223+		return NF_ACCEPT;
224+	}
225+	
226+	/* Only look at packets with 0x00030002/196610 on bytes 36->39 of TCP payload */
227+	
228+	if( (MMS_SRV_MSG_OFFSET < datalen) && 
229+	    ((*(u32 *)(data+MMS_SRV_MSG_OFFSET)) == MMS_SRV_MSG_ID)) {
230+		DEBUGP("ip_conntrack_mms: offset 37: %u %u %u %u, datalen:%u\n", 
231+		       (u8)*(data+36), (u8)*(data+37), 
232+		       (u8)*(data+38), (u8)*(data+39),
233+		       datalen);
234+		if(parse_mms(data, datalen, &mms_ip, &mms_proto, &mms_port,
235+		             &mms_string_b, &mms_string_e, &mms_padding_e))
236+			if(net_ratelimit())
237+				
238+				printk(KERN_WARNING
239+				       "ip_conntrack_mms: Unable to parse data payload\n");
240+
241+		memset(&expect, 0, sizeof(expect));
242+
243+		sprintf(mms_proto_string, "(%u)", mms_proto);
244+		DEBUGP("ip_conntrack_mms: adding %s expectation %u.%u.%u.%u -> %u.%u.%u.%u:%u\n",
245+		       mms_proto == IPPROTO_TCP ? "TCP"
246+		       : mms_proto == IPPROTO_UDP ? "UDP":mms_proto_string,
247+		       NIPQUAD(ct->tuplehash[!dir].tuple.src.ip),
248+		       NIPQUAD(mms_ip),
249+		       mms_port);
250+		
251+		/* it's possible that the client will just ask the server to tunnel
252+		   the stream over the same TCP session (from port 1755): there's 
253+		   shouldn't be a need to add an expectation in that case, but it
254+		   makes NAT packet mangling so much easier */
255+		LOCK_BH(&ip_mms_lock);
256+
257+		DEBUGP("ip_conntrack_mms: tcph->seq = %u\n", tcph->seq);
258+		
259+		exp->seq = ntohl(tcph->seq) + (mms_string_b - data);
260+		exp_mms_info->len     = (mms_string_e  - mms_string_b);
261+		exp_mms_info->padding = (mms_padding_e - mms_string_e);
262+		exp_mms_info->port    = mms_port;
263+		
264+		DEBUGP("ip_conntrack_mms: wrote info seq=%u (ofs=%u), len=%d, padding=%u\n",
265+		       exp->seq, (mms_string_e - data), exp_mms_info->len, exp_mms_info->padding);
266+		
267+		exp->tuple = ((struct ip_conntrack_tuple)
268+		              { { ct->tuplehash[!dir].tuple.src.ip, { 0 } },
269+		              { mms_ip,
270+		                { (__u16) ntohs(mms_port) },
271+		                mms_proto } }
272+		             );
273+		exp->mask  = ((struct ip_conntrack_tuple)
274+		             { { 0xFFFFFFFF, { 0 } },
275+		               { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
276+		exp->expectfn = NULL;
277+		ip_conntrack_expect_related(ct, &expect);
278+		UNLOCK_BH(&ip_mms_lock);
279+	}
280+
281+	return NF_ACCEPT;
282+}
283+
284+static struct ip_conntrack_helper mms[MAX_PORTS];
285+static char mms_names[MAX_PORTS][10];
286+
287+/* Not __exit: called from init() */
288+static void fini(void)
289+{
290+	int i;
291+	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
292+		DEBUGP("ip_conntrack_mms: unregistering helper for port %d\n",
293+				ports[i]);
294+		ip_conntrack_helper_unregister(&mms[i]);
295+	}
296+}
297+
298+static int __init init(void)
299+{
300+	int i, ret;
301+	char *tmpname;
302+
303+	if (ports[0] == 0)
304+		ports[0] = MMS_PORT;
305+
306+	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
307+		memset(&mms[i], 0, sizeof(struct ip_conntrack_helper));
308+		mms[i].tuple.src.u.tcp.port = htons(ports[i]);
309+		mms[i].tuple.dst.protonum = IPPROTO_TCP;
310+		mms[i].mask.src.u.tcp.port = 0xFFFF;
311+		mms[i].mask.dst.protonum = 0xFFFF;
312+		mms[i].max_expected = 1;
313+		mms[i].timeout = 0;
314+		mms[i].flags = IP_CT_HELPER_F_REUSE_EXPECT;
315+		mms[i].me = THIS_MODULE;
316+		mms[i].help = help;
317+
318+		tmpname = &mms_names[i][0];
319+		if (ports[i] == MMS_PORT)
320+			sprintf(tmpname, "mms");
321+		else
322+			sprintf(tmpname, "mms-%d", ports[i]);
323+		mms[i].name = tmpname;
324+
325+		DEBUGP("ip_conntrack_mms: registering helper for port %d\n", 
326+				ports[i]);
327+		ret = ip_conntrack_helper_register(&mms[i]);
328+
329+		if (ret) {
330+			fini();
331+			return ret;
332+		}
333+		ports_c++;
334+	}
335+	return 0;
336+}
337+
338+module_init(init);
339+module_exit(fini);
340diff -urN -X dontdiff linux-2.4.20-pre7/net/ipv4/netfilter/ip_nat_mms.c linux-2.4.20-pre7-mms/net/ipv4/netfilter/ip_nat_mms.c
341--- linux-2.4.20-pre7/net/ipv4/netfilter/ip_nat_mms.c	1970-01-01 01:00:00.000000000 +0100
342+++ linux-2.4.20-pre7-mms/net/ipv4/netfilter/ip_nat_mms.c	2002-09-22 19:25:27.000000000 +0200
343@@ -0,0 +1,350 @@
344+/* MMS extension for TCP NAT alteration.
345+ * (C) 2002 by Filip Sneppe <filip.sneppe@cronos.be>
346+ * based on ip_nat_ftp.c and ip_nat_irc.c
347+ *
348+ * ip_nat_mms.c v0.3 2002-09-22
349+ *
350+ *      This program is free software; you can redistribute it and/or
351+ *      modify it under the terms of the GNU General Public License
352+ *      as published by the Free Software Foundation; either version
353+ *      2 of the License, or (at your option) any later version.
354+ *
355+ *      Module load syntax:
356+ *      insmod ip_nat_mms.o ports=port1,port2,...port<MAX_PORTS>
357+ *
358+ *      Please give the ports of all MMS servers You wish to connect to.
359+ *      If you don't specify ports, the default will be TCP port 1755.
360+ *
361+ *      More info on MMS protocol, firewalls and NAT:
362+ *      http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwmt/html/MMSFirewall.asp
363+ *      http://www.microsoft.com/windows/windowsmedia/serve/firewall.asp
364+ *
365+ *      The SDP project people are reverse-engineering MMS:
366+ *      http://get.to/sdp
367+ */
368+
369+
370+
371+#include <linux/module.h>
372+#include <linux/netfilter_ipv4.h>
373+#include <linux/ip.h>
374+#include <linux/tcp.h>
375+#include <net/tcp.h>
376+#include <linux/netfilter_ipv4/ip_nat.h>
377+#include <linux/netfilter_ipv4/ip_nat_helper.h>
378+#include <linux/netfilter_ipv4/ip_nat_rule.h>
379+#include <linux/netfilter_ipv4/ip_conntrack_mms.h>
380+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
381+
382+#if 0 
383+#define DEBUGP printk
384+#define DUMP_BYTES(address, counter)                                \
385+({                                                                  \
386+	int temp_counter;                                           \
387+	for(temp_counter=0; temp_counter<counter; ++temp_counter) { \
388+		DEBUGP("%u ", (u8)*(address+temp_counter));         \
389+	};                                                          \
390+	DEBUGP("\n");                                               \
391+})
392+#else
393+#define DEBUGP(format, args...)
394+#define DUMP_BYTES(address, counter)
395+#endif
396+
397+#define MAX_PORTS 8
398+static int ports[MAX_PORTS];
399+static int ports_c = 0;
400+
401+#ifdef MODULE_PARM
402+MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
403+#endif
404+
405+MODULE_AUTHOR("Filip Sneppe <filip.sneppe@cronos.be>");
406+MODULE_DESCRIPTION("Microsoft Windows Media Services (MMS) NAT module");
407+MODULE_LICENSE("GPL");
408+
409+DECLARE_LOCK_EXTERN(ip_mms_lock);
410+
411+
412+
413+static int mms_data_fixup(const struct ip_ct_mms_expect *ct_mms_info,
414+                          struct ip_conntrack *ct,
415+                          struct sk_buff **pskb,
416+                          enum ip_conntrack_info ctinfo,
417+                          struct ip_conntrack_expect *expect)
418+{
419+	u_int32_t newip;
420+	struct ip_conntrack_tuple t;
421+	struct iphdr *iph = (*pskb)->nh.iph;
422+	struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
423+	char *data = (char *)tcph + tcph->doff * 4;
424+	int i, j, k, port;
425+	u_int16_t mms_proto;
426+
427+	u_int32_t *mms_chunkLenLV    = (u_int32_t *)(data + MMS_SRV_CHUNKLENLV_OFFSET);
428+	u_int32_t *mms_chunkLenLM    = (u_int32_t *)(data + MMS_SRV_CHUNKLENLM_OFFSET);
429+	u_int32_t *mms_messageLength = (u_int32_t *)(data + MMS_SRV_MESSAGELENGTH_OFFSET);
430+
431+	int zero_padding;
432+
433+	char buffer[28];         /* "\\255.255.255.255\UDP\65635" * 2 (for unicode) */
434+	char unicode_buffer[75]; /* 27*2 (unicode) + 20 + 1 */
435+	char proto_string[6];
436+	
437+	MUST_BE_LOCKED(&ip_mms_lock);
438+
439+	/* what was the protocol again ? */
440+	mms_proto = expect->tuple.dst.protonum;
441+	sprintf(proto_string, "%u", mms_proto);
442+	
443+	DEBUGP("ip_nat_mms: mms_data_fixup: info (seq %u + %u) in %u, proto %s\n",
444+	       expect->seq, ct_mms_info->len, ntohl(tcph->seq),
445+	       mms_proto == IPPROTO_UDP ? "UDP"
446+	       : mms_proto == IPPROTO_TCP ? "TCP":proto_string);
447+	
448+	newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
449+
450+	/* Alter conntrack's expectations. */
451+	t = expect->tuple;
452+	t.dst.ip = newip;
453+	for (port = ct_mms_info->port; port != 0; port++) {
454+		t.dst.u.tcp.port = htons(port);
455+		if (ip_conntrack_change_expect(expect, &t) == 0) {
456+			DEBUGP("ip_nat_mms: mms_data_fixup: using port %d\n", port);
457+			break;
458+		}
459+	}
460+	
461+	if(port == 0)
462+		return 0;
463+
464+	sprintf(buffer, "\\\\%u.%u.%u.%u\\%s\\%u",
465+	        NIPQUAD(newip),
466+		expect->tuple.dst.protonum == IPPROTO_UDP ? "UDP"
467+		: expect->tuple.dst.protonum == IPPROTO_TCP ? "TCP":proto_string,
468+		port);
469+	DEBUGP("ip_nat_mms: new unicode string=%s\n", buffer);
470+	
471+	memset(unicode_buffer, 0, sizeof(char)*75);
472+
473+	for (i=0; i<strlen(buffer); ++i)
474+		*(unicode_buffer+i*2)=*(buffer+i);
475+	
476+	DEBUGP("ip_nat_mms: mms_data_fixup: padding: %u len: %u\n", ct_mms_info->padding, ct_mms_info->len);
477+	DEBUGP("ip_nat_mms: mms_data_fixup: offset: %u\n", MMS_SRV_UNICODE_STRING_OFFSET+ct_mms_info->len);
478+	DUMP_BYTES(data+MMS_SRV_UNICODE_STRING_OFFSET, 60);
479+	
480+	/* add end of packet to it */
481+	for (j=0; j<ct_mms_info->padding; ++j) {
482+		DEBUGP("ip_nat_mms: mms_data_fixup: i=%u j=%u byte=%u\n", 
483+		       i, j, (u8)*(data+MMS_SRV_UNICODE_STRING_OFFSET+ct_mms_info->len+j));
484+		*(unicode_buffer+i*2+j) = *(data+MMS_SRV_UNICODE_STRING_OFFSET+ct_mms_info->len+j);
485+	}
486+
487+	/* pad with zeroes at the end ? see explanation of weird math below */
488+	zero_padding = (8-(strlen(buffer)*2 + ct_mms_info->padding + 4)%8)%8;
489+	for (k=0; k<zero_padding; ++k)
490+		*(unicode_buffer+i*2+j+k)= (char)0;
491+	
492+	DEBUGP("ip_nat_mms: mms_data_fixup: zero_padding = %u\n", zero_padding);
493+	DEBUGP("ip_nat_mms: original=> chunkLenLV=%u chunkLenLM=%u messageLength=%u\n",
494+	       *mms_chunkLenLV, *mms_chunkLenLM, *mms_messageLength);
495+	
496+	/* explanation, before I forget what I did:
497+	   strlen(buffer)*2 + ct_mms_info->padding + 4 must be divisable by 8;
498+	   divide by 8 and add 3 to compute the mms_chunkLenLM field,
499+	   but note that things may have to be padded with zeroes to align by 8 
500+	   bytes, hence we add 7 and divide by 8 to get the correct length */ 
501+	*mms_chunkLenLM    = (u_int32_t) (3+(strlen(buffer)*2+ct_mms_info->padding+11)/8);
502+	*mms_chunkLenLV    = *mms_chunkLenLM+2;
503+	*mms_messageLength = *mms_chunkLenLV*8;
504+	
505+	DEBUGP("ip_nat_mms: modified=> chunkLenLV=%u chunkLenLM=%u messageLength=%u\n",
506+	       *mms_chunkLenLV, *mms_chunkLenLM, *mms_messageLength);
507+	
508+	ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, 
509+	                         expect->seq - ntohl(tcph->seq),
510+	                         ct_mms_info->len + ct_mms_info->padding, unicode_buffer,
511+	                         strlen(buffer)*2 + ct_mms_info->padding + zero_padding);
512+	DUMP_BYTES(unicode_buffer, 60);
513+	
514+	return 1;
515+}
516+
517+static unsigned int
518+mms_nat_expected(struct sk_buff **pskb,
519+                 unsigned int hooknum,
520+                 struct ip_conntrack *ct,
521+                 struct ip_nat_info *info)
522+{
523+	struct ip_nat_multi_range mr;
524+	u_int32_t newdstip, newsrcip, newip;
525+
526+	struct ip_conntrack *master = master_ct(ct);
527+
528+	IP_NF_ASSERT(info);
529+	IP_NF_ASSERT(master);
530+
531+	IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
532+
533+	DEBUGP("ip_nat_mms: mms_nat_expected: We have a connection!\n");
534+
535+	newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
536+	newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
537+	DEBUGP("ip_nat_mms: mms_nat_expected: hook %s: newsrc->newdst %u.%u.%u.%u->%u.%u.%u.%u\n",
538+	       hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
539+	       : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
540+	       : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???",
541+	       NIPQUAD(newsrcip), NIPQUAD(newdstip));
542+
543+	if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
544+		newip = newsrcip;
545+	else
546+		newip = newdstip;
547+
548+	DEBUGP("ip_nat_mms: mms_nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip));
549+
550+	mr.rangesize = 1;
551+	/* We don't want to manip the per-protocol, just the IPs. */
552+	mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
553+	mr.range[0].min_ip = mr.range[0].max_ip = newip;
554+
555+	return ip_nat_setup_info(ct, &mr, hooknum);
556+}
557+
558+
559+static unsigned int mms_nat_help(struct ip_conntrack *ct,
560+			 struct ip_conntrack_expect *exp,
561+			 struct ip_nat_info *info,
562+			 enum ip_conntrack_info ctinfo,
563+			 unsigned int hooknum,
564+			 struct sk_buff **pskb)
565+{
566+	struct iphdr *iph = (*pskb)->nh.iph;
567+	struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
568+	unsigned int datalen;
569+	int dir;
570+	struct ip_ct_mms_expect *ct_mms_info;
571+
572+	if (!exp)
573+		DEBUGP("ip_nat_mms: no exp!!");
574+
575+	ct_mms_info = &exp->help.exp_mms_info;
576+	
577+	/* Only mangle things once: original direction in POST_ROUTING
578+	   and reply direction on PRE_ROUTING. */
579+	dir = CTINFO2DIR(ctinfo);
580+	if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)
581+	    ||(hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) {
582+		DEBUGP("ip_nat_mms: mms_nat_help: not touching dir %s at hook %s\n",
583+		       dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
584+		       hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
585+		       : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
586+		       : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");
587+		return NF_ACCEPT;
588+	}
589+	DEBUGP("ip_nat_mms: mms_nat_help: beyond not touching (dir %s at hook %s)\n",
590+	       dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
591+	       hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
592+	       : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
593+	       : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");
594+	
595+	datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4;
596+	
597+	DEBUGP("ip_nat_mms: mms_nat_help: %u+%u=%u %u %u\n", exp->seq, ct_mms_info->len,
598+	       exp->seq + ct_mms_info->len,
599+	       ntohl(tcph->seq),
600+	       ntohl(tcph->seq) + datalen);
601+	
602+	LOCK_BH(&ip_mms_lock);
603+	/* Check wether the whole IP/proto/port pattern is carried in the payload */
604+	if (between(exp->seq + ct_mms_info->len,
605+	    ntohl(tcph->seq),
606+	    ntohl(tcph->seq) + datalen)) {
607+		if (!mms_data_fixup(ct_mms_info, ct, pskb, ctinfo, exp)) {
608+			UNLOCK_BH(&ip_mms_lock);
609+			return NF_DROP;
610+		}
611+	} else {
612+		/* Half a match?  This means a partial retransmisison.
613+		   It's a cracker being funky. */
614+		if (net_ratelimit()) {
615+			printk("ip_nat_mms: partial packet %u/%u in %u/%u\n",
616+			       exp->seq, ct_mms_info->len,
617+			       ntohl(tcph->seq),
618+			       ntohl(tcph->seq) + datalen);
619+		}
620+		UNLOCK_BH(&ip_mms_lock);
621+		return NF_DROP;
622+	}
623+	UNLOCK_BH(&ip_mms_lock);
624+	
625+	return NF_ACCEPT;
626+}
627+
628+static struct ip_nat_helper mms[MAX_PORTS];
629+static char mms_names[MAX_PORTS][10];
630+
631+/* Not __exit: called from init() */
632+static void fini(void)
633+{
634+	int i;
635+
636+	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
637+		DEBUGP("ip_nat_mms: unregistering helper for port %d\n", ports[i]);
638+		ip_nat_helper_unregister(&mms[i]);
639+	}
640+}
641+
642+static int __init init(void)
643+{
644+	int i, ret = 0;
645+	char *tmpname;
646+
647+	if (ports[0] == 0)
648+		ports[0] = MMS_PORT;
649+
650+	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
651+
652+		memset(&mms[i], 0, sizeof(struct ip_nat_helper));
653+
654+		mms[i].tuple.dst.protonum = IPPROTO_TCP;
655+		mms[i].tuple.src.u.tcp.port = htons(ports[i]);
656+		mms[i].mask.dst.protonum = 0xFFFF;
657+		mms[i].mask.src.u.tcp.port = 0xFFFF;
658+		mms[i].help = mms_nat_help;
659+		mms[i].me = THIS_MODULE;
660+		mms[i].flags = 0;
661+		mms[i].expect = mms_nat_expected;
662+
663+		tmpname = &mms_names[i][0];
664+		if (ports[i] == MMS_PORT)
665+			sprintf(tmpname, "mms");
666+		else
667+			sprintf(tmpname, "mms-%d", i);
668+		mms[i].name = tmpname;
669+
670+		DEBUGP("ip_nat_mms: register helper for port %d\n",
671+				ports[i]);
672+		ret = ip_nat_helper_register(&mms[i]);
673+
674+		if (ret) {
675+			printk("ip_nat_mms: error registering "
676+			       "helper for port %d\n", ports[i]);
677+			fini();
678+			return ret;
679+		}
680+		ports_c++;
681+	}
682+
683+	return ret;
684+}
685+
686+module_init(init);
687+module_exit(fini);
688