1diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.20-plain/include/linux/netfilter_ipv4/ip_conntrack.h
2--- linux-2.4.19-plain/include/linux/netfilter_ipv4/ip_conntrack.h	Sat Aug  3 02:39:45 2002
3+++ linux-2.4.20-plain/include/linux/netfilter_ipv4/ip_conntrack.h	Fri Nov 29 00:53:15 2002
4@@ -6,6 +6,7 @@
5 
6 #include <linux/config.h>
7 #include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
8+#include <asm/atomic.h>
9 
10 enum ip_conntrack_info
11 {
12@@ -42,12 +43,57 @@
13 	IPS_ASSURED = (1 << IPS_ASSURED_BIT),
14 };
15 
16+#include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
17+#include <linux/netfilter_ipv4/ip_conntrack_icmp.h>
18+
19+/* per conntrack: protocol private data */
20+union ip_conntrack_proto {
21+	/* insert conntrack proto private data here */
22+	struct ip_ct_tcp tcp;
23+	struct ip_ct_icmp icmp;
24+};
25+
26+union ip_conntrack_expect_proto {
27+	/* insert expect proto private data here */
28+};
29+
30+/* Add protocol helper include file here */
31+#include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
32+#include <linux/netfilter_ipv4/ip_conntrack_irc.h>
33+
34+/* per expectation: application helper private data */
35+union ip_conntrack_expect_help {
36+	/* insert conntrack helper private data (expect) here */
37+	struct ip_ct_ftp_expect exp_ftp_info;
38+	struct ip_ct_irc_expect exp_irc_info;
39+
40+#ifdef CONFIG_IP_NF_NAT_NEEDED
41+	union {
42+		/* insert nat helper private data (expect) here */
43+	} nat;
44+#endif
45+};
46+
47+/* per conntrack: application helper private data */
48+union ip_conntrack_help {
49+	/* insert conntrack helper private data (master) here */
50+	struct ip_ct_ftp_master ct_ftp_info;
51+	struct ip_ct_irc_master ct_irc_info;
52+};
53+
54+#ifdef CONFIG_IP_NF_NAT_NEEDED
55+#include <linux/netfilter_ipv4/ip_nat.h>
56+
57+/* per conntrack: nat application helper private data */
58+union ip_conntrack_nat_help {
59+	/* insert nat helper private data here */
60+};
61+#endif
62+
63 #ifdef __KERNEL__
64 
65 #include <linux/types.h>
66 #include <linux/skbuff.h>
67-#include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
68-#include <linux/netfilter_ipv4/ip_conntrack_icmp.h>
69 
70 #ifdef CONFIG_NF_DEBUG
71 #define IP_NF_ASSERT(x)							\
72@@ -64,26 +110,45 @@
73 
74 struct ip_conntrack_expect
75 {
76-	/* Internal linked list */
77+	/* Internal linked list (global expectation list) */
78 	struct list_head list;
79 
80+	/* reference count */
81+	atomic_t use;
82+
83+	/* expectation list for this master */
84+	struct list_head expected_list;
85+
86+	/* The conntrack of the master connection */
87+	struct ip_conntrack *expectant;
88+
89+	/* The conntrack of the sibling connection, set after
90+	 * expectation arrived */
91+	struct ip_conntrack *sibling;
92+
93+	/* Tuple saved for conntrack */
94+	struct ip_conntrack_tuple ct_tuple;
95+
96+	/* Timer function; deletes the expectation. */
97+	struct timer_list timeout;
98+
99+	/* Data filled out by the conntrack helpers follow: */
100+
101 	/* We expect this tuple, with the following mask */
102 	struct ip_conntrack_tuple tuple, mask;
103 
104 	/* Function to call after setup and insertion */
105 	int (*expectfn)(struct ip_conntrack *new);
106 
107-	/* The conntrack we are part of (set iff we're live) */
108-	struct ip_conntrack *expectant;
109-};
110+	/* At which sequence number did this expectation occur */
111+	u_int32_t seq;
112+  
113+	union ip_conntrack_expect_proto proto;
114 
115-#ifdef CONFIG_IP_NF_NAT_NEEDED
116-#include <linux/netfilter_ipv4/ip_nat.h>
117-#endif
118-
119-#include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
120-#include <linux/netfilter_ipv4/ip_conntrack_irc.h>
121+	union ip_conntrack_expect_help help;
122+};
123 
124+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
125 struct ip_conntrack
126 {
127 	/* Usage count in here is 1 for hash table/destruct timer, 1 per skb,
128@@ -101,10 +166,13 @@
129 
130 	/* If we're expecting another related connection, this will be
131            in expected linked list */
132-	struct ip_conntrack_expect expected;
133+	struct list_head sibling_list;
134+	
135+	/* Current number of expected connections */
136+	unsigned int expecting;
137 
138-	/* If we were expected by another connection, this will be it */
139-	struct nf_ct_info master;
140+	/* If we were expected by an expectation, this will be it */
141+	struct ip_conntrack_expect *master;
142 
143 	/* Helper, if any. */
144 	struct ip_conntrack_helper *helper;
145@@ -115,22 +183,14 @@
146 
147 	/* Storage reserved for other modules: */
148 
149-	union {
150-		struct ip_ct_tcp tcp;
151-		struct ip_ct_icmp icmp;
152-	} proto;
153+	union ip_conntrack_proto proto;
154 
155-	union {
156-		struct ip_ct_ftp ct_ftp_info;
157-		struct ip_ct_irc ct_irc_info;
158-	} help;
159+	union ip_conntrack_help help;
160 
161 #ifdef CONFIG_IP_NF_NAT_NEEDED
162 	struct {
163 		struct ip_nat_info info;
164-		union {
165-			/* insert nat helper private data here */
166-		} help;
167+		union ip_conntrack_nat_help help;
168 #if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \
169 	defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE)
170 		int masq_index;
171@@ -140,6 +200,9 @@
172 
173 };
174 
175+/* get master conntrack via master expectation */
176+#define master_ct(conntr) (conntr->master ? conntr->master->expectant : NULL)
177+
178 /* Alter reply tuple (maybe alter helper).  If it's already taken,
179    return 0 and don't do alteration. */
180 extern int
181@@ -155,6 +218,16 @@
182 /* Return conntrack_info and tuple hash for given skb. */
183 extern struct ip_conntrack *
184 ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo);
185+
186+/* decrement reference count on a conntrack */
187+extern inline void ip_conntrack_put(struct ip_conntrack *ct);
188+
189+/* find unconfirmed expectation based on tuple */
190+struct ip_conntrack_expect *
191+ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple);
192+
193+/* decrement reference count on an expectation */
194+void ip_conntrack_expect_put(struct ip_conntrack_expect *exp);
195 
196 extern struct module *ip_conntrack_module;
197 
198diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/include/linux/netfilter_ipv4/ip_conntrack_core.h linux-2.4.20-plain/include/linux/netfilter_ipv4/ip_conntrack_core.h
199--- linux-2.4.19-plain/include/linux/netfilter_ipv4/ip_conntrack_core.h	Fri Apr 27 23:15:01 2001
200+++ linux-2.4.20-plain/include/linux/netfilter_ipv4/ip_conntrack_core.h	Fri Nov 29 00:53:15 2002
201@@ -15,9 +15,9 @@
202 extern void ip_conntrack_cleanup(void);
203 
204 struct ip_conntrack_protocol;
205-extern struct ip_conntrack_protocol *find_proto(u_int8_t protocol);
206+extern struct ip_conntrack_protocol *ip_ct_find_proto(u_int8_t protocol);
207 /* Like above, but you already have conntrack read lock. */
208-extern struct ip_conntrack_protocol *__find_proto(u_int8_t protocol);
209+extern struct ip_conntrack_protocol *__ip_ct_find_proto(u_int8_t protocol);
210 extern struct list_head protocol_list;
211 
212 /* Returns conntrack if it dealt with ICMP, and filled in skb->nfct */
213@@ -45,7 +45,7 @@
214 }
215 
216 extern struct list_head *ip_conntrack_hash;
217-extern struct list_head expect_list;
218+extern struct list_head ip_conntrack_expect_list;
219 DECLARE_RWLOCK_EXTERN(ip_conntrack_lock);
220 #endif /* _IP_CONNTRACK_CORE_H */
221 
222diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/include/linux/netfilter_ipv4/ip_conntrack_ftp.h linux-2.4.20-plain/include/linux/netfilter_ipv4/ip_conntrack_ftp.h
223--- linux-2.4.19-plain/include/linux/netfilter_ipv4/ip_conntrack_ftp.h	Thu Apr 26 00:00:28 2001
224+++ linux-2.4.20-plain/include/linux/netfilter_ipv4/ip_conntrack_ftp.h	Fri Nov 29 00:53:15 2002
225@@ -2,15 +2,17 @@
226 #define _IP_CONNTRACK_FTP_H
227 /* FTP tracking. */
228 
229-#ifndef __KERNEL__
230-#error Only in kernel.
231-#endif
232+#ifdef __KERNEL__
233 
234 #include <linux/netfilter_ipv4/lockhelp.h>
235 
236 /* Protects ftp part of conntracks */
237 DECLARE_LOCK_EXTERN(ip_ftp_lock);
238 
239+#define FTP_PORT	21
240+
241+#endif /* __KERNEL__ */
242+
243 enum ip_ct_ftp_type
244 {
245 	/* PORT command from client */
246@@ -23,18 +25,20 @@
247 	IP_CT_FTP_EPSV,
248 };
249 
250-/* We record seq number and length of ftp ip/port text here: all in
251-   host order. */
252-struct ip_ct_ftp
253+/* This structure is per expected connection */
254+struct ip_ct_ftp_expect
255 {
256-	/* This tells NAT that this is an ftp connection */
257-	int is_ftp;
258-	u_int32_t seq;
259-	/* 0 means not found yet */
260-	u_int32_t len;
261-	enum ip_ct_ftp_type ftptype;
262-	/* Port that was to be used */
263-	u_int16_t port;
264+	/* We record seq number and length of ftp ip/port text here: all in
265+	 * host order. */
266+
267+ 	/* sequence number of IP address in packet is in ip_conntrack_expect */
268+	u_int32_t len;			/* length of IP address */
269+	enum ip_ct_ftp_type ftptype;	/* PORT or PASV ? */
270+	u_int16_t port; 		/* TCP port that was to be used */
271+};
272+
273+/* This structure exists only once per master */
274+struct ip_ct_ftp_master {
275 	/* Next valid seq position for cmd matching after newline */
276 	u_int32_t seq_aft_nl[IP_CT_DIR_MAX];
277 	/* 0 means seq_match_aft_nl not set */
278diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/include/linux/netfilter_ipv4/ip_conntrack_helper.h linux-2.4.20-plain/include/linux/netfilter_ipv4/ip_conntrack_helper.h
279--- linux-2.4.19-plain/include/linux/netfilter_ipv4/ip_conntrack_helper.h	Mon Dec 11 22:31:23 2000
280+++ linux-2.4.20-plain/include/linux/netfilter_ipv4/ip_conntrack_helper.h	Fri Nov 29 00:53:15 2002
281@@ -5,10 +5,19 @@
282 
283 struct module;
284 
285+/* Reuse expectation when max_expected reached */
286+#define IP_CT_HELPER_F_REUSE_EXPECT	0x01
287+
288 struct ip_conntrack_helper
289 {	
290-	/* Internal use. */
291-	struct list_head list;
292+	struct list_head list; 		/* Internal use. */
293+
294+	const char *name;		/* name of the module */
295+	unsigned char flags;		/* Flags (see above) */
296+	struct module *me;		/* pointer to self */
297+	unsigned int max_expected;	/* Maximum number of concurrent 
298+					 * expected connections */
299+	unsigned int timeout;		/* timeout for expecteds */
300 
301 	/* Mask of things we will help (compared against server response) */
302 	struct ip_conntrack_tuple tuple;
303@@ -24,11 +33,13 @@
304 extern int ip_conntrack_helper_register(struct ip_conntrack_helper *);
305 extern void ip_conntrack_helper_unregister(struct ip_conntrack_helper *);
306 
307-/* Add an expected connection: can only have one per connection */
308+extern struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple);
309+
310+/* Add an expected connection: can have more than one per connection */
311 extern int ip_conntrack_expect_related(struct ip_conntrack *related_to,
312-				       const struct ip_conntrack_tuple *tuple,
313-				       const struct ip_conntrack_tuple *mask,
314-				       int (*expectfn)(struct ip_conntrack *));
315-extern void ip_conntrack_unexpect_related(struct ip_conntrack *related_to);
316+				       struct ip_conntrack_expect *exp);
317+extern int ip_conntrack_change_expect(struct ip_conntrack_expect *expect,
318+				      struct ip_conntrack_tuple *newtuple);
319+extern void ip_conntrack_unexpect_related(struct ip_conntrack_expect *exp);
320 
321 #endif /*_IP_CONNTRACK_HELPER_H*/
322diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/include/linux/netfilter_ipv4/ip_conntrack_irc.h linux-2.4.20-plain/include/linux/netfilter_ipv4/ip_conntrack_irc.h
323--- linux-2.4.19-plain/include/linux/netfilter_ipv4/ip_conntrack_irc.h	Wed Oct 31 00:08:12 2001
324+++ linux-2.4.20-plain/include/linux/netfilter_ipv4/ip_conntrack_irc.h	Fri Nov 29 00:53:15 2002
325@@ -14,13 +14,28 @@
326 #ifndef _IP_CONNTRACK_IRC_H
327 #define _IP_CONNTRACK_IRC_H
328 
329-#ifndef __KERNEL__
330-#error Only in kernel.
331-#endif
332+/* We record seq number and length of irc ip/port text here: all in
333+   host order. */
334+
335+/* This structure is per expected connection */
336+struct ip_ct_irc_expect
337+{
338+	/* length of IP address */
339+	u_int32_t len;
340+	/* Port that was to be used */
341+	u_int16_t port;
342+};
343+
344+/* This structure exists only once per master */
345+struct ip_ct_irc_master {
346+};
347+
348+
349+#ifdef __KERNEL__
350 
351 #include <linux/netfilter_ipv4/lockhelp.h>
352 
353-#define IP_CONNTR_IRC	2
354+#define IRC_PORT	6667
355 
356 struct dccproto {
357 	char* match;
358@@ -30,18 +45,6 @@
359 /* Protects irc part of conntracks */
360 DECLARE_LOCK_EXTERN(ip_irc_lock);
361 
362-/* We record seq number and length of irc ip/port text here: all in
363-   host order. */
364-struct ip_ct_irc
365-{
366-	/* This tells NAT that this is an IRC connection */
367-	int is_irc;
368-	/* sequence number where address part of DCC command begins */
369-	u_int32_t seq;
370-	/* 0 means not found yet */
371-	u_int32_t len;
372-	/* Port that was to be used */
373-	u_int16_t port;
374-};
375+#endif /* __KERNEL__ */
376 
377 #endif /* _IP_CONNTRACK_IRC_H */
378diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/include/linux/netfilter_ipv4/ip_conntrack_protocol.h linux-2.4.20-plain/include/linux/netfilter_ipv4/ip_conntrack_protocol.h
379--- linux-2.4.19-plain/include/linux/netfilter_ipv4/ip_conntrack_protocol.h	Sat Aug  3 02:39:45 2002
380+++ linux-2.4.20-plain/include/linux/netfilter_ipv4/ip_conntrack_protocol.h	Fri Nov 29 00:53:15 2002
381@@ -45,6 +45,10 @@
382 	/* Called when a conntrack entry is destroyed */
383 	void (*destroy)(struct ip_conntrack *conntrack);
384 
385+	/* Has to decide if a expectation matches one packet or not */
386+	int (*exp_matches_pkt)(struct ip_conntrack_expect *exp,
387+			       struct sk_buff **pskb);
388+
389 	/* Module (if any) which this is connected to. */
390 	struct module *me;
391 };
392diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/include/linux/netfilter_ipv4/ip_conntrack_tcp.h linux-2.4.20-plain/include/linux/netfilter_ipv4/ip_conntrack_tcp.h
393--- linux-2.4.19-plain/include/linux/netfilter_ipv4/ip_conntrack_tcp.h	Fri Aug  4 22:07:24 2000
394+++ linux-2.4.20-plain/include/linux/netfilter_ipv4/ip_conntrack_tcp.h	Fri Nov 29 00:53:15 2002
395@@ -2,10 +2,6 @@
396 #define _IP_CONNTRACK_TCP_H
397 /* TCP tracking. */
398 
399-#ifndef __KERNEL__
400-#error Only in kernel.
401-#endif
402-
403 enum tcp_conntrack {
404 	TCP_CONNTRACK_NONE,
405 	TCP_CONNTRACK_ESTABLISHED,
406diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/include/linux/netfilter_ipv4/ip_nat.h linux-2.4.20-plain/include/linux/netfilter_ipv4/ip_nat.h
407--- linux-2.4.19-plain/include/linux/netfilter_ipv4/ip_nat.h	Sat Aug  3 02:39:45 2002
408+++ linux-2.4.20-plain/include/linux/netfilter_ipv4/ip_nat.h	Fri Nov 29 00:53:15 2002
409@@ -60,22 +60,6 @@
410 	struct ip_nat_range range[1];
411 };
412 
413-#ifdef __KERNEL__
414-#include <linux/list.h>
415-#include <linux/netfilter_ipv4/lockhelp.h>
416-
417-/* Protects NAT hash tables, and NAT-private part of conntracks. */
418-DECLARE_RWLOCK_EXTERN(ip_nat_lock);
419-
420-/* Hashes for by-source and IP/protocol. */
421-struct ip_nat_hash
422-{
423-	struct list_head list;
424-
425-	/* conntrack we're embedded in: NULL if not in hash. */
426-	struct ip_conntrack *conntrack;
427-};
428-
429 /* Worst case: local-out manip + 1 post-routing, and reverse dirn. */
430 #define IP_NAT_MAX_MANIPS (2*3)
431 
432@@ -93,7 +77,23 @@
433 	/* Manipulations to occur at each conntrack in this dirn. */
434 	struct ip_conntrack_manip manip;
435 };
436-	
437+
438+#ifdef __KERNEL__
439+#include <linux/list.h>
440+#include <linux/netfilter_ipv4/lockhelp.h>
441+
442+/* Protects NAT hash tables, and NAT-private part of conntracks. */
443+DECLARE_RWLOCK_EXTERN(ip_nat_lock);
444+
445+/* Hashes for by-source and IP/protocol. */
446+struct ip_nat_hash
447+{
448+	struct list_head list;
449+
450+	/* conntrack we're embedded in: NULL if not in hash. */
451+	struct ip_conntrack *conntrack;
452+};
453+
454 /* The structure embedded in the conntrack structure. */
455 struct ip_nat_info
456 {
457diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/include/linux/netfilter_ipv4/ip_nat_helper.h linux-2.4.20-plain/include/linux/netfilter_ipv4/ip_nat_helper.h
458--- linux-2.4.19-plain/include/linux/netfilter_ipv4/ip_nat_helper.h	Thu Apr 26 00:00:28 2001
459+++ linux-2.4.20-plain/include/linux/netfilter_ipv4/ip_nat_helper.h	Fri Nov 29 00:53:15 2002
460@@ -6,23 +6,37 @@
461 
462 struct sk_buff;
463 
464+/* Flags */
465+/* NAT helper must be called on every packet (for TCP) */
466+#define IP_NAT_HELPER_F_ALWAYS		0x01
467+/* Standalone NAT helper, without a conntrack part */
468+#define IP_NAT_HELPER_F_STANDALONE	0x02
469+
470 struct ip_nat_helper
471 {
472-	/* Internal use */
473-	struct list_head list;
474+	struct list_head list;		/* Internal use */
475 
476+	const char *name;		/* name of the module */
477+	unsigned char flags;		/* Flags (see above) */
478+	struct module *me;		/* pointer to self */
479+	
480 	/* Mask of things we will help: vs. tuple from server */
481 	struct ip_conntrack_tuple tuple;
482 	struct ip_conntrack_tuple mask;
483 	
484 	/* Helper function: returns verdict */
485 	unsigned int (*help)(struct ip_conntrack *ct,
486+			     struct ip_conntrack_expect *exp,
487 			     struct ip_nat_info *info,
488 			     enum ip_conntrack_info ctinfo,
489 			     unsigned int hooknum,
490 			     struct sk_buff **pskb);
491 
492-	const char *name;
493+	/* Returns verdict and sets up NAT for this connection */
494+	unsigned int (*expect)(struct sk_buff **pskb,
495+			       unsigned int hooknum,
496+			       struct ip_conntrack *ct,
497+			       struct ip_nat_info *info);
498 };
499 
500 extern struct list_head helpers;
501@@ -39,5 +53,5 @@
502 extern int ip_nat_seq_adjust(struct sk_buff *skb,
503 				struct ip_conntrack *ct,
504 				enum ip_conntrack_info ctinfo);
505-extern void ip_nat_delete_sack(struct sk_buff *skb, struct tcphdr *tcph);
506+extern void ip_nat_delete_sack(struct sk_buff *skb);
507 #endif
508diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/include/linux/netfilter_ipv4/ip_nat_rule.h linux-2.4.20-plain/include/linux/netfilter_ipv4/ip_nat_rule.h
509--- linux-2.4.19-plain/include/linux/netfilter_ipv4/ip_nat_rule.h	Mon Dec 11 22:31:32 2000
510+++ linux-2.4.20-plain/include/linux/netfilter_ipv4/ip_nat_rule.h	Fri Nov 29 00:53:15 2002
511@@ -5,24 +5,7 @@
512 #include <linux/netfilter_ipv4/ip_nat.h>
513 
514 #ifdef __KERNEL__
515-/* Want to be told when we first NAT an expected packet for a conntrack? */
516-struct ip_nat_expect
517-{
518-	struct list_head list;
519 
520-	/* Returns 1 (and sets verdict) if it has setup NAT for this
521-           connection */
522-	int (*expect)(struct sk_buff **pskb,
523-		      unsigned int hooknum,
524-		      struct ip_conntrack *ct,
525-		      struct ip_nat_info *info,
526-		      struct ip_conntrack *master,
527-		      struct ip_nat_info *masterinfo,
528-		      unsigned int *verdict);
529-};
530-
531-extern int ip_nat_expect_register(struct ip_nat_expect *expect);
532-extern void ip_nat_expect_unregister(struct ip_nat_expect *expect);
533 extern int ip_nat_rule_init(void) __init;
534 extern void ip_nat_rule_cleanup(void);
535 extern int ip_nat_rule_find(struct sk_buff **pskb,
536diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/include/linux/netfilter_ipv4/ipt_DSCP.h linux-2.4.20-plain/include/linux/netfilter_ipv4/ipt_DSCP.h
537--- linux-2.4.19-plain/include/linux/netfilter_ipv4/ipt_DSCP.h	Thu Jan  1 01:00:00 1970
538+++ linux-2.4.20-plain/include/linux/netfilter_ipv4/ipt_DSCP.h	Fri Nov 29 00:53:15 2002
539@@ -0,0 +1,20 @@
540+/* iptables module for setting the IPv4 DSCP field
541+ *
542+ * (C) 2002 Harald Welte <laforge@gnumonks.org>
543+ * based on ipt_FTOS.c (C) 2000 by Matthew G. Marsh <mgm@paktronix.com>
544+ * This software is distributed under GNU GPL v2, 1991
545+ * 
546+ * See RFC2474 for a description of the DSCP field within the IP Header.
547+ *
548+ * ipt_DSCP.h,v 1.7 2002/03/14 12:03:13 laforge Exp
549+*/
550+#ifndef _IPT_DSCP_TARGET_H
551+#define _IPT_DSCP_TARGET_H
552+#include <linux/netfilter_ipv4/ipt_dscp.h>
553+
554+/* target info */
555+struct ipt_DSCP_info {
556+	u_int8_t dscp;
557+};
558+
559+#endif /* _IPT_DSCP_TARGET_H */
560diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/include/linux/netfilter_ipv4/ipt_ECN.h linux-2.4.20-plain/include/linux/netfilter_ipv4/ipt_ECN.h
561--- linux-2.4.19-plain/include/linux/netfilter_ipv4/ipt_ECN.h	Thu Jan  1 01:00:00 1970
562+++ linux-2.4.20-plain/include/linux/netfilter_ipv4/ipt_ECN.h	Fri Nov 29 00:53:15 2002
563@@ -0,0 +1,31 @@
564+/* Header file for iptables ipt_ECN target
565+ *
566+ * (C) 2002 by Harald Welte <laforge@gnumonks.org>
567+ *
568+ * This software is distributed under GNU GPL v2, 1991
569+ * 
570+ * ipt_ECN.h,v 1.3 2002/05/29 12:17:40 laforge Exp
571+*/
572+#ifndef _IPT_ECN_TARGET_H
573+#define _IPT_ECN_TARGET_H
574+#include <linux/netfilter_ipv4/ipt_DSCP.h>
575+
576+#define IPT_ECN_IP_MASK	(~IPT_DSCP_MASK)
577+
578+#define IPT_ECN_OP_SET_IP	0x01	/* set ECN bits of IPv4 header */
579+#define IPT_ECN_OP_SET_ECE	0x10	/* set ECE bit of TCP header */
580+#define IPT_ECN_OP_SET_CWR	0x20	/* set CWR bit of TCP header */
581+
582+#define IPT_ECN_OP_MASK		0xce
583+
584+struct ipt_ECN_info {
585+	u_int8_t operation;	/* bitset of operations */
586+	u_int8_t ip_ect;	/* ECT codepoint of IPv4 header, pre-shifted */
587+	union {
588+		struct {
589+			u_int8_t ece:1, cwr:1; /* TCP ECT bits */
590+		} tcp;
591+	} proto;
592+};
593+
594+#endif /* _IPT_ECN_TARGET_H */
595diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/include/linux/netfilter_ipv4/ipt_conntrack.h linux-2.4.20-plain/include/linux/netfilter_ipv4/ipt_conntrack.h
596--- linux-2.4.19-plain/include/linux/netfilter_ipv4/ipt_conntrack.h	Thu Jan  1 01:00:00 1970
597+++ linux-2.4.20-plain/include/linux/netfilter_ipv4/ipt_conntrack.h	Fri Nov 29 00:53:15 2002
598@@ -0,0 +1,38 @@
599+/* Header file for kernel module to match connection tracking information.
600+ * GPL (C) 2001  Marc Boucher (marc@mbsi.ca).
601+ */
602+
603+#ifndef _IPT_CONNTRACK_H
604+#define _IPT_CONNTRACK_H
605+
606+#define IPT_CONNTRACK_STATE_BIT(ctinfo) (1 << ((ctinfo)%IP_CT_IS_REPLY+1))
607+#define IPT_CONNTRACK_STATE_INVALID (1 << 0)
608+
609+#define IPT_CONNTRACK_STATE_SNAT (1 << (IP_CT_NUMBER + 1))
610+#define IPT_CONNTRACK_STATE_DNAT (1 << (IP_CT_NUMBER + 2))
611+
612+/* flags, invflags: */
613+#define IPT_CONNTRACK_STATE	0x01
614+#define IPT_CONNTRACK_PROTO	0x02
615+#define IPT_CONNTRACK_ORIGSRC	0x04
616+#define IPT_CONNTRACK_ORIGDST	0x08
617+#define IPT_CONNTRACK_REPLSRC	0x10
618+#define IPT_CONNTRACK_REPLDST	0x20
619+#define IPT_CONNTRACK_STATUS	0x40
620+#define IPT_CONNTRACK_EXPIRES	0x80
621+
622+struct ipt_conntrack_info
623+{
624+	unsigned int statemask, statusmask;
625+
626+	struct ip_conntrack_tuple tuple[IP_CT_DIR_MAX];
627+	struct in_addr sipmsk[IP_CT_DIR_MAX], dipmsk[IP_CT_DIR_MAX];
628+
629+	unsigned long expires_min, expires_max;
630+
631+	/* Flags word */
632+	u_int8_t flags;
633+	/* Inverse flags */
634+	u_int8_t invflags;
635+};
636+#endif /*_IPT_CONNTRACK_H*/
637diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/include/linux/netfilter_ipv4/ipt_dscp.h linux-2.4.20-plain/include/linux/netfilter_ipv4/ipt_dscp.h
638--- linux-2.4.19-plain/include/linux/netfilter_ipv4/ipt_dscp.h	Thu Jan  1 01:00:00 1970
639+++ linux-2.4.20-plain/include/linux/netfilter_ipv4/ipt_dscp.h	Fri Nov 29 00:53:15 2002
640@@ -0,0 +1,23 @@
641+/* iptables module for matching the IPv4 DSCP field
642+ *
643+ * (C) 2002 Harald Welte <laforge@gnumonks.org>
644+ * This software is distributed under GNU GPL v2, 1991
645+ * 
646+ * See RFC2474 for a description of the DSCP field within the IP Header.
647+ *
648+ * ipt_dscp.h,v 1.3 2002/08/05 19:00:21 laforge Exp
649+*/
650+#ifndef _IPT_DSCP_H
651+#define _IPT_DSCP_H
652+
653+#define IPT_DSCP_MASK	0xfc	/* 11111100 */
654+#define IPT_DSCP_SHIFT	2
655+#define IPT_DSCP_MAX	0x3f	/* 00111111 */
656+
657+/* match info */
658+struct ipt_dscp_info {
659+	u_int8_t dscp;
660+	u_int8_t invert;
661+};
662+
663+#endif /* _IPT_DSCP_H */
664diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/include/linux/netfilter_ipv4/ipt_ecn.h linux-2.4.20-plain/include/linux/netfilter_ipv4/ipt_ecn.h
665--- linux-2.4.19-plain/include/linux/netfilter_ipv4/ipt_ecn.h	Thu Jan  1 01:00:00 1970
666+++ linux-2.4.20-plain/include/linux/netfilter_ipv4/ipt_ecn.h	Fri Nov 29 00:53:15 2002
667@@ -0,0 +1,33 @@
668+/* iptables module for matching the ECN header in IPv4 and TCP header
669+ *
670+ * (C) 2002 Harald Welte <laforge@gnumonks.org>
671+ *
672+ * This software is distributed under GNU GPL v2, 1991
673+ * 
674+ * ipt_ecn.h,v 1.4 2002/08/05 19:39:00 laforge Exp
675+*/
676+#ifndef _IPT_ECN_H
677+#define _IPT_ECN_H
678+#include <linux/netfilter_ipv4/ipt_dscp.h>
679+
680+#define IPT_ECN_IP_MASK	(~IPT_DSCP_MASK)
681+
682+#define IPT_ECN_OP_MATCH_IP	0x01
683+#define IPT_ECN_OP_MATCH_ECE	0x10
684+#define IPT_ECN_OP_MATCH_CWR	0x20
685+
686+#define IPT_ECN_OP_MATCH_MASK	0xce
687+
688+/* match info */
689+struct ipt_ecn_info {
690+	u_int8_t operation;
691+	u_int8_t invert;
692+	u_int8_t ip_ect;
693+	union {
694+		struct {
695+			u_int8_t ect;
696+		} tcp;
697+	} proto;
698+};
699+
700+#endif /* _IPT_ECN_H */
701diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/include/linux/netfilter_ipv4/ipt_helper.h linux-2.4.20-plain/include/linux/netfilter_ipv4/ipt_helper.h
702--- linux-2.4.19-plain/include/linux/netfilter_ipv4/ipt_helper.h	Thu Jan  1 01:00:00 1970
703+++ linux-2.4.20-plain/include/linux/netfilter_ipv4/ipt_helper.h	Fri Nov 29 00:53:15 2002
704@@ -0,0 +1,8 @@
705+#ifndef _IPT_HELPER_H
706+#define _IPT_HELPER_H
707+
708+struct ipt_helper_info {
709+	int invert;
710+	char name[30];
711+};
712+#endif /* _IPT_HELPER_H */
713diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/include/linux/netfilter_ipv4/ipt_owner.h linux-2.4.20-plain/include/linux/netfilter_ipv4/ipt_owner.h
714--- linux-2.4.19-plain/include/linux/netfilter_ipv4/ipt_owner.h	Fri Mar 17 19:56:20 2000
715+++ linux-2.4.20-plain/include/linux/netfilter_ipv4/ipt_owner.h	Fri Nov 29 00:53:15 2002
716@@ -6,12 +6,14 @@
717 #define IPT_OWNER_GID	0x02
718 #define IPT_OWNER_PID	0x04
719 #define IPT_OWNER_SID	0x08
720+#define IPT_OWNER_COMM	0x10
721 
722 struct ipt_owner_info {
723     uid_t uid;
724     gid_t gid;
725     pid_t pid;
726     pid_t sid;
727+    char comm[16];
728     u_int8_t match, invert;	/* flags */
729 };
730 
731diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/include/linux/netfilter_ipv4/ipt_pkttype.h linux-2.4.20-plain/include/linux/netfilter_ipv4/ipt_pkttype.h
732--- linux-2.4.19-plain/include/linux/netfilter_ipv4/ipt_pkttype.h	Thu Jan  1 01:00:00 1970
733+++ linux-2.4.20-plain/include/linux/netfilter_ipv4/ipt_pkttype.h	Fri Nov 29 00:53:15 2002
734@@ -0,0 +1,8 @@
735+#ifndef _IPT_PKTTYPE_H
736+#define _IPT_PKTTYPE_H
737+
738+struct ipt_pkttype_info {
739+	int	pkttype;
740+	int	invert;
741+};
742+#endif /*_IPT_PKTTYPE_H*/
743diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/include/linux/netfilter_ipv6/ip6t_length.h linux-2.4.20-plain/include/linux/netfilter_ipv6/ip6t_length.h
744--- linux-2.4.19-plain/include/linux/netfilter_ipv6/ip6t_length.h	Thu Jan  1 01:00:00 1970
745+++ linux-2.4.20-plain/include/linux/netfilter_ipv6/ip6t_length.h	Fri Nov 29 00:53:15 2002
746@@ -0,0 +1,10 @@
747+#ifndef _IP6T_LENGTH_H
748+#define _IP6T_LENGTH_H
749+
750+struct ip6t_length_info {
751+	u_int16_t  min, max;
752+	u_int8_t   invert;
753+};
754+
755+#endif /*_IP6T_LENGTH_H*/
756+	
757diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv4/netfilter/Config.in linux-2.4.20-plain/net/ipv4/netfilter/Config.in
758--- linux-2.4.19-plain/net/ipv4/netfilter/Config.in	Sat Aug  3 02:39:46 2002
759+++ linux-2.4.20-plain/net/ipv4/netfilter/Config.in	Fri Nov 29 00:53:15 2002
760@@ -18,15 +18,24 @@
761 # The simple matches.
762   dep_tristate '  limit match support' CONFIG_IP_NF_MATCH_LIMIT $CONFIG_IP_NF_IPTABLES
763   dep_tristate '  MAC address match support' CONFIG_IP_NF_MATCH_MAC $CONFIG_IP_NF_IPTABLES
764+  dep_tristate '  Packet type match support' CONFIG_IP_NF_MATCH_PKTTYPE $CONFIG_IP_NF_IPTABLES
765   dep_tristate '  netfilter MARK match support' CONFIG_IP_NF_MATCH_MARK $CONFIG_IP_NF_IPTABLES
766   dep_tristate '  Multiple port match support' CONFIG_IP_NF_MATCH_MULTIPORT $CONFIG_IP_NF_IPTABLES
767   dep_tristate '  TOS match support' CONFIG_IP_NF_MATCH_TOS $CONFIG_IP_NF_IPTABLES
768+  dep_tristate '  ECN match support' CONFIG_IP_NF_MATCH_ECN $CONFIG_IP_NF_IPTABLES
769+ 
770+  dep_tristate '  DSCP match support' CONFIG_IP_NF_MATCH_DSCP $CONFIG_IP_NF_IPTABLES
771+ 
772   dep_tristate '  AH/ESP match support' CONFIG_IP_NF_MATCH_AH_ESP $CONFIG_IP_NF_IPTABLES
773   dep_tristate '  LENGTH match support' CONFIG_IP_NF_MATCH_LENGTH $CONFIG_IP_NF_IPTABLES
774   dep_tristate '  TTL match support' CONFIG_IP_NF_MATCH_TTL $CONFIG_IP_NF_IPTABLES
775   dep_tristate '  tcpmss match support' CONFIG_IP_NF_MATCH_TCPMSS $CONFIG_IP_NF_IPTABLES
776   if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then
777+    dep_tristate '  Helper match support' CONFIG_IP_NF_MATCH_HELPER $CONFIG_IP_NF_IPTABLES
778+  fi
779+  if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then
780     dep_tristate '  Connection state match support' CONFIG_IP_NF_MATCH_STATE $CONFIG_IP_NF_CONNTRACK $CONFIG_IP_NF_IPTABLES 
781+    dep_tristate '  Connection tracking match support' CONFIG_IP_NF_MATCH_CONNTRACK $CONFIG_IP_NF_CONNTRACK $CONFIG_IP_NF_IPTABLES 
782   fi
783   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
784     dep_tristate '  Unclean match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_UNCLEAN $CONFIG_IP_NF_IPTABLES
785@@ -73,6 +82,10 @@
786   dep_tristate '  Packet mangling' CONFIG_IP_NF_MANGLE $CONFIG_IP_NF_IPTABLES 
787   if [ "$CONFIG_IP_NF_MANGLE" != "n" ]; then
788     dep_tristate '    TOS target support' CONFIG_IP_NF_TARGET_TOS $CONFIG_IP_NF_MANGLE
789+    dep_tristate '    ECN target support' CONFIG_IP_NF_TARGET_ECN $CONFIG_IP_NF_MANGLE
790+ 
791+    dep_tristate '    DSCP target support' CONFIG_IP_NF_TARGET_DSCP $CONFIG_IP_NF_MANGLE
792+ 
793     dep_tristate '    MARK target support' CONFIG_IP_NF_TARGET_MARK $CONFIG_IP_NF_MANGLE
794   fi
795   dep_tristate '  LOG target support' CONFIG_IP_NF_TARGET_LOG $CONFIG_IP_NF_IPTABLES
796diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv4/netfilter/Makefile linux-2.4.20-plain/net/ipv4/netfilter/Makefile
797--- linux-2.4.19-plain/net/ipv4/netfilter/Makefile	Sat Aug  3 02:39:46 2002
798+++ linux-2.4.20-plain/net/ipv4/netfilter/Makefile	Fri Nov 29 00:53:15 2002
799@@ -9,18 +9,18 @@
800 
801 O_TARGET := netfilter.o
802 
803-export-objs = ip_conntrack_standalone.o ip_conntrack_ftp.o ip_fw_compat.o ip_nat_standalone.o ip_tables.o arp_tables.o
804+export-objs = ip_conntrack_standalone.o ip_fw_compat.o ip_nat_standalone.o ip_tables.o arp_tables.o
805 
806 # Multipart objects.
807 list-multi		:= ip_conntrack.o iptable_nat.o ipfwadm.o ipchains.o
808 
809 # objects for the conntrack and NAT core (used by standalone and backw. compat)
810 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
811-ip_nf_nat-objs		:= ip_nat_core.o ip_nat_proto_unknown.o ip_nat_proto_tcp.o ip_nat_proto_udp.o ip_nat_proto_icmp.o
812+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
813 
814 # objects for the standalone - connection tracking / NAT
815 ip_conntrack-objs	:= ip_conntrack_standalone.o $(ip_nf_conntrack-objs)
816-iptable_nat-objs	:= ip_nat_standalone.o ip_nat_rule.o ip_nat_helper.o $(ip_nf_nat-objs)
817+iptable_nat-objs	:= ip_nat_standalone.o ip_nat_rule.o $(ip_nf_nat-objs)
818 
819 # objects for backwards compatibility mode
820 ip_nf_compat-objs	:= ip_fw_compat.o ip_fw_compat_redir.o ip_fw_compat_masq.o $(ip_nf_conntrack-objs) $(ip_nf_nat-objs)
821@@ -33,7 +33,14 @@
822 
823 # connection tracking helpers
824 obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o
825+ifdef CONFIG_IP_NF_NAT_FTP
826+	export-objs += ip_conntrack_ftp.o
827+endif
828+
829 obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o
830+ifdef CONFIG_IP_NF_NAT_IRC
831+	export-objs += ip_conntrack_irc.o
832+endif
833 
834 # NAT helpers 
835 obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o
836@@ -48,18 +55,24 @@
837 obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o
838 
839 # matches
840+obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o
841 obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o
842 obj-$(CONFIG_IP_NF_MATCH_MARK) += ipt_mark.o
843 obj-$(CONFIG_IP_NF_MATCH_MAC) += ipt_mac.o
844+
845+obj-$(CONFIG_IP_NF_MATCH_PKTTYPE) += ipt_pkttype.o
846 obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o
847 obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o
848 obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
849+obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o
850+obj-$(CONFIG_IP_NF_MATCH_DSCP) += ipt_dscp.o
851 obj-$(CONFIG_IP_NF_MATCH_AH_ESP) += ipt_ah.o ipt_esp.o
852 
853 obj-$(CONFIG_IP_NF_MATCH_LENGTH) += ipt_length.o
854 
855 obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
856 obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o
857+obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o
858 obj-$(CONFIG_IP_NF_MATCH_UNCLEAN) += ipt_unclean.o
859 obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o
860 
861@@ -67,6 +80,8 @@
862 obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
863 obj-$(CONFIG_IP_NF_TARGET_MIRROR) += ipt_MIRROR.o
864 obj-$(CONFIG_IP_NF_TARGET_TOS) += ipt_TOS.o
865+obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o
866+obj-$(CONFIG_IP_NF_TARGET_DSCP) += ipt_DSCP.o
867 obj-$(CONFIG_IP_NF_TARGET_MARK) += ipt_MARK.o
868 obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
869 obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
870diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv4/netfilter/ip_conntrack_core.c linux-2.4.20-plain/net/ipv4/netfilter/ip_conntrack_core.c
871--- linux-2.4.19-plain/net/ipv4/netfilter/ip_conntrack_core.c	Sat Aug  3 02:39:46 2002
872+++ linux-2.4.20-plain/net/ipv4/netfilter/ip_conntrack_core.c	Fri Nov 29 00:53:15 2002
873@@ -3,7 +3,15 @@
874    extension. */
875 
876 /* (c) 1999 Paul `Rusty' Russell.  Licenced under the GNU General
877-   Public Licence. */
878+ * Public Licence. 
879+ *
880+ * 23 Apr 2001: Harald Welte <laforge@gnumonks.org>
881+ * 	- new API and handling of conntrack/nat helpers
882+ * 	- now capable of multiple expectations for one master
883+ * 16 Jul 2002: Harald Welte <laforge@gnumonks.org>
884+ * 	- add usage/reference counts to ip_conntrack_expect
885+ *	- export ip_conntrack[_expect]_{find_get,put} functions
886+ * */
887 
888 #ifdef MODULE
889 #define __NO_VERSION__
890@@ -37,6 +45,8 @@
891 #include <linux/netfilter_ipv4/ip_conntrack_core.h>
892 #include <linux/netfilter_ipv4/listhelp.h>
893 
894+#define IP_CONNTRACK_VERSION	"2.1"
895+
896 #if 0
897 #define DEBUGP printk
898 #else
899@@ -44,9 +54,10 @@
900 #endif
901 
902 DECLARE_RWLOCK(ip_conntrack_lock);
903+DECLARE_RWLOCK(ip_conntrack_expect_tuple_lock);
904 
905 void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack) = NULL;
906-LIST_HEAD(expect_list);
907+LIST_HEAD(ip_conntrack_expect_list);
908 LIST_HEAD(protocol_list);
909 static LIST_HEAD(helpers);
910 unsigned int ip_conntrack_htable_size = 0;
911@@ -63,7 +74,7 @@
912 	return protocol == curr->proto;
913 }
914 
915-struct ip_conntrack_protocol *__find_proto(u_int8_t protocol)
916+struct ip_conntrack_protocol *__ip_ct_find_proto(u_int8_t protocol)
917 {
918 	struct ip_conntrack_protocol *p;
919 
920@@ -76,17 +87,18 @@
921 	return p;
922 }
923 
924-struct ip_conntrack_protocol *find_proto(u_int8_t protocol)
925+struct ip_conntrack_protocol *ip_ct_find_proto(u_int8_t protocol)
926 {
927 	struct ip_conntrack_protocol *p;
928 
929 	READ_LOCK(&ip_conntrack_lock);
930-	p = __find_proto(protocol);
931+	p = __ip_ct_find_proto(protocol);
932 	READ_UNLOCK(&ip_conntrack_lock);
933 	return p;
934 }
935 
936-static inline void ip_conntrack_put(struct ip_conntrack *ct)
937+inline void 
938+ip_conntrack_put(struct ip_conntrack *ct)
939 {
940 	IP_NF_ASSERT(ct);
941 	IP_NF_ASSERT(ct->infos[0].master);
942@@ -150,9 +162,135 @@
943 	return protocol->invert_tuple(inverse, orig);
944 }
945 
946+
947+/* ip_conntrack_expect helper functions */
948+
949+/* Compare tuple parts depending on mask. */
950+static inline int expect_cmp(const struct ip_conntrack_expect *i,
951+			     const struct ip_conntrack_tuple *tuple)
952+{
953+	MUST_BE_READ_LOCKED(&ip_conntrack_expect_tuple_lock);
954+	return ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask);
955+}
956+
957+static void
958+destroy_expect(struct ip_conntrack_expect *exp)
959+{
960+	DEBUGP("destroy_expect(%p) use=%d\n", exp, atomic_read(exp->use));
961+	IP_NF_ASSERT(atomic_read(exp->use));
962+	IP_NF_ASSERT(!timer_pending(&exp->timeout));
963+
964+	kfree(exp);
965+}
966+
967+
968+inline void ip_conntrack_expect_put(struct ip_conntrack_expect *exp)
969+{
970+	IP_NF_ASSERT(exp);
971+
972+	if (atomic_dec_and_test(&exp->use)) {
973+		/* usage count dropped to zero */
974+		destroy_expect(exp);
975+	}
976+}
977+
978+static inline struct ip_conntrack_expect *
979+__ip_ct_expect_find(const struct ip_conntrack_tuple *tuple)
980+{
981+	MUST_BE_READ_LOCKED(&ip_conntrack_lock);
982+	MUST_BE_READ_LOCKED(&ip_conntrack_expect_tuple_lock);
983+	return LIST_FIND(&ip_conntrack_expect_list, expect_cmp, 
984+			 struct ip_conntrack_expect *, tuple);
985+}
986+
987+/* Find a expectation corresponding to a tuple. */
988+struct ip_conntrack_expect *
989+ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple)
990+{
991+	struct ip_conntrack_expect *exp;
992+
993+	READ_LOCK(&ip_conntrack_lock);
994+	READ_LOCK(&ip_conntrack_expect_tuple_lock);
995+	exp = __ip_ct_expect_find(tuple);
996+	if (exp)
997+		atomic_inc(&exp->use);
998+	READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
999+	READ_UNLOCK(&ip_conntrack_lock);
1000+
1001+	return exp;
1002+}
1003+
1004+/* remove one specific expectation from all lists and drop refcount,
1005+ * does _NOT_ delete the timer. */
1006+static void __unexpect_related(struct ip_conntrack_expect *expect)
1007+{
1008+	DEBUGP("unexpect_related(%p)\n", expect);
1009+	MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
1010+
1011+	/* we're not allowed to unexpect a confirmed expectation! */
1012+	IP_NF_ASSERT(!expect->sibling);
1013+
1014+	/* delete from global and local lists */
1015+	list_del(&expect->list);
1016+	list_del(&expect->expected_list);
1017+
1018+	/* decrement expect-count of master conntrack */
1019+	if (expect->expectant)
1020+		expect->expectant->expecting--;
1021+
1022+	ip_conntrack_expect_put(expect);
1023+}
1024+
1025+/* remove one specific expecatation from all lists, drop refcount
1026+ * and expire timer. 
1027+ * This function can _NOT_ be called for confirmed expects! */
1028+static void unexpect_related(struct ip_conntrack_expect *expect)
1029+{
1030+	IP_NF_ASSERT(expect->expectant);
1031+	IP_NF_ASSERT(expect->expectant->helper);
1032+	/* if we are supposed to have a timer, but we can't delete
1033+	 * it: race condition.  __unexpect_related will
1034+	 * be calledd by timeout function */
1035+	if (expect->expectant->helper->timeout
1036+	    && !del_timer(&expect->timeout))
1037+		return;
1038+
1039+	__unexpect_related(expect);
1040+}
1041+
1042+/* delete all unconfirmed expectations for this conntrack */
1043+static void remove_expectations(struct ip_conntrack *ct)
1044+{
1045+	struct list_head *exp_entry, *next;
1046+	struct ip_conntrack_expect *exp;
1047+
1048+	DEBUGP("remove_expectations(%p)\n", ct);
1049+
1050+	for (exp_entry = ct->sibling_list.next;
1051+	     exp_entry != &ct->sibling_list; exp_entry = next) {
1052+		next = exp_entry->next;
1053+		exp = list_entry(exp_entry, struct ip_conntrack_expect,
1054+				 expected_list);
1055+
1056+		/* we skip established expectations, as we want to delete
1057+		 * the un-established ones only */
1058+		if (exp->sibling) {
1059+			DEBUGP("remove_expectations: skipping established %p of %p\n", exp->sibling, ct);
1060+			continue;
1061+		}
1062+
1063+		IP_NF_ASSERT(list_inlist(&ip_conntrack_expect_list, exp));
1064+		IP_NF_ASSERT(exp->expectant == ct);
1065+
1066+		/* delete expectation from global and private lists */
1067+		unexpect_related(exp);
1068+	}
1069+}
1070+
1071 static void
1072 clean_from_lists(struct ip_conntrack *ct)
1073 {
1074+	DEBUGP("clean_from_lists(%p)\n", ct);
1075 	MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
1076 	/* Remove from both hash lists: must not NULL out next ptrs,
1077            otherwise we'll look unconfirmed.  Fortunately, LIST_DELETE
1078@@ -163,12 +301,9 @@
1079 	LIST_DELETE(&ip_conntrack_hash
1080 		    [hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple)],
1081 		    &ct->tuplehash[IP_CT_DIR_REPLY]);
1082-	/* If our expected is in the list, take it out. */
1083-	if (ct->expected.expectant) {
1084-		IP_NF_ASSERT(list_inlist(&expect_list, &ct->expected));
1085-		IP_NF_ASSERT(ct->expected.expectant == ct);
1086-		LIST_DELETE(&expect_list, &ct->expected);
1087-	}
1088+
1089+	/* Destroy all un-established, pending expectations */
1090+	remove_expectations(ct);
1091 }
1092 
1093 static void
1094@@ -177,21 +312,34 @@
1095 	struct ip_conntrack *ct = (struct ip_conntrack *)nfct;
1096 	struct ip_conntrack_protocol *proto;
1097 
1098+	DEBUGP("destroy_conntrack(%p)\n", ct);
1099 	IP_NF_ASSERT(atomic_read(&nfct->use) == 0);
1100 	IP_NF_ASSERT(!timer_pending(&ct->timeout));
1101 
1102-	if (ct->master.master)
1103-		nf_conntrack_put(&ct->master);
1104+	if (ct->master && master_ct(ct))
1105+		ip_conntrack_put(master_ct(ct));
1106 
1107 	/* To make sure we don't get any weird locking issues here:
1108 	 * destroy_conntrack() MUST NOT be called with a write lock
1109 	 * to ip_conntrack_lock!!! -HW */
1110-	proto = find_proto(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum);
1111+	proto = ip_ct_find_proto(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum);
1112 	if (proto && proto->destroy)
1113 		proto->destroy(ct);
1114 
1115 	if (ip_conntrack_destroyed)
1116 		ip_conntrack_destroyed(ct);
1117+
1118+	WRITE_LOCK(&ip_conntrack_lock);
1119+	/* Delete our master expectation */
1120+	if (ct->master) {
1121+		/* can't call __unexpect_related here,
1122+		 * since it would screw up expect_list */
1123+		list_del(&ct->master->expected_list);
1124+		kfree(ct->master);
1125+	}
1126+	WRITE_UNLOCK(&ip_conntrack_lock);
1127+
1128+	DEBUGP("destroy_conntrack: returning ct=%p to slab\n", ct);
1129 	kmem_cache_free(ip_conntrack_cachep, ct);
1130 	atomic_dec(&ip_conntrack_count);
1131 }
1132@@ -315,7 +463,7 @@
1133 			     &ct->tuplehash[IP_CT_DIR_REPLY]);
1134 		/* Timer relative to confirmation time, not original
1135 		   setting time, otherwise we'd get timer wrap in
1136-		   wierd delay cases. */
1137+		   weird delay cases. */
1138 		ct->timeout.expires += jiffies;
1139 		add_timer(&ct->timeout);
1140 		atomic_inc(&ct->ct_general.use);
1141@@ -389,7 +537,7 @@
1142 		return NULL;
1143 	}
1144 
1145-	innerproto = find_proto(inner->protocol);
1146+	innerproto = ip_ct_find_proto(inner->protocol);
1147 	/* Are they talking about one of our connections? */
1148 	if (inner->ihl * 4 + 8 > datalen
1149 	    || !get_tuple(inner, datalen, &origtuple, innerproto)) {
1150@@ -469,11 +617,11 @@
1151 	return ip_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask);
1152 }
1153 
1154-/* Compare parts depending on mask. */
1155-static inline int expect_cmp(const struct ip_conntrack_expect *i,
1156-			     const struct ip_conntrack_tuple *tuple)
1157+struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple)
1158 {
1159-	return ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask);
1160+	return LIST_FIND(&helpers, helper_cmp,
1161+			 struct ip_conntrack_helper *,
1162+			 tuple);
1163 }
1164 
1165 /* Allocate a new conntrack: we return -ENOMEM if classification
1166@@ -521,7 +669,7 @@
1167 		return ERR_PTR(-ENOMEM);
1168 	}
1169 
1170-	memset(conntrack, 0, sizeof(struct ip_conntrack));
1171+	memset(conntrack, 0, sizeof(*conntrack));
1172 	atomic_set(&conntrack->ct_general.use, 1);
1173 	conntrack->ct_general.destroy = destroy_conntrack;
1174 	conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *tuple;
1175@@ -540,31 +688,44 @@
1176 	conntrack->timeout.data = (unsigned long)conntrack;
1177 	conntrack->timeout.function = death_by_timeout;
1178 
1179+	INIT_LIST_HEAD(&conntrack->sibling_list);
1180+
1181 	/* Mark clearly that it's not in the hash table. */
1182 	conntrack->tuplehash[IP_CT_DIR_ORIGINAL].list.next = NULL;
1183 
1184-	/* Write lock required for deletion of expected.  Without
1185-           this, a read-lock would do. */
1186 	WRITE_LOCK(&ip_conntrack_lock);
1187-	conntrack->helper = LIST_FIND(&helpers, helper_cmp,
1188-				      struct ip_conntrack_helper *,
1189-				      &repl_tuple);
1190 	/* Need finding and deleting of expected ONLY if we win race */
1191-	expected = LIST_FIND(&expect_list, expect_cmp,
1192+	READ_LOCK(&ip_conntrack_expect_tuple_lock);
1193+	expected = LIST_FIND(&ip_conntrack_expect_list, expect_cmp,
1194 			     struct ip_conntrack_expect *, tuple);
1195+	READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
1196+
1197+	/* Look up the conntrack helper for master connections only */
1198+	if (!expected)
1199+		conntrack->helper = ip_ct_find_helper(&repl_tuple);
1200+
1201+	/* If the expectation is dying, then this is a looser. */
1202+	if (expected
1203+	    && expected->expectant->helper->timeout
1204+	    && ! del_timer(&expected->timeout))
1205+		expected = NULL;
1206+
1207 	/* If master is not in hash table yet (ie. packet hasn't left
1208 	   this machine yet), how can other end know about expected?
1209 	   Hence these are not the droids you are looking for (if
1210 	   master ct never got confirmed, we'd hold a reference to it
1211 	   and weird things would happen to future packets). */
1212 	if (expected && is_confirmed(expected->expectant)) {
1213+		DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n",
1214+			conntrack, expected);
1215 		/* Welcome, Mr. Bond.  We've been expecting you... */
1216+		IP_NF_ASSERT(master_ct(conntrack));
1217 		conntrack->status = IPS_EXPECTED;
1218-		conntrack->master.master = &expected->expectant->ct_general;
1219-		IP_NF_ASSERT(conntrack->master.master);
1220-		LIST_DELETE(&expect_list, expected);
1221-		expected->expectant = NULL;
1222-		nf_conntrack_get(&conntrack->master);
1223+		conntrack->master = expected;
1224+		expected->sibling = conntrack;
1225+		LIST_DELETE(&ip_conntrack_expect_list, expected);
1226+		expected->expectant->expecting--;
1227+		nf_conntrack_get(&master_ct(conntrack)->infos[0]);
1228 	}
1229 	atomic_inc(&ip_conntrack_count);
1230 	WRITE_UNLOCK(&ip_conntrack_lock);
1231@@ -669,7 +830,7 @@
1232 			return NF_STOLEN;
1233 	}
1234 
1235-	proto = find_proto((*pskb)->nh.iph->protocol);
1236+	proto = ip_ct_find_proto((*pskb)->nh.iph->protocol);
1237 
1238 	/* It may be an icmp error... */
1239 	if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP 
1240@@ -713,66 +874,229 @@
1241 int invert_tuplepr(struct ip_conntrack_tuple *inverse,
1242 		   const struct ip_conntrack_tuple *orig)
1243 {
1244-	return invert_tuple(inverse, orig, find_proto(orig->dst.protonum));
1245+	return invert_tuple(inverse, orig, ip_ct_find_proto(orig->dst.protonum));
1246 }
1247 
1248-static void unexpect_related(struct ip_conntrack *related_to)
1249-{
1250-	MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
1251-	list_del(&related_to->expected.list);
1252-	related_to->expected.expectant = NULL;
1253+static inline int resent_expect(const struct ip_conntrack_expect *i,
1254+			        const struct ip_conntrack_tuple *tuple,
1255+			        const struct ip_conntrack_tuple *mask)
1256+{
1257+	DEBUGP("resent_expect\n");
1258+	DEBUGP("   tuple:   "); DUMP_TUPLE(&i->tuple);
1259+	DEBUGP("ct_tuple:   "); DUMP_TUPLE(&i->ct_tuple);
1260+	DEBUGP("test tuple: "); DUMP_TUPLE(tuple);
1261+	return (((i->ct_tuple.dst.protonum == 0 && ip_ct_tuple_equal(&i->tuple, tuple))
1262+	         || (i->ct_tuple.dst.protonum && ip_ct_tuple_equal(&i->ct_tuple, tuple)))
1263+		&& ip_ct_tuple_equal(&i->mask, mask));
1264 }
1265 
1266 /* Would two expected things clash? */
1267 static inline int expect_clash(const struct ip_conntrack_expect *i,
1268-			       const struct ip_conntrack_expect *new)
1269+			       const struct ip_conntrack_tuple *tuple,
1270+			       const struct ip_conntrack_tuple *mask)
1271 {
1272 	/* Part covered by intersection of masks must be unequal,
1273            otherwise they clash */
1274 	struct ip_conntrack_tuple intersect_mask
1275-		= { { i->mask.src.ip & new->mask.src.ip,
1276-		      { i->mask.src.u.all & new->mask.src.u.all } },
1277-		    { i->mask.dst.ip & new->mask.dst.ip,
1278-		      { i->mask.dst.u.all & new->mask.dst.u.all },
1279-		      i->mask.dst.protonum & new->mask.dst.protonum } };
1280+		= { { i->mask.src.ip & mask->src.ip,
1281+		      { i->mask.src.u.all & mask->src.u.all } },
1282+		    { i->mask.dst.ip & mask->dst.ip,
1283+		      { i->mask.dst.u.all & mask->dst.u.all },
1284+		      i->mask.dst.protonum & mask->dst.protonum } };
1285+
1286+	return ip_ct_tuple_mask_cmp(&i->tuple, tuple, &intersect_mask);
1287+}
1288+
1289+inline void ip_conntrack_unexpect_related(struct ip_conntrack_expect *expect)
1290+{
1291+	WRITE_LOCK(&ip_conntrack_lock);
1292+	unexpect_related(expect);
1293+	WRITE_UNLOCK(&ip_conntrack_lock);
1294+}
1295+	
1296+static void expectation_timed_out(unsigned long ul_expect)
1297+{
1298+	struct ip_conntrack_expect *expect = (void *) ul_expect;
1299 
1300-	return ip_ct_tuple_mask_cmp(&i->tuple, &new->tuple, &intersect_mask);
1301+	DEBUGP("expectation %p timed out\n", expect);	
1302+	WRITE_LOCK(&ip_conntrack_lock);
1303+	__unexpect_related(expect);
1304+	WRITE_UNLOCK(&ip_conntrack_lock);
1305 }
1306 
1307 /* Add a related connection. */
1308 int ip_conntrack_expect_related(struct ip_conntrack *related_to,
1309-				const struct ip_conntrack_tuple *tuple,
1310-				const struct ip_conntrack_tuple *mask,
1311-				int (*expectfn)(struct ip_conntrack *))
1312+				struct ip_conntrack_expect *expect)
1313 {
1314+	struct ip_conntrack_expect *old, *new;
1315+	int ret = 0;
1316+
1317 	WRITE_LOCK(&ip_conntrack_lock);
1318-	if (related_to->expected.expectant)
1319-		unexpect_related(related_to);
1320+	/* Because of the write lock, no reader can walk the lists,
1321+	 * so there is no need to use the tuple lock too */
1322+
1323+	DEBUGP("ip_conntrack_expect_related %p\n", related_to);
1324+	DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple);
1325+	DEBUGP("mask:  "); DUMP_TUPLE(&expect->mask);
1326+
1327+	old = LIST_FIND(&ip_conntrack_expect_list, resent_expect,
1328+		        struct ip_conntrack_expect *, &expect->tuple, 
1329+			&expect->mask);
1330+	if (old) {
1331+		/* Helper private data may contain offsets but no pointers
1332+		   pointing into the payload - otherwise we should have to copy 
1333+		   the data filled out by the helper over the old one */
1334+		DEBUGP("expect_related: resent packet\n");
1335+		if (related_to->helper->timeout) {
1336+			if (!del_timer(&old->timeout)) {
1337+				/* expectation is dying. Fall through */
1338+				old = NULL;
1339+			} else {
1340+				old->timeout.expires = jiffies + 
1341+					related_to->helper->timeout * HZ;
1342+				add_timer(&old->timeout);
1343+			}
1344+		}
1345+
1346+		if (old) {
1347+			WRITE_UNLOCK(&ip_conntrack_lock);
1348+			return -EEXIST;
1349+		}
1350+	} else if (related_to->helper->max_expected && 
1351+		   related_to->expecting >= related_to->helper->max_expected) {
1352+		struct list_head *cur_item;
1353+		/* old == NULL */
1354+	    	if (net_ratelimit())
1355+		    	printk(KERN_WARNING 
1356+		    	       "ip_conntrack: max number of expected "
1357+			       "connections %i of %s reached for "
1358+			       "%u.%u.%u.%u->%u.%u.%u.%u%s\n",
1359+		    	       related_to->helper->max_expected, 
1360+		    	       related_to->helper->name,
1361+		    	       NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
1362+		    	       NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip),
1363+		    	       related_to->helper->flags & IP_CT_HELPER_F_REUSE_EXPECT ?
1364+		    	       ", reusing" : "");
1365+		if (!(related_to->helper->flags & 
1366+		      IP_CT_HELPER_F_REUSE_EXPECT)) {
1367+			WRITE_UNLOCK(&ip_conntrack_lock);
1368+			return -EPERM;
1369+		}
1370 
1371-	related_to->expected.tuple = *tuple;
1372-	related_to->expected.mask = *mask;
1373-	related_to->expected.expectfn = expectfn;
1374+		/* choose the the oldest expectation to evict */
1375+		list_for_each(cur_item, &related_to->sibling_list) { 
1376+			struct ip_conntrack_expect *cur;
1377+
1378+			cur = list_entry(cur_item, 
1379+					 struct ip_conntrack_expect,
1380+					 expected_list);
1381+			if (cur->sibling == NULL) {
1382+				old = cur;
1383+				break;
1384+			}
1385+		}
1386 
1387-	if (LIST_FIND(&expect_list, expect_clash,
1388-		      struct ip_conntrack_expect *, &related_to->expected)) {
1389+		/* (!old) cannot happen, since related_to->expecting is the
1390+		 * number of unconfirmed expects */
1391+		IP_NF_ASSERT(old);
1392+
1393+		/* newnat14 does not reuse the real allocated memory
1394+		 * structures but rather unexpects the old and
1395+		 * allocates a new.  unexpect_related will decrement
1396+		 * related_to->expecting. 
1397+		 */
1398+		unexpect_related(old);
1399+		ret = -EPERM;
1400+	} else if (LIST_FIND(&ip_conntrack_expect_list, expect_clash,
1401+			     struct ip_conntrack_expect *, &expect->tuple, 
1402+			     &expect->mask)) {
1403 		WRITE_UNLOCK(&ip_conntrack_lock);
1404+		DEBUGP("expect_related: busy!\n");
1405 		return -EBUSY;
1406 	}
1407+	
1408+	new = (struct ip_conntrack_expect *) 
1409+	      kmalloc(sizeof(struct ip_conntrack_expect), GFP_ATOMIC);
1410+	if (!new) {
1411+		WRITE_UNLOCK(&ip_conntrack_lock);
1412+		DEBUGP("expect_relaed: OOM allocating expect\n");
1413+		return -ENOMEM;
1414+	}
1415+	
1416+	/* Zero out the new structure, then fill out it with the data */
1417+	DEBUGP("new expectation %p of conntrack %p\n", new, related_to);
1418+	memset(new, 0, sizeof(*expect));
1419+	INIT_LIST_HEAD(&new->list);
1420+	INIT_LIST_HEAD(&new->expected_list);
1421+	memcpy(new, expect, sizeof(*expect));
1422+	new->expectant = related_to;
1423+	new->sibling = NULL;
1424+	/* increase usage count. This sucks. The memset above overwrites
1425+	 * old usage count [if still present] and we increase to one.  Only
1426+	 * works because everything is done under ip_conntrack_lock() */
1427+	atomic_inc(&new->use);
1428+	
1429+	/* add to expected list for this connection */	
1430+	list_add(&new->expected_list, &related_to->sibling_list);
1431+	/* add to global list of expectations */
1432+	list_prepend(&ip_conntrack_expect_list, &new->list);
1433+	/* add and start timer if required */
1434+	if (related_to->helper->timeout) {
1435+		init_timer(&new->timeout);
1436+		new->timeout.data = (unsigned long)new;
1437+		new->timeout.function = expectation_timed_out;
1438+		new->timeout.expires = jiffies + 
1439+					related_to->helper->timeout * HZ;
1440+		add_timer(&new->timeout);
1441+	}
1442+	related_to->expecting++;
1443 
1444-	list_prepend(&expect_list, &related_to->expected);
1445-	related_to->expected.expectant = related_to;
1446 	WRITE_UNLOCK(&ip_conntrack_lock);
1447 
1448-	return 0;
1449+	return ret;
1450 }
1451 
1452-void ip_conntrack_unexpect_related(struct ip_conntrack *related_to)
1453+/* Change tuple in an existing expectation */
1454+int ip_conntrack_change_expect(struct ip_conntrack_expect *expect,
1455+			       struct ip_conntrack_tuple *newtuple)
1456 {
1457-	WRITE_LOCK(&ip_conntrack_lock);
1458-	unexpect_related(related_to);
1459-	WRITE_UNLOCK(&ip_conntrack_lock);
1460-}
1461+	int ret;
1462+
1463+	MUST_BE_READ_LOCKED(&ip_conntrack_lock);
1464+	WRITE_LOCK(&ip_conntrack_expect_tuple_lock);
1465+
1466+	DEBUGP("change_expect:\n");
1467+	DEBUGP("exp tuple: "); DUMP_TUPLE(&expect->tuple);
1468+	DEBUGP("exp mask:  "); DUMP_TUPLE(&expect->mask);
1469+	DEBUGP("newtuple:  "); DUMP_TUPLE(newtuple);
1470+	if (expect->ct_tuple.dst.protonum == 0) {
1471+		/* Never seen before */
1472+		DEBUGP("change expect: never seen before\n");
1473+		if (!ip_ct_tuple_equal(&expect->tuple, newtuple) 
1474+		    && LIST_FIND(&ip_conntrack_expect_list, expect_clash,
1475+			         struct ip_conntrack_expect *, newtuple, &expect->mask)) {
1476+			/* Force NAT to find an unused tuple */
1477+			ret = -1;
1478+		} else {
1479+			memcpy(&expect->ct_tuple, &expect->tuple, sizeof(expect->tuple));
1480+			memcpy(&expect->tuple, newtuple, sizeof(expect->tuple));
1481+			ret = 0;
1482+		}
1483+	} else {
1484+		/* Resent packet */
1485+		DEBUGP("change expect: resent packet\n");
1486+		if (ip_ct_tuple_equal(&expect->tuple, newtuple)) {
1487+			ret = 0;
1488+		} else {
1489+			/* Force NAT to choose again the same port */
1490+			ret = -1;
1491+		}
1492+	}
1493+	WRITE_UNLOCK(&ip_conntrack_expect_tuple_lock);
1494 	
1495+	return ret;
1496+}
1497+
1498 /* Alter reply tuple (maybe alter helper).  If it's already taken,
1499    return 0 and don't do alteration. */
1500 int ip_conntrack_alter_reply(struct ip_conntrack *conntrack,
1501@@ -790,10 +1114,12 @@
1502 	DUMP_TUPLE(newreply);
1503 
1504 	conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
1505-	conntrack->helper = LIST_FIND(&helpers, helper_cmp,
1506-				      struct ip_conntrack_helper *,
1507-				      newreply);
1508+	if (!conntrack->master)
1509+		conntrack->helper = LIST_FIND(&helpers, helper_cmp,
1510+					      struct ip_conntrack_helper *,
1511+					      newreply);
1512 	WRITE_UNLOCK(&ip_conntrack_lock);
1513+
1514 	return 1;
1515 }
1516 
1517@@ -812,14 +1138,10 @@
1518 			 const struct ip_conntrack_helper *me)
1519 {
1520 	if (i->ctrack->helper == me) {
1521-		i->ctrack->helper = NULL;
1522 		/* Get rid of any expected. */
1523-		if (i->ctrack->expected.expectant) {
1524-			IP_NF_ASSERT(i->ctrack->expected.expectant
1525-				     == i->ctrack);
1526-			LIST_DELETE(&expect_list, &i->ctrack->expected);
1527-			i->ctrack->expected.expectant = NULL;
1528-		}
1529+		remove_expectations(i->ctrack);
1530+		/* And *then* set helper to NULL */
1531+		i->ctrack->helper = NULL;
1532 	}
1533 	return 0;
1534 }
1535@@ -1100,18 +1422,22 @@
1536 	}
1537 	ip_conntrack_max = 8 * ip_conntrack_htable_size;
1538 
1539-	printk("ip_conntrack (%u buckets, %d max)\n",
1540-	       ip_conntrack_htable_size, ip_conntrack_max);
1541+	printk("ip_conntrack version %s (%u buckets, %d max)"
1542+	       " - %d bytes per conntrack\n", IP_CONNTRACK_VERSION,
1543+	       ip_conntrack_htable_size, ip_conntrack_max,
1544+	       sizeof(struct ip_conntrack));
1545 
1546 	ret = nf_register_sockopt(&so_getorigdst);
1547-	if (ret != 0)
1548+	if (ret != 0) {
1549+		printk(KERN_ERR "Unable to register netfilter socket option\n");
1550 		return ret;
1551+	}
1552 
1553 	ip_conntrack_hash = vmalloc(sizeof(struct list_head)
1554 				    * ip_conntrack_htable_size);
1555 	if (!ip_conntrack_hash) {
1556-		nf_unregister_sockopt(&so_getorigdst);
1557-		return -ENOMEM;
1558+		printk(KERN_ERR "Unable to create ip_conntrack_hash\n");
1559+		goto err_unreg_sockopt;
1560 	}
1561 
1562 	ip_conntrack_cachep = kmem_cache_create("ip_conntrack",
1563@@ -1119,11 +1445,8 @@
1564 	                                        SLAB_HWCACHE_ALIGN, NULL, NULL);
1565 	if (!ip_conntrack_cachep) {
1566 		printk(KERN_ERR "Unable to create ip_conntrack slab cache\n");
1567-		vfree(ip_conntrack_hash);
1568-		nf_unregister_sockopt(&so_getorigdst);
1569-		return -ENOMEM;
1570+		goto err_free_hash;
1571 	}
1572-	
1573 	/* Don't NEED lock here, but good form anyway. */
1574 	WRITE_LOCK(&ip_conntrack_lock);
1575 	/* Sew in builtin protocols. */
1576@@ -1142,14 +1465,20 @@
1577 	ip_conntrack_sysctl_header
1578 		= register_sysctl_table(ip_conntrack_root_table, 0);
1579 	if (ip_conntrack_sysctl_header == NULL) {
1580-		kmem_cache_destroy(ip_conntrack_cachep);
1581-		vfree(ip_conntrack_hash);
1582-		nf_unregister_sockopt(&so_getorigdst);
1583-		return -ENOMEM;
1584+		goto err_free_ct_cachep;
1585 	}
1586 #endif /*CONFIG_SYSCTL*/
1587 
1588 	/* For use by ipt_REJECT */
1589 	ip_ct_attach = ip_conntrack_attach;
1590 	return ret;
1591+
1592+err_free_ct_cachep:
1593+	kmem_cache_destroy(ip_conntrack_cachep);
1594+err_free_hash:
1595+	vfree(ip_conntrack_hash);
1596+err_unreg_sockopt:
1597+	nf_unregister_sockopt(&so_getorigdst);
1598+
1599+	return -ENOMEM;
1600 }
1601diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv4/netfilter/ip_conntrack_ftp.c linux-2.4.20-plain/net/ipv4/netfilter/ip_conntrack_ftp.c
1602--- linux-2.4.19-plain/net/ipv4/netfilter/ip_conntrack_ftp.c	Wed Oct 31 00:08:12 2001
1603+++ linux-2.4.20-plain/net/ipv4/netfilter/ip_conntrack_ftp.c	Fri Nov 29 00:53:15 2002
1604@@ -1,4 +1,5 @@
1605 /* FTP extension for IP connection tracking. */
1606+#include <linux/config.h>
1607 #include <linux/module.h>
1608 #include <linux/netfilter.h>
1609 #include <linux/ip.h>
1610@@ -15,7 +16,7 @@
1611 
1612 #define MAX_PORTS 8
1613 static int ports[MAX_PORTS];
1614-static int ports_c;
1615+static int ports_c = 0;
1616 #ifdef MODULE_PARM
1617 MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
1618 #endif
1619@@ -242,8 +243,10 @@
1620 	u_int32_t array[6] = { 0 };
1621 	int dir = CTINFO2DIR(ctinfo);
1622 	unsigned int matchlen, matchoff;
1623-	struct ip_conntrack_tuple t, mask;
1624-	struct ip_ct_ftp *info = &ct->help.ct_ftp_info;
1625+	struct ip_ct_ftp_master *ct_ftp_info = &ct->help.ct_ftp_info;
1626+	struct ip_conntrack_expect expect, *exp = &expect;
1627+	struct ip_ct_ftp_expect *exp_ftp_info = &exp->help.exp_ftp_info;
1628+
1629 	unsigned int i;
1630 	int found = 0;
1631 
1632@@ -271,8 +274,8 @@
1633 	}
1634 
1635 	LOCK_BH(&ip_ftp_lock);
1636-	old_seq_aft_nl_set = info->seq_aft_nl_set[dir];
1637-	old_seq_aft_nl = info->seq_aft_nl[dir];
1638+	old_seq_aft_nl_set = ct_ftp_info->seq_aft_nl_set[dir];
1639+	old_seq_aft_nl = ct_ftp_info->seq_aft_nl[dir];
1640 
1641 	DEBUGP("conntrack_ftp: datalen %u\n", datalen);
1642 	if ((datalen > 0) && (data[datalen-1] == '\n')) {
1643@@ -281,8 +284,9 @@
1644 		    || after(ntohl(tcph->seq) + datalen, old_seq_aft_nl)) {
1645 			DEBUGP("conntrack_ftp: updating nl to %u\n",
1646 			       ntohl(tcph->seq) + datalen);
1647-			info->seq_aft_nl[dir] = ntohl(tcph->seq) + datalen;
1648-			info->seq_aft_nl_set[dir] = 1;
1649+			ct_ftp_info->seq_aft_nl[dir] = 
1650+						ntohl(tcph->seq) + datalen;
1651+			ct_ftp_info->seq_aft_nl_set[dir] = 1;
1652 		}
1653 	}
1654 	UNLOCK_BH(&ip_ftp_lock);
1655@@ -330,16 +334,17 @@
1656 	DEBUGP("conntrack_ftp: match `%.*s' (%u bytes at %u)\n",
1657 	       (int)matchlen, data + matchoff,
1658 	       matchlen, ntohl(tcph->seq) + matchoff);
1659+	       
1660+	memset(&expect, 0, sizeof(expect));
1661 
1662 	/* Update the ftp info */
1663 	LOCK_BH(&ip_ftp_lock);
1664 	if (htonl((array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3])
1665 	    == ct->tuplehash[dir].tuple.src.ip) {
1666-		info->is_ftp = 21;
1667-		info->seq = ntohl(tcph->seq) + matchoff;
1668-		info->len = matchlen;
1669-		info->ftptype = search[i].ftptype;
1670-		info->port = array[4] << 8 | array[5];
1671+		exp->seq = ntohl(tcph->seq) + matchoff;
1672+		exp_ftp_info->len = matchlen;
1673+		exp_ftp_info->ftptype = search[i].ftptype;
1674+		exp_ftp_info->port = array[4] << 8 | array[5];
1675 	} else {
1676 		/* Enrico Scholz's passive FTP to partially RNAT'd ftp
1677 		   server: it really wants us to connect to a
1678@@ -356,18 +361,21 @@
1679 		if (!loose) goto out;
1680 	}
1681 
1682-	t = ((struct ip_conntrack_tuple)
1683+	exp->tuple = ((struct ip_conntrack_tuple)
1684 		{ { ct->tuplehash[!dir].tuple.src.ip,
1685 		    { 0 } },
1686 		  { htonl((array[0] << 24) | (array[1] << 16)
1687 			  | (array[2] << 8) | array[3]),
1688 		    { htons(array[4] << 8 | array[5]) },
1689 		    IPPROTO_TCP }});
1690-	mask = ((struct ip_conntrack_tuple)
1691+	exp->mask = ((struct ip_conntrack_tuple)
1692 		{ { 0xFFFFFFFF, { 0 } },
1693 		  { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
1694+
1695+	exp->expectfn = NULL;
1696+
1697 	/* Ignore failure; should only happen with NAT */
1698-	ip_conntrack_expect_related(ct, &t, &mask, NULL);
1699+	ip_conntrack_expect_related(ct, &expect);
1700  out:
1701 	UNLOCK_BH(&ip_ftp_lock);
1702 
1703@@ -375,12 +383,13 @@
1704 }
1705 
1706 static struct ip_conntrack_helper ftp[MAX_PORTS];
1707+static char ftp_names[MAX_PORTS][10];
1708 
1709 /* Not __exit: called from init() */
1710 static void fini(void)
1711 {
1712 	int i;
1713-	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
1714+	for (i = 0; i < ports_c; i++) {
1715 		DEBUGP("ip_ct_ftp: unregistering helper for port %d\n",
1716 				ports[i]);
1717 		ip_conntrack_helper_unregister(&ftp[i]);
1718@@ -390,9 +399,10 @@
1719 static int __init init(void)
1720 {
1721 	int i, ret;
1722+	char *tmpname;
1723 
1724 	if (ports[0] == 0)
1725-		ports[0] = 21;
1726+		ports[0] = FTP_PORT;
1727 
1728 	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
1729 		memset(&ftp[i], 0, sizeof(struct ip_conntrack_helper));
1730@@ -400,7 +410,19 @@
1731 		ftp[i].tuple.dst.protonum = IPPROTO_TCP;
1732 		ftp[i].mask.src.u.tcp.port = 0xFFFF;
1733 		ftp[i].mask.dst.protonum = 0xFFFF;
1734+		ftp[i].max_expected = 1;
1735+		ftp[i].timeout = 0;
1736+		ftp[i].flags = IP_CT_HELPER_F_REUSE_EXPECT;
1737+		ftp[i].me = ip_conntrack_ftp;
1738 		ftp[i].help = help;
1739+
1740+		tmpname = &ftp_names[i][0];
1741+		if (ports[i] == FTP_PORT)
1742+			sprintf(tmpname, "ftp");
1743+		else
1744+			sprintf(tmpname, "ftp-%d", ports[i]);
1745+		ftp[i].name = tmpname;
1746+
1747 		DEBUGP("ip_ct_ftp: registering helper for port %d\n", 
1748 				ports[i]);
1749 		ret = ip_conntrack_helper_register(&ftp[i]);
1750@@ -414,10 +436,10 @@
1751 	return 0;
1752 }
1753 
1754-
1755+#ifdef CONFIG_IP_NF_NAT_NEEDED
1756 EXPORT_SYMBOL(ip_ftp_lock);
1757-EXPORT_SYMBOL(ip_conntrack_ftp);
1758-MODULE_LICENSE("GPL");
1759+#endif
1760 
1761+MODULE_LICENSE("GPL");
1762 module_init(init);
1763 module_exit(fini);
1764diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv4/netfilter/ip_conntrack_irc.c linux-2.4.20-plain/net/ipv4/netfilter/ip_conntrack_irc.c
1765--- linux-2.4.19-plain/net/ipv4/netfilter/ip_conntrack_irc.c	Mon Feb 25 20:38:14 2002
1766+++ linux-2.4.20-plain/net/ipv4/netfilter/ip_conntrack_irc.c	Fri Nov 29 00:53:15 2002
1767@@ -11,12 +11,18 @@
1768  **
1769  *	Module load syntax:
1770  * 	insmod ip_conntrack_irc.o ports=port1,port2,...port<MAX_PORTS>
1771+ *			    max_dcc_channels=n dcc_timeout=secs
1772  *	
1773  * 	please give the ports of all IRC servers You wish to connect to.
1774- *	If You don't specify ports, the default will be port 6667
1775+ *	If You don't specify ports, the default will be port 6667.
1776+ *	With max_dcc_channels you can define the maximum number of not
1777+ *	yet answered DCC channels per IRC session (default 8).
1778+ *	With dcc_timeout you can specify how long the system waits for 
1779+ *	an expected DCC channel (default 300 seconds).
1780  *
1781  */
1782 
1783+#include <linux/config.h>
1784 #include <linux/module.h>
1785 #include <linux/netfilter.h>
1786 #include <linux/ip.h>
1787@@ -29,7 +35,9 @@
1788 
1789 #define MAX_PORTS 8
1790 static int ports[MAX_PORTS];
1791-static int ports_n_c = 0;
1792+static int ports_c = 0;
1793+static int max_dcc_channels = 8;
1794+static unsigned int dcc_timeout = 300;
1795 
1796 MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
1797 MODULE_DESCRIPTION("IRC (DCC) connection tracking module");
1798@@ -37,6 +45,10 @@
1799 #ifdef MODULE_PARM
1800 MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
1801 MODULE_PARM_DESC(ports, "port numbers of IRC servers");
1802+MODULE_PARM(max_dcc_channels, "i");
1803+MODULE_PARM_DESC(max_dcc_channels, "max number of expected DCC channels per IRC session");
1804+MODULE_PARM(dcc_timeout, "i");
1805+MODULE_PARM_DESC(dcc_timeout, "timeout on for unestablished DCC channels");
1806 #endif
1807 
1808 #define NUM_DCCPROTO 	5
1809@@ -103,23 +115,15 @@
1810 	u_int32_t tcplen = len - iph->ihl * 4;
1811 	u_int32_t datalen = tcplen - tcph->doff * 4;
1812 	int dir = CTINFO2DIR(ctinfo);
1813-	struct ip_conntrack_tuple t, mask;
1814+	struct ip_conntrack_expect expect, *exp = &expect;
1815+	struct ip_ct_irc_expect *exp_irc_info = &exp->help.exp_irc_info;
1816 
1817 	u_int32_t dcc_ip;
1818 	u_int16_t dcc_port;
1819 	int i;
1820 	char *addr_beg_p, *addr_end_p;
1821 
1822-	struct ip_ct_irc *info = &ct->help.ct_irc_info;
1823-
1824-	mask = ((struct ip_conntrack_tuple)
1825-		{ { 0, { 0 } },
1826-		  { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
1827-
1828 	DEBUGP("entered\n");
1829-	/* Can't track connections formed before we registered */
1830-	if (!info)
1831-		return NF_ACCEPT;
1832 
1833 	/* If packet is coming from IRC server */
1834 	if (dir == IP_CT_DIR_REPLY)
1835@@ -189,33 +193,37 @@
1836 
1837 				continue;
1838 			}
1839+			
1840+			memset(&expect, 0, sizeof(expect));
1841 
1842 			LOCK_BH(&ip_irc_lock);
1843 
1844 			/* save position of address in dcc string,
1845 			 * neccessary for NAT */
1846-			info->is_irc = IP_CONNTR_IRC;
1847 			DEBUGP("tcph->seq = %u\n", tcph->seq);
1848-			info->seq = ntohl(tcph->seq) + (addr_beg_p - _data);
1849-			info->len = (addr_end_p - addr_beg_p);
1850-			info->port = dcc_port;
1851+			exp->seq = ntohl(tcph->seq) + (addr_beg_p - _data);
1852+			exp_irc_info->len = (addr_end_p - addr_beg_p);
1853+			exp_irc_info->port = dcc_port;
1854 			DEBUGP("wrote info seq=%u (ofs=%u), len=%d\n",
1855-				info->seq, (addr_end_p - _data), info->len);
1856+				exp->seq, (addr_end_p - _data), exp_irc_info->len);
1857 
1858-			memset(&t, 0, sizeof(t));
1859-			t.src.ip = 0;
1860-			t.src.u.tcp.port = 0;
1861-			t.dst.ip = htonl(dcc_ip);
1862-			t.dst.u.tcp.port = htons(info->port);
1863-			t.dst.protonum = IPPROTO_TCP;
1864+			exp->tuple = ((struct ip_conntrack_tuple)
1865+				{ { 0, { 0 } },
1866+				  { htonl(dcc_ip), { htons(dcc_port) },
1867+				    IPPROTO_TCP }});
1868+			exp->mask = ((struct ip_conntrack_tuple)
1869+				{ { 0, { 0 } },
1870+				  { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
1871+
1872+			exp->expectfn = NULL;
1873 
1874 			DEBUGP("expect_related %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n",
1875-				NIPQUAD(t.src.ip),
1876-				ntohs(t.src.u.tcp.port),
1877-				NIPQUAD(t.dst.ip),
1878-				ntohs(t.dst.u.tcp.port));
1879+				NIPQUAD(exp->tuple.src.ip),
1880+				ntohs(exp->tuple.src.u.tcp.port),
1881+				NIPQUAD(exp->tuple.dst.ip),
1882+				ntohs(exp->tuple.dst.u.tcp.port));
1883 
1884-			ip_conntrack_expect_related(ct, &t, &mask, NULL);
1885+			ip_conntrack_expect_related(ct, &expect);
1886 			UNLOCK_BH(&ip_irc_lock);
1887 
1888 			return NF_ACCEPT;
1889@@ -226,29 +234,53 @@
1890 }
1891 
1892 static struct ip_conntrack_helper irc_helpers[MAX_PORTS];
1893+static char irc_names[MAX_PORTS][10];
1894 
1895 static void fini(void);
1896 
1897 static int __init init(void)
1898 {
1899 	int i, ret;
1900+	struct ip_conntrack_helper *hlpr;
1901+	char *tmpname;
1902 
1903+	if (max_dcc_channels < 1) {
1904+		printk("ip_conntrack_irc: max_dcc_channels must be a positive integer\n");
1905+		return -EBUSY;
1906+	}
1907+	if (dcc_timeout < 0) {
1908+		printk("ip_conntrack_irc: dcc_timeout must be a positive integer\n");
1909+		return -EBUSY;
1910+	}
1911+	
1912 	/* If no port given, default to standard irc port */
1913 	if (ports[0] == 0)
1914-		ports[0] = 6667;
1915+		ports[0] = IRC_PORT;
1916 
1917 	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
1918-		memset(&irc_helpers[i], 0,
1919+		hlpr = &irc_helpers[i];
1920+		memset(hlpr, 0,
1921 		       sizeof(struct ip_conntrack_helper));
1922-		irc_helpers[i].tuple.src.u.tcp.port = htons(ports[i]);
1923-		irc_helpers[i].tuple.dst.protonum = IPPROTO_TCP;
1924-		irc_helpers[i].mask.src.u.tcp.port = 0xFFFF;
1925-		irc_helpers[i].mask.dst.protonum = 0xFFFF;
1926-		irc_helpers[i].help = help;
1927+		hlpr->tuple.src.u.tcp.port = htons(ports[i]);
1928+		hlpr->tuple.dst.protonum = IPPROTO_TCP;
1929+		hlpr->mask.src.u.tcp.port = 0xFFFF;
1930+		hlpr->mask.dst.protonum = 0xFFFF;
1931+		hlpr->max_expected = max_dcc_channels;
1932+		hlpr->timeout = dcc_timeout;
1933+		hlpr->flags = IP_CT_HELPER_F_REUSE_EXPECT;
1934+		hlpr->me = ip_conntrack_irc;
1935+		hlpr->help = help;
1936+
1937+		tmpname = &irc_names[i][0];
1938+		if (ports[i] == IRC_PORT)
1939+			sprintf(tmpname, "irc");
1940+		else
1941+			sprintf(tmpname, "irc-%d", i);
1942+		hlpr->name = tmpname;
1943 
1944 		DEBUGP("port #%d: %d\n", i, ports[i]);
1945 
1946-		ret = ip_conntrack_helper_register(&irc_helpers[i]);
1947+		ret = ip_conntrack_helper_register(hlpr);
1948 
1949 		if (ret) {
1950 			printk("ip_conntrack_irc: ERROR registering port %d\n",
1951@@ -256,7 +288,7 @@
1952 			fini();
1953 			return -EBUSY;
1954 		}
1955-		ports_n_c++;
1956+		ports_c++;
1957 	}
1958 	return 0;
1959 }
1960@@ -266,12 +298,16 @@
1961 static void fini(void)
1962 {
1963 	int i;
1964-	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
1965+	for (i = 0; i < ports_c; i++) {
1966 		DEBUGP("unregistering port %d\n",
1967 		       ports[i]);
1968 		ip_conntrack_helper_unregister(&irc_helpers[i]);
1969 	}
1970 }
1971+
1972+#ifdef CONFIG_IP_NF_NAT_NEEDED
1973+EXPORT_SYMBOL(ip_irc_lock);
1974+#endif
1975 
1976 module_init(init);
1977 module_exit(fini);
1978diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv4/netfilter/ip_conntrack_proto_generic.c linux-2.4.20-plain/net/ipv4/netfilter/ip_conntrack_proto_generic.c
1979--- linux-2.4.19-plain/net/ipv4/netfilter/ip_conntrack_proto_generic.c	Sat Aug  3 02:39:46 2002
1980+++ linux-2.4.20-plain/net/ipv4/netfilter/ip_conntrack_proto_generic.c	Fri Nov 29 00:53:15 2002
1981@@ -57,5 +57,5 @@
1982 struct ip_conntrack_protocol ip_conntrack_generic_protocol
1983 = { { NULL, NULL }, 0, "unknown",
1984     generic_pkt_to_tuple, generic_invert_tuple, generic_print_tuple,
1985-    generic_print_conntrack, established, new, NULL, NULL };
1986+    generic_print_conntrack, established, new, NULL, NULL, NULL };
1987 
1988diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv4/netfilter/ip_conntrack_proto_icmp.c linux-2.4.20-plain/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
1989--- linux-2.4.19-plain/net/ipv4/netfilter/ip_conntrack_proto_icmp.c	Sat Aug  3 02:39:46 2002
1990+++ linux-2.4.20-plain/net/ipv4/netfilter/ip_conntrack_proto_icmp.c	Fri Nov 29 00:53:15 2002
1991@@ -113,4 +113,4 @@
1992 struct ip_conntrack_protocol ip_conntrack_protocol_icmp
1993 = { { NULL, NULL }, IPPROTO_ICMP, "icmp",
1994     icmp_pkt_to_tuple, icmp_invert_tuple, icmp_print_tuple,
1995-    icmp_print_conntrack, icmp_packet, icmp_new, NULL, NULL };
1996+    icmp_print_conntrack, icmp_packet, icmp_new, NULL, NULL, NULL };
1997diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv4/netfilter/ip_conntrack_proto_tcp.c linux-2.4.20-plain/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
1998--- linux-2.4.19-plain/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	Sat Aug  3 02:39:46 2002
1999+++ linux-2.4.20-plain/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	Fri Nov 29 00:53:15 2002
2000@@ -7,6 +7,10 @@
2001 #include <linux/in.h>
2002 #include <linux/ip.h>
2003 #include <linux/tcp.h>
2004+#include <linux/string.h>
2005+
2006+#include <net/tcp.h>
2007+
2008 #include <linux/netfilter_ipv4/ip_conntrack.h>
2009 #include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
2010 #include <linux/netfilter_ipv4/lockhelp.h>
2011@@ -227,7 +231,19 @@
2012 	return 1;
2013 }
2014 
2015+static int tcp_exp_matches_pkt(struct ip_conntrack_expect *exp,
2016+			       struct sk_buff **pskb)
2017+{
2018+	struct iphdr *iph = (*pskb)->nh.iph;
2019+	struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph + iph->ihl);
2020+	unsigned int datalen;
2021+
2022+	datalen = (*pskb)->len - iph->ihl*4 - tcph->doff*4;
2023+
2024+	return between(exp->seq, ntohl(tcph->seq), ntohl(tcph->seq) + datalen);
2025+}
2026+
2027 struct ip_conntrack_protocol ip_conntrack_protocol_tcp
2028 = { { NULL, NULL }, IPPROTO_TCP, "tcp",
2029     tcp_pkt_to_tuple, tcp_invert_tuple, tcp_print_tuple, tcp_print_conntrack,
2030-    tcp_packet, tcp_new, NULL, NULL };
2031+    tcp_packet, tcp_new, NULL, tcp_exp_matches_pkt, NULL };
2032diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv4/netfilter/ip_conntrack_proto_udp.c linux-2.4.20-plain/net/ipv4/netfilter/ip_conntrack_proto_udp.c
2033--- linux-2.4.19-plain/net/ipv4/netfilter/ip_conntrack_proto_udp.c	Sat Aug  3 02:39:46 2002
2034+++ linux-2.4.20-plain/net/ipv4/netfilter/ip_conntrack_proto_udp.c	Fri Nov 29 00:53:15 2002
2035@@ -71,4 +71,4 @@
2036 struct ip_conntrack_protocol ip_conntrack_protocol_udp
2037 = { { NULL, NULL }, IPPROTO_UDP, "udp",
2038     udp_pkt_to_tuple, udp_invert_tuple, udp_print_tuple, udp_print_conntrack,
2039-    udp_packet, udp_new, NULL, NULL };
2040+    udp_packet, udp_new, NULL, NULL, NULL };
2041diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv4/netfilter/ip_conntrack_standalone.c linux-2.4.20-plain/net/ipv4/netfilter/ip_conntrack_standalone.c
2042--- linux-2.4.19-plain/net/ipv4/netfilter/ip_conntrack_standalone.c	Sat Aug  3 02:39:46 2002
2043+++ linux-2.4.20-plain/net/ipv4/netfilter/ip_conntrack_standalone.c	Fri Nov 29 00:53:15 2002
2044@@ -62,10 +62,16 @@
2045 {
2046 	unsigned int len;
2047 
2048-	len = sprintf(buffer, "EXPECTING: proto=%u ",
2049-		      expect->tuple.dst.protonum);
2050+	if (expect->expectant->helper->timeout)
2051+		len = sprintf(buffer, "EXPECTING: %lu ",
2052+			      timer_pending(&expect->timeout)
2053+			      ? (expect->timeout.expires - jiffies)/HZ : 0);
2054+	else
2055+		len = sprintf(buffer, "EXPECTING: - ");
2056+	len += sprintf(buffer + len, "use=%u proto=%u ",
2057+		      atomic_read(&expect->use), expect->tuple.dst.protonum);
2058 	len += print_tuple(buffer + len, &expect->tuple,
2059-			   __find_proto(expect->tuple.dst.protonum));
2060+			   __ip_ct_find_proto(expect->tuple.dst.protonum));
2061 	len += sprintf(buffer + len, "\n");
2062 	return len;
2063 }
2064@@ -75,7 +81,7 @@
2065 {
2066 	unsigned int len;
2067 	struct ip_conntrack_protocol *proto
2068-		= __find_proto(conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
2069+		= __ip_ct_find_proto(conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
2070 			       .tuple.dst.protonum);
2071 
2072 	len = sprintf(buffer, "%-8s %u %lu ",
2073@@ -147,7 +153,8 @@
2074 	}
2075 
2076 	/* Now iterate through expecteds. */
2077-	for (e = expect_list.next; e != &expect_list; e = e->next) {
2078+	for (e = ip_conntrack_expect_list.next; 
2079+	     e != &ip_conntrack_expect_list; e = e->next) {
2080 		unsigned int last_len;
2081 		struct ip_conntrack_expect *expect
2082 			= (struct ip_conntrack_expect *)e;
2083@@ -314,7 +321,7 @@
2084 {
2085 	WRITE_LOCK(&ip_conntrack_lock);
2086 
2087-	/* find_proto() returns proto_generic in case there is no protocol 
2088+	/* ip_ct_find_proto() returns proto_generic in case there is no protocol 
2089 	 * helper. So this should be enough - HW */
2090 	LIST_DELETE(&protocol_list, proto);
2091 	WRITE_UNLOCK(&ip_conntrack_lock);
2092@@ -353,8 +360,19 @@
2093 EXPORT_SYMBOL(ip_conntrack_helper_unregister);
2094 EXPORT_SYMBOL(ip_ct_selective_cleanup);
2095 EXPORT_SYMBOL(ip_ct_refresh);
2096+EXPORT_SYMBOL(ip_ct_find_proto);
2097+EXPORT_SYMBOL(__ip_ct_find_proto);
2098+EXPORT_SYMBOL(ip_ct_find_helper);
2099 EXPORT_SYMBOL(ip_conntrack_expect_related);
2100+EXPORT_SYMBOL(ip_conntrack_change_expect);
2101 EXPORT_SYMBOL(ip_conntrack_unexpect_related);
2102+EXPORT_SYMBOL_GPL(ip_conntrack_expect_find_get);
2103+EXPORT_SYMBOL_GPL(ip_conntrack_expect_put);
2104 EXPORT_SYMBOL(ip_conntrack_tuple_taken);
2105 EXPORT_SYMBOL(ip_ct_gather_frags);
2106 EXPORT_SYMBOL(ip_conntrack_htable_size);
2107+EXPORT_SYMBOL(ip_conntrack_expect_list);
2108+EXPORT_SYMBOL(ip_conntrack_lock);
2109+EXPORT_SYMBOL(ip_conntrack_hash);
2110+EXPORT_SYMBOL_GPL(ip_conntrack_find_get);
2111+EXPORT_SYMBOL_GPL(ip_conntrack_put);
2112diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv4/netfilter/ip_fw_compat_masq.c linux-2.4.20-plain/net/ipv4/netfilter/ip_fw_compat_masq.c
2113--- linux-2.4.19-plain/net/ipv4/netfilter/ip_fw_compat_masq.c	Mon Feb 25 20:38:14 2002
2114+++ linux-2.4.20-plain/net/ipv4/netfilter/ip_fw_compat_masq.c	Fri Nov 29 00:53:15 2002
2115@@ -130,7 +130,7 @@
2116 	struct ip_conntrack *ct;
2117 	int ret;
2118 
2119-	protocol = find_proto(iph->protocol);
2120+	protocol = ip_ct_find_proto(iph->protocol);
2121 
2122 	/* We don't feed packets to conntrack system unless we know
2123            they're part of an connection already established by an
2124diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv4/netfilter/ip_nat_core.c linux-2.4.20-plain/net/ipv4/netfilter/ip_nat_core.c
2125--- linux-2.4.19-plain/net/ipv4/netfilter/ip_nat_core.c	Sat Aug  3 02:39:46 2002
2126+++ linux-2.4.20-plain/net/ipv4/netfilter/ip_nat_core.c	Fri Nov 29 00:53:15 2002
2127@@ -21,10 +21,14 @@
2128 #define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock)
2129 #define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock)
2130 
2131+#include <linux/netfilter_ipv4/ip_conntrack.h>
2132+#include <linux/netfilter_ipv4/ip_conntrack_core.h>
2133+#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
2134 #include <linux/netfilter_ipv4/ip_nat.h>
2135 #include <linux/netfilter_ipv4/ip_nat_protocol.h>
2136 #include <linux/netfilter_ipv4/ip_nat_core.h>
2137 #include <linux/netfilter_ipv4/ip_nat_helper.h>
2138+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
2139 #include <linux/netfilter_ipv4/listhelp.h>
2140 
2141 #if 0
2142@@ -34,6 +38,7 @@
2143 #endif
2144 
2145 DECLARE_RWLOCK(ip_nat_lock);
2146+DECLARE_RWLOCK_EXTERN(ip_conntrack_lock);
2147 
2148 /* Calculated at init based on memory size */
2149 static unsigned int ip_nat_htable_size;
2150@@ -198,6 +203,7 @@
2151 		return NULL;
2152 }
2153 
2154+#ifdef CONFIG_IP_NF_NAT_LOCAL
2155 /* If it's really a local destination manip, it may need to do a
2156    source manip too. */
2157 static int
2158@@ -216,6 +222,7 @@
2159 	ip_rt_put(rt);
2160 	return 1;
2161 }
2162+#endif
2163 
2164 /* Simple way to iterate through all. */
2165 static inline int fake_cmp(const struct ip_nat_hash *i,
2166@@ -628,8 +635,9 @@
2167 	}
2168 
2169 	/* If there's a helper, assign it; based on new tuple. */
2170-	info->helper = LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,
2171-				 &reply);
2172+	if (!conntrack->master)
2173+		info->helper = LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,
2174+					 &reply);
2175 
2176 	/* It's done. */
2177 	info->initialized |= (1 << HOOK2MANIP(hooknum));
2178@@ -724,6 +732,20 @@
2179 #endif
2180 }
2181 
2182+static inline int exp_for_packet(struct ip_conntrack_expect *exp,
2183+			         struct sk_buff **pskb)
2184+{
2185+	struct ip_conntrack_protocol *proto;
2186+	int ret = 1;
2187+
2188+	MUST_BE_READ_LOCKED(&ip_conntrack_lock);
2189+	proto = __ip_ct_find_proto((*pskb)->nh.iph->protocol);
2190+	if (proto->exp_matches_pkt)
2191+		ret = proto->exp_matches_pkt(exp, pskb);
2192+
2193+	return ret;
2194+}
2195+
2196 /* Do packet manipulations according to binding. */
2197 unsigned int
2198 do_bindings(struct ip_conntrack *ct,
2199@@ -735,6 +757,7 @@
2200 	unsigned int i;
2201 	struct ip_nat_helper *helper;
2202 	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
2203+	int is_tcp = (*pskb)->nh.iph->protocol == IPPROTO_TCP;
2204 
2205 	/* Need nat lock to protect against modification, but neither
2206 	   conntrack (referenced) and helper (deleted with
2207@@ -773,11 +796,66 @@
2208 	READ_UNLOCK(&ip_nat_lock);
2209 
2210 	if (helper) {
2211+		struct ip_conntrack_expect *exp = NULL;
2212+		struct list_head *cur_item;
2213+		int ret = NF_ACCEPT;
2214+
2215+		DEBUGP("do_bindings: helper existing for (%p)\n", ct);
2216+
2217 		/* Always defragged for helpers */
2218 		IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off
2219-			       & __constant_htons(IP_MF|IP_OFFSET)));
2220-		return helper->help(ct, info, ctinfo, hooknum, pskb);
2221-	} else return NF_ACCEPT;
2222+			       & htons(IP_MF|IP_OFFSET)));
2223+
2224+		/* Have to grab read lock before sibling_list traversal */
2225+		READ_LOCK(&ip_conntrack_lock);
2226+		list_for_each(cur_item, &ct->sibling_list) { 
2227+			exp = list_entry(cur_item, struct ip_conntrack_expect, 
2228+					 expected_list);
2229+					 
2230+			/* if this expectation is already established, skip */
2231+			if (exp->sibling)
2232+				continue;
2233+
2234+			if (exp_for_packet(exp, pskb)) {
2235+				
2236+				DEBUGP("calling nat helper (exp=%p) for packet\n",
2237+					exp);
2238+				ret = helper->help(ct, exp, info, ctinfo, 
2239+						   hooknum, pskb);
2240+				if (ret != NF_ACCEPT) {
2241+					READ_UNLOCK(&ip_conntrack_lock);
2242+					return ret;
2243+				}
2244+			}
2245+		}
2246+		/* Helper might want to manip the packet even when there is no expectation */
2247+		if (!exp && helper->flags & IP_NAT_HELPER_F_ALWAYS) {
2248+			DEBUGP("calling nat helper for packet without expectation\n");
2249+			ret = helper->help(ct, NULL, info, ctinfo, 
2250+					   hooknum, pskb);
2251+			if (ret != NF_ACCEPT) {
2252+				READ_UNLOCK(&ip_conntrack_lock);
2253+				return ret;
2254+			}
2255+		}
2256+		READ_UNLOCK(&ip_conntrack_lock);
2257+		
2258+		/* Adjust sequence number only once per packet 
2259+		 * (helper is called at all hooks) */
2260+		if (is_tcp && (hooknum == NF_IP_POST_ROUTING
2261+			       || hooknum == NF_IP_LOCAL_IN)) {
2262+			DEBUGP("ip_nat_core: adjusting sequence number\n");
2263+			/* future: put this in a l4-proto specific function,
2264+			 * and call this function here. */
2265+			ip_nat_seq_adjust(*pskb, ct, ctinfo);
2266+		}
2267+
2268+		return ret;
2269+
2270+	} else 
2271+		return NF_ACCEPT;
2272+
2273+	/* not reached */
2274 }
2275 
2276 unsigned int
2277@@ -816,7 +894,7 @@
2278 
2279-static int
2280+static unsigned int
2281 ftp_nat_expected(struct sk_buff **pskb,
2282 		 unsigned int hooknum,
2283 		 struct ip_conntrack *ct,
2284-		 struct ip_nat_info *info,
2285-		 struct ip_conntrack *master,
2286-		 struct ip_nat_info *masterinfo,
2287-		 unsigned int *verdict)
2288+		 struct ip_nat_info *info)
2289 {
2290 	struct ip_nat_multi_range mr;
2291 	u_int32_t newdstip, newsrcip, newip;
2292-	struct ip_ct_ftp *ftpinfo;
2293+	struct ip_ct_ftp_expect *exp_ftp_info;
2294 
2295+	struct ip_conntrack *master = master_ct(ct);
2296+	
2297 	IP_NF_ASSERT(info);
2298 	IP_NF_ASSERT(master);
2299-	IP_NF_ASSERT(masterinfo);
2300 
2301 	IP_NF_ASSERT(!(info->initialized & (1<<HOOK2MANIP(hooknum))));
2302 
2303 	DEBUGP("nat_expected: We have a connection!\n");
2304-	/* Master must be an ftp connection */
2305-	ftpinfo = &master->help.ct_ftp_info;
2306+	exp_ftp_info = &ct->master->help.exp_ftp_info;
2307 
2308 	LOCK_BH(&ip_ftp_lock);
2309-	if (ftpinfo->is_ftp != 21) {
2310-		UNLOCK_BH(&ip_ftp_lock);
2311-		DEBUGP("nat_expected: master not ftp\n");
2312-		return 0;
2313-	}
2314 
2315-	if (ftpinfo->ftptype == IP_CT_FTP_PORT
2316-	    || ftpinfo->ftptype == IP_CT_FTP_EPRT) {
2317+	if (exp_ftp_info->ftptype == IP_CT_FTP_PORT
2318+	    || exp_ftp_info->ftptype == IP_CT_FTP_EPRT) {
2319 		/* PORT command: make connection go to the client. */
2320 		newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
2321 		newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
2322@@ -92,11 +84,9 @@
2323 		mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
2324 		mr.range[0].min = mr.range[0].max
2325 			= ((union ip_conntrack_manip_proto)
2326-				{ htons(ftpinfo->port) });
2327+				{ htons(exp_ftp_info->port) });
2328 	}
2329-	*verdict = ip_nat_setup_info(ct, &mr, hooknum);
2330-
2331-	return 1;
2332+	return ip_nat_setup_info(ct, &mr, hooknum);
2333 }
2334 
2335 static int
2336@@ -176,27 +166,22 @@
2337     [IP_CT_FTP_EPSV] mangle_epsv_packet
2338 };
2339 
2340-static int ftp_data_fixup(const struct ip_ct_ftp *ct_ftp_info,
2341+static int ftp_data_fixup(const struct ip_ct_ftp_expect *ct_ftp_info,
2342 			  struct ip_conntrack *ct,
2343-			  unsigned int datalen,
2344 			  struct sk_buff **pskb,
2345-			  enum ip_conntrack_info ctinfo)
2346+			  enum ip_conntrack_info ctinfo,
2347+			  struct ip_conntrack_expect *expect)
2348 {
2349 	u_int32_t newip;
2350 	struct iphdr *iph = (*pskb)->nh.iph;
2351 	struct tcphdr *tcph = (void *)iph + iph->ihl*4;
2352 	u_int16_t port;
2353-	struct ip_conntrack_tuple tuple;
2354-	/* Don't care about source port */
2355-	const struct ip_conntrack_tuple mask
2356-		= { { 0xFFFFFFFF, { 0 } },
2357-		    { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF } };
2358+	struct ip_conntrack_tuple newtuple;
2359 
2360-	memset(&tuple, 0, sizeof(tuple));
2361 	MUST_BE_LOCKED(&ip_ftp_lock);
2362-	DEBUGP("FTP_NAT: seq %u + %u in %u + %u\n",
2363-	       ct_ftp_info->seq, ct_ftp_info->len,
2364-	       ntohl(tcph->seq), datalen);
2365+	DEBUGP("FTP_NAT: seq %u + %u in %u\n",
2366+	       expect->seq, ct_ftp_info->len,
2367+	       ntohl(tcph->seq));
2368 
2369 	/* Change address inside packet to match way we're mapping
2370 	   this connection. */
2371@@ -206,29 +191,34 @@
2372 		   is */
2373 		newip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
2374 		/* Expect something from client->server */
2375-		tuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
2376-		tuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
2377+		newtuple.src.ip = 
2378+			ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
2379+		newtuple.dst.ip = 
2380+			ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
2381 	} else {
2382 		/* PORT command: must be where server thinks client is */
2383 		newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
2384 		/* Expect something from server->client */
2385-		tuple.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
2386-		tuple.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
2387+		newtuple.src.ip = 
2388+			ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
2389+		newtuple.dst.ip = 
2390+			ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
2391 	}
2392-	tuple.dst.protonum = IPPROTO_TCP;
2393+	newtuple.dst.protonum = IPPROTO_TCP;
2394+	newtuple.src.u.tcp.port = expect->tuple.src.u.tcp.port;
2395 
2396 	/* Try to get same port: if not, try to change it. */
2397 	for (port = ct_ftp_info->port; port != 0; port++) {
2398-		tuple.dst.u.tcp.port = htons(port);
2399+		newtuple.dst.u.tcp.port = htons(port);
2400 
2401-		if (ip_conntrack_expect_related(ct, &tuple, &mask, NULL) == 0)
2402+		if (ip_conntrack_change_expect(expect, &newtuple) == 0)
2403 			break;
2404 	}
2405 	if (port == 0)
2406 		return 0;
2407 
2408 	if (!mangle[ct_ftp_info->ftptype](pskb, newip, port,
2409-					  ct_ftp_info->seq - ntohl(tcph->seq),
2410+					  expect->seq - ntohl(tcph->seq),
2411 					  ct_ftp_info->len, ct, ctinfo))
2412 		return 0;
2413 
2414@@ -236,6 +226,7 @@
2415 }
2416 
2417 static unsigned int help(struct ip_conntrack *ct,
2418+			 struct ip_conntrack_expect *exp,
2419 			 struct ip_nat_info *info,
2420 			 enum ip_conntrack_info ctinfo,
2421 			 unsigned int hooknum,
2422@@ -245,13 +236,12 @@
2423 	struct tcphdr *tcph = (void *)iph + iph->ihl*4;
2424 	unsigned int datalen;
2425 	int dir;
2426-	int score;
2427-	struct ip_ct_ftp *ct_ftp_info
2428-		= &ct->help.ct_ftp_info;
2429-
2430-	/* Delete SACK_OK on initial TCP SYNs. */
2431-	if (tcph->syn && !tcph->ack)
2432-		ip_nat_delete_sack(*pskb, tcph);
2433+	struct ip_ct_ftp_expect *ct_ftp_info;
2434+
2435+	if (!exp)
2436+		DEBUGP("ip_nat_ftp: no exp!!");
2437+
2438+	ct_ftp_info = &exp->help.exp_ftp_info;
2439 
2440 	/* Only mangle things once: original direction in POST_ROUTING
2441 	   and reply direction on PRE_ROUTING. */
2442@@ -267,103 +257,87 @@
2443 	}
2444 
2445 	datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4;
2446-	score = 0;
2447 	LOCK_BH(&ip_ftp_lock);
2448-	if (ct_ftp_info->len) {
2449-		/* If it's in the right range... */
2450-		score += between(ct_ftp_info->seq, ntohl(tcph->seq),
2451-				 ntohl(tcph->seq) + datalen);
2452-		score += between(ct_ftp_info->seq + ct_ftp_info->len,
2453-				 ntohl(tcph->seq),
2454-				 ntohl(tcph->seq) + datalen);
2455-		if (score == 1) {
2456-			/* Half a match?  This means a partial retransmisison.
2457-			   It's a cracker being funky. */
2458-			if (net_ratelimit()) {
2459-				printk("FTP_NAT: partial packet %u/%u in %u/%u\n",
2460-				       ct_ftp_info->seq, ct_ftp_info->len,
2461-				       ntohl(tcph->seq),
2462-				       ntohl(tcph->seq) + datalen);
2463-			}
2464+	/* If it's in the right range... */
2465+	if (between(exp->seq + ct_ftp_info->len,
2466+		    ntohl(tcph->seq),
2467+		    ntohl(tcph->seq) + datalen)) {
2468+		if (!ftp_data_fixup(ct_ftp_info, ct, pskb, ctinfo, exp)) {
2469 			UNLOCK_BH(&ip_ftp_lock);
2470 			return NF_DROP;
2471-		} else if (score == 2) {
2472-			if (!ftp_data_fixup(ct_ftp_info, ct, datalen,
2473-					    pskb, ctinfo)) {
2474-				UNLOCK_BH(&ip_ftp_lock);
2475-				return NF_DROP;
2476-			}
2477-			/* skb may have been reallocated */
2478-			iph = (*pskb)->nh.iph;
2479-			tcph = (void *)iph + iph->ihl*4;
2480 		}
2481+	} else {
2482+		/* Half a match?  This means a partial retransmisison.
2483+		   It's a cracker being funky. */
2484+		if (net_ratelimit()) {
2485+			printk("FTP_NAT: partial packet %u/%u in %u/%u\n",
2486+			       exp->seq, ct_ftp_info->len,
2487+			       ntohl(tcph->seq),
2488+			       ntohl(tcph->seq) + datalen);
2489+		}
2490+		UNLOCK_BH(&ip_ftp_lock);
2491+		return NF_DROP;
2492 	}
2493-
2494 	UNLOCK_BH(&ip_ftp_lock);
2495 
2496-	ip_nat_seq_adjust(*pskb, ct, ctinfo);
2497-
2498 	return NF_ACCEPT;
2499 }
2500 
2501 static struct ip_nat_helper ftp[MAX_PORTS];
2502-static char ftp_names[MAX_PORTS][6];
2503-
2504-static struct ip_nat_expect ftp_expect
2505-= { { NULL, NULL }, ftp_nat_expected };
2506+static char ftp_names[MAX_PORTS][10];
2507 
2508 /* Not __exit: called from init() */
2509 static void fini(void)
2510 {
2511 	int i;
2512 
2513-	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
2514+	for (i = 0; i < ports_c; i++) {
2515 		DEBUGP("ip_nat_ftp: unregistering port %d\n", ports[i]);
2516 		ip_nat_helper_unregister(&ftp[i]);
2517 	}
2518-
2519-	ip_nat_expect_unregister(&ftp_expect);
2520 }
2521 
2522 static int __init init(void)
2523 {
2524-	int i, ret;
2525+	int i, ret = 0;
2526 	char *tmpname;
2527 
2528-	ret = ip_nat_expect_register(&ftp_expect);
2529-	if (ret == 0) {
2530-		if (ports[0] == 0)
2531-			ports[0] = 21;
2532-
2533-		for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
2534-
2535-			memset(&ftp[i], 0, sizeof(struct ip_nat_helper));
2536-
2537-			ftp[i].tuple.dst.protonum = IPPROTO_TCP;
2538-			ftp[i].tuple.src.u.tcp.port = htons(ports[i]);
2539-			ftp[i].mask.dst.protonum = 0xFFFF;
2540-			ftp[i].mask.src.u.tcp.port = 0xFFFF;
2541-			ftp[i].help = help;
2542-
2543-			tmpname = &ftp_names[i][0];
2544-			sprintf(tmpname, "ftp%2.2d", i);
2545-			ftp[i].name = tmpname;
2546-
2547-			DEBUGP("ip_nat_ftp: Trying to register for port %d\n",
2548-					ports[i]);
2549-			ret = ip_nat_helper_register(&ftp[i]);
2550-
2551-			if (ret) {
2552-				printk("ip_nat_ftp: error registering helper for port %d\n", ports[i]);
2553-				fini();
2554-				return ret;
2555-			}
2556-			ports_c++;
2557-		}
2558+	if (ports[0] == 0)
2559+		ports[0] = FTP_PORT;
2560 
2561-	} else {
2562-		ip_nat_expect_unregister(&ftp_expect);
2563+	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
2564+
2565+		memset(&ftp[i], 0, sizeof(struct ip_nat_helper));
2566+
2567+		ftp[i].tuple.dst.protonum = IPPROTO_TCP;
2568+		ftp[i].tuple.src.u.tcp.port = htons(ports[i]);
2569+		ftp[i].mask.dst.protonum = 0xFFFF;
2570+		ftp[i].mask.src.u.tcp.port = 0xFFFF;
2571+		ftp[i].help = help;
2572+		ftp[i].me = THIS_MODULE;
2573+		ftp[i].flags = 0;
2574+		ftp[i].expect = ftp_nat_expected;
2575+
2576+		tmpname = &ftp_names[i][0];
2577+		if (ports[i] == FTP_PORT)
2578+			sprintf(tmpname, "ftp");
2579+		else
2580+			sprintf(tmpname, "ftp-%d", i);
2581+		ftp[i].name = tmpname;
2582+
2583+		DEBUGP("ip_nat_ftp: Trying to register for port %d\n",
2584+				ports[i]);
2585+		ret = ip_nat_helper_register(&ftp[i]);
2586+
2587+		if (ret) {
2588+			printk("ip_nat_ftp: error registering "
2589+			       "helper for port %d\n", ports[i]);
2590+			fini();
2591+			return ret;
2592+		}
2593+		ports_c++;
2594 	}
2595+
2596 	return ret;
2597 }
2598 
2599diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv4/netfilter/ip_nat_helper.c linux-2.4.20-plain/net/ipv4/netfilter/ip_nat_helper.c
2600--- linux-2.4.19-plain/net/ipv4/netfilter/ip_nat_helper.c	Fri Dec 21 18:42:05 2001
2601+++ linux-2.4.20-plain/net/ipv4/netfilter/ip_nat_helper.c	Fri Nov 29 00:53:15 2002
2602@@ -1,11 +1,18 @@
2603 /* ip_nat_mangle.c - generic support functions for NAT helpers 
2604  *
2605- * (C) 2000 by Harald Welte <laforge@gnumonks.org>
2606+ * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>
2607  *
2608  * distributed under the terms of GNU GPL
2609+ *
2610+ * 	14 Jan 2002 Harald Welte <laforge@gnumonks.org>:
2611+ *		- add support for SACK adjustment 
2612+ *	14 Mar 2002 Harald Welte <laforge@gnumonks.org>:
2613+ *		- merge SACK support into newnat API
2614  */
2615 #include <linux/version.h>
2616+#include <linux/config.h>
2617 #include <linux/module.h>
2618+#include <linux/kmod.h>
2619 #include <linux/types.h>
2620 #include <linux/timer.h>
2621 #include <linux/skbuff.h>
2622@@ -19,6 +26,8 @@
2623 #define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock)
2624 #define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock)
2625 
2626+#include <linux/netfilter_ipv4/ip_conntrack.h>
2627+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
2628 #include <linux/netfilter_ipv4/ip_nat.h>
2629 #include <linux/netfilter_ipv4/ip_nat_protocol.h>
2630 #include <linux/netfilter_ipv4/ip_nat_core.h>
2631@@ -32,7 +41,7 @@
2632 #define DEBUGP(format, args...)
2633 #define DUMP_OFFSET(x)
2634 #endif
2635-	
2636+
2637 DECLARE_LOCK(ip_nat_seqofs_lock);
2638 			 
2639 static inline int 
2640@@ -199,6 +208,103 @@
2641 	return 1;
2642 }
2643 
2644+/* Adjust one found SACK option including checksum correction */
2645+static void
2646+sack_adjust(struct tcphdr *tcph, 
2647+	    unsigned char *ptr, 
2648+	    struct ip_nat_seq *natseq)
2649+{
2650+	struct tcp_sack_block *sp = (struct tcp_sack_block *)(ptr+2);
2651+	int num_sacks = (ptr[1] - TCPOLEN_SACK_BASE)>>3;
2652+	int i;
2653+
2654+	for (i = 0; i < num_sacks; i++, sp++) {
2655+		u_int32_t new_start_seq, new_end_seq;
2656+
2657+		if (after(ntohl(sp->start_seq) - natseq->offset_before,
2658+			  natseq->correction_pos))
2659+			new_start_seq = ntohl(sp->start_seq) 
2660+					- natseq->offset_after;
2661+		else
2662+			new_start_seq = ntohl(sp->start_seq) 
2663+					- natseq->offset_before;
2664+		new_start_seq = htonl(new_start_seq);
2665+
2666+		if (after(ntohl(sp->end_seq) - natseq->offset_before,
2667+			  natseq->correction_pos))
2668+			new_end_seq = ntohl(sp->end_seq)
2669+				      - natseq->offset_after;
2670+		else
2671+			new_end_seq = ntohl(sp->end_seq)
2672+				      - natseq->offset_before;
2673+		new_end_seq = htonl(new_end_seq);
2674+
2675+		DEBUGP("sack_adjust: start_seq: %d->%d, end_seq: %d->%d\n",
2676+			ntohl(sp->start_seq), new_start_seq,
2677+			ntohl(sp->end_seq), new_end_seq);
2678+
2679+		tcph->check = 
2680+			ip_nat_cheat_check(~sp->start_seq, new_start_seq,
2681+					   ip_nat_cheat_check(~sp->end_seq, 
2682+						   	      new_end_seq,
2683+							      tcph->check));
2684+
2685+		sp->start_seq = new_start_seq;
2686+		sp->end_seq = new_end_seq;
2687+	}
2688+}
2689+			
2690+
2691+/* TCP SACK sequence number adjustment, return 0 if sack found and adjusted */
2692+static inline int
2693+ip_nat_sack_adjust(struct sk_buff *skb,
2694+			struct ip_conntrack *ct,
2695+			enum ip_conntrack_info ctinfo)
2696+{
2697+	struct iphdr *iph;
2698+	struct tcphdr *tcph;
2699+	unsigned char *ptr;
2700+	int length, dir, sack_adjusted = 0;
2701+
2702+	iph = skb->nh.iph;
2703+	tcph = (void *)iph + iph->ihl*4;
2704+	length = (tcph->doff*4)-sizeof(struct tcphdr);
2705+	ptr = (unsigned char *)(tcph+1);
2706+
2707+	dir = CTINFO2DIR(ctinfo);
2708+
2709+	while (length > 0) {
2710+		int opcode = *ptr++;
2711+		int opsize;
2712+
2713+		switch (opcode) {
2714+		case TCPOPT_EOL:
2715+			return !sack_adjusted;
2716+		case TCPOPT_NOP:
2717+			length--;
2718+			continue;
2719+		default:
2720+			opsize = *ptr++;
2721+			if (opsize > length) /* no partial opts */
2722+				return !sack_adjusted;
2723+			if (opcode == TCPOPT_SACK) {
2724+				/* found SACK */
2725+				if((opsize >= (TCPOLEN_SACK_BASE
2726+					       +TCPOLEN_SACK_PERBLOCK)) &&
2727+				   !((opsize - TCPOLEN_SACK_BASE)
2728+				     % TCPOLEN_SACK_PERBLOCK))
2729+					sack_adjust(tcph, ptr-2,
2730+						    &ct->nat.info.seq[!dir]);
2731+				
2732+				sack_adjusted = 1;
2733+			}
2734+			ptr += opsize-2;
2735+			length -= opsize;
2736+		}
2737+	}
2738+	return !sack_adjusted;
2739+}
2740+
2741 /* TCP sequence number adjustment */
2742 int 
2743 ip_nat_seq_adjust(struct sk_buff *skb, 
2744@@ -243,51 +349,9 @@
2745 	tcph->seq = newseq;
2746 	tcph->ack_seq = newack;
2747 
2748-	return 0;
2749-}
2750-
2751-/* Grrr... SACK.  Fuck me even harder.  Don't want to fix it on the
2752-   fly, so blow it away. */
2753-void
2754-ip_nat_delete_sack(struct sk_buff *skb, struct tcphdr *tcph)
2755-{
2756-	unsigned int i;
2757-	u_int8_t *opt = (u_int8_t *)tcph;
2758-
2759-	DEBUGP("Seeking SACKPERM in SYN packet (doff = %u).\n",
2760-	       tcph->doff * 4);
2761-	for (i = sizeof(struct tcphdr); i < tcph->doff * 4;) {
2762-		DEBUGP("%u ", opt[i]);
2763-		switch (opt[i]) {
2764-		case TCPOPT_NOP:
2765-		case TCPOPT_EOL:
2766-			i++;
2767-			break;
2768+	ip_nat_sack_adjust(skb, ct, ctinfo);
2769 
2770-		case TCPOPT_SACK_PERM:
2771-			goto found_opt;
2772-
2773-		default:
2774-			/* Worst that can happen: it will take us over. */
2775-			i += opt[i+1] ?: 1;
2776-		}
2777-	}
2778-	DEBUGP("\n");
2779-	return;
2780-
2781- found_opt:
2782-	DEBUGP("\n");
2783-	DEBUGP("Found SACKPERM at offset %u.\n", i);
2784-
2785-	/* Must be within TCP header, and valid SACK perm. */
2786-	if (i + opt[i+1] <= tcph->doff*4 && opt[i+1] == 2) {
2787-		/* Replace with NOPs. */
2788-		tcph->check
2789-			= ip_nat_cheat_check(*((u_int16_t *)(opt + i))^0xFFFF,
2790-					     (TCPOPT_NOP<<8)|TCPOPT_NOP, tcph->check);
2791-		opt[i] = opt[i+1] = TCPOPT_NOP;
2792-	}
2793-	else DEBUGP("Something wrong with SACK_PERM.\n");
2794+	return 0;
2795 }
2796 
2797 static inline int
2798@@ -297,10 +361,51 @@
2799 	return ip_ct_tuple_mask_cmp(tuple, &helper->tuple, &helper->mask);
2800 }
2801 
2802+#define MODULE_MAX_NAMELEN		32
2803+
2804 int ip_nat_helper_register(struct ip_nat_helper *me)
2805 {
2806 	int ret = 0;
2807 
2808+	if (me->me && !(me->flags & IP_NAT_HELPER_F_STANDALONE)) {
2809+		struct ip_conntrack_helper *ct_helper;
2810+		
2811+		if ((ct_helper = ip_ct_find_helper(&me->tuple))
2812+		    && ct_helper->me) {
2813+			__MOD_INC_USE_COUNT(ct_helper->me);
2814+		} else {
2815+
2816+			/* We are a NAT helper for protocol X.  If we need
2817+			 * respective conntrack helper for protoccol X, compute
2818+			 * conntrack helper name and try to load module */
2819+			char name[MODULE_MAX_NAMELEN];
2820+			const char *tmp = me->me->name;
2821+			
2822+			if (strlen(tmp) + 6 > MODULE_MAX_NAMELEN) {
2823+				printk(__FUNCTION__ ": unable to "
2824+				       "compute conntrack helper name "
2825+				       "from %s\n", tmp);
2826+				return -EBUSY;
2827+			}
2828+			tmp += 6;
2829+			sprintf(name, "ip_conntrack%s", tmp);
2830+#ifdef CONFIG_KMOD
2831+			if (!request_module(name)
2832+			    && (ct_helper = ip_ct_find_helper(&me->tuple))
2833+			    && ct_helper->me) {
2834+				__MOD_INC_USE_COUNT(ct_helper->me);
2835+			} else {
2836+				printk("unable to load module %s\n", name);
2837+				return -EBUSY;
2838+			}
2839+#else
2840+			printk("unable to load module %s automatically "
2841+			       "because kernel was compiled without kernel "
2842+			       "module loader support\n", name);
2843+			return -EBUSY;
2844+#endif
2845+		}
2846+	}
2847 	WRITE_LOCK(&ip_nat_lock);
2848 	if (LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,&me->tuple))
2849 		ret = -EBUSY;
2850@@ -327,8 +432,14 @@
2851 
2852 void ip_nat_helper_unregister(struct ip_nat_helper *me)
2853 {
2854+	int found = 0;
2855+	
2856 	WRITE_LOCK(&ip_nat_lock);
2857-	LIST_DELETE(&helpers, me);
2858+	/* Autoloading conntrack helper might have failed */
2859+	if (LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,&me->tuple)) {
2860+		LIST_DELETE(&helpers, me);
2861+		found = 1;
2862+	}
2863 	WRITE_UNLOCK(&ip_nat_lock);
2864 
2865 	/* Someone could be still looking at the helper in a bh. */
2866@@ -344,5 +455,19 @@
2867 	   worse. --RR */
2868 	ip_ct_selective_cleanup(kill_helper, me);
2869 
2870-	MOD_DEC_USE_COUNT;
2871+	if (found)
2872+		MOD_DEC_USE_COUNT;
2873+
2874+	/* If we are no standalone NAT helper, we need to decrement usage count
2875+	 * on our conntrack helper */
2876+	if (me->me && !(me->flags & IP_NAT_HELPER_F_STANDALONE)) {
2877+		struct ip_conntrack_helper *ct_helper;
2878+		
2879+		if ((ct_helper = ip_ct_find_helper(&me->tuple))
2880+		    && ct_helper->me) {
2881+			__MOD_DEC_USE_COUNT(ct_helper->me);
2882+		} else 
2883+			printk(__FUNCTION__ ": unable to decrement usage count"
2884+			       " of conntrack helper %s\n", me->me->name);
2885+	}
2886 }
2887diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv4/netfilter/ip_nat_irc.c linux-2.4.20-plain/net/ipv4/netfilter/ip_nat_irc.c
2888--- linux-2.4.19-plain/net/ipv4/netfilter/ip_nat_irc.c	Fri Dec 21 18:42:05 2001
2889+++ linux-2.4.20-plain/net/ipv4/netfilter/ip_nat_irc.c	Fri Nov 29 00:53:15 2002
2890@@ -51,42 +51,29 @@
2891 
2892 
2893-static int
2894+static unsigned int
2895 irc_nat_expected(struct sk_buff **pskb,
2896 		 unsigned int hooknum,
2897 		 struct ip_conntrack *ct,
2898-		 struct ip_nat_info *info,
2899-		 struct ip_conntrack *master,
2900-		 struct ip_nat_info *masterinfo, unsigned int *verdict)
2901+		 struct ip_nat_info *info)
2902 {
2903 	struct ip_nat_multi_range mr;
2904 	u_int32_t newdstip, newsrcip, newip;
2905-	struct ip_ct_irc *ircinfo;
2906+
2907+	struct ip_conntrack *master = master_ct(ct);
2908 
2909 	IP_NF_ASSERT(info);
2910 	IP_NF_ASSERT(master);
2911-	IP_NF_ASSERT(masterinfo);
2912 
2913 	IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
2914 
2915 	DEBUGP("nat_expected: We have a connection!\n");
2916 
2917-	/* Master must be an irc connection */
2918-	ircinfo = &master->help.ct_irc_info;
2919-	LOCK_BH(&ip_irc_lock);
2920-	if (ircinfo->is_irc != IP_CONNTR_IRC) {
2921-		UNLOCK_BH(&ip_irc_lock);
2922-		DEBUGP("nat_expected: master not irc\n");
2923-		return 0;
2924-	}
2925-
2926 	newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
2927 	newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
2928 	DEBUGP("nat_expected: DCC cmd. %u.%u.%u.%u->%u.%u.%u.%u\n",
2929 	       NIPQUAD(newsrcip), NIPQUAD(newdstip));
2930 
2931-	UNLOCK_BH(&ip_irc_lock);
2932-
2933 	if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
2934 		newip = newsrcip;
2935 	else
2936@@ -99,16 +86,14 @@
2937 	mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
2938 	mr.range[0].min_ip = mr.range[0].max_ip = newip;
2939 
2940-	*verdict = ip_nat_setup_info(ct, &mr, hooknum);
2941-
2942-	return 1;
2943+	return ip_nat_setup_info(ct, &mr, hooknum);
2944 }
2945 
2946-static int irc_data_fixup(const struct ip_ct_irc *ct_irc_info,
2947+static int irc_data_fixup(const struct ip_ct_irc_expect *ct_irc_info,
2948 			  struct ip_conntrack *ct,
2949-			  unsigned int datalen,
2950 			  struct sk_buff **pskb,
2951-			  enum ip_conntrack_info ctinfo)
2952+			  enum ip_conntrack_info ctinfo,
2953+			  struct ip_conntrack_expect *expect)
2954 {
2955 	u_int32_t newip;
2956 	struct ip_conntrack_tuple t;
2957@@ -121,9 +106,9 @@
2958 
2959 	MUST_BE_LOCKED(&ip_irc_lock);
2960 
2961-	DEBUGP("IRC_NAT: info (seq %u + %u) packet(seq %u + %u)\n",
2962-	       ct_irc_info->seq, ct_irc_info->len,
2963-	       ntohl(tcph->seq), datalen);
2964+	DEBUGP("IRC_NAT: info (seq %u + %u) in %u\n",
2965+	       expect->seq, ct_irc_info->len,
2966+	       ntohl(tcph->seq));
2967 
2968 	newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
2969 
2970@@ -133,13 +118,11 @@
2971 	   only set in ip_conntrack_irc, with ip_irc_lock held
2972 	   writable */
2973 
2974-	t = ct->expected.tuple;
2975+	t = expect->tuple;
2976 	t.dst.ip = newip;
2977 	for (port = ct_irc_info->port; port != 0; port++) {
2978 		t.dst.u.tcp.port = htons(port);
2979-		if (ip_conntrack_expect_related(ct, &t,
2980-						&ct->expected.mask,
2981-						NULL) == 0) {
2982+		if (ip_conntrack_change_expect(expect, &t) == 0) {
2983 			DEBUGP("using port %d", port);
2984 			break;
2985 		}
2986@@ -166,26 +149,28 @@
2987 	       buffer, NIPQUAD(newip), port);
2988 
2989 	return ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, 
2990-					ct_irc_info->seq - ntohl(tcph->seq),
2991+					expect->seq - ntohl(tcph->seq),
2992 					ct_irc_info->len, buffer, 
2993 					strlen(buffer));
2994 }
2995 
2996 static unsigned int help(struct ip_conntrack *ct,
2997+			 struct ip_conntrack_expect *exp,
2998 			 struct ip_nat_info *info,
2999 			 enum ip_conntrack_info ctinfo,
3000-			 unsigned int hooknum, struct sk_buff **pskb)
3001+			 unsigned int hooknum, 
3002+			 struct sk_buff **pskb)
3003 {
3004 	struct iphdr *iph = (*pskb)->nh.iph;
3005 	struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
3006 	unsigned int datalen;
3007 	int dir;
3008-	int score;
3009-	struct ip_ct_irc *ct_irc_info = &ct->help.ct_irc_info;
3010+	struct ip_ct_irc_expect *ct_irc_info;
3011 
3012-	/* Delete SACK_OK on initial TCP SYNs. */
3013-	if (tcph->syn && !tcph->ack)
3014-		ip_nat_delete_sack(*pskb, tcph);
3015+	if (!exp)
3016+		DEBUGP("ip_nat_irc: no exp!!");
3017+		
3018+	ct_irc_info = &exp->help.exp_irc_info;
3019 
3020 	/* Only mangle things once: original direction in POST_ROUTING
3021 	   and reply direction on PRE_ROUTING. */
3022@@ -202,55 +187,35 @@
3023 	DEBUGP("got beyond not touching\n");
3024 
3025 	datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4;
3026-	score = 0;
3027 	LOCK_BH(&ip_irc_lock);
3028-	if (ct_irc_info->len) {
3029-		DEBUGP("got beyond ct_irc_info->len\n");
3030-
3031-		/* If it's in the right range... */
3032-		score += between(ct_irc_info->seq, ntohl(tcph->seq),
3033-				 ntohl(tcph->seq) + datalen);
3034-		score += between(ct_irc_info->seq + ct_irc_info->len,
3035-				 ntohl(tcph->seq),
3036-				 ntohl(tcph->seq) + datalen);
3037-		if (score == 1) {
3038-			/* Half a match?  This means a partial retransmisison.
3039-			   It's a cracker being funky. */
3040-			if (net_ratelimit()) {
3041-				printk
3042-				    ("IRC_NAT: partial packet %u/%u in %u/%u\n",
3043-				     ct_irc_info->seq, ct_irc_info->len,
3044-				     ntohl(tcph->seq),
3045-				     ntohl(tcph->seq) + datalen);
3046-			}
3047+	/* Check wether the whole IP/address pattern is carried in the payload */
3048+	if (between(exp->seq + ct_irc_info->len,
3049+		    ntohl(tcph->seq),
3050+		    ntohl(tcph->seq) + datalen)) {
3051+		if (!irc_data_fixup(ct_irc_info, ct, pskb, ctinfo, exp)) {
3052 			UNLOCK_BH(&ip_irc_lock);
3053 			return NF_DROP;
3054-		} else if (score == 2) {
3055-			DEBUGP("IRC_NAT: score=2, calling fixup\n");
3056-			if (!irc_data_fixup(ct_irc_info, ct, datalen,
3057-					    pskb, ctinfo)) {
3058-				UNLOCK_BH(&ip_irc_lock);
3059-				return NF_DROP;
3060-			}
3061-			/* skb may have been reallocated */
3062-			iph = (*pskb)->nh.iph;
3063-			tcph = (void *) iph + iph->ihl * 4;
3064 		}
3065+	} else { 
3066+		/* Half a match?  This means a partial retransmisison.
3067+		   It's a cracker being funky. */
3068+		if (net_ratelimit()) {
3069+			printk
3070+			    ("IRC_NAT: partial packet %u/%u in %u/%u\n",
3071+			     exp->seq, ct_irc_info->len,
3072+			     ntohl(tcph->seq),
3073+			     ntohl(tcph->seq) + datalen);
3074+		}
3075+		UNLOCK_BH(&ip_irc_lock);
3076+		return NF_DROP;
3077 	}
3078-
3079 	UNLOCK_BH(&ip_irc_lock);
3080 
3081-	ip_nat_seq_adjust(*pskb, ct, ctinfo);
3082-
3083 	return NF_ACCEPT;
3084 }
3085 
3086 static struct ip_nat_helper ip_nat_irc_helpers[MAX_PORTS];
3087-static char ip_nih_names[MAX_PORTS][6];
3088-
3089-static struct ip_nat_expect irc_expect
3090-    = { {NULL, NULL}, irc_nat_expected };
3091-
3092+static char irc_names[MAX_PORTS][10];
3093 
3094 /* This function is intentionally _NOT_ defined as  __exit, because
3095  * it is needed by init() */
3096@@ -262,52 +227,54 @@
3097 		DEBUGP("ip_nat_irc: unregistering helper for port %d\n",
3098 		       ports[i]);
3099 		ip_nat_helper_unregister(&ip_nat_irc_helpers[i]);
3100-	}
3101-	ip_nat_expect_unregister(&irc_expect);
3102+	} 
3103 }
3104+
3105 static int __init init(void)
3106 {
3107-	int ret;
3108+	int ret = 0;
3109 	int i;
3110 	struct ip_nat_helper *hlpr;
3111 	char *tmpname;
3112 
3113-	ret = ip_nat_expect_register(&irc_expect);
3114-	if (ret == 0) {
3115-
3116-		if (ports[0] == 0) {
3117-			ports[0] = 6667;
3118-		}
3119+	if (ports[0] == 0) {
3120+		ports[0] = IRC_PORT;
3121+	}
3122 
3123-		for (i = 0; (i < MAX_PORTS) && ports[i] != 0; i++) {
3124-			hlpr = &ip_nat_irc_helpers[i];
3125-			memset(hlpr, 0,
3126-			       sizeof(struct ip_nat_helper));
3127-
3128-			hlpr->tuple.dst.protonum = IPPROTO_TCP;
3129-			hlpr->tuple.src.u.tcp.port = htons(ports[i]);
3130-			hlpr->mask.src.u.tcp.port = 0xFFFF;
3131-			hlpr->mask.dst.protonum = 0xFFFF;
3132-			hlpr->help = help;
3133-
3134-			tmpname = &ip_nih_names[i][0];
3135-			sprintf(tmpname, "irc%2.2d", i);
3136-
3137-			hlpr->name = tmpname;
3138-			DEBUGP
3139-			    ("ip_nat_irc: Trying to register helper for port %d: name %s\n",
3140-			     ports[i], hlpr->name);
3141-			ret = ip_nat_helper_register(hlpr);
3142-
3143-			if (ret) {
3144-				printk
3145-				    ("ip_nat_irc: error registering helper for port %d\n",
3146-				     ports[i]);
3147-				fini();
3148-				return 1;
3149-			}
3150-			ports_c++;
3151+	for (i = 0; (i < MAX_PORTS) && ports[i] != 0; i++) {
3152+		hlpr = &ip_nat_irc_helpers[i];
3153+		memset(hlpr, 0,
3154+		       sizeof(struct ip_nat_helper));
3155+
3156+		hlpr->tuple.dst.protonum = IPPROTO_TCP;
3157+		hlpr->tuple.src.u.tcp.port = htons(ports[i]);
3158+		hlpr->mask.src.u.tcp.port = 0xFFFF;
3159+		hlpr->mask.dst.protonum = 0xFFFF;
3160+		hlpr->help = help;
3161+		hlpr->flags = 0;
3162+		hlpr->me = THIS_MODULE;
3163+		hlpr->expect = irc_nat_expected;
3164+
3165+		tmpname = &irc_names[i][0];
3166+		if (ports[i] == IRC_PORT)
3167+			sprintf(tmpname, "irc");
3168+		else
3169+			sprintf(tmpname, "irc-%d", i);
3170+		hlpr->name = tmpname;
3171+
3172+		DEBUGP
3173+		    ("ip_nat_irc: Trying to register helper for port %d: name %s\n",
3174+		     ports[i], hlpr->name);
3175+		ret = ip_nat_helper_register(hlpr);
3176+
3177+		if (ret) {
3178+			printk
3179+			    ("ip_nat_irc: error registering helper for port %d\n",
3180+			     ports[i]);
3181+			fini();
3182+			return 1;
3183 		}
3184+		ports_c++;
3185 	}
3186 	return ret;
3187 }
3188diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv4/netfilter/ip_nat_proto_tcp.c linux-2.4.20-plain/net/ipv4/netfilter/ip_nat_proto_tcp.c
3189--- linux-2.4.19-plain/net/ipv4/netfilter/ip_nat_proto_tcp.c	Tue Aug  7 17:30:50 2001
3190+++ linux-2.4.20-plain/net/ipv4/netfilter/ip_nat_proto_tcp.c	Fri Nov 29 00:53:15 2002
3191@@ -4,7 +4,6 @@
3192 #include <linux/ip.h>
3193 #include <linux/tcp.h>
3194 #include <linux/if.h>
3195-
3196 #include <linux/netfilter_ipv4/ip_nat.h>
3197 #include <linux/netfilter_ipv4/ip_nat_rule.h>
3198 #include <linux/netfilter_ipv4/ip_nat_protocol.h>
3199diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv4/netfilter/ip_nat_proto_unknown.c linux-2.4.20-plain/net/ipv4/netfilter/ip_nat_proto_unknown.c
3200--- linux-2.4.19-plain/net/ipv4/netfilter/ip_nat_proto_unknown.c	Fri Mar 17 19:56:20 2000
3201+++ linux-2.4.20-plain/net/ipv4/netfilter/ip_nat_proto_unknown.c	Fri Nov 29 00:53:15 2002
3202@@ -1,5 +1,5 @@
3203 /* The "unknown" protocol.  This is what is used for protocols we
3204- * don't understand.  It's returned by find_proto().
3205+ * don't understand.  It's returned by ip_ct_find_proto().
3206  */
3207 
3208 #include <linux/types.h>
3209diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv4/netfilter/ip_nat_rule.c linux-2.4.20-plain/net/ipv4/netfilter/ip_nat_rule.c
3210--- linux-2.4.19-plain/net/ipv4/netfilter/ip_nat_rule.c	Sat Aug  3 02:39:46 2002
3211+++ linux-2.4.20-plain/net/ipv4/netfilter/ip_nat_rule.c	Fri Nov 29 00:53:15 2002
3212@@ -106,8 +106,6 @@
3213 = { { NULL, NULL }, "nat", &nat_initial_table.repl,
3214     NAT_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL, THIS_MODULE };
3215 
3216-LIST_HEAD(nat_expect_list);
3217-
3218 /* Source NAT */
3219 static unsigned int ipt_snat_target(struct sk_buff **pskb,
3220 				    unsigned int hooknum,
3221@@ -254,19 +252,6 @@
3222 	return ip_nat_setup_info(conntrack, &mr, hooknum);
3223 }
3224 
3225-static inline int call_expect(const struct ip_nat_expect *i,
3226-			      struct sk_buff **pskb,
3227-			      unsigned int hooknum,
3228-			      struct ip_conntrack *ct,
3229-			      struct ip_nat_info *info,
3230-			      struct ip_conntrack *master,
3231-			      struct ip_nat_info *masterinfo,
3232-			      unsigned int *verdict)
3233-{
3234-	return i->expect(pskb, hooknum, ct, info, master, masterinfo,
3235-			 verdict);
3236-}
3237-
3238 int ip_nat_rule_find(struct sk_buff **pskb,
3239 		     unsigned int hooknum,
3240 		     const struct net_device *in,
3241@@ -276,41 +261,14 @@
3242 {
3243 	int ret;
3244 
3245-	/* Master won't vanish while this ctrack still alive */
3246-	if (ct->master.master) {
3247-		struct ip_conntrack *master;
3248-
3249-		master = (struct ip_conntrack *)ct->master.master;
3250-		if (LIST_FIND(&nat_expect_list,
3251-			      call_expect,
3252-			      struct ip_nat_expect *,
3253-			      pskb, hooknum, ct, info,
3254-			      master, &master->nat.info, &ret))
3255-			return ret;
3256-	}
3257 	ret = ipt_do_table(pskb, hooknum, in, out, &nat_table, NULL);
3258+
3259 	if (ret == NF_ACCEPT) {
3260 		if (!(info->initialized & (1 << HOOK2MANIP(hooknum))))
3261 			/* NUL mapping */
3262 			ret = alloc_null_binding(ct, info, hooknum);
3263 	}
3264 	return ret;
3265-}
3266-
3267-int ip_nat_expect_register(struct ip_nat_expect *expect)
3268-{
3269-	WRITE_LOCK(&ip_nat_lock);
3270-	list_prepend(&nat_expect_list, expect);
3271-	WRITE_UNLOCK(&ip_nat_lock);
3272-
3273-	return 0;
3274-}
3275-
3276-void ip_nat_expect_unregister(struct ip_nat_expect *expect)
3277-{
3278-	WRITE_LOCK(&ip_nat_lock);
3279-	LIST_DELETE(&nat_expect_list, expect);
3280-	WRITE_UNLOCK(&ip_nat_lock);
3281 }
3282 
3283 static struct ipt_target ipt_snat_reg
3284diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv4/netfilter/ip_nat_snmp_basic.c linux-2.4.20-plain/net/ipv4/netfilter/ip_nat_snmp_basic.c
3285--- linux-2.4.19-plain/net/ipv4/netfilter/ip_nat_snmp_basic.c	Wed Oct 31 00:08:12 2001
3286+++ linux-2.4.20-plain/net/ipv4/netfilter/ip_nat_snmp_basic.c	Fri Nov 29 00:53:15 2002
3287@@ -1243,6 +1243,7 @@
3288  * NAT helper function, packets arrive here from NAT code.
3289  */
3290 static unsigned int nat_help(struct ip_conntrack *ct,
3291+			     struct ip_conntrack_expect *exp,
3292                              struct ip_nat_info *info,
3293                              enum ip_conntrack_info ctinfo,
3294                              unsigned int hooknum,
3295@@ -1259,9 +1260,9 @@
3296 	 * on post routing (SNAT).
3297 	 */
3298 	if (!((dir == IP_CT_DIR_REPLY && hooknum == NF_IP_PRE_ROUTING &&
3299-			udph->source == __constant_ntohs(SNMP_PORT)) ||
3300+			udph->source == ntohs(SNMP_PORT)) ||
3301 	      (dir == IP_CT_DIR_ORIGINAL && hooknum == NF_IP_POST_ROUTING &&
3302-	      		udph->dest == __constant_ntohs(SNMP_TRAP_PORT)))) {
3303+	      		udph->dest == ntohs(SNMP_TRAP_PORT)))) {
3304 		spin_unlock_bh(&snmp_lock);
3305 		return NF_ACCEPT;
3306 	}
3307@@ -1303,19 +1304,27 @@
3308 	return NF_DROP;
3309 }
3310 
3311-static struct ip_nat_helper snmp = { { NULL, NULL },
3312+static struct ip_nat_helper snmp = { 
3313+	{ NULL, NULL },
3314+	"snmp",
3315+	IP_NAT_HELPER_F_STANDALONE,
3316+	THIS_MODULE,
3317 	{ { 0, { __constant_htons(SNMP_PORT) } },
3318 	  { 0, { 0 }, IPPROTO_UDP } },
3319 	{ { 0, { 0xFFFF } },
3320 	  { 0, { 0 }, 0xFFFF } },
3321-	  nat_help, "snmp" };
3322+	nat_help, NULL };
3323  
3324-static struct ip_nat_helper snmp_trap = { { NULL, NULL },
3325+static struct ip_nat_helper snmp_trap = { 
3326+	{ NULL, NULL },
3327+	"snmp_trap",
3328+	IP_NAT_HELPER_F_STANDALONE,
3329+	THIS_MODULE,
3330 	{ { 0, { __constant_htons(SNMP_TRAP_PORT) } },
3331 	  { 0, { 0 }, IPPROTO_UDP } },
3332 	{ { 0, { 0xFFFF } },
3333 	  { 0, { 0 }, 0xFFFF } },
3334-	nat_help, "snmp_trap" };
3335+	nat_help, NULL };
3336 
3337 /*****************************************************************************
3338  *
3339diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv4/netfilter/ip_nat_standalone.c linux-2.4.20-plain/net/ipv4/netfilter/ip_nat_standalone.c
3340--- linux-2.4.19-plain/net/ipv4/netfilter/ip_nat_standalone.c	Sat Aug  3 02:39:46 2002
3341+++ linux-2.4.20-plain/net/ipv4/netfilter/ip_nat_standalone.c	Fri Nov 29 00:53:15 2002
3342@@ -5,7 +5,12 @@
3343 */
3344 
3345 /* (c) 1999 Paul `Rusty' Russell.  Licenced under the GNU General
3346-   Public Licence. */
3347+ * Public Licence.
3348+ *
3349+ * 23 Apr 2001: Harald Welte <laforge@gnumonks.org>
3350+ * 	- new API and handling of conntrack/nat helpers
3351+ * 	- now capable of multiple expectations for one master
3352+ * */
3353 
3354 #include <linux/config.h>
3355 #include <linux/types.h>
3356@@ -44,6 +49,15 @@
3357 			         : ((hooknum) == NF_IP_LOCAL_IN ? "LOCAL_IN"  \
3358 				    : "*ERROR*")))
3359 
3360+static inline int call_expect(struct ip_conntrack *master,
3361+			      struct sk_buff **pskb,
3362+			      unsigned int hooknum,
3363+			      struct ip_conntrack *ct,
3364+			      struct ip_nat_info *info)
3365+{
3366+	return master->nat.info.helper->expect(pskb, hooknum, ct, info);
3367+}
3368+
3369 static unsigned int
3370 ip_nat_fn(unsigned int hooknum,
3371 	  struct sk_buff **pskb,
3372@@ -60,7 +74,7 @@
3373 	/* We never see fragments: conntrack defrags on pre-routing
3374 	   and local-out, and ip_nat_out protects post-routing. */
3375 	IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off
3376-		       & __constant_htons(IP_MF|IP_OFFSET)));
3377+		       & htons(IP_MF|IP_OFFSET)));
3378 
3379 	(*pskb)->nfcache |= NFC_UNKNOWN;
3380 
3381@@ -110,8 +124,16 @@
3382 			int in_hashes = info->initialized;
3383 			unsigned int ret;
3384 
3385-			ret = ip_nat_rule_find(pskb, hooknum, in, out,
3386-					       ct, info);
3387+			if (ct->master
3388+			    && master_ct(ct)->nat.info.helper
3389+			    && master_ct(ct)->nat.info.helper->expect) {
3390+				ret = call_expect(master_ct(ct), pskb, 
3391+						  hooknum, ct, info);
3392+			} else {
3393+				ret = ip_nat_rule_find(pskb, hooknum, in, out,
3394+						       ct, info);
3395+			}
3396+
3397 			if (ret != NF_ACCEPT) {
3398 				WRITE_UNLOCK(&ip_nat_lock);
3399 				return ret;
3400@@ -163,7 +185,7 @@
3401 
3402 	   I'm starting to have nightmares about fragments.  */
3403 
3404-	if ((*pskb)->nh.iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) {
3405+	if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
3406 		*pskb = ip_ct_gather_frags(*pskb);
3407 
3408 		if (!*pskb)
3409@@ -334,11 +356,7 @@
3410 EXPORT_SYMBOL(ip_nat_protocol_unregister);
3411 EXPORT_SYMBOL(ip_nat_helper_register);
3412 EXPORT_SYMBOL(ip_nat_helper_unregister);
3413-EXPORT_SYMBOL(ip_nat_expect_register);
3414-EXPORT_SYMBOL(ip_nat_expect_unregister);
3415 EXPORT_SYMBOL(ip_nat_cheat_check);
3416 EXPORT_SYMBOL(ip_nat_mangle_tcp_packet);
3417-EXPORT_SYMBOL(ip_nat_seq_adjust);
3418-EXPORT_SYMBOL(ip_nat_delete_sack);
3419 EXPORT_SYMBOL(ip_nat_used_tuple);
3420 MODULE_LICENSE("GPL");
3421diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv4/netfilter/ip_queue.c linux-2.4.20-plain/net/ipv4/netfilter/ip_queue.c
3422--- linux-2.4.19-plain/net/ipv4/netfilter/ip_queue.c	Sat Aug  3 02:39:46 2002
3423+++ linux-2.4.20-plain/net/ipv4/netfilter/ip_queue.c	Fri Nov 29 00:53:15 2002
3424@@ -2,13 +2,14 @@
3425  * This is a module which is used for queueing IPv4 packets and
3426  * communicating with userspace via netlink.
3427  *
3428- * (C) 2000 James Morris, this code is GPL.
3429+ * (C) 2000-2002 James Morris, this code is GPL.
3430  *
3431  * 2000-03-27: Simplified code (thanks to Andi Kleen for clues).
3432  * 2000-05-20: Fixed notifier problems (following Miguel Freitas' report).
3433  * 2000-06-19: Fixed so nfmark is copied to metadata (reported by Sebastian 
3434  *             Zander).
3435  * 2000-08-01: Added Nick Williams' MAC support.
3436+ * 2002-06-25: Code cleanup.
3437  *
3438  */
3439 #include <linux/module.h>
3440@@ -18,205 +19,310 @@
3441 #include <linux/notifier.h>
3442 #include <linux/netdevice.h>
3443 #include <linux/netfilter.h>
3444+#include <linux/netfilter_ipv4/ip_queue.h>
3445+#include <linux/netfilter_ipv4/ip_tables.h>
3446 #include <linux/netlink.h>
3447 #include <linux/spinlock.h>
3448-#include <linux/rtnetlink.h>
3449+#include <linux/brlock.h>
3450 #include <linux/sysctl.h>
3451 #include <linux/proc_fs.h>
3452 #include <net/sock.h>
3453 #include <net/route.h>
3454 
3455-#include <linux/netfilter_ipv4/ip_queue.h>
3456-#include <linux/netfilter_ipv4/ip_tables.h>
3457-
3458 #define IPQ_QMAX_DEFAULT 1024
3459 #define IPQ_PROC_FS_NAME "ip_queue"
3460 #define NET_IPQ_QMAX 2088
3461 #define NET_IPQ_QMAX_NAME "ip_queue_maxlen"
3462 
3463-typedef struct ipq_rt_info {
3464+struct ipq_rt_info {
3465 	__u8 tos;
3466 	__u32 daddr;
3467 	__u32 saddr;
3468-} ipq_rt_info_t;
3469+};
3470 
3471-typedef struct ipq_queue_element {
3472-	struct list_head list;		/* Links element into queue */
3473-	int verdict;			/* Current verdict */
3474-	struct nf_info *info;		/* Extra info from netfilter */
3475-	struct sk_buff *skb;		/* Packet inside */
3476-	ipq_rt_info_t rt_info;		/* May need post-mangle routing */
3477-} ipq_queue_element_t;
3478-
3479-typedef int (*ipq_send_cb_t)(ipq_queue_element_t *e);
3480-
3481-typedef struct ipq_peer {
3482-	pid_t pid;			/* PID of userland peer */
3483-	unsigned char died;		/* We think the peer died */
3484-	unsigned char copy_mode;	/* Copy packet as well as metadata? */
3485-	size_t copy_range;		/* Range past metadata to copy */
3486-	ipq_send_cb_t send;		/* Callback for sending data to peer */
3487-} ipq_peer_t;
3488-
3489-typedef struct ipq_queue {
3490- 	int len;			/* Current queue len */
3491- 	int *maxlen;			/* Maximum queue len, via sysctl */
3492- 	unsigned char flushing;		/* If queue is being flushed */
3493- 	unsigned char terminate;	/* If the queue is being terminated */
3494- 	struct list_head list;		/* Head of packet queue */
3495- 	spinlock_t lock;		/* Queue spinlock */
3496- 	ipq_peer_t peer;		/* Userland peer */
3497-} ipq_queue_t;
3498+struct ipq_queue_entry {
3499+	struct list_head list;
3500+	struct nf_info *info;
3501+	struct sk_buff *skb;
3502+	struct ipq_rt_info rt_info;
3503+};
3504 
3505-/****************************************************************************
3506- *
3507- * Packet queue
3508- *
3509- ****************************************************************************/
3510-/* Dequeue a packet if matched by cmp, or the next available if cmp is NULL */
3511-static ipq_queue_element_t *
3512-ipq_dequeue(ipq_queue_t *q,
3513-            int (*cmp)(ipq_queue_element_t *, unsigned long),
3514-            unsigned long data)
3515-{
3516-	struct list_head *i;
3517-
3518-	spin_lock_bh(&q->lock);
3519-	for (i = q->list.prev; i != &q->list; i = i->prev) {
3520-		ipq_queue_element_t *e = (ipq_queue_element_t *)i;
3521-		
3522-		if (!cmp || cmp(e, data)) {
3523-			list_del(&e->list);
3524-			q->len--;
3525-			spin_unlock_bh(&q->lock);
3526-			return e;
3527-		}
3528+typedef int (*ipq_cmpfn)(struct ipq_queue_entry *, unsigned long);
3529+
3530+static unsigned char copy_mode = IPQ_COPY_NONE;
3531+static unsigned int queue_maxlen = IPQ_QMAX_DEFAULT;
3532+static rwlock_t queue_lock = RW_LOCK_UNLOCKED;
3533+static int peer_pid;
3534+static unsigned int copy_range;
3535+static unsigned int queue_total;
3536+static struct sock *ipqnl;
3537+static LIST_HEAD(queue_list);
3538+static DECLARE_MUTEX(ipqnl_sem);
3539+
3540+static void
3541+ipq_issue_verdict(struct ipq_queue_entry *entry, int verdict)
3542+{
3543+	nf_reinject(entry->skb, entry->info, verdict);
3544+	kfree(entry);
3545+}
3546+
3547+static inline int
3548+__ipq_enqueue_entry(struct ipq_queue_entry *entry)
3549+{
3550+       if (queue_total >= queue_maxlen) {
3551+               if (net_ratelimit()) 
3552+                       printk(KERN_WARNING "ip_queue: full at %d entries, "
3553+                              "dropping packet(s).\n", queue_total);
3554+               return -ENOSPC;
3555+       }
3556+       list_add(&entry->list, &queue_list);
3557+       queue_total++;
3558+       return 0;
3559+}
3560+
3561+/*
3562+ * Find and return a queued entry matched by cmpfn, or return the last
3563+ * entry if cmpfn is NULL.
3564+ */
3565+static inline struct ipq_queue_entry *
3566+__ipq_find_entry(ipq_cmpfn cmpfn, unsigned long data)
3567+{
3568+	struct list_head *p;
3569+
3570+	list_for_each_prev(p, &queue_list) {
3571+		struct ipq_queue_entry *entry = (struct ipq_queue_entry *)p;
3572+		
3573+		if (!cmpfn || cmpfn(entry, data))
3574+			return entry;
3575 	}
3576-	spin_unlock_bh(&q->lock);
3577 	return NULL;
3578 }
3579 
3580-/* Flush all packets */
3581-static void ipq_flush(ipq_queue_t *q)
3582+static inline void
3583+__ipq_dequeue_entry(struct ipq_queue_entry *entry)
3584 {
3585-	ipq_queue_element_t *e;
3586-	
3587-	spin_lock_bh(&q->lock);
3588-	q->flushing = 1;
3589-	spin_unlock_bh(&q->lock);
3590-	while ((e = ipq_dequeue(q, NULL, 0))) {
3591-		e->verdict = NF_DROP;
3592-		nf_reinject(e->skb, e->info, e->verdict);
3593-		kfree(e);
3594-	}
3595-	spin_lock_bh(&q->lock);
3596-	q->flushing = 0;
3597-	spin_unlock_bh(&q->lock);
3598-}
3599-
3600-static ipq_queue_t *ipq_create_queue(nf_queue_outfn_t outfn,
3601-                                     ipq_send_cb_t send_cb,
3602-                                     int *errp, int *sysctl_qmax)
3603+	list_del(&entry->list);
3604+	queue_total--;
3605+}
3606+
3607+static inline struct ipq_queue_entry *
3608+__ipq_find_dequeue_entry(ipq_cmpfn cmpfn, unsigned long data)
3609 {
3610-	int status;
3611-	ipq_queue_t *q;
3612+	struct ipq_queue_entry *entry;
3613 
3614-	*errp = 0;
3615-	q = kmalloc(sizeof(ipq_queue_t), GFP_KERNEL);
3616-	if (q == NULL) {
3617-		*errp = -ENOMEM;
3618+	entry = __ipq_find_entry(cmpfn, data);
3619+	if (entry == NULL)
3620 		return NULL;
3621+
3622+	__ipq_dequeue_entry(entry);
3623+	return entry;
3624+}
3625+
3626+
3627+static inline void
3628+__ipq_flush(int verdict)
3629+{
3630+	struct ipq_queue_entry *entry;
3631+	
3632+	while ((entry = __ipq_find_dequeue_entry(NULL, 0)))
3633+		ipq_issue_verdict(entry, verdict);
3634+}
3635+
3636+static inline int
3637+__ipq_set_mode(unsigned char mode, unsigned int range)
3638+{
3639+	int status = 0;
3640+	
3641+	switch(mode) {
3642+	case IPQ_COPY_NONE:
3643+	case IPQ_COPY_META:
3644+		copy_mode = mode;
3645+		copy_range = 0;
3646+		break;
3647+		
3648+	case IPQ_COPY_PACKET:
3649+		copy_mode = mode;
3650+		copy_range = range;
3651+		if (copy_range > 0xFFFF)
3652+			copy_range = 0xFFFF;
3653+		break;
3654+		
3655+	default:
3656+		status = -EINVAL;
3657+
3658 	}
3659-	q->peer.pid = 0;
3660-	q->peer.died = 0;
3661-	q->peer.copy_mode = IPQ_COPY_NONE;
3662-	q->peer.copy_range = 0;
3663-	q->peer.send = send_cb;
3664-	q->len = 0;
3665-	q->maxlen = sysctl_qmax;
3666-	q->flushing = 0;
3667-	q->terminate = 0;
3668-	INIT_LIST_HEAD(&q->list);
3669-	spin_lock_init(&q->lock);
3670-	status = nf_register_queue_handler(PF_INET, outfn, q);
3671-	if (status < 0) {
3672-		*errp = -EBUSY;
3673-		kfree(q);
3674+	return status;
3675+}
3676+
3677+static inline void
3678+__ipq_reset(void)
3679+{
3680+	peer_pid = 0;
3681+	__ipq_set_mode(IPQ_COPY_NONE, 0);
3682+	__ipq_flush(NF_DROP);
3683+}
3684+
3685+static struct ipq_queue_entry *
3686+ipq_find_dequeue_entry(ipq_cmpfn cmpfn, unsigned long data)
3687+{
3688+	struct ipq_queue_entry *entry;
3689+	
3690+	write_lock_bh(&queue_lock);
3691+	entry = __ipq_find_dequeue_entry(cmpfn, data);
3692+	write_unlock_bh(&queue_lock);
3693+	return entry;
3694+}
3695+
3696+static void
3697+ipq_flush(int verdict)
3698+{
3699+	write_lock_bh(&queue_lock);
3700+	__ipq_flush(verdict);
3701+	write_unlock_bh(&queue_lock);
3702+}
3703+
3704+static struct sk_buff *
3705+ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp)
3706+{
3707+	unsigned char *old_tail;
3708+	size_t size = 0;
3709+	size_t data_len = 0;
3710+	struct sk_buff *skb;
3711+	struct ipq_packet_msg *pmsg;
3712+	struct nlmsghdr *nlh;
3713+
3714+	read_lock_bh(&queue_lock);
3715+	
3716+	switch (copy_mode) {
3717+	case IPQ_COPY_META:
3718+	case IPQ_COPY_NONE:
3719+		size = NLMSG_SPACE(sizeof(*pmsg));
3720+		data_len = 0;
3721+		break;
3722+	
3723+	case IPQ_COPY_PACKET:
3724+		if (copy_range == 0 || copy_range > entry->skb->len)
3725+			data_len = entry->skb->len;
3726+		else
3727+			data_len = copy_range;
3728+		
3729+		size = NLMSG_SPACE(sizeof(*pmsg) + data_len);
3730+		break;
3731+	
3732+	default:
3733+		*errp = -EINVAL;
3734+		read_unlock_bh(&queue_lock);
3735 		return NULL;
3736 	}
3737-	return q;
3738+
3739+	read_unlock_bh(&queue_lock);
3740+
3741+	skb = alloc_skb(size, GFP_ATOMIC);
3742+	if (!skb)
3743+		goto nlmsg_failure;
3744+		
3745+	old_tail= skb->tail;
3746+	nlh = NLMSG_PUT(skb, 0, 0, IPQM_PACKET, size - sizeof(*nlh));
3747+	pmsg = NLMSG_DATA(nlh);
3748+	memset(pmsg, 0, sizeof(*pmsg));
3749+
3750+	pmsg->packet_id       = (unsigned long )entry;
3751+	pmsg->data_len        = data_len;
3752+	pmsg->timestamp_sec   = entry->skb->stamp.tv_sec;
3753+	pmsg->timestamp_usec  = entry->skb->stamp.tv_usec;
3754+	pmsg->mark            = entry->skb->nfmark;
3755+	pmsg->hook            = entry->info->hook;
3756+	pmsg->hw_protocol     = entry->skb->protocol;
3757+	
3758+	if (entry->info->indev)
3759+		strcpy(pmsg->indev_name, entry->info->indev->name);
3760+	else
3761+		pmsg->indev_name[0] = '\0';
3762+	
3763+	if (entry->info->outdev)
3764+		strcpy(pmsg->outdev_name, entry->info->outdev->name);
3765+	else
3766+		pmsg->outdev_name[0] = '\0';
3767+	
3768+	if (entry->info->indev && entry->skb->dev) {
3769+		pmsg->hw_type = entry->skb->dev->type;
3770+		if (entry->skb->dev->hard_header_parse)
3771+			pmsg->hw_addrlen =
3772+				entry->skb->dev->hard_header_parse(entry->skb,
3773+				                                   pmsg->hw_addr);
3774+	}
3775+	
3776+	if (data_len)
3777+		memcpy(pmsg->payload, entry->skb->data, data_len);
3778+		
3779+	nlh->nlmsg_len = skb->tail - old_tail;
3780+	return skb;
3781+
3782+nlmsg_failure:
3783+	if (skb)
3784+		kfree_skb(skb);
3785+	*errp = -EINVAL;
3786+	printk(KERN_ERR "ip_queue: error creating packet message\n");
3787+	return NULL;
3788 }
3789 
3790-static int ipq_enqueue(ipq_queue_t *q,
3791-                       struct sk_buff *skb, struct nf_info *info)
3792+static int
3793+ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info, void *data)
3794 {
3795-	ipq_queue_element_t *e;
3796-	int status;
3797-	
3798-	e = kmalloc(sizeof(*e), GFP_ATOMIC);
3799-	if (e == NULL) {
3800-		printk(KERN_ERR "ip_queue: OOM in enqueue\n");
3801+	int status = -EINVAL;
3802+	struct sk_buff *nskb;
3803+	struct ipq_queue_entry *entry;
3804+
3805+	if (copy_mode == IPQ_COPY_NONE)
3806+		return -EAGAIN;
3807+
3808+	entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
3809+	if (entry == NULL) {
3810+		printk(KERN_ERR "ip_queue: OOM in ipq_enqueue_packet()\n");
3811 		return -ENOMEM;
3812 	}
3813 
3814-	e->verdict = NF_DROP;
3815-	e->info = info;
3816-	e->skb = skb;
3817+	entry->info = info;
3818+	entry->skb = skb;
3819 
3820-	if (e->info->hook == NF_IP_LOCAL_OUT) {
3821+	if (entry->info->hook == NF_IP_LOCAL_OUT) {
3822 		struct iphdr *iph = skb->nh.iph;
3823 
3824-		e->rt_info.tos = iph->tos;
3825-		e->rt_info.daddr = iph->daddr;
3826-		e->rt_info.saddr = iph->saddr;
3827-	}
3828-
3829-	spin_lock_bh(&q->lock);
3830-	if (q->len >= *q->maxlen) {
3831-		spin_unlock_bh(&q->lock);
3832-		if (net_ratelimit()) 
3833-			printk(KERN_WARNING "ip_queue: full at %d entries, "
3834-			       "dropping packet(s).\n", q->len);
3835-		goto free_drop;
3836-	}
3837-	if (q->flushing || q->peer.copy_mode == IPQ_COPY_NONE
3838-	    || q->peer.pid == 0 || q->peer.died || q->terminate) {
3839-		spin_unlock_bh(&q->lock);
3840-		goto free_drop;
3841-	}
3842-	status = q->peer.send(e);
3843-	if (status > 0) {
3844-		list_add(&e->list, &q->list);
3845-		q->len++;
3846-		spin_unlock_bh(&q->lock);
3847-		return status;
3848-	}
3849-	spin_unlock_bh(&q->lock);
3850-	if (status == -ECONNREFUSED) {
3851-		printk(KERN_INFO "ip_queue: peer %d died, "
3852-		       "resetting state and flushing queue\n", q->peer.pid);
3853-			q->peer.died = 1;
3854-			q->peer.pid = 0;
3855-			q->peer.copy_mode = IPQ_COPY_NONE;
3856-			q->peer.copy_range = 0;
3857-			ipq_flush(q);
3858-	}
3859-free_drop:
3860-	kfree(e);
3861-	return -EBUSY;
3862-}
3863+		entry->rt_info.tos = iph->tos;
3864+		entry->rt_info.daddr = iph->daddr;
3865+		entry->rt_info.saddr = iph->saddr;
3866+	}
3867 
3868-static void ipq_destroy_queue(ipq_queue_t *q)
3869-{
3870-	nf_unregister_queue_handler(PF_INET);
3871-	spin_lock_bh(&q->lock);
3872-	q->terminate = 1;
3873-	spin_unlock_bh(&q->lock);
3874-	ipq_flush(q);
3875-	kfree(q);
3876+	nskb = ipq_build_packet_message(entry, &status);
3877+	if (nskb == NULL)
3878+		goto err_out_free;
3879+		
3880+	write_lock_bh(&queue_lock);
3881+	
3882+	if (!peer_pid)
3883+		goto err_out_unlock;
3884+
3885+	status = netlink_unicast(ipqnl, nskb, peer_pid, MSG_DONTWAIT);
3886+	if (status < 0)
3887+		goto err_out_unlock;
3888+	
3889+	status = __ipq_enqueue_entry(entry);
3890+	if (status < 0)
3891+		goto err_out_unlock;
3892+
3893+	write_unlock_bh(&queue_lock);
3894+	return status;
3895+	
3896+err_out_unlock:
3897+	write_unlock_bh(&queue_lock);
3898+
3899+err_out_free:
3900+	kfree(entry);
3901+	return status;
3902 }
3903 
3904-static int ipq_mangle_ipv4(ipq_verdict_msg_t *v, ipq_queue_element_t *e)
3905+static int
3906+ipq_mangle_ipv4(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
3907 {
3908 	int diff;
3909 	struct iphdr *user_iph = (struct iphdr *)v->payload;
3910@@ -266,296 +372,216 @@
3911 	return 0;
3912 }
3913 
3914-static inline int id_cmp(ipq_queue_element_t *e, unsigned long id)
3915+static inline int
3916+id_cmp(struct ipq_queue_entry *e, unsigned long id)
3917 {
3918 	return (id == (unsigned long )e);
3919 }
3920 
3921-static int ipq_set_verdict(ipq_queue_t *q,
3922-                           ipq_verdict_msg_t *v, unsigned int len)
3923+static int
3924+ipq_set_verdict(struct ipq_verdict_msg *vmsg, unsigned int len)
3925 {
3926-	ipq_queue_element_t *e;
3927+	struct ipq_queue_entry *entry;
3928 
3929-	if (v->value > NF_MAX_VERDICT)
3930+	if (vmsg->value > NF_MAX_VERDICT)
3931 		return -EINVAL;
3932-	e = ipq_dequeue(q, id_cmp, v->id);
3933-	if (e == NULL)
3934+
3935+	entry = ipq_find_dequeue_entry(id_cmp, vmsg->id);
3936+	if (entry == NULL)
3937 		return -ENOENT;
3938 	else {
3939-		e->verdict = v->value;
3940-		if (v->data_len && v->data_len == len)
3941-			if (ipq_mangle_ipv4(v, e) < 0)
3942-				e->verdict = NF_DROP;
3943-		nf_reinject(e->skb, e->info, e->verdict);
3944-		kfree(e);
3945+		int verdict = vmsg->value;
3946+		
3947+		if (vmsg->data_len && vmsg->data_len == len)
3948+			if (ipq_mangle_ipv4(vmsg, entry) < 0)
3949+				verdict = NF_DROP;
3950+		
3951+		ipq_issue_verdict(entry, verdict);
3952 		return 0;
3953 	}
3954 }
3955 
3956-static int ipq_receive_peer(ipq_queue_t *q, ipq_peer_msg_t *m,
3957-                            unsigned char type, unsigned int len)
3958+static int
3959+ipq_set_mode(unsigned char mode, unsigned int range)
3960 {
3961+	int status;
3962+
3963+	write_lock_bh(&queue_lock);
3964+	status = __ipq_set_mode(mode, range);
3965+	write_unlock_bh(&queue_lock);
3966+	return status;
3967+}
3968 
3969+static int
3970+ipq_receive_peer(struct ipq_peer_msg *pmsg,
3971+                 unsigned char type, unsigned int len)
3972+{
3973 	int status = 0;
3974-	int busy;
3975-		
3976-	spin_lock_bh(&q->lock);
3977-	busy = (q->terminate || q->flushing);
3978-	spin_unlock_bh(&q->lock);
3979-	if (busy)
3980-		return -EBUSY;
3981-	if (len < sizeof(ipq_peer_msg_t))
3982+
3983+	if (len < sizeof(*pmsg))
3984 		return -EINVAL;
3985+
3986 	switch (type) {
3987-		case IPQM_MODE:
3988-			switch (m->msg.mode.value) {
3989-				case IPQ_COPY_META:
3990-					q->peer.copy_mode = IPQ_COPY_META;
3991-					q->peer.copy_range = 0;
3992-					break;
3993-				case IPQ_COPY_PACKET:
3994-					q->peer.copy_mode = IPQ_COPY_PACKET;
3995-					q->peer.copy_range = m->msg.mode.range;
3996-					if (q->peer.copy_range > 0xFFFF)
3997-						q->peer.copy_range = 0xFFFF;
3998-					break;
3999-				default:
4000-					status = -EINVAL;
4001-			}
4002-			break;
4003-		case IPQM_VERDICT:
4004-			if (m->msg.verdict.value > NF_MAX_VERDICT)
4005-				status = -EINVAL;
4006-			else
4007-				status = ipq_set_verdict(q,
4008-				                         &m->msg.verdict,
4009-				                         len - sizeof(*m));
4010+	case IPQM_MODE:
4011+		status = ipq_set_mode(pmsg->msg.mode.value,
4012+		                      pmsg->msg.mode.range);
4013+		break;
4014+		
4015+	case IPQM_VERDICT:
4016+		if (pmsg->msg.verdict.value > NF_MAX_VERDICT)
4017+			status = -EINVAL;
4018+		else
4019+			status = ipq_set_verdict(&pmsg->msg.verdict,
4020+			                         len - sizeof(*pmsg));
4021 			break;
4022-		default:
4023-			 status = -EINVAL;
4024+	default:
4025+		status = -EINVAL;
4026 	}
4027 	return status;
4028 }
4029 
4030-static inline int dev_cmp(ipq_queue_element_t *e, unsigned long ifindex)
4031+static int
4032+dev_cmp(struct ipq_queue_entry *entry, unsigned long ifindex)
4033 {
4034-	if (e->info->indev)
4035-		if (e->info->indev->ifindex == ifindex)
4036+	if (entry->info->indev)
4037+		if (entry->info->indev->ifindex == ifindex)
4038 			return 1;
4039-	if (e->info->outdev)
4040-		if (e->info->outdev->ifindex == ifindex)
4041+			
4042+	if (entry->info->outdev)
4043+		if (entry->info->outdev->ifindex == ifindex)
4044 			return 1;
4045+
4046 	return 0;
4047 }
4048 
4049-/* Drop any queued packets associated with device ifindex */
4050-static void ipq_dev_drop(ipq_queue_t *q, int ifindex)
4051+static void
4052+ipq_dev_drop(int ifindex)
4053 {
4054-	ipq_queue_element_t *e;
4055+	struct ipq_queue_entry *entry;
4056 	
4057-	while ((e = ipq_dequeue(q, dev_cmp, ifindex))) {
4058-		e->verdict = NF_DROP;
4059-		nf_reinject(e->skb, e->info, e->verdict);
4060-		kfree(e);
4061-	}
4062-}
4063-
4064-/****************************************************************************
4065- *
4066- * Netfilter interface
4067- *
4068- ****************************************************************************/
4069-
4070-/*
4071- * Packets arrive here from netfilter for queuing to userspace.
4072- * All of them must be fed back via nf_reinject() or Alexey will kill Rusty.
4073- */
4074-static int netfilter_receive(struct sk_buff *skb,
4075-                             struct nf_info *info, void *data)
4076-{
4077-	return ipq_enqueue((ipq_queue_t *)data, skb, info);
4078-}
4079-
4080-/****************************************************************************
4081- *
4082- * Netlink interface.
4083- *
4084- ****************************************************************************/
4085-
4086-static struct sock *nfnl = NULL;
4087-ipq_queue_t *nlq = NULL;
4088-
4089-static struct sk_buff *netlink_build_message(ipq_queue_element_t *e, int *errp)
4090-{
4091-	unsigned char *old_tail;
4092-	size_t size = 0;
4093-	size_t data_len = 0;
4094-	struct sk_buff *skb;
4095-	ipq_packet_msg_t *pm;
4096-	struct nlmsghdr *nlh;
4097-
4098-	switch (nlq->peer.copy_mode) {
4099-		size_t copy_range;
4100-
4101-		case IPQ_COPY_META:
4102-			size = NLMSG_SPACE(sizeof(*pm));
4103-			data_len = 0;
4104-			break;
4105-		case IPQ_COPY_PACKET:
4106-			copy_range = nlq->peer.copy_range;
4107-			if (copy_range == 0 || copy_range > e->skb->len)
4108-				data_len = e->skb->len;
4109-			else
4110-				data_len = copy_range;
4111-			size = NLMSG_SPACE(sizeof(*pm) + data_len);
4112-			
4113-			break;
4114-		case IPQ_COPY_NONE:
4115-		default:
4116-			*errp = -EINVAL;
4117-			return NULL;
4118-	}
4119-	skb = alloc_skb(size, GFP_ATOMIC);
4120-	if (!skb)
4121-		goto nlmsg_failure;
4122-	old_tail = skb->tail;
4123-	nlh = NLMSG_PUT(skb, 0, 0, IPQM_PACKET, size - sizeof(*nlh));
4124-	pm = NLMSG_DATA(nlh);
4125-	memset(pm, 0, sizeof(*pm));
4126-	pm->packet_id = (unsigned long )e;
4127-	pm->data_len = data_len;
4128-	pm->timestamp_sec = e->skb->stamp.tv_sec;
4129-	pm->timestamp_usec = e->skb->stamp.tv_usec;
4130-	pm->mark = e->skb->nfmark;
4131-	pm->hook = e->info->hook;
4132-	if (e->info->indev) strcpy(pm->indev_name, e->info->indev->name);
4133-	else pm->indev_name[0] = '\0';
4134-	if (e->info->outdev) strcpy(pm->outdev_name, e->info->outdev->name);
4135-	else pm->outdev_name[0] = '\0';
4136-	pm->hw_protocol = e->skb->protocol;
4137-	if (e->info->indev && e->skb->dev) {
4138-		pm->hw_type = e->skb->dev->type;
4139-		if (e->skb->dev->hard_header_parse)
4140-			pm->hw_addrlen =
4141-				e->skb->dev->hard_header_parse(e->skb,
4142-				                               pm->hw_addr);
4143-	}
4144-	if (data_len)
4145-		memcpy(pm->payload, e->skb->data, data_len);
4146-	nlh->nlmsg_len = skb->tail - old_tail;
4147-	NETLINK_CB(skb).dst_groups = 0;
4148-	return skb;
4149-nlmsg_failure:
4150-	if (skb)
4151-		kfree_skb(skb);
4152-	*errp = 0;
4153-	printk(KERN_ERR "ip_queue: error creating netlink message\n");
4154-	return NULL;
4155-}
4156-
4157-static int netlink_send_peer(ipq_queue_element_t *e)
4158-{
4159-	int status = 0;
4160-	struct sk_buff *skb;
4161-
4162-	skb = netlink_build_message(e, &status);
4163-	if (skb == NULL)
4164-		return status;
4165-	return netlink_unicast(nfnl, skb, nlq->peer.pid, MSG_DONTWAIT);
4166+	while ((entry = ipq_find_dequeue_entry(dev_cmp, ifindex)) != NULL)
4167+		ipq_issue_verdict(entry, NF_DROP);
4168 }
4169 
4170 #define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0)
4171 
4172-static __inline__ void netlink_receive_user_skb(struct sk_buff *skb)
4173+static inline void
4174+ipq_rcv_skb(struct sk_buff *skb)
4175 {
4176-	int status, type;
4177+	int status, type, pid, flags, nlmsglen, skblen;
4178 	struct nlmsghdr *nlh;
4179 
4180-	if (skb->len < sizeof(struct nlmsghdr))
4181+	skblen = skb->len;
4182+	if (skblen < sizeof(*nlh))
4183 		return;
4184 
4185 	nlh = (struct nlmsghdr *)skb->data;
4186-	if (nlh->nlmsg_len < sizeof(struct nlmsghdr)
4187-	    || skb->len < nlh->nlmsg_len)
4188-	    	return;
4189-
4190-	if(nlh->nlmsg_pid <= 0
4191-	    || !(nlh->nlmsg_flags & NLM_F_REQUEST)
4192-	    || nlh->nlmsg_flags & NLM_F_MULTI)
4193+	nlmsglen = nlh->nlmsg_len;
4194+	if (nlmsglen < sizeof(*nlh) || skblen < nlmsglen)
4195+		return;
4196+
4197+	pid = nlh->nlmsg_pid;
4198+	flags = nlh->nlmsg_flags;
4199+	
4200+	if(pid <= 0 || !(flags & NLM_F_REQUEST) || flags & NLM_F_MULTI)
4201 		RCV_SKB_FAIL(-EINVAL);
4202-	if (nlh->nlmsg_flags & MSG_TRUNC)
4203+		
4204+	if (flags & MSG_TRUNC)
4205 		RCV_SKB_FAIL(-ECOMM);
4206+		
4207 	type = nlh->nlmsg_type;
4208 	if (type < NLMSG_NOOP || type >= IPQM_MAX)
4209 		RCV_SKB_FAIL(-EINVAL);
4210+		
4211 	if (type <= IPQM_BASE)
4212 		return;
4213+		
4214 	if(!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
4215 		RCV_SKB_FAIL(-EPERM);
4216-	if (nlq->peer.pid && !nlq->peer.died
4217-	    && (nlq->peer.pid != nlh->nlmsg_pid)) {
4218-	    	printk(KERN_WARNING "ip_queue: peer pid changed from %d to "
4219-	    	      "%d, flushing queue\n", nlq->peer.pid, nlh->nlmsg_pid);
4220-		ipq_flush(nlq);
4221-	}	
4222-	nlq->peer.pid = nlh->nlmsg_pid;
4223-	nlq->peer.died = 0;
4224-	status = ipq_receive_peer(nlq, NLMSG_DATA(nlh),
4225-	                          type, skb->len - NLMSG_LENGTH(0));
4226+	
4227+	write_lock_bh(&queue_lock);
4228+	
4229+	if (peer_pid) {
4230+		if (peer_pid != pid) {
4231+			write_unlock_bh(&queue_lock);
4232+			RCV_SKB_FAIL(-EBUSY);
4233+		}
4234+	}
4235+	else
4236+		peer_pid = pid;
4237+		
4238+	write_unlock_bh(&queue_lock);
4239+	
4240+	status = ipq_receive_peer(NLMSG_DATA(nlh), type,
4241+	                          skblen - NLMSG_LENGTH(0));
4242 	if (status < 0)
4243 		RCV_SKB_FAIL(status);
4244-	if (nlh->nlmsg_flags & NLM_F_ACK)
4245+		
4246+	if (flags & NLM_F_ACK)
4247 		netlink_ack(skb, nlh, 0);
4248         return;
4249 }
4250 
4251-/* Note: we are only dealing with single part messages at the moment. */
4252-static void netlink_receive_user_sk(struct sock *sk, int len)
4253+static void
4254+ipq_rcv_sk(struct sock *sk, int len)
4255 {
4256 	do {
4257 		struct sk_buff *skb;
4258 
4259-		if (rtnl_shlock_nowait())
4260+		if (down_trylock(&ipqnl_sem))
4261 			return;
4262+			
4263 		while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
4264-			netlink_receive_user_skb(skb);
4265+			ipq_rcv_skb(skb);
4266 			kfree_skb(skb);
4267 		}
4268-		up(&rtnl_sem);
4269-	} while (nfnl && nfnl->receive_queue.qlen);
4270-}
4271+		
4272+		up(&ipqnl_sem);
4273 
4274-/****************************************************************************
4275- *
4276- * System events
4277- *
4278- ****************************************************************************/
4279+	} while (ipqnl && ipqnl->receive_queue.qlen);
4280+}
4281 
4282-static int receive_event(struct notifier_block *this,
4283-                         unsigned long event, void *ptr)
4284+static int
4285+ipq_rcv_dev_event(struct notifier_block *this,
4286+                  unsigned long event, void *ptr)
4287 {
4288 	struct net_device *dev = ptr;
4289 
4290 	/* Drop any packets associated with the downed device */
4291 	if (event == NETDEV_DOWN)
4292-		ipq_dev_drop(nlq, dev->ifindex);
4293+		ipq_dev_drop(dev->ifindex);
4294 	return NOTIFY_DONE;
4295 }
4296 
4297-struct notifier_block ipq_dev_notifier = {
4298-	receive_event,
4299+static struct notifier_block ipq_dev_notifier = {
4300+	ipq_rcv_dev_event,
4301 	NULL,
4302 	0
4303 };
4304 
4305-/****************************************************************************
4306- *
4307- * Sysctl - queue tuning.
4308- *
4309- ****************************************************************************/
4310+static int
4311+ipq_rcv_nl_event(struct notifier_block *this,
4312+                 unsigned long event, void *ptr)
4313+{
4314+	struct netlink_notify *n = ptr;
4315+
4316+	if (event == NETLINK_URELEASE &&
4317+	    n->protocol == NETLINK_FIREWALL && n->pid) {
4318+		write_lock_bh(&queue_lock);
4319+		if (n->pid == peer_pid)
4320+			__ipq_reset();
4321+		write_unlock_bh(&queue_lock);
4322+	}
4323+	return NOTIFY_DONE;
4324+}
4325 
4326-static int sysctl_maxlen = IPQ_QMAX_DEFAULT;
4327+static struct notifier_block ipq_nl_notifier = {
4328+	ipq_rcv_nl_event,
4329+	NULL,
4330+	0
4331+};
4332 
4333+static int sysctl_maxlen = IPQ_QMAX_DEFAULT;
4334 static struct ctl_table_header *ipq_sysctl_header;
4335 
4336 static ctl_table ipq_table[] = {
4337@@ -574,35 +600,27 @@
4338 	{ 0 }
4339 };
4340 
4341-/****************************************************************************
4342- *
4343- * Procfs - debugging info.
4344- *
4345- ****************************************************************************/
4346-
4347-static int ipq_get_info(char *buffer, char **start, off_t offset, int length)
4348+static int
4349+ipq_get_info(char *buffer, char **start, off_t offset, int length)
4350 {
4351 	int len;
4352 
4353-	spin_lock_bh(&nlq->lock);
4354+	read_lock_bh(&queue_lock);
4355+	
4356 	len = sprintf(buffer,
4357-	              "Peer pid            : %d\n"
4358-	              "Peer died           : %d\n"
4359-	              "Peer copy mode      : %d\n"
4360-	              "Peer copy range     : %Zu\n"
4361-	              "Queue length        : %d\n"
4362-	              "Queue max. length   : %d\n"
4363-	              "Queue flushing      : %d\n"
4364-	              "Queue terminate     : %d\n",
4365-	              nlq->peer.pid,
4366-	              nlq->peer.died,
4367-	              nlq->peer.copy_mode,
4368-	              nlq->peer.copy_range,
4369-	              nlq->len,
4370-	              *nlq->maxlen,
4371-	              nlq->flushing,
4372-	              nlq->terminate);
4373-	spin_unlock_bh(&nlq->lock);
4374+	              "Peer PID          : %d\n"
4375+	              "Copy mode         : %hu\n"
4376+	              "Copy range        : %u\n"
4377+	              "Queue length      : %u\n"
4378+	              "Queue max. length : %u\n",
4379+	              peer_pid,
4380+	              copy_mode,
4381+	              copy_range,
4382+	              queue_total,
4383+	              queue_maxlen);
4384+
4385+	read_unlock_bh(&queue_lock);
4386+	
4387 	*start = buffer + offset;
4388 	len -= offset;
4389 	if (len > length)
4390@@ -612,53 +630,74 @@
4391 	return len;
4392 }
4393 
4394-/****************************************************************************
4395- *
4396- * Module stuff.
4397- *
4398- ****************************************************************************/
4399-
4400-static int __init init(void)
4401+static int
4402+init_or_cleanup(int init)
4403 {
4404-	int status = 0;
4405+	int status = -ENOMEM;
4406 	struct proc_dir_entry *proc;
4407 	
4408-	nfnl = netlink_kernel_create(NETLINK_FIREWALL, netlink_receive_user_sk);
4409-	if (nfnl == NULL) {
4410-		printk(KERN_ERR "ip_queue: initialisation failed: unable to "
4411-		       "create kernel netlink socket\n");
4412-		return -ENOMEM;
4413-	}
4414-	nlq = ipq_create_queue(netfilter_receive,
4415-	                       netlink_send_peer, &status, &sysctl_maxlen);
4416-	if (nlq == NULL) {
4417-		printk(KERN_ERR "ip_queue: initialisation failed: unable to "
4418-		       "create queue\n");
4419-		sock_release(nfnl->socket);
4420-		return status;
4421+	if (!init)
4422+		goto cleanup;
4423+
4424+	netlink_register_notifier(&ipq_nl_notifier);
4425+	ipqnl = netlink_kernel_create(NETLINK_FIREWALL, ipq_rcv_sk);
4426+	if (ipqnl == NULL) {
4427+		printk(KERN_ERR "ip_queue: failed to create netlink socket\n");
4428+		goto cleanup_netlink_notifier;
4429 	}
4430+
4431 	proc = proc_net_create(IPQ_PROC_FS_NAME, 0, ipq_get_info);
4432-	if (proc) proc->owner = THIS_MODULE;
4433+	if (proc)
4434+		proc->owner = THIS_MODULE;
4435 	else {
4436-		ipq_destroy_queue(nlq);
4437-		sock_release(nfnl->socket);
4438-		return -ENOMEM;
4439+		printk(KERN_ERR "ip_queue: failed to create proc entry\n");
4440+		goto cleanup_ipqnl;
4441 	}
4442+	
4443 	register_netdevice_notifier(&ipq_dev_notifier);
4444 	ipq_sysctl_header = register_sysctl_table(ipq_root_table, 0);
4445+	
4446+	status = nf_register_queue_handler(PF_INET, ipq_enqueue_packet, NULL);
4447+	if (status < 0) {
4448+		printk(KERN_ERR "ip_queue: failed to register queue handler\n");
4449+		goto cleanup_sysctl;
4450+	}
4451+	return status;
4452+
4453+cleanup:
4454+	nf_unregister_queue_handler(PF_INET);
4455+	br_write_lock_bh(BR_NETPROTO_LOCK);
4456+	br_write_unlock_bh(BR_NETPROTO_LOCK);
4457+	ipq_flush(NF_DROP);
4458+	
4459+cleanup_sysctl:
4460+	unregister_sysctl_table(ipq_sysctl_header);
4461+	unregister_netdevice_notifier(&ipq_dev_notifier);
4462+	proc_net_remove(IPQ_PROC_FS_NAME);
4463+	
4464+cleanup_ipqnl:
4465+	sock_release(ipqnl->socket);
4466+	down(&ipqnl_sem);
4467+	up(&ipqnl_sem);
4468+	
4469+cleanup_netlink_notifier:
4470+	netlink_unregister_notifier(&ipq_nl_notifier);
4471 	return status;
4472 }
4473 
4474+static int __init init(void)
4475+{
4476+	
4477+	return init_or_cleanup(1);
4478+}
4479+
4480 static void __exit fini(void)
4481 {
4482-	unregister_sysctl_table(ipq_sysctl_header);
4483-	proc_net_remove(IPQ_PROC_FS_NAME);
4484-	unregister_netdevice_notifier(&ipq_dev_notifier);
4485-	ipq_destroy_queue(nlq);
4486-	sock_release(nfnl->socket);
4487+	init_or_cleanup(0);
4488 }
4489 
4490 MODULE_DESCRIPTION("IPv4 packet queue handler");
4491+MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>");
4492 MODULE_LICENSE("GPL");
4493 
4494 module_init(init);
4495diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv4/netfilter/ip_tables.c linux-2.4.20-plain/net/ipv4/netfilter/ip_tables.c
4496--- linux-2.4.19-plain/net/ipv4/netfilter/ip_tables.c	Mon Feb 25 20:38:14 2002
4497+++ linux-2.4.20-plain/net/ipv4/netfilter/ip_tables.c	Fri Nov 29 00:53:15 2002
4498@@ -9,6 +9,7 @@
4499  * 	  a table
4500  */
4501 #include <linux/config.h>
4502+#include <linux/cache.h>
4503 #include <linux/skbuff.h>
4504 #include <linux/kmod.h>
4505 #include <linux/vmalloc.h>
4506@@ -97,7 +98,7 @@
4507 	unsigned int underflow[NF_IP_NUMHOOKS];
4508 
4509 	/* ipt_entry tables: one per CPU */
4510-	char entries[0] __attribute__((aligned(SMP_CACHE_BYTES)));
4511+	char entries[0] ____cacheline_aligned;
4512 };
4513 
4514 static LIST_HEAD(ipt_target);
4515diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv4/netfilter/ipchains_core.c linux-2.4.20-plain/net/ipv4/netfilter/ipchains_core.c
4516--- linux-2.4.19-plain/net/ipv4/netfilter/ipchains_core.c	Sat Aug  3 02:39:46 2002
4517+++ linux-2.4.20-plain/net/ipv4/netfilter/ipchains_core.c	Fri Nov 29 00:53:15 2002
4518@@ -1252,7 +1252,7 @@
4519 		return NULL;
4520 	}
4521 
4522-	fwkern = kmalloc(SIZEOF_STRUCT_IP_FW_KERNEL, GFP_KERNEL);
4523+	fwkern = kmalloc(SIZEOF_STRUCT_IP_FW_KERNEL, GFP_ATOMIC);
4524 	if (!fwkern) {
4525 		duprintf("convert_ipfw: kmalloc failed!\n");
4526 		*errno = ENOMEM;
4527@@ -1779,4 +1779,4 @@
4528 #endif
4529 	return ret;
4530 }
4531-MODULE_LICENSE("BSD without advertisement clause");
4532+MODULE_LICENSE("Dual BSD/GPL");
4533diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv4/netfilter/ipt_DSCP.c linux-2.4.20-plain/net/ipv4/netfilter/ipt_DSCP.c
4534--- linux-2.4.19-plain/net/ipv4/netfilter/ipt_DSCP.c	Thu Jan  1 01:00:00 1970
4535+++ linux-2.4.20-plain/net/ipv4/netfilter/ipt_DSCP.c	Fri Nov 29 00:53:15 2002
4536@@ -0,0 +1,108 @@
4537+/* iptables module for setting the IPv4 DSCP field, Version 1.8
4538+ *
4539+ * (C) 2002 by Harald Welte <laforge@gnumonks.org>
4540+ * based on ipt_FTOS.c (C) 2000 by Matthew G. Marsh <mgm@paktronix.com>
4541+ * This software is distributed under GNU GPL v2, 1991
4542+ * 
4543+ * See RFC2474 for a description of the DSCP field within the IP Header.
4544+ *
4545+ * ipt_DSCP.c,v 1.8 2002/08/06 18:41:57 laforge Exp
4546+*/
4547+
4548+#include <linux/module.h>
4549+#include <linux/skbuff.h>
4550+#include <linux/ip.h>
4551+#include <net/checksum.h>
4552+
4553+#include <linux/netfilter_ipv4/ip_tables.h>
4554+#include <linux/netfilter_ipv4/ipt_DSCP.h>
4555+
4556+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
4557+MODULE_DESCRIPTION("IP tables DSCP modification module");
4558+MODULE_LICENSE("GPL");
4559+
4560+static unsigned int
4561+target(struct sk_buff **pskb,
4562+       unsigned int hooknum,
4563+       const struct net_device *in,
4564+       const struct net_device *out,
4565+       const void *targinfo,
4566+       void *userinfo)
4567+{
4568+	struct iphdr *iph = (*pskb)->nh.iph;
4569+	const struct ipt_DSCP_info *dinfo = targinfo;
4570+	u_int8_t sh_dscp = ((dinfo->dscp << IPT_DSCP_SHIFT) & IPT_DSCP_MASK);
4571+
4572+
4573+	if ((iph->tos & IPT_DSCP_MASK) != sh_dscp) {
4574+		u_int16_t diffs[2];
4575+
4576+		/* raw socket (tcpdump) may have clone of incoming
4577+		 * skb: don't disturb it --RR */
4578+		if (skb_cloned(*pskb) && !(*pskb)->sk) {
4579+			struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
4580+			if (!nskb)
4581+				return NF_DROP;
4582+			kfree_skb(*pskb);
4583+			*pskb = nskb;
4584+			iph = (*pskb)->nh.iph;
4585+		}
4586+
4587+		diffs[0] = htons(iph->tos) ^ 0xFFFF;
4588+		iph->tos = (iph->tos & ~IPT_DSCP_MASK) | sh_dscp;
4589+		diffs[1] = htons(iph->tos);
4590+		iph->check = csum_fold(csum_partial((char *)diffs,
4591+		                                    sizeof(diffs),
4592+		                                    iph->check^0xFFFF));
4593+		(*pskb)->nfcache |= NFC_ALTERED;
4594+	}
4595+	return IPT_CONTINUE;
4596+}
4597+
4598+static int
4599+checkentry(const char *tablename,
4600+	   const struct ipt_entry *e,
4601+           void *targinfo,
4602+           unsigned int targinfosize,
4603+           unsigned int hook_mask)
4604+{
4605+	const u_int8_t dscp = ((struct ipt_DSCP_info *)targinfo)->dscp;
4606+
4607+	if (targinfosize != IPT_ALIGN(sizeof(struct ipt_DSCP_info))) {
4608+		printk(KERN_WARNING "DSCP: targinfosize %u != %Zu\n",
4609+		       targinfosize,
4610+		       IPT_ALIGN(sizeof(struct ipt_DSCP_info)));
4611+		return 0;
4612+	}
4613+
4614+	if (strcmp(tablename, "mangle") != 0) {
4615+		printk(KERN_WARNING "DSCP: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
4616+		return 0;
4617+	}
4618+
4619+	if ((dscp > IPT_DSCP_MAX)) {
4620+		printk(KERN_WARNING "DSCP: dscp %x out of range\n", dscp);
4621+		return 0;
4622+	}
4623+
4624+	return 1;
4625+}
4626+
4627+static struct ipt_target ipt_dscp_reg
4628+= { { NULL, NULL }, "DSCP", target, checkentry, NULL, THIS_MODULE };
4629+
4630+static int __init init(void)
4631+{
4632+	if (ipt_register_target(&ipt_dscp_reg))
4633+		return -EINVAL;
4634+
4635+	return 0;
4636+}
4637+
4638+static void __exit fini(void)
4639+{
4640+	ipt_unregister_target(&ipt_dscp_reg);
4641+}
4642+
4643+module_init(init);
4644+module_exit(fini);
4645diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv4/netfilter/ipt_ECN.c linux-2.4.20-plain/net/ipv4/netfilter/ipt_ECN.c
4646--- linux-2.4.19-plain/net/ipv4/netfilter/ipt_ECN.c	Thu Jan  1 01:00:00 1970
4647+++ linux-2.4.20-plain/net/ipv4/netfilter/ipt_ECN.c	Fri Nov 29 00:53:15 2002
4648@@ -0,0 +1,183 @@
4649+/* iptables module for the IPv4 and TCP ECN bits, Version 1.2
4650+ *
4651+ * (C) 2002 by Harald Welte <laforge@gnumonks.org>
4652+ * 
4653+ * This software is distributed under GNU GPL v2, 1991
4654+ * 
4655+ * ipt_ECN.c,v 1.4 2002/08/05 19:36:51 laforge Exp
4656+*/
4657+
4658+#include <linux/module.h>
4659+#include <linux/skbuff.h>
4660+#include <linux/ip.h>
4661+#include <net/checksum.h>
4662+
4663+#include <linux/netfilter_ipv4/ip_tables.h>
4664+#include <linux/netfilter_ipv4/ipt_ECN.h>
4665+
4666+MODULE_LICENSE("GPL");
4667+
4668+/* set ECT codepoint from IP header.
4669+ * 	return 0 in case there was no ECT codepoint
4670+ * 	return 1 in case ECT codepoint has been overwritten
4671+ * 	return < 0 in case there was error */
4672+static int inline
4673+set_ect_ip(struct sk_buff **pskb, struct iphdr *iph,
4674+	   const struct ipt_ECN_info *einfo)
4675+{
4676+	if ((iph->tos & IPT_ECN_IP_MASK)
4677+	    != (einfo->ip_ect & IPT_ECN_IP_MASK)) {
4678+		u_int16_t diffs[2];
4679+
4680+		/* raw socket (tcpdump) may have clone of incoming
4681+		 * skb: don't disturb it --RR */
4682+		if (skb_cloned(*pskb) && !(*pskb)->sk) {
4683+			struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
4684+			if (!nskb)
4685+				return NF_DROP;
4686+			kfree_skb(*pskb);
4687+			*pskb = nskb;
4688+			iph = (*pskb)->nh.iph;
4689+		}
4690+
4691+		diffs[0] = htons(iph->tos) ^ 0xFFFF;
4692+		iph->tos = iph->tos & ~IPT_ECN_IP_MASK;
4693+		iph->tos = iph->tos | (einfo->ip_ect & IPT_ECN_IP_MASK);
4694+		diffs[1] = htons(iph->tos);
4695+		iph->check = csum_fold(csum_partial((char *)diffs,
4696+		                                    sizeof(diffs),
4697+		                                    iph->check^0xFFFF));
4698+		(*pskb)->nfcache |= NFC_ALTERED;
4699+
4700+		return 1;
4701+	} 
4702+	return 0;
4703+}
4704+
4705+static int inline
4706+set_ect_tcp(struct sk_buff **pskb, struct iphdr *iph,
4707+	    const struct ipt_ECN_info *einfo)
4708+{
4709+
4710+	struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
4711+	u_int16_t *tcpflags = (u_int16_t *)tcph + 6;
4712+	u_int16_t diffs[2];
4713+
4714+	/* raw socket (tcpdump) may have clone of incoming
4715+	 * skb: don't disturb it --RR */
4716+	if (skb_cloned(*pskb) && !(*pskb)->sk) {
4717+		struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
4718+		if (!nskb)
4719+			return NF_DROP;
4720+		kfree_skb(*pskb);
4721+		*pskb = nskb;
4722+		iph = (*pskb)->nh.iph;
4723+	}
4724+
4725+	diffs[0] = *tcpflags;
4726+
4727+	if (einfo->operation & IPT_ECN_OP_SET_ECE
4728+	    && tcph->ece != einfo->proto.tcp.ece) {
4729+		tcph->ece = einfo->proto.tcp.ece;
4730+	}
4731+
4732+	if (einfo->operation & IPT_ECN_OP_SET_CWR
4733+	    && tcph->cwr != einfo->proto.tcp.cwr) {
4734+		tcph->cwr = einfo->proto.tcp.cwr;
4735+	}
4736+	
4737+	if (diffs[0] != *tcpflags) {
4738+		diffs[0] = htons(diffs[0]) ^ 0xFFFF;
4739+		diffs[1] = htons(*tcpflags);
4740+		tcph->check = csum_fold(csum_partial((char *)diffs,
4741+		                                    sizeof(diffs),
4742+		                                    tcph->check^0xFFFF));
4743+		(*pskb)->nfcache |= NFC_ALTERED;
4744+
4745+		return 1;
4746+	}
4747+
4748+	return 0;
4749+}
4750+
4751+static unsigned int
4752+target(struct sk_buff **pskb,
4753+       unsigned int hooknum,
4754+       const struct net_device *in,
4755+       const struct net_device *out,
4756+       const void *targinfo,
4757+       void *userinfo)
4758+{
4759+	struct iphdr *iph = (*pskb)->nh.iph;
4760+	const struct ipt_ECN_info *einfo = targinfo;
4761+
4762+	if (einfo->operation & IPT_ECN_OP_SET_IP)
4763+		set_ect_ip(pskb, iph, einfo);
4764+
4765+	if (einfo->operation & (IPT_ECN_OP_SET_ECE | IPT_ECN_OP_SET_CWR)
4766+	    && iph->protocol == IPPROTO_TCP)
4767+		set_ect_tcp(pskb, iph, einfo);
4768+
4769+	return IPT_CONTINUE;
4770+}
4771+
4772+static int
4773+checkentry(const char *tablename,
4774+	   const struct ipt_entry *e,
4775+           void *targinfo,
4776+           unsigned int targinfosize,
4777+           unsigned int hook_mask)
4778+{
4779+	const struct ipt_ECN_info *einfo = (struct ipt_ECN_info *)targinfo;
4780+
4781+	if (targinfosize != IPT_ALIGN(sizeof(struct ipt_ECN_info))) {
4782+		printk(KERN_WARNING "ECN: targinfosize %u != %Zu\n",
4783+		       targinfosize,
4784+		       IPT_ALIGN(sizeof(struct ipt_ECN_info)));
4785+		return 0;
4786+	}
4787+
4788+	if (strcmp(tablename, "mangle") != 0) {
4789+		printk(KERN_WARNING "ECN: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
4790+		return 0;
4791+	}
4792+
4793+	if (einfo->operation & IPT_ECN_OP_MASK) {
4794+		printk(KERN_WARNING "ECN: unsupported ECN operation %x\n",
4795+			einfo->operation);
4796+		return 0;
4797+	}
4798+	if (einfo->ip_ect & ~IPT_ECN_IP_MASK) {
4799+		printk(KERN_WARNING "ECN: new ECT codepoint %x out of mask\n",
4800+			einfo->ip_ect);
4801+		return 0;
4802+	}
4803+
4804+	if ((einfo->operation & (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR))
4805+	    && e->ip.proto != IPPROTO_TCP) {
4806+		printk(KERN_WARNING "ECN: cannot use TCP operations on a "
4807+		       "non-tcp rule\n");
4808+		return 0;
4809+	}
4810+
4811+	return 1;
4812+}
4813+
4814+static struct ipt_target ipt_ecn_reg
4815+= { { NULL, NULL }, "ECN", target, checkentry, NULL, THIS_MODULE };
4816+
4817+static int __init init(void)
4818+{
4819+	if (ipt_register_target(&ipt_ecn_reg))
4820+		return -EINVAL;
4821+
4822+	return 0;
4823+}
4824+
4825+static void __exit fini(void)
4826+{
4827+	ipt_unregister_target(&ipt_ecn_reg);
4828+}
4829+
4830+module_init(init);
4831+module_exit(fini);
4832diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv4/netfilter/ipt_REJECT.c linux-2.4.20-plain/net/ipv4/netfilter/ipt_REJECT.c
4833--- linux-2.4.19-plain/net/ipv4/netfilter/ipt_REJECT.c	Sat Aug  3 02:39:46 2002
4834+++ linux-2.4.20-plain/net/ipv4/netfilter/ipt_REJECT.c	Fri Nov 29 00:53:15 2002
4835@@ -75,6 +75,7 @@
4836 #ifdef CONFIG_NETFILTER_DEBUG
4837 	nskb->nf_debug = 0;
4838 #endif
4839+	nskb->nfmark = 0;
4840 
4841 	tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl);
4842 
4843diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv4/netfilter/ipt_ULOG.c linux-2.4.20-plain/net/ipv4/netfilter/ipt_ULOG.c
4844--- linux-2.4.19-plain/net/ipv4/netfilter/ipt_ULOG.c	Sat Aug  3 02:39:46 2002
4845+++ linux-2.4.20-plain/net/ipv4/netfilter/ipt_ULOG.c	Fri Nov 29 00:53:15 2002
4846@@ -10,6 +10,8 @@
4847  *            nlgroup now global (sysctl)
4848  * 2001/04/19 ulog-queue reworked, now fixed buffer size specified at
4849  * 	      module loadtime -HW
4850+ * 2002/07/07 remove broken nflog_rcv() function -HW
4851+ * 2002/08/29 fix shifted/unshifted nlgroup bug -HW
4852  *
4853  * Released under the terms of the GPL
4854  *
4855@@ -29,7 +31,7 @@
4856  *   Specify, after how many clock ticks (intel: 100 per second) the queue
4857  * should be flushed even if it is not full yet.
4858  *
4859- * ipt_ULOG.c,v 1.18 2002/04/16 07:33:00 laforge Exp
4860+ * ipt_ULOG.c,v 1.21 2002/08/29 10:54:34 laforge Exp
4861  */
4862 
4863 #include <linux/module.h>
4864@@ -48,8 +50,11 @@
4865 #include <linux/netfilter_ipv4/ipt_ULOG.h>
4866 #include <linux/netfilter_ipv4/lockhelp.h>
4867 #include <net/sock.h>
4868+#include <linux/bitops.h>
4869 
4870 MODULE_LICENSE("GPL");
4871+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
4872+MODULE_DESCRIPTION("IP tables userspace logging module");
4873 
4874 #define ULOG_NL_EVENT		111		/* Harald's favorite number */
4875 #define ULOG_MAXNLGROUPS	32		/* numer of nlgroups */
4876@@ -63,10 +68,6 @@
4877 
4878 #define PRINTR(format, args...) do { if (net_ratelimit()) printk(format, ## args); } while (0)
4879 
4880-MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
4881-MODULE_DESCRIPTION("IP tables userspace logging module");
4882-
4883-
4884 static unsigned int nlbufsiz = 4096;
4885 MODULE_PARM(nlbufsiz, "i");
4886 MODULE_PARM_DESC(nlbufsiz, "netlink buffer size");
4887@@ -91,9 +92,9 @@
4888 DECLARE_LOCK(ulog_lock);	/* spinlock */
4889 
4890 /* send one ulog_buff_t to userspace */
4891-static void ulog_send(unsigned int nlgroup)
4892+static void ulog_send(unsigned int nlgroupnum)
4893 {
4894-	ulog_buff_t *ub = &ulog_buffers[nlgroup];
4895+	ulog_buff_t *ub = &ulog_buffers[nlgroupnum];
4896 
4897 	if (timer_pending(&ub->timer)) {
4898 		DEBUGP("ipt_ULOG: ulog_send: timer was pending, deleting\n");
4899@@ -104,10 +105,10 @@
4900 	if (ub->qlen > 1)
4901 		ub->lastnlh->nlmsg_type = NLMSG_DONE;
4902 
4903-	NETLINK_CB(ub->skb).dst_groups = nlgroup;
4904+	NETLINK_CB(ub->skb).dst_groups = (1 << nlgroupnum);
4905 	DEBUGP("ipt_ULOG: throwing %d packets to netlink mask %u\n",
4906 		ub->qlen, nlgroup);
4907-	netlink_broadcast(nflognl, ub->skb, 0, nlgroup, GFP_ATOMIC);
4908+	netlink_broadcast(nflognl, ub->skb, 0, (1 << nlgroupnum), GFP_ATOMIC);
4909 
4910 	ub->qlen = 0;
4911 	ub->skb = NULL;
4912@@ -128,11 +129,6 @@
4913 	UNLOCK_BH(&ulog_lock);
4914 }
4915 
4916-static void nflog_rcv(struct sock *sk, int len)
4917-{
4918-	printk("ipt_ULOG:nflog_rcv() did receive netlink message ?!?\n");
4919-}
4920-
4921 struct sk_buff *ulog_alloc_skb(unsigned int size)
4922 {
4923 	struct sk_buff *skb;
4924@@ -169,6 +165,11 @@
4925 	struct nlmsghdr *nlh;
4926 	struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
4927 
4928+	/* ffs == find first bit set, necessary because userspace
4929+	 * is already shifting groupnumber, but we need unshifted.
4930+	 * ffs() returns [1..32], we need [0..31] */
4931+	unsigned int groupnum = ffs(loginfo->nl_group) - 1;
4932+
4933 	/* calculate the size of the skb needed */
4934 	if ((loginfo->copy_range == 0) ||
4935 	    (loginfo->copy_range > (*pskb)->len)) {
4936@@ -179,7 +180,7 @@
4937 
4938 	size = NLMSG_SPACE(sizeof(*pm) + copy_len);
4939 
4940-	ub = &ulog_buffers[loginfo->nl_group];
4941+	ub = &ulog_buffers[groupnum];
4942 	
4943 	LOCK_BH(&ulog_lock);
4944 
4945@@ -191,7 +192,7 @@
4946 		/* either the queue len is too high or we don't have 
4947 		 * enough room in nlskb left. send it to userspace. */
4948 
4949-		ulog_send(loginfo->nl_group);
4950+		ulog_send(groupnum);
4951 
4952 		if (!(ub->skb = ulog_alloc_skb(size)))
4953 			goto alloc_failure;
4954@@ -325,7 +326,7 @@
4955 		ulog_buffers[i].timer.data = i;
4956 	}
4957 
4958-	nflognl = netlink_kernel_create(NETLINK_NFLOG, nflog_rcv);
4959+	nflognl = netlink_kernel_create(NETLINK_NFLOG, NULL);
4960 	if (!nflognl)
4961 		return -ENOMEM;
4962 
4963diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv4/netfilter/ipt_ah.c linux-2.4.20-plain/net/ipv4/netfilter/ipt_ah.c
4964--- linux-2.4.19-plain/net/ipv4/netfilter/ipt_ah.c	Mon Feb 25 20:38:14 2002
4965+++ linux-2.4.20-plain/net/ipv4/netfilter/ipt_ah.c	Fri Nov 29 00:53:15 2002
4966@@ -91,12 +91,12 @@
4967 static struct ipt_match ah_match
4968 = { { NULL, NULL }, "ah", &match, &checkentry, NULL, THIS_MODULE };
4969 
4970-int __init init(void)
4971+static int __init init(void)
4972 {
4973 	return ipt_register_match(&ah_match);
4974 }
4975 
4976-void __exit cleanup(void)
4977+static void __exit cleanup(void)
4978 {
4979 	ipt_unregister_match(&ah_match);
4980 }
4981diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv4/netfilter/ipt_conntrack.c linux-2.4.20-plain/net/ipv4/netfilter/ipt_conntrack.c
4982--- linux-2.4.19-plain/net/ipv4/netfilter/ipt_conntrack.c	Thu Jan  1 01:00:00 1970
4983+++ linux-2.4.20-plain/net/ipv4/netfilter/ipt_conntrack.c	Fri Nov 29 00:53:15 2002
4984@@ -0,0 +1,123 @@
4985+/* Kernel module to match connection tracking information.
4986+ * Superset of Rusty's minimalistic state match.
4987+ * GPL (C) 2001  Marc Boucher (marc@mbsi.ca).
4988+ */
4989+#include <linux/module.h>
4990+#include <linux/skbuff.h>
4991+#include <linux/netfilter_ipv4/ip_conntrack.h>
4992+#include <linux/netfilter_ipv4/ip_tables.h>
4993+#include <linux/netfilter_ipv4/ipt_conntrack.h>
4994+
4995+static int
4996+match(const struct sk_buff *skb,
4997+      const struct net_device *in,
4998+      const struct net_device *out,
4999+      const void *matchinfo,
5000+      int offset,
5001+      const void *hdr,
5002+      u_int16_t datalen,
5003+      int *hotdrop)
5004+{
5005+	const struct ipt_conntrack_info *sinfo = matchinfo;
5006+	struct ip_conntrack *ct;
5007+	enum ip_conntrack_info ctinfo;
5008+	unsigned int statebit;
5009+
5010+	ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
5011+
5012+#define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
5013+
5014+	statebit = ct ? IPT_CONNTRACK_STATE_INVALID : IPT_CONNTRACK_STATE_BIT(ctinfo);
5015+	if(sinfo->flags & IPT_CONNTRACK_STATE) {
5016+		if (ct) {
5017+			if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip !=
5018+			    ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip)
5019+				statebit |= IPT_CONNTRACK_STATE_SNAT;
5020+
5021+			if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip !=
5022+			    ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip)
5023+				statebit |= IPT_CONNTRACK_STATE_DNAT;
5024+		}
5025+
5026+		if (FWINV((statebit & sinfo->statemask) == 0, IPT_CONNTRACK_STATE))
5027+			return 0;
5028+	}
5029+
5030+	if(sinfo->flags & IPT_CONNTRACK_PROTO) {
5031+		if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, IPT_CONNTRACK_PROTO))
5032+                	return 0;
5033+	}
5034+
5035+	if(sinfo->flags & IPT_CONNTRACK_ORIGSRC) {
5036+		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, IPT_CONNTRACK_ORIGSRC))
5037+			return 0;
5038+	}
5039+
5040+	if(sinfo->flags & IPT_CONNTRACK_ORIGDST) {
5041+		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, IPT_CONNTRACK_ORIGDST))
5042+			return 0;
5043+	}
5044+
5045+	if(sinfo->flags & IPT_CONNTRACK_REPLSRC) {
5046+		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].src.ip, IPT_CONNTRACK_REPLSRC))
5047+			return 0;
5048+	}
5049+
5050+	if(sinfo->flags & IPT_CONNTRACK_REPLDST) {
5051+		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, IPT_CONNTRACK_REPLDST))
5052+			return 0;
5053+	}
5054+
5055+	if(sinfo->flags & IPT_CONNTRACK_STATUS) {
5056+		if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, IPT_CONNTRACK_STATUS))
5057+			return 0;
5058+	}
5059+
5060+	if(sinfo->flags & IPT_CONNTRACK_EXPIRES) {
5061+		unsigned long expires;
5062+
5063+		if(!ct)
5064+			return 0;
5065+
5066+		expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0;
5067+
5068+		if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), IPT_CONNTRACK_EXPIRES))
5069+			return 0;
5070+	}
5071+
5072+	return 1;
5073+}
5074+
5075+static int check(const char *tablename,
5076+		 const struct ipt_ip *ip,
5077+		 void *matchinfo,
5078+		 unsigned int matchsize,
5079+		 unsigned int hook_mask)
5080+{
5081+	if (matchsize != IPT_ALIGN(sizeof(struct ipt_conntrack_info)))
5082+		return 0;
5083+
5084+	return 1;
5085+}
5086+
5087+static struct ipt_match conntrack_match
5088+= { { NULL, NULL }, "conntrack", &match, &check, NULL, THIS_MODULE };
5089+
5090+static int __init init(void)
5091+{
5092+	/* NULL if ip_conntrack not a module */
5093+	if (ip_conntrack_module)
5094+		__MOD_INC_USE_COUNT(ip_conntrack_module);
5095+	return ipt_register_match(&conntrack_match);
5096+}
5097+
5098+static void __exit fini(void)
5099+{
5100+	ipt_unregister_match(&conntrack_match);
5101+	if (ip_conntrack_module)
5102+		__MOD_DEC_USE_COUNT(ip_conntrack_module);
5103+}
5104+
5105+module_init(init);
5106+module_exit(fini);
5107+MODULE_LICENSE("GPL");
5108diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv4/netfilter/ipt_dscp.c linux-2.4.20-plain/net/ipv4/netfilter/ipt_dscp.c
5109--- linux-2.4.19-plain/net/ipv4/netfilter/ipt_dscp.c	Thu Jan  1 01:00:00 1970
5110+++ linux-2.4.20-plain/net/ipv4/netfilter/ipt_dscp.c	Fri Nov 29 00:53:15 2002
5111@@ -0,0 +1,58 @@
5112+/* IP tables module for matching the value of the IPv4 DSCP field
5113+ *
5114+ * ipt_dscp.c,v 1.3 2002/08/05 19:00:21 laforge Exp
5115+ *
5116+ * (C) 2002 by Harald Welte <laforge@gnumonks.org>
5117+ *
5118+ * This software is distributed under the terms  GNU GPL
5119+ */
5120+
5121+#include <linux/module.h>
5122+#include <linux/skbuff.h>
5123+
5124+#include <linux/netfilter_ipv4/ipt_dscp.h>
5125+#include <linux/netfilter_ipv4/ip_tables.h>
5126+
5127+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
5128+MODULE_DESCRIPTION("IP tables DSCP matching module");
5129+MODULE_LICENSE("GPL");
5130+
5131+static int match(const struct sk_buff *skb, const struct net_device *in,
5132+		 const struct net_device *out, const void *matchinfo,
5133+		 int offset, const void *hdr, u_int16_t datalen,
5134+		 int *hotdrop)
5135+{
5136+	const struct ipt_dscp_info *info = matchinfo;
5137+	const struct iphdr *iph = skb->nh.iph;
5138+
5139+	u_int8_t sh_dscp = ((info->dscp << IPT_DSCP_SHIFT) & IPT_DSCP_MASK);
5140+
5141+	return ((iph->tos&IPT_DSCP_MASK) == sh_dscp) ^ info->invert;
5142+}
5143+
5144+static int checkentry(const char *tablename, const struct ipt_ip *ip,
5145+		      void *matchinfo, unsigned int matchsize,
5146+		      unsigned int hook_mask)
5147+{
5148+	if (matchsize != IPT_ALIGN(sizeof(struct ipt_dscp_info)))
5149+		return 0;
5150+
5151+	return 1;
5152+}
5153+
5154+static struct ipt_match dscp_match = { { NULL, NULL }, "dscp", &match,
5155+		&checkentry, NULL, THIS_MODULE };
5156+
5157+static int __init init(void)
5158+{
5159+	return ipt_register_match(&dscp_match);
5160+}
5161+
5162+static void __exit fini(void)
5163+{
5164+	ipt_unregister_match(&dscp_match);
5165+
5166+}
5167+
5168+module_init(init);
5169+module_exit(fini);
5170diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv4/netfilter/ipt_ecn.c linux-2.4.20-plain/net/ipv4/netfilter/ipt_ecn.c
5171--- linux-2.4.19-plain/net/ipv4/netfilter/ipt_ecn.c	Thu Jan  1 01:00:00 1970
5172+++ linux-2.4.20-plain/net/ipv4/netfilter/ipt_ecn.c	Fri Nov 29 00:53:15 2002
5173@@ -0,0 +1,118 @@
5174+/* IP tables module for matching the value of the IPv4 and TCP ECN bits
5175+ *
5176+ * ipt_ecn.c,v 1.3 2002/05/29 15:09:00 laforge Exp
5177+ *
5178+ * (C) 2002 by Harald Welte <laforge@gnumonks.org>
5179+ *
5180+ * This software is distributed under the terms GNU GPL v2
5181+ */
5182+
5183+#include <linux/module.h>
5184+#include <linux/skbuff.h>
5185+#include <linux/tcp.h>
5186+
5187+#include <linux/netfilter_ipv4/ip_tables.h>
5188+#include <linux/netfilter_ipv4/ipt_ecn.h>
5189+
5190+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
5191+MODULE_DESCRIPTION("IP tables ECN matching module");
5192+MODULE_LICENSE("GPL");
5193+
5194+static inline int match_ip(const struct sk_buff *skb,
5195+			   const struct iphdr *iph,
5196+			   const struct ipt_ecn_info *einfo)
5197+{
5198+	return ((iph->tos&IPT_ECN_IP_MASK) == einfo->ip_ect);
5199+}
5200+
5201+static inline int match_tcp(const struct sk_buff *skb,
5202+			    const struct iphdr *iph,
5203+			    const struct ipt_ecn_info *einfo)
5204+{
5205+	struct tcphdr *tcph = (void *)iph + iph->ihl*4;
5206+
5207+	if (einfo->operation & IPT_ECN_OP_MATCH_ECE) {
5208+		if (einfo->invert & IPT_ECN_OP_MATCH_ECE) {
5209+			if (tcph->ece == 1)
5210+				return 0;
5211+		} else {
5212+			if (tcph->ece == 0)
5213+				return 0;
5214+		}
5215+	}
5216+
5217+	if (einfo->operation & IPT_ECN_OP_MATCH_CWR) {
5218+		if (einfo->invert & IPT_ECN_OP_MATCH_CWR) {
5219+			if (tcph->cwr == 1)
5220+				return 0;
5221+		} else {
5222+			if (tcph->cwr == 0)
5223+				return 0;
5224+		}
5225+	}
5226+
5227+	return 1;
5228+}
5229+
5230+static int match(const struct sk_buff *skb, const struct net_device *in,
5231+		 const struct net_device *out, const void *matchinfo,
5232+		 int offset, const void *hdr, u_int16_t datalen,
5233+		 int *hotdrop)
5234+{
5235+	const struct ipt_ecn_info *info = matchinfo;
5236+	const struct iphdr *iph = skb->nh.iph;
5237+
5238+	if (info->operation & IPT_ECN_OP_MATCH_IP)
5239+		if (!match_ip(skb, iph, info))
5240+			return 0;
5241+
5242+	if (info->operation & (IPT_ECN_OP_MATCH_ECE|IPT_ECN_OP_MATCH_CWR)) {
5243+		if (iph->protocol != IPPROTO_TCP)
5244+			return 0;
5245+		if (!match_tcp(skb, iph, info))
5246+			return 0;
5247+	}
5248+
5249+	return 1;
5250+}
5251+
5252+static int checkentry(const char *tablename, const struct ipt_ip *ip,
5253+		      void *matchinfo, unsigned int matchsize,
5254+		      unsigned int hook_mask)
5255+{
5256+	const struct ipt_ecn_info *info = matchinfo;
5257+
5258+	if (matchsize != IPT_ALIGN(sizeof(struct ipt_ecn_info)))
5259+		return 0;
5260+
5261+	if (info->operation & IPT_ECN_OP_MATCH_MASK)
5262+		return 0;
5263+
5264+	if (info->invert & IPT_ECN_OP_MATCH_MASK)
5265+		return 0;
5266+
5267+	if (info->operation & (IPT_ECN_OP_MATCH_ECE|IPT_ECN_OP_MATCH_CWR)
5268+	    && ip->proto != IPPROTO_TCP) {
5269+		printk(KERN_WARNING "ipt_ecn: can't match TCP bits in rule for"
5270+		       " non-tcp packets\n");
5271+		return 0;
5272+	}
5273+
5274+	return 1;
5275+}
5276+
5277+static struct ipt_match ecn_match = { { NULL, NULL }, "ecn", &match,
5278+		&checkentry, NULL, THIS_MODULE };
5279+
5280+static int __init init(void)
5281+{
5282+	return ipt_register_match(&ecn_match);
5283+}
5284+
5285+static void __exit fini(void)
5286+{
5287+	ipt_unregister_match(&ecn_match);
5288+}
5289+
5290+module_init(init);
5291+module_exit(fini);
5292diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv4/netfilter/ipt_helper.c linux-2.4.20-plain/net/ipv4/netfilter/ipt_helper.c
5293--- linux-2.4.19-plain/net/ipv4/netfilter/ipt_helper.c	Thu Jan  1 01:00:00 1970
5294+++ linux-2.4.20-plain/net/ipv4/netfilter/ipt_helper.c	Fri Nov 29 00:53:15 2002
5295@@ -0,0 +1,112 @@
5296+/*
5297+ * iptables module to match on related connections
5298+ *   (c) 2001 Martin Josefsson <gandalf@wlug.westbo.se>
5299+ *
5300+ * Released under the terms of GNU GPLv2.
5301+ *
5302+ *   19 Mar 2002 Harald Welte <laforge@gnumonks.org>:
5303+ *   		 - Port to newnat infrastructure
5304+ */
5305+#include <linux/module.h>
5306+#include <linux/skbuff.h>
5307+#include <linux/netfilter_ipv4/ip_conntrack.h>
5308+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
5309+#include <linux/netfilter_ipv4/ip_tables.h>
5310+#include <linux/netfilter_ipv4/ipt_helper.h>
5311+
5312+MODULE_LICENSE("GPL");
5313+
5314+#if 0
5315+#define DEBUGP printk
5316+#else
5317+#define DEBUGP(format, args...)
5318+#endif
5319+
5320+static int
5321+match(const struct sk_buff *skb,
5322+      const struct net_device *in,
5323+      const struct net_device *out,
5324+      const void *matchinfo,
5325+      int offset,
5326+      const void *hdr,
5327+      u_int16_t datalen,
5328+      int *hotdrop)
5329+{
5330+	const struct ipt_helper_info *info = matchinfo;
5331+	struct ip_conntrack_expect *exp;
5332+	struct ip_conntrack *ct;
5333+	enum ip_conntrack_info ctinfo;
5334+	
5335+	ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
5336+	if (!ct) {
5337+		DEBUGP("ipt_helper: Eek! invalid conntrack?\n");
5338+		return 0;
5339+	}
5340+
5341+	if (!ct->master) {
5342+		DEBUGP("ipt_helper: conntrack %p has no master\n", ct);
5343+		return 0;
5344+	}
5345+
5346+	exp = ct->master;
5347+	if (!exp->expectant) {
5348+		DEBUGP("ipt_helper: expectation %p without expectant !?!\n", 
5349+			exp);
5350+		return 0;
5351+	}
5352+
5353+	if (!exp->expectant->helper) {
5354+		DEBUGP("ipt_helper: master ct %p has no helper\n", 
5355+			exp->expectant);
5356+		return 0;
5357+	}
5358+
5359+	DEBUGP("master's name = %s , info->name = %s\n", 
5360+		exp->expectant->helper->name, info->name);
5361+
5362+	return !strncmp(exp->expectant->helper->name, info->name, 
5363+			strlen(exp->expectant->helper->name)) ^ info->invert;
5364+}
5365+
5366+static int check(const char *tablename,
5367+		 const struct ipt_ip *ip,
5368+		 void *matchinfo,
5369+		 unsigned int matchsize,
5370+		 unsigned int hook_mask)
5371+{
5372+	struct ipt_helper_info *info = matchinfo;
5373+
5374+	info->name[29] = '\0';
5375+
5376+	/* verify size */
5377+	if (matchsize != IPT_ALIGN(sizeof(struct ipt_helper_info)))
5378+		return 0;
5379+
5380+	/* verify that we actually should match anything */
5381+	if ( strlen(info->name) == 0 )
5382+		return 0;
5383+	
5384+	return 1;
5385+}
5386+
5387+static struct ipt_match helper_match
5388+= { { NULL, NULL }, "helper", &match, &check, NULL, THIS_MODULE };
5389+
5390+static int __init init(void)
5391+{
5392+	/* NULL if ip_conntrack not a module */
5393+	if (ip_conntrack_module)
5394+		__MOD_INC_USE_COUNT(ip_conntrack_module);
5395+	return ipt_register_match(&helper_match);
5396+}
5397+
5398+static void __exit fini(void)
5399+{
5400+	ipt_unregister_match(&helper_match);
5401+	if (ip_conntrack_module)
5402+		__MOD_DEC_USE_COUNT(ip_conntrack_module);
5403+}
5404+
5405+module_init(init);
5406+module_exit(fini);
5407+
5408diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv4/netfilter/ipt_owner.c linux-2.4.20-plain/net/ipv4/netfilter/ipt_owner.c
5409--- linux-2.4.19-plain/net/ipv4/netfilter/ipt_owner.c	Sun Sep 30 21:26:08 2001
5410+++ linux-2.4.20-plain/net/ipv4/netfilter/ipt_owner.c	Fri Nov 29 00:53:15 2002
5411@@ -12,6 +12,38 @@
5412 #include <linux/netfilter_ipv4/ip_tables.h>
5413 
5414 static int
5415+match_comm(const struct sk_buff *skb, const char *comm)
5416+{
5417+	struct task_struct *p;
5418+	struct files_struct *files;
5419+	int i;
5420+
5421+	read_lock(&tasklist_lock);
5422+	for_each_task(p) {
5423+		if(strncmp(p->comm, comm, sizeof(p->comm)))
5424+			continue;
5425+
5426+		task_lock(p);
5427+		files = p->files;
5428+		if(files) {
5429+			read_lock(&files->file_lock);
5430+			for (i=0; i < files->max_fds; i++) {
5431+				if (fcheck_files(files, i) == skb->sk->socket->file) {
5432+					read_unlock(&files->file_lock);
5433+					task_unlock(p);
5434+					read_unlock(&tasklist_lock);
5435+					return 1;
5436+				}
5437+			}
5438+			read_unlock(&files->file_lock);
5439+		}
5440+		task_unlock(p);
5441+	}
5442+	read_unlock(&tasklist_lock);
5443+	return 0;
5444+}
5445+
5446+static int
5447 match_pid(const struct sk_buff *skb, pid_t pid)
5448 {
5449 	struct task_struct *p;
5450@@ -112,6 +144,12 @@
5451 	if(info->match & IPT_OWNER_SID) {
5452 		if (!match_sid(skb, info->sid) ^
5453 		    !!(info->invert & IPT_OWNER_SID))
5454+			return 0;
5455+	}
5456+
5457+	if(info->match & IPT_OWNER_COMM) {
5458+		if (!match_comm(skb, info->comm) ^
5459+		    !!(info->invert & IPT_OWNER_COMM))
5460 			return 0;
5461 	}
5462 
5463diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv4/netfilter/ipt_pkttype.c linux-2.4.20-plain/net/ipv4/netfilter/ipt_pkttype.c
5464--- linux-2.4.19-plain/net/ipv4/netfilter/ipt_pkttype.c	Thu Jan  1 01:00:00 1970
5465+++ linux-2.4.20-plain/net/ipv4/netfilter/ipt_pkttype.c	Fri Nov 29 00:53:15 2002
5466@@ -0,0 +1,59 @@
5467+#include <linux/module.h>
5468+#include <linux/skbuff.h>
5469+#include <linux/if_ether.h>
5470+#include <linux/if_packet.h>
5471+
5472+#include <linux/netfilter_ipv4/ipt_pkttype.h>
5473+#include <linux/netfilter_ipv4/ip_tables.h>
5474+
5475+MODULE_LICENSE("GPL");
5476+
5477+static int match(const struct sk_buff *skb,
5478+      const struct net_device *in,
5479+      const struct net_device *out,
5480+      const void *matchinfo,
5481+      int offset,
5482+      const void *hdr,
5483+      u_int16_t datalen,
5484+      int *hotdrop)
5485+{
5486+    const struct ipt_pkttype_info *info = matchinfo;
5487+
5488+    return (skb->pkt_type == info->pkttype) ^ info->invert;
5489+}
5490+
5491+static int checkentry(const char *tablename,
5492+		   const struct ipt_ip *ip,
5493+		   void *matchinfo,
5494+		   unsigned int matchsize,
5495+		   unsigned int hook_mask)
5496+{
5497+/*
5498+	if (hook_mask
5499+	    & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN)
5500+		| (1 << NF_IP_FORWARD))) {
5501+		printk("ipt_pkttype: only valid for PRE_ROUTING, LOCAL_IN or FORWARD.\n");
5502+		return 0;
5503+	}
5504+*/
5505+	if (matchsize != IPT_ALIGN(sizeof(struct ipt_pkttype_info)))
5506+		return 0;
5507+
5508+	return 1;
5509+}
5510+
5511+static struct ipt_match pkttype_match
5512+= { { NULL, NULL }, "pkttype", &match, &checkentry, NULL, THIS_MODULE };
5513+
5514+static int __init init(void)
5515+{
5516+	return ipt_register_match(&pkttype_match);
5517+}
5518+
5519+static void __exit fini(void)
5520+{
5521+	ipt_unregister_match(&pkttype_match);
5522+}
5523+
5524+module_init(init);
5525+module_exit(fini);
5526diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv4/netfilter/ipt_unclean.c linux-2.4.20-plain/net/ipv4/netfilter/ipt_unclean.c
5527--- linux-2.4.19-plain/net/ipv4/netfilter/ipt_unclean.c	Fri Dec 21 18:42:05 2001
5528+++ linux-2.4.20-plain/net/ipv4/netfilter/ipt_unclean.c	Fri Nov 29 00:53:15 2002
5529@@ -211,15 +211,14 @@
5530 
5531 	/* Bad checksum?  Don't print, just say it's unclean. */
5532-	if (!more_frags && !embedded
5533+	if (!more_frags && !embedded && udph->check
5534 	    && csum_tcpudp_magic(iph->saddr, iph->daddr, datalen, IPPROTO_UDP,
5535 				 csum_partial((char *)udph, datalen, 0)) != 0)
5536 		return 0;
5537 
5538-	/* CHECK: Ports can't be zero. */
5539-	if (!udph->source || !udph->dest) {
5540-		limpk("UDP zero ports %u/%u\n",
5541-		      ntohs(udph->source), ntohs(udph->dest));
5542+	/* CHECK: Destination port can't be zero. */
5543+	if (!udph->dest) {
5544+		limpk("UDP zero destination port\n");
5545 		return 0;
5546 	}
5547 
5548diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv6/netfilter/Config.in linux-2.4.20-plain/net/ipv6/netfilter/Config.in
5549--- linux-2.4.19-plain/net/ipv6/netfilter/Config.in	Mon Feb 25 20:38:14 2002
5550+++ linux-2.4.20-plain/net/ipv6/netfilter/Config.in	Fri Nov 29 00:53:15 2002
5551@@ -24,6 +24,10 @@
5552   fi
5553 #  dep_tristate '  MAC address match support' CONFIG_IP6_NF_MATCH_MAC $CONFIG_IP6_NF_IPTABLES
5554   dep_tristate '  netfilter MARK match support' CONFIG_IP6_NF_MATCH_MARK $CONFIG_IP6_NF_IPTABLES
5555+  dep_tristate '  Packet Length match support' CONFIG_IP6_NF_MATCH_LENGTH $CONFIG_IP6_NF_IPTABLES
5556+  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
5557+    dep_tristate '  EUI64 address check (EXPERIMENTAL)' CONFIG_IP6_NF_MATCH_EUI64 $CONFIG_IP6_NF_IPTABLES
5558+  fi
5559 #  dep_tristate '  Multiple port match support' CONFIG_IP6_NF_MATCH_MULTIPORT $CONFIG_IP6_NF_IPTABLES
5560 #  dep_tristate '  TOS match support' CONFIG_IP6_NF_MATCH_TOS $CONFIG_IP6_NF_IPTABLES
5561 #  if [ "$CONFIG_IP6_NF_CONNTRACK" != "n" ]; then
5562diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv6/netfilter/Makefile linux-2.4.20-plain/net/ipv6/netfilter/Makefile
5563--- linux-2.4.19-plain/net/ipv6/netfilter/Makefile	Mon Feb 25 20:38:14 2002
5564+++ linux-2.4.20-plain/net/ipv6/netfilter/Makefile	Fri Nov 29 00:53:15 2002
5565@@ -15,7 +15,9 @@
5566 obj-$(CONFIG_IP6_NF_IPTABLES) += ip6_tables.o
5567 obj-$(CONFIG_IP6_NF_MATCH_LIMIT) += ip6t_limit.o
5568 obj-$(CONFIG_IP6_NF_MATCH_MARK) += ip6t_mark.o
5569+obj-$(CONFIG_IP6_NF_MATCH_LENGTH) += ip6t_length.o
5570 obj-$(CONFIG_IP6_NF_MATCH_MAC) += ip6t_mac.o
5571+obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o
5572 obj-$(CONFIG_IP6_NF_MATCH_MULTIPORT) += ip6t_multiport.o
5573 obj-$(CONFIG_IP6_NF_MATCH_OWNER) += ip6t_owner.o
5574 obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o
5575diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv6/netfilter/ip6_queue.c linux-2.4.20-plain/net/ipv6/netfilter/ip6_queue.c
5576--- linux-2.4.19-plain/net/ipv6/netfilter/ip6_queue.c	Sat Aug  3 02:39:46 2002
5577+++ linux-2.4.20-plain/net/ipv6/netfilter/ip6_queue.c	Fri Nov 29 00:53:15 2002
5578@@ -15,7 +15,7 @@
5579  *             real coder of this.
5580  *             Few changes needed, mainly the hard_routing code and
5581  *             the netlink socket protocol (we're NETLINK_IP6_FW).
5582- *
5583+ * 2002-06-25: Code cleanup. [JM: ported cleanup over from ip_queue.c]
5584  */
5585 #include <linux/module.h>
5586 #include <linux/skbuff.h>
5587@@ -26,18 +26,12 @@
5588 #include <linux/netfilter.h>
5589 #include <linux/netlink.h>
5590 #include <linux/spinlock.h>
5591-#include <linux/rtnetlink.h>
5592+#include <linux/brlock.h>
5593 #include <linux/sysctl.h>
5594 #include <linux/proc_fs.h>
5595 #include <net/sock.h>
5596 #include <net/ipv6.h>
5597 #include <net/ip6_route.h>
5598-
5599-/* We're still usign the following structs. No need to change them: */
5600-/*   ipq_packet_msg                                                 */
5601-/*   ipq_mode_msg                                                   */
5602-/*   ipq_verdict_msg                                                */
5603-/*   ipq_peer_msg                                                   */
5604 #include <linux/netfilter_ipv4/ip_queue.h>
5605 #include <linux/netfilter_ipv4/ip_tables.h>
5606 #include <linux/netfilter_ipv6/ip6_tables.h>
5607@@ -47,184 +41,289 @@
5608 #define NET_IPQ_QMAX 2088
5609 #define NET_IPQ_QMAX_NAME "ip6_queue_maxlen"
5610 
5611-typedef struct ip6q_rt_info {
5612+struct ipq_rt_info {
5613 	struct in6_addr daddr;
5614 	struct in6_addr saddr;
5615-} ip6q_rt_info_t;
5616+};
5617 
5618-typedef struct ip6q_queue_element {
5619-	struct list_head list;		/* Links element into queue */
5620-	int verdict;			/* Current verdict */
5621-	struct nf_info *info;		/* Extra info from netfilter */
5622-	struct sk_buff *skb;		/* Packet inside */
5623-	ip6q_rt_info_t rt_info;		/* May need post-mangle routing */
5624-} ip6q_queue_element_t;
5625-
5626-typedef int (*ip6q_send_cb_t)(ip6q_queue_element_t *e);
5627-
5628-typedef struct ip6q_peer {
5629-	pid_t pid;			/* PID of userland peer */
5630-	unsigned char died;		/* We think the peer died */
5631-	unsigned char copy_mode;	/* Copy packet as well as metadata? */
5632-	size_t copy_range;		/* Range past metadata to copy */
5633-	ip6q_send_cb_t send;		/* Callback for sending data to peer */
5634-} ip6q_peer_t;
5635-
5636-typedef struct ip6q_queue {
5637- 	int len;			/* Current queue len */
5638- 	int *maxlen;			/* Maximum queue len, via sysctl */
5639- 	unsigned char flushing;		/* If queue is being flushed */
5640- 	unsigned char terminate;	/* If the queue is being terminated */
5641- 	struct list_head list;		/* Head of packet queue */
5642- 	spinlock_t lock;		/* Queue spinlock */
5643- 	ip6q_peer_t peer;		/* Userland peer */
5644-} ip6q_queue_t;
5645+struct ipq_queue_entry {
5646+	struct list_head list;
5647+	struct nf_info *info;
5648+	struct sk_buff *skb;
5649+	struct ipq_rt_info rt_info;
5650+};
5651 
5652-/****************************************************************************
5653- *
5654- * Packet queue
5655- *
5656- ****************************************************************************/
5657-/* Dequeue a packet if matched by cmp, or the next available if cmp is NULL */
5658-static ip6q_queue_element_t *
5659-ip6q_dequeue(ip6q_queue_t *q,
5660-            int (*cmp)(ip6q_queue_element_t *, unsigned long),
5661-            unsigned long data)
5662-{
5663-	struct list_head *i;
5664-
5665-	spin_lock_bh(&q->lock);
5666-	for (i = q->list.prev; i != &q->list; i = i->prev) {
5667-		ip6q_queue_element_t *e = (ip6q_queue_element_t *)i;
5668-		
5669-		if (!cmp || cmp(e, data)) {
5670-			list_del(&e->list);
5671-			q->len--;
5672-			spin_unlock_bh(&q->lock);
5673-			return e;
5674-		}
5675+typedef int (*ipq_cmpfn)(struct ipq_queue_entry *, unsigned long);
5676+
5677+static unsigned char copy_mode = IPQ_COPY_NONE;
5678+static unsigned int queue_maxlen = IPQ_QMAX_DEFAULT;
5679+static rwlock_t queue_lock = RW_LOCK_UNLOCKED;
5680+static int peer_pid;
5681+static unsigned int copy_range;
5682+static unsigned int queue_total;
5683+static struct sock *ipqnl;
5684+static LIST_HEAD(queue_list);
5685+static DECLARE_MUTEX(ipqnl_sem);
5686+
5687+static void
5688+ipq_issue_verdict(struct ipq_queue_entry *entry, int verdict)
5689+{
5690+	nf_reinject(entry->skb, entry->info, verdict);
5691+	kfree(entry);
5692+}
5693+
5694+static inline int
5695+__ipq_enqueue_entry(struct ipq_queue_entry *entry)
5696+{
5697+       if (queue_total >= queue_maxlen) {
5698+               if (net_ratelimit()) 
5699+                       printk(KERN_WARNING "ip6_queue: full at %d entries, "
5700+                              "dropping packet(s).\n", queue_total);
5701+               return -ENOSPC;
5702+       }
5703+       list_add(&entry->list, &queue_list);
5704+       queue_total++;
5705+       return 0;
5706+}
5707+
5708+/*
5709+ * Find and return a queued entry matched by cmpfn, or return the last
5710+ * entry if cmpfn is NULL.
5711+ */
5712+static inline struct ipq_queue_entry *
5713+__ipq_find_entry(ipq_cmpfn cmpfn, unsigned long data)
5714+{
5715+	struct list_head *p;
5716+
5717+	list_for_each_prev(p, &queue_list) {
5718+		struct ipq_queue_entry *entry = (struct ipq_queue_entry *)p;
5719+		
5720+		if (!cmpfn || cmpfn(entry, data))
5721+			return entry;
5722 	}
5723-	spin_unlock_bh(&q->lock);
5724 	return NULL;
5725 }
5726 
5727-/* Flush all packets */
5728-static void ip6q_flush(ip6q_queue_t *q)
5729+static inline void
5730+__ipq_dequeue_entry(struct ipq_queue_entry *entry)
5731 {
5732-	ip6q_queue_element_t *e;
5733-	
5734-	spin_lock_bh(&q->lock);
5735-	q->flushing = 1;
5736-	spin_unlock_bh(&q->lock);
5737-	while ((e = ip6q_dequeue(q, NULL, 0))) {
5738-		e->verdict = NF_DROP;
5739-		nf_reinject(e->skb, e->info, e->verdict);
5740-		kfree(e);
5741-	}
5742-	spin_lock_bh(&q->lock);
5743-	q->flushing = 0;
5744-	spin_unlock_bh(&q->lock);
5745-}
5746-
5747-static ip6q_queue_t *ip6q_create_queue(nf_queue_outfn_t outfn,
5748-                                     ip6q_send_cb_t send_cb,
5749-                                     int *errp, int *sysctl_qmax)
5750+	list_del(&entry->list);
5751+	queue_total--;
5752+}
5753+
5754+static inline struct ipq_queue_entry *
5755+__ipq_find_dequeue_entry(ipq_cmpfn cmpfn, unsigned long data)
5756 {
5757-	int status;
5758-	ip6q_queue_t *q;
5759+	struct ipq_queue_entry *entry;
5760 
5761-	*errp = 0;
5762-	q = kmalloc(sizeof(ip6q_queue_t), GFP_KERNEL);
5763-	if (q == NULL) {
5764-		*errp = -ENOMEM;
5765+	entry = __ipq_find_entry(cmpfn, data);
5766+	if (entry == NULL)
5767 		return NULL;
5768+
5769+	__ipq_dequeue_entry(entry);
5770+	return entry;
5771+}
5772+
5773+
5774+static inline void
5775+__ipq_flush(int verdict)
5776+{
5777+	struct ipq_queue_entry *entry;
5778+	
5779+	while ((entry = __ipq_find_dequeue_entry(NULL, 0)))
5780+		ipq_issue_verdict(entry, verdict);
5781+}
5782+
5783+static inline int
5784+__ipq_set_mode(unsigned char mode, unsigned int range)
5785+{
5786+	int status = 0;
5787+	
5788+	switch(mode) {
5789+	case IPQ_COPY_NONE:
5790+	case IPQ_COPY_META:
5791+		copy_mode = mode;
5792+		copy_range = 0;
5793+		break;
5794+		
5795+	case IPQ_COPY_PACKET:
5796+		copy_mode = mode;
5797+		copy_range = range;
5798+		if (copy_range > 0xFFFF)
5799+			copy_range = 0xFFFF;
5800+		break;
5801+		
5802+	default:
5803+		status = -EINVAL;
5804+
5805 	}
5806-	q->peer.pid = 0;
5807-	q->peer.died = 0;
5808-	q->peer.copy_mode = IPQ_COPY_NONE;
5809-	q->peer.copy_range = 0;
5810-	q->peer.send = send_cb;
5811-	q->len = 0;
5812-	q->maxlen = sysctl_qmax;
5813-	q->flushing = 0;
5814-	q->terminate = 0;
5815-	INIT_LIST_HEAD(&q->list);
5816-	spin_lock_init(&q->lock);
5817-	status = nf_register_queue_handler(PF_INET6, outfn, q);
5818-	if (status < 0) {
5819-		*errp = -EBUSY;
5820-		kfree(q);
5821+	return status;
5822+}
5823+
5824+static inline void
5825+__ipq_reset(void)
5826+{
5827+	peer_pid = 0;
5828+	__ipq_set_mode(IPQ_COPY_NONE, 0);
5829+	__ipq_flush(NF_DROP);
5830+}
5831+
5832+static struct ipq_queue_entry *
5833+ipq_find_dequeue_entry(ipq_cmpfn cmpfn, unsigned long data)
5834+{
5835+	struct ipq_queue_entry *entry;
5836+	
5837+	write_lock_bh(&queue_lock);
5838+	entry = __ipq_find_dequeue_entry(cmpfn, data);
5839+	write_unlock_bh(&queue_lock);
5840+	return entry;
5841+}
5842+
5843+static void
5844+ipq_flush(int verdict)
5845+{
5846+	write_lock_bh(&queue_lock);
5847+	__ipq_flush(verdict);
5848+	write_unlock_bh(&queue_lock);
5849+}
5850+
5851+static struct sk_buff *
5852+ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp)
5853+{
5854+	unsigned char *old_tail;
5855+	size_t size = 0;
5856+	size_t data_len = 0;
5857+	struct sk_buff *skb;
5858+	struct ipq_packet_msg *pmsg;
5859+	struct nlmsghdr *nlh;
5860+
5861+	read_lock_bh(&queue_lock);
5862+	
5863+	switch (copy_mode) {
5864+	case IPQ_COPY_META:
5865+	case IPQ_COPY_NONE:
5866+		size = NLMSG_SPACE(sizeof(*pmsg));
5867+		data_len = 0;
5868+		break;
5869+	
5870+	case IPQ_COPY_PACKET:
5871+		if (copy_range == 0 || copy_range > entry->skb->len)
5872+			data_len = entry->skb->len;
5873+		else
5874+			data_len = copy_range;
5875+		
5876+		size = NLMSG_SPACE(sizeof(*pmsg) + data_len);
5877+		break;
5878+	
5879+	default:
5880+		*errp = -EINVAL;
5881+		read_unlock_bh(&queue_lock);
5882 		return NULL;
5883 	}
5884-	return q;
5885+
5886+	read_unlock_bh(&queue_lock);
5887+
5888+	skb = alloc_skb(size, GFP_ATOMIC);
5889+	if (!skb)
5890+		goto nlmsg_failure;
5891+		
5892+	old_tail= skb->tail;
5893+	nlh = NLMSG_PUT(skb, 0, 0, IPQM_PACKET, size - sizeof(*nlh));
5894+	pmsg = NLMSG_DATA(nlh);
5895+	memset(pmsg, 0, sizeof(*pmsg));
5896+
5897+	pmsg->packet_id       = (unsigned long )entry;
5898+	pmsg->data_len        = data_len;
5899+	pmsg->timestamp_sec   = entry->skb->stamp.tv_sec;
5900+	pmsg->timestamp_usec  = entry->skb->stamp.tv_usec;
5901+	pmsg->mark            = entry->skb->nfmark;
5902+	pmsg->hook            = entry->info->hook;
5903+	pmsg->hw_protocol     = entry->skb->protocol;
5904+	
5905+	if (entry->info->indev)
5906+		strcpy(pmsg->indev_name, entry->info->indev->name);
5907+	else
5908+		pmsg->indev_name[0] = '\0';
5909+	
5910+	if (entry->info->outdev)
5911+		strcpy(pmsg->outdev_name, entry->info->outdev->name);
5912+	else
5913+		pmsg->outdev_name[0] = '\0';
5914+	
5915+	if (entry->info->indev && entry->skb->dev) {
5916+		pmsg->hw_type = entry->skb->dev->type;
5917+		if (entry->skb->dev->hard_header_parse)
5918+			pmsg->hw_addrlen =
5919+				entry->skb->dev->hard_header_parse(entry->skb,
5920+				                                   pmsg->hw_addr);
5921+	}
5922+	
5923+	if (data_len)
5924+		memcpy(pmsg->payload, entry->skb->data, data_len);
5925+		
5926+	nlh->nlmsg_len = skb->tail - old_tail;
5927+	return skb;
5928+
5929+nlmsg_failure:
5930+	if (skb)
5931+		kfree_skb(skb);
5932+	*errp = -EINVAL;
5933+	printk(KERN_ERR "ip6_queue: error creating packet message\n");
5934+	return NULL;
5935 }
5936 
5937-static int ip6q_enqueue(ip6q_queue_t *q,
5938-                       struct sk_buff *skb, struct nf_info *info)
5939+static int
5940+ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info, void *data)
5941 {
5942-	ip6q_queue_element_t *e;
5943-	int status;
5944-	
5945-	e = kmalloc(sizeof(*e), GFP_ATOMIC);
5946-	if (e == NULL) {
5947-		printk(KERN_ERR "ip6_queue: OOM in enqueue\n");
5948+	int status = -EINVAL;
5949+	struct sk_buff *nskb;
5950+	struct ipq_queue_entry *entry;
5951+
5952+	if (copy_mode == IPQ_COPY_NONE)
5953+		return -EAGAIN;
5954+
5955+	entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
5956+	if (entry == NULL) {
5957+		printk(KERN_ERR "ip6_queue: OOM in ipq_enqueue_packet()\n");
5958 		return -ENOMEM;
5959 	}
5960 
5961-	e->verdict = NF_DROP;
5962-	e->info = info;
5963-	e->skb = skb;
5964+	entry->info = info;
5965+	entry->skb = skb;
5966 
5967-	if (e->info->hook == NF_IP_LOCAL_OUT) {
5968+	if (entry->info->hook == NF_IP_LOCAL_OUT) {
5969 		struct ipv6hdr *iph = skb->nh.ipv6h;
5970 
5971-		e->rt_info.daddr = iph->daddr;
5972-		e->rt_info.saddr = iph->saddr;
5973+		entry->rt_info.daddr = iph->daddr;
5974+		entry->rt_info.saddr = iph->saddr;
5975 	}
5976 
5977-	spin_lock_bh(&q->lock);
5978-	if (q->len >= *q->maxlen) {
5979-		spin_unlock_bh(&q->lock);
5980-		if (net_ratelimit()) 
5981-			printk(KERN_WARNING "ip6_queue: full at %d entries, "
5982-			       "dropping packet(s).\n", q->len);
5983-		goto free_drop;
5984-	}
5985-	if (q->flushing || q->peer.copy_mode == IPQ_COPY_NONE
5986-	    || q->peer.pid == 0 || q->peer.died || q->terminate) {
5987-		spin_unlock_bh(&q->lock);
5988-		goto free_drop;
5989-	}
5990-	status = q->peer.send(e);
5991-	if (status > 0) {
5992-		list_add(&e->list, &q->list);
5993-		q->len++;
5994-		spin_unlock_bh(&q->lock);
5995-		return status;
5996-	}
5997-	spin_unlock_bh(&q->lock);
5998-	if (status == -ECONNREFUSED) {
5999-		printk(KERN_INFO "ip6_queue: peer %d died, "
6000-		       "resetting state and flushing queue\n", q->peer.pid);
6001-			q->peer.died = 1;
6002-			q->peer.pid = 0;
6003-			q->peer.copy_mode = IPQ_COPY_NONE;
6004-			q->peer.copy_range = 0;
6005-			ip6q_flush(q);
6006-	}
6007-free_drop:
6008-	kfree(e);
6009-	return -EBUSY;
6010-}
6011+	nskb = ipq_build_packet_message(entry, &status);
6012+	if (nskb == NULL)
6013+		goto err_out_free;
6014+		
6015+	write_lock_bh(&queue_lock);
6016+	
6017+	if (!peer_pid)
6018+		goto err_out_unlock;
6019 
6020-static void ip6q_destroy_queue(ip6q_queue_t *q)
6021-{
6022-	nf_unregister_queue_handler(PF_INET6);
6023-	spin_lock_bh(&q->lock);
6024-	q->terminate = 1;
6025-	spin_unlock_bh(&q->lock);
6026-	ip6q_flush(q);
6027-	kfree(q);
6028+	status = netlink_unicast(ipqnl, nskb, peer_pid, MSG_DONTWAIT);
6029+	if (status < 0)
6030+		goto err_out_unlock;
6031+	
6032+	status = __ipq_enqueue_entry(entry);
6033+	if (status < 0)
6034+		goto err_out_unlock;
6035+
6036+	write_unlock_bh(&queue_lock);
6037+	return status;
6038+	
6039+err_out_unlock:
6040+	write_unlock_bh(&queue_lock);
6041+
6042+err_out_free:
6043+	kfree(entry);
6044+	return status;
6045 }
6046 
6047 /*
6048@@ -236,7 +335,8 @@
6049  *
6050  * If that one is modified, this one should be modified too.
6051  */
6052-static int route6_me_harder(struct sk_buff *skb)
6053+static int
6054+route6_me_harder(struct sk_buff *skb)
6055 {
6056 	struct ipv6hdr *iph = skb->nh.ipv6h;
6057 	struct dst_entry *dst;
6058@@ -264,7 +364,9 @@
6059 	skb->dst = dst;
6060 	return 0;
6061 }
6062-static int ip6q_mangle_ipv6(ipq_verdict_msg_t *v, ip6q_queue_element_t *e)
6063+
6064+static int
6065+ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
6066 {
6067 	int diff;
6068 	struct ipv6hdr *user_iph = (struct ipv6hdr *)v->payload;
6069@@ -306,357 +408,262 @@
6070 	 */
6071 	if (e->info->hook == NF_IP_LOCAL_OUT) {
6072 		struct ipv6hdr *iph = e->skb->nh.ipv6h;
6073-		if (!(   iph->daddr.in6_u.u6_addr32[0] == e->rt_info.daddr.in6_u.u6_addr32[0]
6074-                      && iph->daddr.in6_u.u6_addr32[1] == e->rt_info.daddr.in6_u.u6_addr32[1]
6075-                      && iph->daddr.in6_u.u6_addr32[2] == e->rt_info.daddr.in6_u.u6_addr32[2]
6076-                      && iph->daddr.in6_u.u6_addr32[3] == e->rt_info.daddr.in6_u.u6_addr32[3]
6077-		      && iph->saddr.in6_u.u6_addr32[0] == e->rt_info.saddr.in6_u.u6_addr32[0]
6078-		      && iph->saddr.in6_u.u6_addr32[1] == e->rt_info.saddr.in6_u.u6_addr32[1]
6079-		      && iph->saddr.in6_u.u6_addr32[2] == e->rt_info.saddr.in6_u.u6_addr32[2]
6080-		      && iph->saddr.in6_u.u6_addr32[3] == e->rt_info.saddr.in6_u.u6_addr32[3]))
6081+		if (ipv6_addr_cmp(&iph->daddr, &e->rt_info.daddr) ||
6082+		    ipv6_addr_cmp(&iph->saddr, &e->rt_info.saddr))
6083 			return route6_me_harder(e->skb);
6084 	}
6085 	return 0;
6086 }
6087 
6088-static inline int id_cmp(ip6q_queue_element_t *e, unsigned long id)
6089+static inline int
6090+id_cmp(struct ipq_queue_entry *e, unsigned long id)
6091 {
6092 	return (id == (unsigned long )e);
6093 }
6094 
6095-static int ip6q_set_verdict(ip6q_queue_t *q,
6096-                           ipq_verdict_msg_t *v, unsigned int len)
6097+static int
6098+ipq_set_verdict(struct ipq_verdict_msg *vmsg, unsigned int len)
6099 {
6100-	ip6q_queue_element_t *e;
6101+	struct ipq_queue_entry *entry;
6102 
6103-	if (v->value > NF_MAX_VERDICT)
6104+	if (vmsg->value > NF_MAX_VERDICT)
6105 		return -EINVAL;
6106-	e = ip6q_dequeue(q, id_cmp, v->id);
6107-	if (e == NULL)
6108+
6109+	entry = ipq_find_dequeue_entry(id_cmp, vmsg->id);
6110+	if (entry == NULL)
6111 		return -ENOENT;
6112 	else {
6113-		e->verdict = v->value;
6114-		if (v->data_len && v->data_len == len)
6115-			if (ip6q_mangle_ipv6(v, e) < 0)
6116-				e->verdict = NF_DROP;
6117-		nf_reinject(e->skb, e->info, e->verdict);
6118-		kfree(e);
6119+		int verdict = vmsg->value;
6120+		
6121+		if (vmsg->data_len && vmsg->data_len == len)
6122+			if (ipq_mangle_ipv6(vmsg, entry) < 0)
6123+				verdict = NF_DROP;
6124+		
6125+		ipq_issue_verdict(entry, verdict);
6126 		return 0;
6127 	}
6128 }
6129 
6130-static int ip6q_receive_peer(ip6q_queue_t* q, ipq_peer_msg_t *m,
6131-                            unsigned char type, unsigned int len)
6132+static int
6133+ipq_set_mode(unsigned char mode, unsigned int range)
6134 {
6135+	int status;
6136+
6137+	write_lock_bh(&queue_lock);
6138+	status = __ipq_set_mode(mode, range);
6139+	write_unlock_bh(&queue_lock);
6140+	return status;
6141+}
6142 
6143+static int
6144+ipq_receive_peer(struct ipq_peer_msg *pmsg,
6145+                 unsigned char type, unsigned int len)
6146+{
6147 	int status = 0;
6148-	int busy;
6149-		
6150-	spin_lock_bh(&q->lock);
6151-	busy = (q->terminate || q->flushing);
6152-	spin_unlock_bh(&q->lock);
6153-	if (busy)
6154-		return -EBUSY;
6155-	if (len < sizeof(ipq_peer_msg_t))
6156+
6157+	if (len < sizeof(*pmsg))
6158 		return -EINVAL;
6159+
6160 	switch (type) {
6161-		case IPQM_MODE:
6162-			switch (m->msg.mode.value) {
6163-				case IPQ_COPY_META:
6164-					q->peer.copy_mode = IPQ_COPY_META;
6165-					q->peer.copy_range = 0;
6166-					break;
6167-				case IPQ_COPY_PACKET:
6168-					q->peer.copy_mode = IPQ_COPY_PACKET;
6169-					q->peer.copy_range = m->msg.mode.range;
6170-					if (q->peer.copy_range > 0xFFFF)
6171-						q->peer.copy_range = 0xFFFF;
6172-					break;
6173-				default:
6174-					status = -EINVAL;
6175-			}
6176-			break;
6177-		case IPQM_VERDICT:
6178-			if (m->msg.verdict.value > NF_MAX_VERDICT)
6179-				status = -EINVAL;
6180-			else
6181-				status = ip6q_set_verdict(q,
6182-				                         &m->msg.verdict,
6183-				                         len - sizeof(*m));
6184+	case IPQM_MODE:
6185+		status = ipq_set_mode(pmsg->msg.mode.value,
6186+		                      pmsg->msg.mode.range);
6187+		break;
6188+		
6189+	case IPQM_VERDICT:
6190+		if (pmsg->msg.verdict.value > NF_MAX_VERDICT)
6191+			status = -EINVAL;
6192+		else
6193+			status = ipq_set_verdict(&pmsg->msg.verdict,
6194+			                         len - sizeof(*pmsg));
6195 			break;
6196-		default:
6197-			 status = -EINVAL;
6198+	default:
6199+		status = -EINVAL;
6200 	}
6201 	return status;
6202 }
6203 
6204-static inline int dev_cmp(ip6q_queue_element_t *e, unsigned long ifindex)
6205+static int
6206+dev_cmp(struct ipq_queue_entry *entry, unsigned long ifindex)
6207 {
6208-	if (e->info->indev)
6209-		if (e->info->indev->ifindex == ifindex)
6210+	if (entry->info->indev)
6211+		if (entry->info->indev->ifindex == ifindex)
6212 			return 1;
6213-	if (e->info->outdev)
6214-		if (e->info->outdev->ifindex == ifindex)
6215+			
6216+	if (entry->info->outdev)
6217+		if (entry->info->outdev->ifindex == ifindex)
6218 			return 1;
6219+
6220 	return 0;
6221 }
6222 
6223-/* Drop any queued packets associated with device ifindex */
6224-static void ip6q_dev_drop(ip6q_queue_t *q, int ifindex)
6225+static void
6226+ipq_dev_drop(int ifindex)
6227 {
6228-	ip6q_queue_element_t *e;
6229+	struct ipq_queue_entry *entry;
6230 	
6231-	while ((e = ip6q_dequeue(q, dev_cmp, ifindex))) {
6232-		e->verdict = NF_DROP;
6233-		nf_reinject(e->skb, e->info, e->verdict);
6234-		kfree(e);
6235-	}
6236-}
6237-
6238-/****************************************************************************
6239- *
6240- * Netfilter interface
6241- *
6242- ****************************************************************************/
6243-
6244-/*
6245- * Packets arrive here from netfilter for queuing to userspace.
6246- * All of them must be fed back via nf_reinject() or Alexey will kill Rusty.
6247- */
6248-static int netfilter6_receive(struct sk_buff *skb,
6249-                             struct nf_info *info, void *data)
6250-{
6251-	return ip6q_enqueue((ip6q_queue_t *)data, skb, info);
6252-}
6253-
6254-/****************************************************************************
6255- *
6256- * Netlink interface.
6257- *
6258- ****************************************************************************/
6259-
6260-static struct sock *nfnl = NULL;
6261-/* This is not a static one, so we should not repeat its name */
6262-ip6q_queue_t *nlq6 = NULL;
6263-
6264-static struct sk_buff *netlink_build_message(ip6q_queue_element_t *e, int *errp)
6265-{
6266-	unsigned char *old_tail;
6267-	size_t size = 0;
6268-	size_t data_len = 0;
6269-	struct sk_buff *skb;
6270-	ipq_packet_msg_t *pm;
6271-	struct nlmsghdr *nlh;
6272-
6273-	switch (nlq6->peer.copy_mode) {
6274-		size_t copy_range;
6275-
6276-		case IPQ_COPY_META:
6277-			size = NLMSG_SPACE(sizeof(*pm));
6278-			data_len = 0;
6279-			break;
6280-		case IPQ_COPY_PACKET:
6281-			copy_range = nlq6->peer.copy_range;
6282-			if (copy_range == 0 || copy_range > e->skb->len)
6283-				data_len = e->skb->len;
6284-			else
6285-				data_len = copy_range;
6286-			size = NLMSG_SPACE(sizeof(*pm) + data_len);
6287-			
6288-			break;
6289-		case IPQ_COPY_NONE:
6290-		default:
6291-			*errp = -EINVAL;
6292-			return NULL;
6293-	}
6294-	skb = alloc_skb(size, GFP_ATOMIC);
6295-	if (!skb)
6296-		goto nlmsg_failure;
6297-	old_tail = skb->tail;
6298-	nlh = NLMSG_PUT(skb, 0, 0, IPQM_PACKET, size - sizeof(*nlh));
6299-	pm = NLMSG_DATA(nlh);
6300-	memset(pm, 0, sizeof(*pm));
6301-	pm->packet_id = (unsigned long )e;
6302-	pm->data_len = data_len;
6303-	pm->timestamp_sec = e->skb->stamp.tv_sec;
6304-	pm->timestamp_usec = e->skb->stamp.tv_usec;
6305-	pm->mark = e->skb->nfmark;
6306-	pm->hook = e->info->hook;
6307-	if (e->info->indev) strcpy(pm->indev_name, e->info->indev->name);
6308-	else pm->indev_name[0] = '\0';
6309-	if (e->info->outdev) strcpy(pm->outdev_name, e->info->outdev->name);
6310-	else pm->outdev_name[0] = '\0';
6311-	pm->hw_protocol = e->skb->protocol;
6312-	if (e->info->indev && e->skb->dev) {
6313-		pm->hw_type = e->skb->dev->type;
6314-		if (e->skb->dev->hard_header_parse)
6315-			pm->hw_addrlen =
6316-				e->skb->dev->hard_header_parse(e->skb,
6317-				                               pm->hw_addr);
6318-	}
6319-	if (data_len)
6320-		memcpy(pm->payload, e->skb->data, data_len);
6321-	nlh->nlmsg_len = skb->tail - old_tail;
6322-	NETLINK_CB(skb).dst_groups = 0;
6323-	return skb;
6324-nlmsg_failure:
6325-	if (skb)
6326-		kfree_skb(skb);
6327-	*errp = 0;
6328-	printk(KERN_ERR "ip6_queue: error creating netlink message\n");
6329-	return NULL;
6330-}
6331-
6332-static int netlink_send_peer(ip6q_queue_element_t *e)
6333-{
6334-	int status = 0;
6335-	struct sk_buff *skb;
6336-
6337-	skb = netlink_build_message(e, &status);
6338-	if (skb == NULL)
6339-		return status;
6340-	return netlink_unicast(nfnl, skb, nlq6->peer.pid, MSG_DONTWAIT);
6341+	while ((entry = ipq_find_dequeue_entry(dev_cmp, ifindex)) != NULL)
6342+		ipq_issue_verdict(entry, NF_DROP);
6343 }
6344 
6345 #define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0)
6346 
6347-static __inline__ void netlink_receive_user_skb(struct sk_buff *skb)
6348+static inline void
6349+ipq_rcv_skb(struct sk_buff *skb)
6350 {
6351-	int status, type;
6352+	int status, type, pid, flags, nlmsglen, skblen;
6353 	struct nlmsghdr *nlh;
6354 
6355-	if (skb->len < sizeof(struct nlmsghdr))
6356+	skblen = skb->len;
6357+	if (skblen < sizeof(*nlh))
6358 		return;
6359 
6360 	nlh = (struct nlmsghdr *)skb->data;
6361-	if (nlh->nlmsg_len < sizeof(struct nlmsghdr)
6362-	    || skb->len < nlh->nlmsg_len)
6363-	    	return;
6364-
6365-	if(nlh->nlmsg_pid <= 0
6366-	    || !(nlh->nlmsg_flags & NLM_F_REQUEST)
6367-	    || nlh->nlmsg_flags & NLM_F_MULTI)
6368+	nlmsglen = nlh->nlmsg_len;
6369+	if (nlmsglen < sizeof(*nlh) || skblen < nlmsglen)
6370+		return;
6371+
6372+	pid = nlh->nlmsg_pid;
6373+	flags = nlh->nlmsg_flags;
6374+	
6375+	if(pid <= 0 || !(flags & NLM_F_REQUEST) || flags & NLM_F_MULTI)
6376 		RCV_SKB_FAIL(-EINVAL);
6377-	if (nlh->nlmsg_flags & MSG_TRUNC)
6378+		
6379+	if (flags & MSG_TRUNC)
6380 		RCV_SKB_FAIL(-ECOMM);
6381+		
6382 	type = nlh->nlmsg_type;
6383 	if (type < NLMSG_NOOP || type >= IPQM_MAX)
6384 		RCV_SKB_FAIL(-EINVAL);
6385+		
6386 	if (type <= IPQM_BASE)
6387 		return;
6388+		
6389 	if(!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
6390 		RCV_SKB_FAIL(-EPERM);
6391-	if (nlq6->peer.pid && !nlq6->peer.died
6392-	    && (nlq6->peer.pid != nlh->nlmsg_pid)) {
6393-	    	printk(KERN_WARNING "ip6_queue: peer pid changed from %d to "
6394-	    	      "%d, flushing queue\n", nlq6->peer.pid, nlh->nlmsg_pid);
6395-		ip6q_flush(nlq6);
6396-	}	
6397-	nlq6->peer.pid = nlh->nlmsg_pid;
6398-	nlq6->peer.died = 0;
6399-	status = ip6q_receive_peer(nlq6, NLMSG_DATA(nlh),
6400-	                          type, skb->len - NLMSG_LENGTH(0));
6401+	
6402+	write_lock_bh(&queue_lock);
6403+	
6404+	if (peer_pid) {
6405+		if (peer_pid != pid) {
6406+			write_unlock_bh(&queue_lock);
6407+			RCV_SKB_FAIL(-EBUSY);
6408+		}
6409+	}
6410+	else
6411+		peer_pid = pid;
6412+		
6413+	write_unlock_bh(&queue_lock);
6414+	
6415+	status = ipq_receive_peer(NLMSG_DATA(nlh), type,
6416+	                          skblen - NLMSG_LENGTH(0));
6417 	if (status < 0)
6418 		RCV_SKB_FAIL(status);
6419-	if (nlh->nlmsg_flags & NLM_F_ACK)
6420+		
6421+	if (flags & NLM_F_ACK)
6422 		netlink_ack(skb, nlh, 0);
6423         return;
6424 }
6425 
6426-/* Note: we are only dealing with single part messages at the moment. */
6427-static void netlink_receive_user_sk(struct sock *sk, int len)
6428+static void
6429+ipq_rcv_sk(struct sock *sk, int len)
6430 {
6431 	do {
6432 		struct sk_buff *skb;
6433 
6434-		if (rtnl_shlock_nowait())
6435+		if (down_trylock(&ipqnl_sem))
6436 			return;
6437+			
6438 		while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
6439-			netlink_receive_user_skb(skb);
6440+			ipq_rcv_skb(skb);
6441 			kfree_skb(skb);
6442 		}
6443-		up(&rtnl_sem);
6444-	} while (nfnl && nfnl->receive_queue.qlen);
6445-}
6446+		
6447+		up(&ipqnl_sem);
6448 
6449-/****************************************************************************
6450- *
6451- * System events
6452- *
6453- ****************************************************************************/
6454+	} while (ipqnl && ipqnl->receive_queue.qlen);
6455+}
6456 
6457-static int receive_event(struct notifier_block *this,
6458-                         unsigned long event, void *ptr)
6459+static int
6460+ipq_rcv_dev_event(struct notifier_block *this,
6461+                  unsigned long event, void *ptr)
6462 {
6463 	struct net_device *dev = ptr;
6464 
6465 	/* Drop any packets associated with the downed device */
6466 	if (event == NETDEV_DOWN)
6467-		ip6q_dev_drop(nlq6, dev->ifindex);
6468+		ipq_dev_drop(dev->ifindex);
6469 	return NOTIFY_DONE;
6470 }
6471 
6472-struct notifier_block ip6q_dev_notifier = {
6473-	receive_event,
6474+static struct notifier_block ipq_dev_notifier = {
6475+	ipq_rcv_dev_event,
6476 	NULL,
6477 	0
6478 };
6479 
6480-/****************************************************************************
6481- *
6482- * Sysctl - queue tuning.
6483- *
6484- ****************************************************************************/
6485+static int
6486+ipq_rcv_nl_event(struct notifier_block *this,
6487+                 unsigned long event, void *ptr)
6488+{
6489+	struct netlink_notify *n = ptr;
6490+
6491+	if (event == NETLINK_URELEASE &&
6492+	    n->protocol == NETLINK_IP6_FW && n->pid) {
6493+		write_lock_bh(&queue_lock);
6494+		if (n->pid == peer_pid)
6495+			__ipq_reset();
6496+		write_unlock_bh(&queue_lock);
6497+	}
6498+	return NOTIFY_DONE;
6499+}
6500 
6501-static int sysctl_maxlen = IPQ_QMAX_DEFAULT;
6502+static struct notifier_block ipq_nl_notifier = {
6503+	ipq_rcv_nl_event,
6504+	NULL,
6505+	0
6506+};
6507 
6508-static struct ctl_table_header *ip6q_sysctl_header;
6509+static int sysctl_maxlen = IPQ_QMAX_DEFAULT;
6510+static struct ctl_table_header *ipq_sysctl_header;
6511 
6512-static ctl_table ip6q_table[] = {
6513+static ctl_table ipq_table[] = {
6514 	{ NET_IPQ_QMAX, NET_IPQ_QMAX_NAME, &sysctl_maxlen,
6515 	  sizeof(sysctl_maxlen), 0644,  NULL, proc_dointvec },
6516  	{ 0 }
6517 };
6518 
6519-static ctl_table ip6q_dir_table[] = {
6520-	{NET_IPV6, "ipv6", NULL, 0, 0555, ip6q_table, 0, 0, 0, 0, 0},
6521+static ctl_table ipq_dir_table[] = {
6522+	{NET_IPV6, "ipv6", NULL, 0, 0555, ipq_table, 0, 0, 0, 0, 0},
6523 	{ 0 }
6524 };
6525 
6526-static ctl_table ip6q_root_table[] = {
6527-	{CTL_NET, "net", NULL, 0, 0555, ip6q_dir_table, 0, 0, 0, 0, 0},
6528+static ctl_table ipq_root_table[] = {
6529+	{CTL_NET, "net", NULL, 0, 0555, ipq_dir_table, 0, 0, 0, 0, 0},
6530 	{ 0 }
6531 };
6532 
6533-/****************************************************************************
6534- *
6535- * Procfs - debugging info.
6536- *
6537- ****************************************************************************/
6538-
6539-static int ip6q_get_info(char *buffer, char **start, off_t offset, int length)
6540+static int
6541+ipq_get_info(char *buffer, char **start, off_t offset, int length)
6542 {
6543 	int len;
6544 
6545-	spin_lock_bh(&nlq6->lock);
6546+	read_lock_bh(&queue_lock);
6547+	
6548 	len = sprintf(buffer,
6549-	              "Peer pid            : %d\n"
6550-	              "Peer died           : %d\n"
6551-	              "Peer copy mode      : %d\n"
6552-	              "Peer copy range     : %Zu\n"
6553-	              "Queue length        : %d\n"
6554-	              "Queue max. length   : %d\n"
6555-	              "Queue flushing      : %d\n"
6556-	              "Queue terminate     : %d\n",
6557-	              nlq6->peer.pid,
6558-	              nlq6->peer.died,
6559-	              nlq6->peer.copy_mode,
6560-	              nlq6->peer.copy_range,
6561-	              nlq6->len,
6562-	              *nlq6->maxlen,
6563-	              nlq6->flushing,
6564-	              nlq6->terminate);
6565-	spin_unlock_bh(&nlq6->lock);
6566+	              "Peer PID          : %d\n"
6567+	              "Copy mode         : %hu\n"
6568+	              "Copy range        : %u\n"
6569+	              "Queue length      : %u\n"
6570+	              "Queue max. length : %u\n",
6571+	              peer_pid,
6572+	              copy_mode,
6573+	              copy_range,
6574+	              queue_total,
6575+	              queue_maxlen);
6576+
6577+	read_unlock_bh(&queue_lock);
6578+	
6579 	*start = buffer + offset;
6580 	len -= offset;
6581 	if (len > length)
6582@@ -666,52 +673,70 @@
6583 	return len;
6584 }
6585 
6586-/****************************************************************************
6587- *
6588- * Module stuff.
6589- *
6590- ****************************************************************************/
6591-
6592-static int __init init(void)
6593+static int
6594+init_or_cleanup(int init)
6595 {
6596-	int status = 0;
6597+	int status = -ENOMEM;
6598 	struct proc_dir_entry *proc;
6599 	
6600-        /* We must create the NETLINK_IP6_FW protocol service */
6601-	nfnl = netlink_kernel_create(NETLINK_IP6_FW, netlink_receive_user_sk);
6602-	if (nfnl == NULL) {
6603-		printk(KERN_ERR "ip6_queue: initialisation failed: unable to "
6604-		       "create kernel netlink socket\n");
6605-		return -ENOMEM;
6606+	if (!init)
6607+		goto cleanup;
6608+
6609+	netlink_register_notifier(&ipq_nl_notifier);
6610+	ipqnl = netlink_kernel_create(NETLINK_IP6_FW, ipq_rcv_sk);
6611+	if (ipqnl == NULL) {
6612+		printk(KERN_ERR "ip6_queue: failed to create netlink socket\n");
6613+		goto cleanup_netlink_notifier;
6614 	}
6615-	nlq6 = ip6q_create_queue(netfilter6_receive,
6616-	                       netlink_send_peer, &status, &sysctl_maxlen);
6617-	if (nlq6 == NULL) {
6618-		printk(KERN_ERR "ip6_queue: initialisation failed: unable to "
6619-		       "create queue\n");
6620-		sock_release(nfnl->socket);
6621-		return status;
6622-	}
6623-        /* The file will be /proc/net/ip6_queue */
6624-	proc = proc_net_create(IPQ_PROC_FS_NAME, 0, ip6q_get_info);
6625-	if (proc) proc->owner = THIS_MODULE;
6626+
6627+	proc = proc_net_create(IPQ_PROC_FS_NAME, 0, ipq_get_info);
6628+	if (proc)
6629+		proc->owner = THIS_MODULE;
6630 	else {
6631-		ip6q_destroy_queue(nlq6);
6632-		sock_release(nfnl->socket);
6633-		return -ENOMEM;
6634+		printk(KERN_ERR "ip6_queue: failed to create proc entry\n");
6635+		goto cleanup_ipqnl;
6636+	}
6637+	
6638+	register_netdevice_notifier(&ipq_dev_notifier);
6639+	ipq_sysctl_header = register_sysctl_table(ipq_root_table, 0);
6640+	
6641+	status = nf_register_queue_handler(PF_INET6, ipq_enqueue_packet, NULL);
6642+	if (status < 0) {
6643+		printk(KERN_ERR "ip6_queue: failed to register queue handler\n");
6644+		goto cleanup_sysctl;
6645 	}
6646-	register_netdevice_notifier(&ip6q_dev_notifier);
6647-	ip6q_sysctl_header = register_sysctl_table(ip6q_root_table, 0);
6648+	return status;
6649+
6650+cleanup:
6651+	nf_unregister_queue_handler(PF_INET6);
6652+	br_write_lock_bh(BR_NETPROTO_LOCK);
6653+	br_write_unlock_bh(BR_NETPROTO_LOCK);
6654+	ipq_flush(NF_DROP);
6655+	
6656+cleanup_sysctl:
6657+	unregister_sysctl_table(ipq_sysctl_header);
6658+	unregister_netdevice_notifier(&ipq_dev_notifier);
6659+	proc_net_remove(IPQ_PROC_FS_NAME);
6660+	
6661+cleanup_ipqnl:
6662+	sock_release(ipqnl->socket);
6663+	down(&ipqnl_sem);
6664+	up(&ipqnl_sem);
6665+	
6666+cleanup_netlink_notifier:
6667+	netlink_unregister_notifier(&ipq_nl_notifier);
6668 	return status;
6669 }
6670 
6671+static int __init init(void)
6672+{
6673+	
6674+	return init_or_cleanup(1);
6675+}
6676+
6677 static void __exit fini(void)
6678 {
6679-	unregister_sysctl_table(ip6q_sysctl_header);
6680-	proc_net_remove(IPQ_PROC_FS_NAME);
6681-	unregister_netdevice_notifier(&ip6q_dev_notifier);
6682-	ip6q_destroy_queue(nlq6);
6683-	sock_release(nfnl->socket);
6684+	init_or_cleanup(0);
6685 }
6686 
6687 MODULE_DESCRIPTION("IPv6 packet queue handler");
6688diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv6/netfilter/ip6_tables.c linux-2.4.20-plain/net/ipv6/netfilter/ip6_tables.c
6689--- linux-2.4.19-plain/net/ipv6/netfilter/ip6_tables.c	Sat Aug  3 02:39:46 2002
6690+++ linux-2.4.20-plain/net/ipv6/netfilter/ip6_tables.c	Fri Nov 29 00:53:15 2002
6691@@ -7,6 +7,8 @@
6692  * 19 Jan 2002 Harald Welte <laforge@gnumonks.org>
6693  * 	- increase module usage count as soon as we have rules inside
6694  * 	  a table
6695+ * 06 Jun 2002 Andras Kis-Szabo <kisza@sch.bme.hu>
6696+ *      - new extension header parser code
6697  */
6698 #include <linux/config.h>
6699 #include <linux/skbuff.h>
6700@@ -25,6 +27,7 @@
6701 #include <linux/netfilter_ipv6/ip6_tables.h>
6702 
6703 #define IPV6_HDR_LEN	(sizeof(struct ipv6hdr))
6704+#define IPV6_OPTHDR_LEN	(sizeof(struct ipv6_opt_hdr))
6705 
6706 /*#define DEBUG_IP_FIREWALL*/
6707 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
6708@@ -133,43 +136,23 @@
6709 	return 0;
6710 }
6711 
6712-/* takes in current header and pointer to the header */
6713-/* if another header exists, sets hdrptr to the next header
6714-   and returns the new header value, else returns 0 */
6715-static u_int8_t ip6_nexthdr(u_int8_t currenthdr, u_int8_t *hdrptr)
6716-{
6717-	int i;
6718-	u_int8_t hdrlen, nexthdr = 0;
6719-	switch(currenthdr){
6720-		case IPPROTO_AH:
6721-		/* whoever decided to do the length of AUTH for ipv6
6722-		in 32bit units unlike other headers should be beaten...
6723-		repeatedly...with a large stick...no, an even LARGER
6724-		stick...no, you're still not thinking big enough */
6725-			nexthdr = *hdrptr;
6726-			hdrlen = hdrptr[i] * 4 + 8;
6727-			hdrptr = hdrptr + hdrlen;
6728-			break;
6729-		/*stupid rfc2402 */
6730-		case IPPROTO_DSTOPTS:
6731-		case IPPROTO_ROUTING:
6732-		case IPPROTO_HOPOPTS:
6733-			nexthdr = *hdrptr;
6734-			hdrlen = hdrptr[1] * 8 + 8;
6735-			hdrptr = hdrptr + hdrlen;
6736-			break;
6737-		case IPPROTO_FRAGMENT:
6738-			nexthdr = *hdrptr;
6739-			hdrptr = hdrptr + 8;
6740-			break;
6741-	}	
6742-	return nexthdr;
6743-
6744+/* Check for an extension */
6745+int 
6746+ip6t_ext_hdr(u8 nexthdr)
6747+{
6748+        return ( (nexthdr == IPPROTO_HOPOPTS)   ||
6749+                 (nexthdr == IPPROTO_ROUTING)   ||
6750+                 (nexthdr == IPPROTO_FRAGMENT)  ||
6751+                 (nexthdr == IPPROTO_ESP)       ||
6752+                 (nexthdr == IPPROTO_AH)        ||
6753+                 (nexthdr == IPPROTO_NONE)      ||
6754+                 (nexthdr == IPPROTO_DSTOPTS) );
6755 }
6756 
6757 /* Returns whether matches rule or not. */
6758 static inline int
6759-ip6_packet_match(const struct ipv6hdr *ipv6,
6760+ip6_packet_match(const struct sk_buff *skb,
6761+		 const struct ipv6hdr *ipv6,
6762 		 const char *indev,
6763 		 const char *outdev,
6764 		 const struct ip6t_ip6 *ip6info,
6765@@ -227,17 +210,58 @@
6766 	/* look for the desired protocol header */
6767 	if((ip6info->flags & IP6T_F_PROTO)) {
6768 		u_int8_t currenthdr = ipv6->nexthdr;
6769-		u_int8_t *hdrptr;
6770-		hdrptr = (u_int8_t *)(ipv6 + 1);
6771-		do {
6772-			if (ip6info->proto == currenthdr) {
6773-				if(ip6info->invflags & IP6T_INV_PROTO)
6774-					return 0;
6775-				return 1;
6776+		struct ipv6_opt_hdr *hdrptr;
6777+		u_int16_t ptr;		/* Header offset in skb */
6778+		u_int16_t hdrlen;	/* Header */
6779+
6780+		ptr = IPV6_HDR_LEN;
6781+
6782+		while (ip6t_ext_hdr(currenthdr)) {
6783+	                /* Is there enough space for the next ext header? */
6784+	                if (skb->len - ptr < IPV6_OPTHDR_LEN)
6785+	                        return 0;
6786+
6787+			/* NONE or ESP: there isn't protocol part */
6788+			/* If we want to count these packets in '-p all',
6789+			 * we will change the return 0 to 1*/
6790+			if ((currenthdr == IPPROTO_NONE) || 
6791+				(currenthdr == IPPROTO_ESP))
6792+				return 0;
6793+
6794+	                hdrptr = (struct ipv6_opt_hdr *)(skb->data + ptr);
6795+
6796+			/* Size calculation */
6797+	                if (currenthdr == IPPROTO_FRAGMENT) {
6798+	                        hdrlen = 8;
6799+	                } else if (currenthdr == IPPROTO_AH)
6800+	                        hdrlen = (hdrptr->hdrlen+2)<<2;
6801+	                else
6802+	                        hdrlen = ipv6_optlen(hdrptr);
6803+
6804+			currenthdr = hdrptr->nexthdr;
6805+	                ptr += hdrlen;
6806+			/* ptr is too large */
6807+	                if ( ptr > skb->len ) 
6808+				return 0;
6809+		}
6810+
6811+		/* currenthdr contains the protocol header */
6812+
6813+		dprintf("Packet protocol %hi ?= %s%hi.\n",
6814+				currenthdr, 
6815+				ip6info->invflags & IP6T_INV_PROTO ? "!":"",
6816+				ip6info->proto);
6817+
6818+		if (ip6info->proto == currenthdr) {
6819+			if(ip6info->invflags & IP6T_INV_PROTO) {
6820+				return 0;
6821 			}
6822-			currenthdr = ip6_nexthdr(currenthdr, hdrptr);
6823-		} while(currenthdr);
6824-		if (!(ip6info->invflags & IP6T_INV_PROTO))
6825+			return 1;
6826+		}
6827+
6828+		/* We need match for the '-p all', too! */
6829+		if ((ip6info->proto != 0) &&
6830+			!(ip6info->invflags & IP6T_INV_PROTO))
6831 			return 0;
6832 	}
6833 	return 1;
6834@@ -360,7 +384,8 @@
6835 		IP_NF_ASSERT(e);
6836 		IP_NF_ASSERT(back);
6837 		(*pskb)->nfcache |= e->nfcache;
6838-		if (ip6_packet_match(ipv6, indev, outdev, &e->ipv6, offset)) {
6839+		if (ip6_packet_match(*pskb, ipv6, indev, outdev, 
6840+			&e->ipv6, offset)) {
6841 			struct ip6t_entry_target *t;
6842 
6843 			if (IP6T_MATCH_ITERATE(e, do_match,
6844@@ -743,7 +768,7 @@
6845 	t = ip6t_get_target(e);
6846 	target = find_target_lock(t->u.user.name, &ret, &ip6t_mutex);
6847 	if (!target) {
6848-	  //		duprintf("check_entry: `%s' not found\n", t->u.name);
6849+		duprintf("check_entry: `%s' not found\n", t->u.user.name);
6850 		goto cleanup_matches;
6851 	}
6852 	if (target->me)
6853@@ -1469,6 +1494,9 @@
6854 	duprintf("table->private->number = %u\n",
6855 		 table->private->number);
6856 
6857+	/* save number of initial entries */
6858+	table->private->initial_entries = table->private->number;
6859+
6860 	table->lock = RW_LOCK_UNLOCKED;
6861 	list_prepend(&ip6t_tables, table);
6862 
6863@@ -1827,6 +1855,7 @@
6864 EXPORT_SYMBOL(ip6t_unregister_match);
6865 EXPORT_SYMBOL(ip6t_register_target);
6866 EXPORT_SYMBOL(ip6t_unregister_target);
6867+EXPORT_SYMBOL(ip6t_ext_hdr);
6868 
6869 module_init(init);
6870 module_exit(fini);
6871diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv6/netfilter/ip6t_LOG.c linux-2.4.20-plain/net/ipv6/netfilter/ip6t_LOG.c
6872--- linux-2.4.19-plain/net/ipv6/netfilter/ip6t_LOG.c	Mon Nov  5 18:53:07 2001
6873+++ linux-2.4.20-plain/net/ipv6/netfilter/ip6t_LOG.c	Fri Nov 29 00:53:15 2002
6874@@ -112,7 +112,7 @@
6875 			printk("FRAG:%u ", ntohs(fhdr->frag_off) & 0xFFF8);
6876 
6877 			/* Max length: 11 "INCOMPLETE " */
6878-			if (fhdr->frag_off & __constant_htons(0x0001))
6879+			if (fhdr->frag_off & htons(0x0001))
6880 				printk("INCOMPLETE ");
6881 
6882 			printk("ID:%08x ", fhdr->identification);
6883@@ -289,12 +289,39 @@
6884 		/* MAC logging for input chain only. */
6885 		printk("MAC=");
6886 		if ((*pskb)->dev && (*pskb)->dev->hard_header_len && (*pskb)->mac.raw != (void*)ipv6h) {
6887-			int i;
6888-			unsigned char *p = (*pskb)->mac.raw;
6889-			for (i = 0; i < (*pskb)->dev->hard_header_len; i++,p++)
6890+			if ((*pskb)->dev->type != ARPHRD_SIT){
6891+			  int i;
6892+			  unsigned char *p = (*pskb)->mac.raw;
6893+			  for (i = 0; i < (*pskb)->dev->hard_header_len; i++,p++)
6894 				printk("%02x%c", *p,
6895-				       i==(*pskb)->dev->hard_header_len - 1
6896-				       ? ' ':':');
6897+			       		i==(*pskb)->dev->hard_header_len - 1
6898+			       		? ' ':':');
6899+			} else {
6900+			  int i;
6901+			  unsigned char *p = (*pskb)->mac.raw;
6902+			  if ( p - (ETH_ALEN*2+2) > (*pskb)->head ){
6903+			    p -= (ETH_ALEN+2);
6904+			    for (i = 0; i < (ETH_ALEN); i++,p++)
6905+				printk("%02x%s", *p,
6906+					i == ETH_ALEN-1 ? "->" : ":");
6907+			    p -= (ETH_ALEN*2);
6908+			    for (i = 0; i < (ETH_ALEN); i++,p++)
6909+				printk("%02x%c", *p,
6910+					i == ETH_ALEN-1 ? ' ' : ':');
6911+			  }
6912+			  
6913+			  if (((*pskb)->dev->addr_len == 4) &&
6914+			      (*pskb)->dev->hard_header_len > 20){
6915+			    printk("TUNNEL=");
6916+			    p = (*pskb)->mac.raw + 12;
6917+			    for (i = 0; i < 4; i++,p++)
6918+				printk("%3d%s", *p,
6919+					i == 3 ? "->" : ".");
6920+			    for (i = 0; i < 4; i++,p++)
6921+				printk("%3d%c", *p,
6922+					i == 3 ? ' ' : '.');
6923+			  }
6924+			}
6925 		} else
6926 			printk(" ");
6927 	}
6928diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv6/netfilter/ip6t_eui64.c linux-2.4.20-plain/net/ipv6/netfilter/ip6t_eui64.c
6929--- linux-2.4.19-plain/net/ipv6/netfilter/ip6t_eui64.c	Thu Jan  1 01:00:00 1970
6930+++ linux-2.4.20-plain/net/ipv6/netfilter/ip6t_eui64.c	Fri Nov 29 00:53:15 2002
6931@@ -0,0 +1,89 @@
6932+/* Kernel module to match EUI64 address parameters. */
6933+#include <linux/module.h>
6934+#include <linux/skbuff.h>
6935+#include <linux/ipv6.h>
6936+#include <linux/if_ether.h>
6937+
6938+#include <linux/netfilter_ipv6/ip6_tables.h>
6939+
6940+static int
6941+match(const struct sk_buff *skb,
6942+      const struct net_device *in,
6943+      const struct net_device *out,
6944+      const void *matchinfo,
6945+      int offset,
6946+      const void *hdr,
6947+      u_int16_t datalen,
6948+      int *hotdrop)
6949+{
6950+
6951+    unsigned char eui64[8];
6952+    int i=0;
6953+
6954+     if ( !(skb->mac.raw >= skb->head
6955+                && (skb->mac.raw + ETH_HLEN) <= skb->data)
6956+                && offset != 0) {
6957+                        *hotdrop = 1;
6958+                        return 0;
6959+                }
6960+    
6961+    memset(eui64, 0, sizeof(eui64));
6962+
6963+    if (skb->mac.ethernet->h_proto == ntohs(ETH_P_IPV6)) {
6964+      if (skb->nh.ipv6h->version == 0x6) { 
6965+         memcpy(eui64, skb->mac.ethernet->h_source, 3);
6966+         memcpy(eui64 + 5, skb->mac.ethernet->h_source + 3, 3);
6967+	 eui64[3]=0xff;
6968+	 eui64[4]=0xfe;
6969+	 eui64[0] |= 0x02;
6970+
6971+	 i=0;
6972+	 while ((skb->nh.ipv6h->saddr.in6_u.u6_addr8[8+i] ==
6973+			 eui64[i]) && (i<8)) i++;
6974+
6975+	 if ( i == 8 )
6976+	 	return 1;
6977+      }
6978+    }
6979+
6980+    return 0;
6981+}
6982+
6983+static int
6984+ip6t_eui64_checkentry(const char *tablename,
6985+		   const struct ip6t_ip6 *ip,
6986+		   void *matchinfo,
6987+		   unsigned int matchsize,
6988+		   unsigned int hook_mask)
6989+{
6990+	if (hook_mask
6991+	    & ~((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_IN) |
6992+		(1 << NF_IP6_PRE_ROUTING) )) {
6993+		printk("ip6t_eui64: only valid for PRE_ROUTING, LOCAL_IN or FORWARD.\n");
6994+		return 0;
6995+	}
6996+
6997+	if (matchsize != IP6T_ALIGN(sizeof(int)))
6998+		return 0;
6999+
7000+	return 1;
7001+}
7002+
7003+static struct ip6t_match eui64_match
7004+= { { NULL, NULL }, "eui64", &match, &ip6t_eui64_checkentry, NULL, THIS_MODULE };
7005+
7006+static int __init init(void)
7007+{
7008+	return ip6t_register_match(&eui64_match);
7009+}
7010+
7011+static void __exit fini(void)
7012+{
7013+	ip6t_unregister_match(&eui64_match);
7014+}
7015+
7016+module_init(init);
7017+module_exit(fini);
7018+MODULE_DESCRIPTION("IPv6 EUI64 address checking match");
7019+MODULE_LICENSE("GPL");
7020+MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
7021diff -Nru --exclude .depend --exclude *.o --exclude *.ver --exclude .*.flags --exclude *.orig --exclude *.rej --exclude *~ linux-2.4.19-plain/net/ipv6/netfilter/ip6t_length.c linux-2.4.20-plain/net/ipv6/netfilter/ip6t_length.c
7022--- linux-2.4.19-plain/net/ipv6/netfilter/ip6t_length.c	Thu Jan  1 01:00:00 1970
7023+++ linux-2.4.20-plain/net/ipv6/netfilter/ip6t_length.c	Fri Nov 29 00:53:15 2002
7024@@ -0,0 +1,51 @@
7025+/* Length Match - IPv6 Port */
7026+
7027+#include <linux/module.h>
7028+#include <linux/skbuff.h>
7029+#include <linux/netfilter_ipv6/ip6t_length.h>
7030+#include <linux/netfilter_ipv6/ip6_tables.h>
7031+
7032+static int
7033+match(const struct sk_buff *skb,
7034+      const struct net_device *in,
7035+      const struct net_device *out,
7036+      const void *matchinfo,
7037+      int offset,
7038+      const void *hdr,
7039+      u_int16_t datalen,
7040+      int *hotdrop)
7041+{
7042+	const struct ip6t_length_info *info = matchinfo;
7043+	u_int16_t pktlen = ntohs(skb->nh.ipv6h->payload_len) + sizeof(struct ipv6hdr);
7044+	
7045+	return (pktlen >= info->min && pktlen <= info->max) ^ info->invert;
7046+}
7047+
7048+static int
7049+checkentry(const char *tablename,
7050+           const struct ip6t_ip6 *ip,
7051+           void *matchinfo,
7052+           unsigned int matchsize,
7053+           unsigned int hook_mask)
7054+{
7055+	if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_length_info)))
7056+		return 0;
7057+
7058+	return 1;
7059+}
7060+
7061+static struct ip6t_match length_match
7062+= { { NULL, NULL }, "length", &match, &checkentry, NULL, THIS_MODULE };
7063+
7064+static int __init init(void)
7065+{
7066+	return ip6t_register_match(&length_match);
7067+}
7068+
7069+static void __exit fini(void)
7070+{
7071+	ip6t_unregister_match(&length_match);
7072+}
7073+
7074+module_init(init);
7075+module_exit(fini);
7076