]> git.pld-linux.org Git - packages/kernel.git/blame - ebtables-v2.0.002_vs_2.4.20.patch
- added description of djurban's branch
[packages/kernel.git] / ebtables-v2.0.002_vs_2.4.20.patch
CommitLineData
9ac33c26 1ebtables-v2.0.002 vs 2.4.20-pre7 - 17 October 2002
2
3--- linux-2.4.20-pre7/net/bridge/br_private.h Mon Feb 25 20:38:14 2002
4+++ linux-2.4.20-pre7-bcnt/net/bridge/br_private.h Thu Oct 17 22:40:38 2002
5@@ -166,7 +166,7 @@ extern void br_get_port_ifindices(struct
6 int *ifindices);
7
8 /* br_input.c */
9-extern void br_handle_frame(struct sk_buff *skb);
10+extern int br_handle_frame(struct sk_buff *skb);
11
12 /* br_ioctl.c */
13 extern void br_call_ioctl_atomic(void (*fn)(void));
14--- linux-2.4.20-pre7/include/linux/if_bridge.h Thu Nov 22 20:47:12 2001
15+++ linux-2.4.20-pre7-bcnt/include/linux/if_bridge.h Thu Oct 17 22:28:23 2002
16@@ -102,7 +102,8 @@ struct net_bridge;
17 struct net_bridge_port;
18
19 extern int (*br_ioctl_hook)(unsigned long arg);
20-extern void (*br_handle_frame_hook)(struct sk_buff *skb);
21+extern int (*br_handle_frame_hook)(struct sk_buff *skb);
22+extern int (*br_should_route_hook)(struct sk_buff **pskb);
23
24 #endif
25
26--- linux-2.4.20-pre7/net/core/dev.c Thu Oct 17 23:42:53 2002
27+++ linux-2.4.20-pre7-bcnt/net/core/dev.c Thu Oct 17 20:31:28 2002
28@@ -1392,7 +1392,7 @@ void net_call_rx_atomic(void (*fn)(void)
29 }
30
31 #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
32-void (*br_handle_frame_hook)(struct sk_buff *skb) = NULL;
33+int (*br_handle_frame_hook)(struct sk_buff *skb) = NULL;
34 #endif
35
36 static __inline__ int handle_bridge(struct sk_buff *skb,
37@@ -1409,7 +1409,6 @@ static __inline__ int handle_bridge(stru
38 }
39 }
40
41- br_handle_frame_hook(skb);
42 return ret;
43 }
44
45@@ -1469,7 +1468,12 @@ int netif_receive_skb(struct sk_buff *sk
46 #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
47 if (skb->dev->br_port != NULL &&
48 br_handle_frame_hook != NULL) {
49- return handle_bridge(skb, pt_prev);
50+ int ret;
51+
52+ ret = handle_bridge(skb, pt_prev);
53+ if (br_handle_frame_hook(skb) == 0)
54+ return ret;
55+ pt_prev = NULL;
56 }
57 #endif
58
59--- linux-2.4.20-pre7/net/bridge/br_input.c Sat Aug 3 02:39:46 2002
60+++ linux-2.4.20-pre7-bcnt/net/bridge/br_input.c Thu Oct 17 20:31:28 2002
61@@ -24,6 +24,9 @@ unsigned char bridge_ula[6] = { 0x01, 0x
62
63 static int br_pass_frame_up_finish(struct sk_buff *skb)
64 {
65+#ifdef CONFIG_NETFILTER_DEBUG
66+ skb->nf_debug = 0;
67+#endif
68 netif_rx(skb);
69
70 return 0;
71@@ -112,7 +115,7 @@ err_nolock:
72 return 0;
73 }
74
75-void br_handle_frame(struct sk_buff *skb)
76+int br_handle_frame(struct sk_buff *skb)
77 {
78 struct net_bridge *br;
79 unsigned char *dest;
80@@ -146,25 +149,31 @@ void br_handle_frame(struct sk_buff *skb
81 goto handle_special_frame;
82
83 if (p->state == BR_STATE_FORWARDING) {
84+ if (br_should_route_hook && br_should_route_hook(&skb)) {
85+ read_unlock(&br->lock);
86+ return -1;
87+ }
88+
89 NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
90 br_handle_frame_finish);
91 read_unlock(&br->lock);
92- return;
93+ return 0;
94 }
95
96 err:
97 read_unlock(&br->lock);
98 err_nolock:
99 kfree_skb(skb);
100- return;
101+ return 0;
102
103 handle_special_frame:
104 if (!dest[5]) {
105 br_stp_handle_bpdu(skb);
106 read_unlock(&br->lock);
107- return;
108+ return 0;
109 }
110
111 read_unlock(&br->lock);
112 kfree_skb(skb);
113+ return 0;
114 }
115--- linux-2.4.20-pre7/net/bridge/br_forward.c Sat Aug 3 02:39:46 2002
116+++ linux-2.4.20-pre7-bcnt/net/bridge/br_forward.c Thu Oct 17 20:31:28 2002
117@@ -49,6 +49,9 @@ static int __br_forward_finish(struct sk
118 static void __br_deliver(struct net_bridge_port *to, struct sk_buff *skb)
119 {
120 skb->dev = to->dev;
121+#ifdef CONFIG_NETFILTER_DEBUG
122+ skb->nf_debug = 0;
123+#endif
124 NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
125 __br_forward_finish);
126 }
127--- linux-2.4.20-pre7/net/bridge/br.c Mon Feb 25 20:38:14 2002
128+++ linux-2.4.20-pre7-bcnt/net/bridge/br.c Thu Oct 17 20:31:28 2002
129@@ -28,6 +28,8 @@
130 #include "../atm/lec.h"
131 #endif
132
133+int (*br_should_route_hook) (struct sk_buff **pskb) = NULL;
134+
135 void br_dec_use_count()
136 {
137 MOD_DEC_USE_COUNT;
138@@ -74,7 +76,7 @@ static void __exit br_deinit(void)
139 #endif
140 }
141
142-EXPORT_NO_SYMBOLS;
143+EXPORT_SYMBOL(br_should_route_hook);
144
145 module_init(br_init)
146 module_exit(br_deinit)
147--- linux-2.4.20-pre7/net/bridge/Makefile Fri Dec 29 23:07:24 2000
148+++ linux-2.4.20-pre7-bcnt/net/bridge/Makefile Thu Oct 17 20:31:28 2002
149@@ -7,6 +7,8 @@
150 #
151 # Note 2! The CFLAGS definition is now in the main makefile...
152
153+export-objs := br.o
154+
155 O_TARGET := bridge.o
156 obj-y := br.o br_device.o br_fdb.o br_forward.o br_if.o br_input.o \
157 br_ioctl.o br_notify.o br_stp.o br_stp_bpdu.o \
158--- linux-2.4.20-pre7/include/linux/netfilter_bridge.h Tue Jun 12 04:15:27 2001
159+++ linux-2.4.20-pre7-bcnt/include/linux/netfilter_bridge.h Thu Oct 17 22:40:51 2002
160@@ -18,7 +18,18 @@
161 #define NF_BR_LOCAL_OUT 3
162 /* Packets about to hit the wire. */
163 #define NF_BR_POST_ROUTING 4
164-#define NF_BR_NUMHOOKS 5
165+/* Not really a hook, but used for the ebtables broute table */
166+#define NF_BR_BROUTING 5
167+#define NF_BR_NUMHOOKS 6
168
169+enum nf_br_hook_priorities {
170+ NF_BR_PRI_FIRST = INT_MIN,
171+ NF_BR_PRI_FILTER_BRIDGED = -200,
172+ NF_BR_PRI_FILTER_OTHER = 200,
173+ NF_BR_PRI_NAT_DST_BRIDGED = -300,
174+ NF_BR_PRI_NAT_DST_OTHER = 100,
175+ NF_BR_PRI_NAT_SRC = 300,
176+ NF_BR_PRI_LAST = INT_MAX,
177+};
178
179 #endif
180--- linux-2.4.20-pre7/net/Makefile Sat Aug 3 02:39:46 2002
181+++ linux-2.4.20-pre7-bcnt/net/Makefile Thu Oct 17 20:31:29 2002
182@@ -7,7 +7,8 @@
183
184 O_TARGET := network.o
185
186-mod-subdirs := ipv4/netfilter ipv6/netfilter ipx irda bluetooth atm netlink sched core
187+mod-subdirs := ipv4/netfilter ipv6/netfilter bridge/netfilter ipx irda \
188+ bluetooth atm netlink sched core
189 export-objs := netsyms.o
190
191 subdir-y := core ethernet
192@@ -23,6 +24,12 @@ subdir-$(CONFIG_IPV6) += ipv6
193 ifneq ($(CONFIG_IPV6),n)
194 ifneq ($(CONFIG_IPV6),)
195 subdir-$(CONFIG_NETFILTER) += ipv6/netfilter
196+endif
197+endif
198+
199+ifneq ($(CONFIG_BRIDGE),n)
200+ifneq ($(CONFIG_BRIDGE),)
201+subdir-$(CONFIG_BRIDGE) += bridge/netfilter
202 endif
203 endif
204
205--- linux-2.4.20-pre7/net/Config.in Sat Aug 3 02:39:46 2002
206+++ linux-2.4.20-pre7-bcnt/net/Config.in Thu Oct 17 20:31:29 2002
207@@ -65,6 +65,9 @@ if [ "$CONFIG_DECNET" != "n" ]; then
208 source net/decnet/Config.in
209 fi
210 dep_tristate '802.1d Ethernet Bridging' CONFIG_BRIDGE $CONFIG_INET
211+if [ "$CONFIG_BRIDGE" != "n" -a "$CONFIG_NETFILTER" != "n" ]; then
212+ source net/bridge/netfilter/Config.in
213+fi
214 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
215 tristate 'CCITT X.25 Packet Layer (EXPERIMENTAL)' CONFIG_X25
216 tristate 'LAPB Data Link Driver (EXPERIMENTAL)' CONFIG_LAPB
217--- /dev/null Thu Aug 24 11:00:32 2000
218+++ linux-2.4.20-pre7-bcnt/net/bridge/netfilter/Makefile Thu Oct 17 20:31:29 2002
219@@ -0,0 +1,27 @@
220+#
221+# Makefile for the netfilter modules on top of bridging.
222+#
223+# Note! Dependencies are done automagically by 'make dep', which also
224+# removes any old dependencies. DON'T put your own dependencies here
225+# unless it's something special (ie not a .c file).
226+#
227+# Note 2! The CFLAGS definition is now in the main makefile...
228+
229+O_TARGET := netfilter.o
230+
231+export-objs := ebtables.o
232+
233+obj-$(CONFIG_BRIDGE_NF_EBTABLES) += ebtables.o
234+obj-$(CONFIG_BRIDGE_EBT_T_FILTER) += ebtable_filter.o
235+obj-$(CONFIG_BRIDGE_EBT_T_NAT) += ebtable_nat.o
236+obj-$(CONFIG_BRIDGE_EBT_BROUTE) += ebtable_broute.o
237+obj-$(CONFIG_BRIDGE_EBT_IPF) += ebt_ip.o
238+obj-$(CONFIG_BRIDGE_EBT_ARPF) += ebt_arp.o
239+obj-$(CONFIG_BRIDGE_EBT_VLANF) += ebt_vlan.o
240+obj-$(CONFIG_BRIDGE_EBT_MARKF) += ebt_mark_m.o
241+obj-$(CONFIG_BRIDGE_EBT_LOG) += ebt_log.o
242+obj-$(CONFIG_BRIDGE_EBT_SNAT) += ebt_snat.o
243+obj-$(CONFIG_BRIDGE_EBT_DNAT) += ebt_dnat.o
244+obj-$(CONFIG_BRIDGE_EBT_REDIRECT) += ebt_redirect.o
245+obj-$(CONFIG_BRIDGE_EBT_MARK_T) += ebt_mark.o
246+include $(TOPDIR)/Rules.make
247--- /dev/null Thu Aug 24 11:00:32 2000
248+++ linux-2.4.20-pre7-bcnt/net/bridge/netfilter/Config.in Thu Oct 17 20:31:29 2002
249@@ -0,0 +1,16 @@
250+#
251+# Bridge netfilter configuration
252+#
253+dep_tristate ' Bridge: ebtables' CONFIG_BRIDGE_NF_EBTABLES $CONFIG_BRIDGE
254+dep_tristate ' ebt: filter table support' CONFIG_BRIDGE_EBT_T_FILTER $CONFIG_BRIDGE_NF_EBTABLES
255+dep_tristate ' ebt: nat table support' CONFIG_BRIDGE_EBT_T_NAT $CONFIG_BRIDGE_NF_EBTABLES
256+dep_tristate ' ebt: broute table support' CONFIG_BRIDGE_EBT_BROUTE $CONFIG_BRIDGE_NF_EBTABLES
257+dep_tristate ' ebt: log support' CONFIG_BRIDGE_EBT_LOG $CONFIG_BRIDGE_NF_EBTABLES
258+dep_tristate ' ebt: IP filter support' CONFIG_BRIDGE_EBT_IPF $CONFIG_BRIDGE_NF_EBTABLES
259+dep_tristate ' ebt: ARP filter support' CONFIG_BRIDGE_EBT_ARPF $CONFIG_BRIDGE_NF_EBTABLES
260+dep_tristate ' ebt: 802.1Q VLAN filter support (EXPERIMENTAL)' CONFIG_BRIDGE_EBT_VLANF $CONFIG_BRIDGE_NF_EBTABLES
261+dep_tristate ' ebt: mark filter support' CONFIG_BRIDGE_EBT_MARKF $CONFIG_BRIDGE_NF_EBTABLES
262+dep_tristate ' ebt: snat target support' CONFIG_BRIDGE_EBT_SNAT $CONFIG_BRIDGE_NF_EBTABLES
263+dep_tristate ' ebt: dnat target support' CONFIG_BRIDGE_EBT_DNAT $CONFIG_BRIDGE_NF_EBTABLES
264+dep_tristate ' ebt: redirect target support' CONFIG_BRIDGE_EBT_REDIRECT $CONFIG_BRIDGE_NF_EBTABLES
265+dep_tristate ' ebt: mark target support' CONFIG_BRIDGE_EBT_MARK_T $CONFIG_BRIDGE_NF_EBTABLES
266--- /dev/null Thu Aug 24 11:00:32 2000
267+++ linux-2.4.20-pre7-bcnt/net/bridge/netfilter/ebtable_filter.c Thu Oct 17 20:31:29 2002
268@@ -0,0 +1,90 @@
269+/*
270+ * ebtable_filter
271+ *
272+ * Authors:
273+ * Bart De Schuymer <bart.de.schuymer@pandora.be>
274+ *
275+ * April, 2002
276+ *
277+ */
278+
279+#include <linux/netfilter_bridge/ebtables.h>
280+#include <linux/module.h>
281+
282+#define FILTER_VALID_HOOKS ((1 << NF_BR_LOCAL_IN) | (1 << NF_BR_FORWARD) | \
283+ (1 << NF_BR_LOCAL_OUT))
284+
285+static struct ebt_entries initial_chains[] =
286+{
287+ {0, "INPUT", 0, EBT_ACCEPT, 0},
288+ {0, "FORWARD", 0, EBT_ACCEPT, 0},
289+ {0, "OUTPUT", 0, EBT_ACCEPT, 0}
290+};
291+
292+static struct ebt_replace initial_table =
293+{
294+ "filter", FILTER_VALID_HOOKS, 0, 3 * sizeof(struct ebt_entries),
295+ { [NF_BR_LOCAL_IN]&initial_chains[0], [NF_BR_FORWARD]&initial_chains[1],
296+ [NF_BR_LOCAL_OUT]&initial_chains[2] }, 0, NULL, (char *)initial_chains
297+};
298+
299+static int check(const struct ebt_table_info *info, unsigned int valid_hooks)
300+{
301+ if (valid_hooks & ~FILTER_VALID_HOOKS)
302+ return -EINVAL;
303+ return 0;
304+}
305+
306+static struct ebt_table frame_filter =
307+{
308+ {NULL, NULL}, "filter", &initial_table, FILTER_VALID_HOOKS,
309+ RW_LOCK_UNLOCKED, check, NULL
310+};
311+
312+static unsigned int
313+ebt_hook (unsigned int hook, struct sk_buff **pskb, const struct net_device *in,
314+ const struct net_device *out, int (*okfn)(struct sk_buff *))
315+{
316+ return ebt_do_table(hook, pskb, in, out, &frame_filter);
317+}
318+
319+static struct nf_hook_ops ebt_ops_filter[] = {
320+ { { NULL, NULL }, ebt_hook, PF_BRIDGE, NF_BR_LOCAL_IN,
321+ NF_BR_PRI_FILTER_BRIDGED},
322+ { { NULL, NULL }, ebt_hook, PF_BRIDGE, NF_BR_FORWARD,
323+ NF_BR_PRI_FILTER_BRIDGED},
324+ { { NULL, NULL }, ebt_hook, PF_BRIDGE, NF_BR_LOCAL_OUT,
325+ NF_BR_PRI_FILTER_OTHER}
326+};
327+
328+static int __init init(void)
329+{
330+ int i, j, ret;
331+
332+ ret = ebt_register_table(&frame_filter);
333+ if (ret < 0)
334+ return ret;
335+ for (i = 0; i < sizeof(ebt_ops_filter) / sizeof(ebt_ops_filter[0]); i++)
336+ if ((ret = nf_register_hook(&ebt_ops_filter[i])) < 0)
337+ goto cleanup;
338+ return ret;
339+cleanup:
340+ for (j = 0; j < i; j++)
341+ nf_unregister_hook(&ebt_ops_filter[j]);
342+ ebt_unregister_table(&frame_filter);
343+ return ret;
344+}
345+
346+static void __exit fini(void)
347+{
348+ int i;
349+
350+ for (i = 0; i < sizeof(ebt_ops_filter) / sizeof(ebt_ops_filter[0]); i++)
351+ nf_unregister_hook(&ebt_ops_filter[i]);
352+ ebt_unregister_table(&frame_filter);
353+}
354+
355+module_init(init);
356+module_exit(fini);
357+EXPORT_NO_SYMBOLS;
358+MODULE_LICENSE("GPL");
359--- /dev/null Thu Aug 24 11:00:32 2000
360+++ linux-2.4.20-pre7-bcnt/net/bridge/netfilter/ebtable_nat.c Thu Oct 17 20:31:29 2002
361@@ -0,0 +1,96 @@
362+/*
363+ * ebtable_nat
364+ *
365+ * Authors:
366+ * Bart De Schuymer <bart.de.schuymer@pandora.be>
367+ *
368+ * April, 2002
369+ *
370+ */
371+
372+#include <linux/netfilter_bridge/ebtables.h>
373+#include <linux/module.h>
374+#define NAT_VALID_HOOKS ((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT) | \
375+ (1 << NF_BR_POST_ROUTING))
376+
377+static struct ebt_entries initial_chains[] =
378+{
379+ {0, "PREROUTING", 0, EBT_ACCEPT, 0},
380+ {0, "OUTPUT", 0, EBT_ACCEPT, 0},
381+ {0, "POSTROUTING", 0, EBT_ACCEPT, 0}
382+};
383+
384+static struct ebt_replace initial_table =
385+{
386+ "nat", NAT_VALID_HOOKS, 0, 3 * sizeof(struct ebt_entries),
387+ { [NF_BR_PRE_ROUTING]&initial_chains[0], [NF_BR_LOCAL_OUT]&initial_chains[1],
388+ [NF_BR_POST_ROUTING]&initial_chains[2] }, 0, NULL, (char *)initial_chains
389+};
390+
391+static int check(const struct ebt_table_info *info, unsigned int valid_hooks)
392+{
393+ if (valid_hooks & ~NAT_VALID_HOOKS)
394+ return -EINVAL;
395+ return 0;
396+}
397+
398+static struct ebt_table frame_nat =
399+{
400+ {NULL, NULL}, "nat", &initial_table, NAT_VALID_HOOKS,
401+ RW_LOCK_UNLOCKED, check, NULL
402+};
403+
404+static unsigned int
405+ebt_nat_dst(unsigned int hook, struct sk_buff **pskb, const struct net_device *in
406+ , const struct net_device *out, int (*okfn)(struct sk_buff *))
407+{
408+ return ebt_do_table(hook, pskb, in, out, &frame_nat);
409+}
410+
411+static unsigned int
412+ebt_nat_src(unsigned int hook, struct sk_buff **pskb, const struct net_device *in
413+ , const struct net_device *out, int (*okfn)(struct sk_buff *))
414+{
415+ return ebt_do_table(hook, pskb, in, out, &frame_nat);
416+}
417+
418+static struct nf_hook_ops ebt_ops_nat[] = {
419+ { { NULL, NULL }, ebt_nat_dst, PF_BRIDGE, NF_BR_LOCAL_OUT,
420+ NF_BR_PRI_NAT_DST_OTHER},
421+ { { NULL, NULL }, ebt_nat_src, PF_BRIDGE, NF_BR_POST_ROUTING,
422+ NF_BR_PRI_NAT_SRC},
423+ { { NULL, NULL }, ebt_nat_dst, PF_BRIDGE, NF_BR_PRE_ROUTING,
424+ NF_BR_PRI_NAT_DST_BRIDGED},
425+};
426+
427+static int __init init(void)
428+{
429+ int i, ret, j;
430+
431+ ret = ebt_register_table(&frame_nat);
432+ if (ret < 0)
433+ return ret;
434+ for (i = 0; i < sizeof(ebt_ops_nat) / sizeof(ebt_ops_nat[0]); i++)
435+ if ((ret = nf_register_hook(&ebt_ops_nat[i])) < 0)
436+ goto cleanup;
437+ return ret;
438+cleanup:
439+ for (j = 0; j < i; j++)
440+ nf_unregister_hook(&ebt_ops_nat[j]);
441+ ebt_unregister_table(&frame_nat);
442+ return ret;
443+}
444+
445+static void __exit fini(void)
446+{
447+ int i;
448+
449+ for (i = 0; i < sizeof(ebt_ops_nat) / sizeof(ebt_ops_nat[0]); i++)
450+ nf_unregister_hook(&ebt_ops_nat[i]);
451+ ebt_unregister_table(&frame_nat);
452+}
453+
454+module_init(init);
455+module_exit(fini);
456+EXPORT_NO_SYMBOLS;
457+MODULE_LICENSE("GPL");
458--- /dev/null Thu Aug 24 11:00:32 2000
459+++ linux-2.4.20-pre7-bcnt/net/bridge/netfilter/ebtable_broute.c Thu Oct 17 20:31:29 2002
460@@ -0,0 +1,79 @@
461+/*
462+ * ebtable_broute
463+ *
464+ * Authors:
465+ * Bart De Schuymer <bart.de.schuymer@pandora.be>
466+ *
467+ * April, 2002
468+ *
469+ * This table lets you choose between routing and bridging for frames
470+ * entering on a bridge enslaved nic. This table is traversed before any
471+ * other ebtables table. See net/bridge/br_input.c.
472+ */
473+
474+#include <linux/netfilter_bridge/ebtables.h>
475+#include <linux/module.h>
476+#include <linux/if_bridge.h>
477+#include <linux/brlock.h>
478+
479+// EBT_ACCEPT means the frame will be bridged
480+// EBT_DROP means the frame will be routed
481+static struct ebt_entries initial_chain =
482+ {0, "BROUTING", 0, EBT_ACCEPT, 0};
483+
484+static struct ebt_replace initial_table =
485+{
486+ "broute", 1 << NF_BR_BROUTING, 0, sizeof(struct ebt_entries),
487+ { [NF_BR_BROUTING]&initial_chain}, 0, NULL, (char *)&initial_chain
488+};
489+
490+static int check(const struct ebt_table_info *info, unsigned int valid_hooks)
491+{
492+ if (valid_hooks & ~(1 << NF_BR_BROUTING))
493+ return -EINVAL;
494+ return 0;
495+}
496+
497+static struct ebt_table broute_table =
498+{
499+ {NULL, NULL}, "broute", &initial_table, 1 << NF_BR_BROUTING,
500+ RW_LOCK_UNLOCKED, check, NULL
501+};
502+
503+static int ebt_broute(struct sk_buff **pskb)
504+{
505+ int ret;
506+
507+ ret = ebt_do_table(NF_BR_BROUTING, pskb, (*pskb)->dev, NULL,
508+ &broute_table);
509+ if (ret == NF_DROP)
510+ return 1; // route it
511+ return 0; // bridge it
512+}
513+
514+static int __init init(void)
515+{
516+ int ret;
517+
518+ ret = ebt_register_table(&broute_table);
519+ if (ret < 0)
520+ return ret;
521+ br_write_lock_bh(BR_NETPROTO_LOCK);
522+ // see br_input.c
523+ br_should_route_hook = ebt_broute;
524+ br_write_unlock_bh(BR_NETPROTO_LOCK);
525+ return ret;
526+}
527+
528+static void __exit fini(void)
529+{
530+ br_write_lock_bh(BR_NETPROTO_LOCK);
531+ br_should_route_hook = NULL;
532+ br_write_unlock_bh(BR_NETPROTO_LOCK);
533+ ebt_unregister_table(&broute_table);
534+}
535+
536+module_init(init);
537+module_exit(fini);
538+EXPORT_NO_SYMBOLS;
539+MODULE_LICENSE("GPL");
540--- /dev/null Thu Aug 24 11:00:32 2000
541+++ linux-2.4.20-pre7-bcnt/net/bridge/netfilter/ebt_mark.c Thu Oct 17 20:31:29 2002
542@@ -0,0 +1,66 @@
543+/*
544+ * ebt_mark
545+ *
546+ * Authors:
547+ * Bart De Schuymer <bart.de.schuymer@pandora.be>
548+ *
549+ * July, 2002
550+ *
551+ */
552+
553+// The mark target can be used in any chain
554+// I believe adding a mangle table just for marking is total overkill
555+// Marking a frame doesn't really change anything in the frame anyway
556+
557+#include <linux/netfilter_bridge/ebtables.h>
558+#include <linux/netfilter_bridge/ebt_mark_t.h>
559+#include <linux/module.h>
560+
561+static int ebt_target_mark(struct sk_buff **pskb, unsigned int hooknr,
562+ const struct net_device *in, const struct net_device *out,
563+ const void *data, unsigned int datalen)
564+{
565+ struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)data;
566+
567+ if ((*pskb)->nfmark != info->mark) {
568+ (*pskb)->nfmark = info->mark;
569+ (*pskb)->nfcache |= NFC_ALTERED;
570+ }
571+ return info->target;
572+}
573+
574+static int ebt_target_mark_check(const char *tablename, unsigned int hookmask,
575+ const struct ebt_entry *e, void *data, unsigned int datalen)
576+{
577+ struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)data;
578+
579+ if (datalen != sizeof(struct ebt_mark_t_info))
580+ return -EINVAL;
581+ if (BASE_CHAIN && info->target == EBT_RETURN)
582+ return -EINVAL;
583+ CLEAR_BASE_CHAIN_BIT;
584+ if (INVALID_TARGET)
585+ return -EINVAL;
586+ return 0;
587+}
588+
589+static struct ebt_target mark_target =
590+{
591+ {NULL, NULL}, EBT_MARK_TARGET, ebt_target_mark,
592+ ebt_target_mark_check, NULL, THIS_MODULE
593+};
594+
595+static int __init init(void)
596+{
597+ return ebt_register_target(&mark_target);
598+}
599+
600+static void __exit fini(void)
601+{
602+ ebt_unregister_target(&mark_target);
603+}
604+
605+module_init(init);
606+module_exit(fini);
607+EXPORT_NO_SYMBOLS;
608+MODULE_LICENSE("GPL");
609--- /dev/null Thu Aug 24 11:00:32 2000
610+++ linux-2.4.20-pre7-bcnt/net/bridge/netfilter/ebt_mark_m.c Thu Oct 17 20:31:29 2002
611@@ -0,0 +1,61 @@
612+/*
613+ * ebt_mark_m
614+ *
615+ * Authors:
616+ * Bart De Schuymer <bart.de.schuymer@pandora.be>
617+ *
618+ * July, 2002
619+ *
620+ */
621+
622+#include <linux/netfilter_bridge/ebtables.h>
623+#include <linux/netfilter_bridge/ebt_mark_m.h>
624+#include <linux/module.h>
625+
626+static int ebt_filter_mark(const struct sk_buff *skb,
627+ const struct net_device *in, const struct net_device *out, const void *data,
628+ unsigned int datalen)
629+{
630+ struct ebt_mark_m_info *info = (struct ebt_mark_m_info *) data;
631+
632+ if (info->bitmask & EBT_MARK_OR)
633+ return !(!!(skb->nfmark & info->mask) ^ info->invert);
634+ return !(((skb->nfmark & info->mask) == info->mark) ^ info->invert);
635+}
636+
637+static int ebt_mark_check(const char *tablename, unsigned int hookmask,
638+ const struct ebt_entry *e, void *data, unsigned int datalen)
639+{
640+ struct ebt_mark_m_info *info = (struct ebt_mark_m_info *) data;
641+
642+ if (datalen != sizeof(struct ebt_mark_m_info))
643+ return -EINVAL;
644+ if (info->bitmask & ~EBT_MARK_MASK)
645+ return -EINVAL;
646+ if ((info->bitmask & EBT_MARK_OR) && (info->bitmask & EBT_MARK_AND))
647+ return -EINVAL;
648+ if (!info->bitmask)
649+ return -EINVAL;
650+ return 0;
651+}
652+
653+static struct ebt_match filter_mark =
654+{
655+ {NULL, NULL}, EBT_MARK_MATCH, ebt_filter_mark, ebt_mark_check, NULL,
656+ THIS_MODULE
657+};
658+
659+static int __init init(void)
660+{
661+ return ebt_register_match(&filter_mark);
662+}
663+
664+static void __exit fini(void)
665+{
666+ ebt_unregister_match(&filter_mark);
667+}
668+
669+module_init(init);
670+module_exit(fini);
671+EXPORT_NO_SYMBOLS;
672+MODULE_LICENSE("GPL");
673--- /dev/null Thu Aug 24 11:00:32 2000
674+++ linux-2.4.20-pre7-bcnt/net/bridge/netfilter/ebt_redirect.c Thu Oct 17 20:31:29 2002
675@@ -0,0 +1,71 @@
676+/*
677+ * ebt_redirect
678+ *
679+ * Authors:
680+ * Bart De Schuymer <bart.de.schuymer@pandora.be>
681+ *
682+ * April, 2002
683+ *
684+ */
685+
686+#include <linux/netfilter_bridge/ebtables.h>
687+#include <linux/netfilter_bridge/ebt_redirect.h>
688+#include <linux/module.h>
689+#include <net/sock.h>
690+#include "../br_private.h"
691+
692+static int ebt_target_redirect(struct sk_buff **pskb, unsigned int hooknr,
693+ const struct net_device *in, const struct net_device *out,
694+ const void *data, unsigned int datalen)
695+{
696+ struct ebt_redirect_info *info = (struct ebt_redirect_info *)data;
697+
698+ if (hooknr != NF_BR_BROUTING)
699+ memcpy((**pskb).mac.ethernet->h_dest,
700+ in->br_port->br->dev.dev_addr, ETH_ALEN);
701+ else {
702+ memcpy((**pskb).mac.ethernet->h_dest,
703+ in->dev_addr, ETH_ALEN);
704+ (*pskb)->pkt_type = PACKET_HOST;
705+ }
706+ return info->target;
707+}
708+
709+static int ebt_target_redirect_check(const char *tablename, unsigned int hookmask,
710+ const struct ebt_entry *e, void *data, unsigned int datalen)
711+{
712+ struct ebt_redirect_info *info = (struct ebt_redirect_info *)data;
713+
714+ if (datalen != sizeof(struct ebt_redirect_info))
715+ return -EINVAL;
716+ if (BASE_CHAIN && info->target == EBT_RETURN)
717+ return -EINVAL;
718+ CLEAR_BASE_CHAIN_BIT;
719+ if ( (strcmp(tablename, "nat") || hookmask & ~(1 << NF_BR_PRE_ROUTING)) &&
720+ (strcmp(tablename, "broute") || hookmask & ~(1 << NF_BR_BROUTING)) )
721+ return -EINVAL;
722+ if (INVALID_TARGET)
723+ return -EINVAL;
724+ return 0;
725+}
726+
727+static struct ebt_target redirect_target =
728+{
729+ {NULL, NULL}, EBT_REDIRECT_TARGET, ebt_target_redirect,
730+ ebt_target_redirect_check, NULL, THIS_MODULE
731+};
732+
733+static int __init init(void)
734+{
735+ return ebt_register_target(&redirect_target);
736+}
737+
738+static void __exit fini(void)
739+{
740+ ebt_unregister_target(&redirect_target);
741+}
742+
743+module_init(init);
744+module_exit(fini);
745+EXPORT_NO_SYMBOLS;
746+MODULE_LICENSE("GPL");
747--- /dev/null Thu Aug 24 11:00:32 2000
748+++ linux-2.4.20-pre7-bcnt/net/bridge/netfilter/ebt_arp.c Thu Oct 17 20:31:29 2002
749@@ -0,0 +1,102 @@
750+/*
751+ * ebt_arp
752+ *
753+ * Authors:
754+ * Bart De Schuymer <bart.de.schuymer@pandora.be>
755+ * Tim Gardner <timg@tpi.com>
756+ *
757+ * April, 2002
758+ *
759+ */
760+
761+#include <linux/netfilter_bridge/ebtables.h>
762+#include <linux/netfilter_bridge/ebt_arp.h>
763+#include <linux/if_arp.h>
764+#include <linux/module.h>
765+
766+static int ebt_filter_arp(const struct sk_buff *skb, const struct net_device *in,
767+ const struct net_device *out, const void *data, unsigned int datalen)
768+{
769+ struct ebt_arp_info *info = (struct ebt_arp_info *)data;
770+
771+ if (info->bitmask & EBT_ARP_OPCODE && FWINV(info->opcode !=
772+ ((*skb).nh.arph)->ar_op, EBT_ARP_OPCODE))
773+ return EBT_NOMATCH;
774+ if (info->bitmask & EBT_ARP_HTYPE && FWINV(info->htype !=
775+ ((*skb).nh.arph)->ar_hrd, EBT_ARP_HTYPE))
776+ return EBT_NOMATCH;
777+ if (info->bitmask & EBT_ARP_PTYPE && FWINV(info->ptype !=
778+ ((*skb).nh.arph)->ar_pro, EBT_ARP_PTYPE))
779+ return EBT_NOMATCH;
780+
781+ if (info->bitmask & (EBT_ARP_SRC_IP | EBT_ARP_DST_IP))
782+ {
783+ uint32_t arp_len = sizeof(struct arphdr) +
784+ (2 * (((*skb).nh.arph)->ar_hln)) +
785+ (2 * (((*skb).nh.arph)->ar_pln));
786+ uint32_t dst;
787+ uint32_t src;
788+
789+ // Make sure the packet is long enough.
790+ if ((((*skb).nh.raw) + arp_len) > (*skb).tail)
791+ return EBT_NOMATCH;
792+ // IPv4 addresses are always 4 bytes.
793+ if (((*skb).nh.arph)->ar_pln != sizeof(uint32_t))
794+ return EBT_NOMATCH;
795+
796+ if (info->bitmask & EBT_ARP_SRC_IP) {
797+ memcpy(&src, ((*skb).nh.raw) + sizeof(struct arphdr) +
798+ ((*skb).nh.arph)->ar_hln, sizeof(uint32_t));
799+ if (FWINV(info->saddr != (src & info->smsk),
800+ EBT_ARP_SRC_IP))
801+ return EBT_NOMATCH;
802+ }
803+
804+ if (info->bitmask & EBT_ARP_DST_IP) {
805+ memcpy(&dst, ((*skb).nh.raw)+sizeof(struct arphdr) +
806+ (2*(((*skb).nh.arph)->ar_hln)) +
807+ (((*skb).nh.arph)->ar_pln), sizeof(uint32_t));
808+ if (FWINV(info->daddr != (dst & info->dmsk),
809+ EBT_ARP_DST_IP))
810+ return EBT_NOMATCH;
811+ }
812+ }
813+ return EBT_MATCH;
814+}
815+
816+static int ebt_arp_check(const char *tablename, unsigned int hookmask,
817+ const struct ebt_entry *e, void *data, unsigned int datalen)
818+{
819+ struct ebt_arp_info *info = (struct ebt_arp_info *)data;
820+
821+ if (datalen != sizeof(struct ebt_arp_info))
822+ return -EINVAL;
823+ if ((e->ethproto != __constant_htons(ETH_P_ARP) &&
824+ e->ethproto != __constant_htons(ETH_P_RARP)) ||
825+ e->invflags & EBT_IPROTO)
826+ return -EINVAL;
827+ if (info->bitmask & ~EBT_ARP_MASK || info->invflags & ~EBT_ARP_MASK)
828+ return -EINVAL;
829+ return 0;
830+}
831+
832+static struct ebt_match filter_arp =
833+{
834+ {NULL, NULL}, EBT_ARP_MATCH, ebt_filter_arp, ebt_arp_check, NULL,
835+ THIS_MODULE
836+};
837+
838+static int __init init(void)
839+{
840+ return ebt_register_match(&filter_arp);
841+}
842+
843+static void __exit fini(void)
844+{
845+ ebt_unregister_match(&filter_arp);
846+}
847+
848+module_init(init);
849+module_exit(fini);
850+EXPORT_NO_SYMBOLS;
851+MODULE_LICENSE("GPL");
852--- /dev/null Thu Aug 24 11:00:32 2000
853+++ linux-2.4.20-pre7-bcnt/net/bridge/netfilter/ebt_ip.c Thu Oct 17 23:22:58 2002
854@@ -0,0 +1,121 @@
855+/*
856+ * ebt_ip
857+ *
858+ * Authors:
859+ * Bart De Schuymer <bart.de.schuymer@pandora.be>
860+ *
861+ * April, 2002
862+ *
863+ * Changes:
864+ * added ip-sport and ip-dport
865+ * Innominate Security Technologies AG <mhopf@innominate.com>
866+ * September, 2002
867+ */
868+
869+#include <linux/netfilter_bridge/ebtables.h>
870+#include <linux/netfilter_bridge/ebt_ip.h>
871+#include <linux/ip.h>
872+#include <linux/in.h>
873+#include <linux/module.h>
874+
875+struct tcpudphdr {
876+ uint16_t src;
877+ uint16_t dst;
878+};
879+
880+union h_u {
881+ unsigned char *raw;
882+ struct tcpudphdr *tuh;
883+};
884+
885+static int ebt_filter_ip(const struct sk_buff *skb, const struct net_device *in,
886+ const struct net_device *out, const void *data,
887+ unsigned int datalen)
888+{
889+ struct ebt_ip_info *info = (struct ebt_ip_info *)data;
890+
891+ if (info->bitmask & EBT_IP_TOS &&
892+ FWINV(info->tos != ((*skb).nh.iph)->tos, EBT_IP_TOS))
893+ return EBT_NOMATCH;
894+ if (info->bitmask & EBT_IP_PROTO) {
895+ if (FWINV(info->protocol != ((*skb).nh.iph)->protocol,
896+ EBT_IP_PROTO))
897+ return EBT_NOMATCH;
898+ if ( info->protocol == IPPROTO_TCP ||
899+ info->protocol == IPPROTO_UDP )
900+ {
901+ union h_u h;
902+ h.raw = skb->data + skb->nh.iph->ihl*4;
903+ if (info->bitmask & EBT_IP_DPORT) {
904+ uint16_t port = ntohs(h.tuh->dst);
905+ if (FWINV(port < info->dport[0] ||
906+ port > info->dport[1],
907+ EBT_IP_DPORT))
908+ return EBT_NOMATCH;
909+ }
910+ if (info->bitmask & EBT_IP_SPORT) {
911+ uint16_t port = ntohs(h.tuh->src);
912+ if (FWINV(port < info->sport[0] ||
913+ port > info->sport[1],
914+ EBT_IP_SPORT))
915+ return EBT_NOMATCH;
916+ }
917+ }
918+ }
919+ if (info->bitmask & EBT_IP_SOURCE &&
920+ FWINV((((*skb).nh.iph)->saddr & info->smsk) !=
921+ info->saddr, EBT_IP_SOURCE))
922+ return EBT_NOMATCH;
923+ if ((info->bitmask & EBT_IP_DEST) &&
924+ FWINV((((*skb).nh.iph)->daddr & info->dmsk) !=
925+ info->daddr, EBT_IP_DEST))
926+ return EBT_NOMATCH;
927+ return EBT_MATCH;
928+}
929+
930+static int ebt_ip_check(const char *tablename, unsigned int hookmask,
931+ const struct ebt_entry *e, void *data, unsigned int datalen)
932+{
933+ struct ebt_ip_info *info = (struct ebt_ip_info *)data;
934+
935+ if (datalen != sizeof(struct ebt_ip_info))
936+ return -EINVAL;
937+ if (e->ethproto != __constant_htons(ETH_P_IP) ||
938+ e->invflags & EBT_IPROTO)
939+ return -EINVAL;
940+ if (info->bitmask & ~EBT_IP_MASK || info->invflags & ~EBT_IP_MASK)
941+ return -EINVAL;
942+ if (info->bitmask & (EBT_IP_DPORT | EBT_IP_SPORT)) {
943+ if (!info->bitmask & EBT_IPROTO)
944+ return -EINVAL;
945+ if (info->protocol != IPPROTO_TCP &&
946+ info->protocol != IPPROTO_UDP)
947+ return -EINVAL;
948+ }
949+ if (info->bitmask & EBT_IP_DPORT && info->dport[0] > info->dport[1])
950+ return -EINVAL;
951+ if (info->bitmask & EBT_IP_SPORT && info->sport[0] > info->sport[1])
952+ return -EINVAL;
953+ return 0;
954+}
955+
956+static struct ebt_match filter_ip =
957+{
958+ {NULL, NULL}, EBT_IP_MATCH, ebt_filter_ip, ebt_ip_check, NULL,
959+ THIS_MODULE
960+};
961+
962+static int __init init(void)
963+{
964+ return ebt_register_match(&filter_ip);
965+}
966+
967+static void __exit fini(void)
968+{
969+ ebt_unregister_match(&filter_ip);
970+}
971+
972+module_init(init);
973+module_exit(fini);
974+EXPORT_NO_SYMBOLS;
975+MODULE_LICENSE("GPL");
976--- /dev/null Thu Aug 24 11:00:32 2000
977+++ linux-2.4.20-pre7-bcnt/net/bridge/netfilter/ebt_vlan.c Thu Oct 17 20:31:29 2002
978@@ -0,0 +1,318 @@
979+/*
980+ * Description: EBTables 802.1Q match extension kernelspace module.
981+ * Authors: Nick Fedchik <nick@fedchik.org.ua>
982+ * Bart De Schuymer <bart.de.schuymer@pandora.be>
983+ *
984+ * This program is free software; you can redistribute it and/or modify
985+ * it under the terms of the GNU General Public License as published by
986+ * the Free Software Foundation; either version 2 of the License, or
987+ * (at your option) any later version.
988+ *
989+ * This program is distributed in the hope that it will be useful,
990+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
991+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
992+ * GNU General Public License for more details.
993+ *
994+ * You should have received a copy of the GNU General Public License
995+ * along with this program; if not, write to the Free Software
996+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
997+ */
998+
999+#include <linux/if_ether.h>
1000+#include <linux/if_vlan.h>
1001+#include <linux/module.h>
1002+#include <linux/netfilter_bridge/ebtables.h>
1003+#include <linux/netfilter_bridge/ebt_vlan.h>
1004+
1005+static unsigned char debug;
1006+#define MODULE_VERSION "0.4 (" __DATE__ " " __TIME__ ")"
1007+
1008+MODULE_PARM (debug, "0-1b");
1009+MODULE_PARM_DESC (debug, "debug=1 is turn on debug messages");
1010+MODULE_AUTHOR ("Nick Fedchik <nick@fedchik.org.ua>");
1011+MODULE_DESCRIPTION ("802.1Q match module (ebtables extension), v"
1012+ MODULE_VERSION);
1013+MODULE_LICENSE ("GPL");
1014+
1015+
1016+#define DEBUG_MSG(...) if (debug) printk (KERN_DEBUG __FILE__ ":" __VA_ARGS__)
1017+#define INV_FLAG(_inv_flag_) (info->invflags & _inv_flag_) ? "!" : ""
1018+#define GET_BITMASK(_BIT_MASK_) info->bitmask & _BIT_MASK_
1019+#define SET_BITMASK(_BIT_MASK_) info->bitmask |= _BIT_MASK_
1020+#define EXIT_ON_MISMATCH(_MATCH_,_MASK_) if (!((info->_MATCH_ == _MATCH_)^!!(info->invflags & _MASK_))) return 1;
1021+
1022+/*
1023+ * Function description: ebt_filter_vlan() is main engine for
1024+ * checking passed 802.1Q frame according to
1025+ * the passed extension parameters (in the *data buffer)
1026+ * ebt_filter_vlan() is called after successfull check the rule params
1027+ * by ebt_check_vlan() function.
1028+ * Parameters:
1029+ * const struct sk_buff *skb - pointer to passed ethernet frame buffer
1030+ * const void *data - pointer to passed extension parameters
1031+ * unsigned int datalen - length of passed *data buffer
1032+ * const struct net_device *in -
1033+ * const struct net_device *out -
1034+ * const struct ebt_counter *c -
1035+ * Returned values:
1036+ * 0 - ok (all rule params matched)
1037+ * 1 - miss (rule params not acceptable to the parsed frame)
1038+ */
1039+static int
1040+ebt_filter_vlan (const struct sk_buff *skb,
1041+ const struct net_device *in,
1042+ const struct net_device *out,
1043+ const void *data,
1044+ unsigned int datalen)
1045+{
1046+ struct ebt_vlan_info *info = (struct ebt_vlan_info *) data; /* userspace data */
1047+ struct vlan_ethhdr *frame = (struct vlan_ethhdr *) skb->mac.raw; /* Passed tagged frame */
1048+
1049+ unsigned short TCI; /* Whole TCI, given from parsed frame */
1050+ unsigned short id; /* VLAN ID, given from frame TCI */
1051+ unsigned char prio; /* user_priority, given from frame TCI */
1052+ unsigned short encap; /* VLAN encapsulated Type/Length field, given from orig frame */
1053+
1054+ /*
1055+ * Tag Control Information (TCI) consists of the following elements:
1056+ * - User_priority. This field allows the tagged frame to carry user_priority
1057+ * information across Bridged LANs in which individual LAN segments may be unable to signal
1058+ * priority information (e.g., 802.3/Ethernet segments).
1059+ * The user_priority field is three bits in length,
1060+ * interpreted as a binary number. The user_priority is therefore
1061+ * capable of representing eight priority levels, 0 through 7.
1062+ * The use and interpretation of this field is defined in ISO/IEC 15802-3.
1063+ * - Canonical Format Indicator (CFI). This field is used,
1064+ * in 802.3/Ethernet, to signal the presence or absence
1065+ * of a RIF field, and, in combination with the Non-canonical Format Indicator (NCFI) carried
1066+ * in the RIF, to signal the bit order of address information carried in the encapsulated
1067+ * frame. The Canonical Format Indicator (CFI) is a single bit flag value.
1068+ * - VLAN Identifier (VID). This field uniquely identifies the VLAN to
1069+ * which the frame belongs. The twelve-bit VLAN Identifier (VID) field
1070+ * uniquely identify the VLAN to which the frame belongs.
1071+ * The VID is encoded as an unsigned binary number.
1072+ */
1073+ TCI = ntohs (frame->h_vlan_TCI);
1074+ id = TCI & 0xFFF;
1075+ prio = TCI >> 13;
1076+ encap = frame->h_vlan_encapsulated_proto;
1077+
1078+ /*
1079+ * First step is to check is null VLAN ID present
1080+ * in the parsed frame
1081+ */
1082+ if (!(id)) {
1083+ /*
1084+ * Checking VLAN Identifier (VID)
1085+ */
1086+ if (GET_BITMASK (EBT_VLAN_ID)) { /* Is VLAN ID parsed? */
1087+ EXIT_ON_MISMATCH (id, EBT_VLAN_ID);
1088+ DEBUG_MSG
1089+ ("matched rule id=%s%d for frame id=%d\n",
1090+ INV_FLAG (EBT_VLAN_ID), info->id, id);
1091+ }
1092+ } else {
1093+ /*
1094+ * Checking user_priority
1095+ */
1096+ if (GET_BITMASK (EBT_VLAN_PRIO)) { /* Is VLAN user_priority parsed? */
1097+ EXIT_ON_MISMATCH (prio, EBT_VLAN_PRIO);
1098+ DEBUG_MSG
1099+ ("matched rule prio=%s%d for frame prio=%d\n",
1100+ INV_FLAG (EBT_VLAN_PRIO), info->prio,
1101+ prio);
1102+ }
1103+ }
1104+ /*
1105+ * Checking Encapsulated Proto (Length/Type) field
1106+ */
1107+ if (GET_BITMASK (EBT_VLAN_ENCAP)) { /* Is VLAN Encap parsed? */
1108+ EXIT_ON_MISMATCH (encap, EBT_VLAN_ENCAP);
1109+ DEBUG_MSG ("matched encap=%s%2.4X for frame encap=%2.4X\n",
1110+ INV_FLAG (EBT_VLAN_ENCAP),
1111+ ntohs (info->encap), ntohs (encap));
1112+ }
1113+ /*
1114+ * All possible extension parameters was parsed.
1115+ * If rule never returned by missmatch, then all ok.
1116+ */
1117+ return 0;
1118+}
1119+
1120+/*
1121+ * Function description: ebt_vlan_check() is called when userspace
1122+ * delivers the table to the kernel,
1123+ * and to check that userspace doesn't give a bad table.
1124+ * Parameters:
1125+ * const char *tablename - table name string
1126+ * unsigned int hooknr - hook number
1127+ * const struct ebt_entry *e - ebtables entry basic set
1128+ * const void *data - pointer to passed extension parameters
1129+ * unsigned int datalen - length of passed *data buffer
1130+ * Returned values:
1131+ * 0 - ok (all delivered rule params are correct)
1132+ * 1 - miss (rule params is out of range, invalid, incompatible, etc.)
1133+ */
1134+static int
1135+ebt_check_vlan (const char *tablename,
1136+ unsigned int hooknr,
1137+ const struct ebt_entry *e, void *data,
1138+ unsigned int datalen)
1139+{
1140+ struct ebt_vlan_info *info = (struct ebt_vlan_info *) data;
1141+
1142+ /*
1143+ * Parameters buffer overflow check
1144+ */
1145+ if (datalen != sizeof (struct ebt_vlan_info)) {
1146+ DEBUG_MSG
1147+ ("params size %d is not eq to ebt_vlan_info (%d)\n",
1148+ datalen, sizeof (struct ebt_vlan_info));
1149+ return -EINVAL;
1150+ }
1151+
1152+ /*
1153+ * Is it 802.1Q frame checked?
1154+ */
1155+ if (e->ethproto != __constant_htons (ETH_P_8021Q)) {
1156+ DEBUG_MSG ("passed entry proto %2.4X is not 802.1Q (8100)\n",
1157+ (unsigned short) ntohs (e->ethproto));
1158+ return -EINVAL;
1159+ }
1160+
1161+ /*
1162+ * Check for bitmask range
1163+ * True if even one bit is out of mask
1164+ */
1165+ if (info->bitmask & ~EBT_VLAN_MASK) {
1166+ DEBUG_MSG ("bitmask %2X is out of mask (%2X)\n",
1167+ info->bitmask, EBT_VLAN_MASK);
1168+ return -EINVAL;
1169+ }
1170+
1171+ /*
1172+ * Check for inversion flags range
1173+ */
1174+ if (info->invflags & ~EBT_VLAN_MASK) {
1175+ DEBUG_MSG ("inversion flags %2X is out of mask (%2X)\n",
1176+ info->invflags, EBT_VLAN_MASK);
1177+ return -EINVAL;
1178+ }
1179+
1180+ /*
1181+ * Reserved VLAN ID (VID) values
1182+ * -----------------------------
1183+ * 0 - The null VLAN ID. Indicates that the tag header contains only user_priority information;
1184+ * no VLAN identifier is present in the frame. This VID value shall not be
1185+ * configured as a PVID, configured in any Filtering Database entry, or used in any
1186+ * Management operation.
1187+ *
1188+ * 1 - The default Port VID (PVID) value used for classifying frames on ingress through a Bridge
1189+ * Port. The PVID value can be changed by management on a per-Port basis.
1190+ *
1191+ * 0x0FFF - Reserved for implementation use. This VID value shall not be configured as a
1192+ * PVID or transmitted in a tag header.
1193+ *
1194+ * The remaining values of VID are available for general use as VLAN identifiers.
1195+ * A Bridge may implement the ability to support less than the full range of VID values;
1196+ * i.e., for a given implementation,
1197+ * an upper limit, N, is defined for the VID values supported, where N is less than or equal to 4094.
1198+ * All implementations shall support the use of all VID values in the range 0 through their defined maximum
1199+ * VID, N.
1200+ *
1201+ * For Linux, N = 4094.
1202+ */
1203+ if (GET_BITMASK (EBT_VLAN_ID)) { /* when vlan-id param was spec-ed */
1204+ if (!!info->id) { /* if id!=0 => check vid range */
1205+ if (info->id > 4094) { /* check if id > than (0x0FFE) */
1206+ DEBUG_MSG
1207+ ("vlan id %d is out of range (1-4094)\n",
1208+ info->id);
1209+ return -EINVAL;
1210+ }
1211+ /*
1212+ * Note: This is valid VLAN-tagged frame point.
1213+ * Any value of user_priority are acceptable, but could be ignored
1214+ * according to 802.1Q Std.
1215+ */
1216+ } else {
1217+ /*
1218+ * if id=0 (null VLAN ID) => Check for user_priority range
1219+ */
1220+ if (GET_BITMASK (EBT_VLAN_PRIO)) {
1221+ if ((unsigned char) info->prio > 7) {
1222+ DEBUG_MSG
1223+ ("prio %d is out of range (0-7)\n",
1224+ info->prio);
1225+ return -EINVAL;
1226+ }
1227+ }
1228+ /*
1229+ * Note2: This is valid priority-tagged frame point
1230+ * with null VID field.
1231+ */
1232+ }
1233+ } else { /* VLAN Id not set */
1234+ if (GET_BITMASK (EBT_VLAN_PRIO)) { /* But user_priority is set - abnormal! */
1235+ info->id = 0; /* Set null VID (case for Priority-tagged frames) */
1236+ SET_BITMASK (EBT_VLAN_ID); /* and set id flag */
1237+ }
1238+ }
1239+ /*
1240+ * Check for encapsulated proto range - it is possible to be any value for u_short range.
1241+ * When relaying a tagged frame between 802.3/Ethernet MACs,
1242+ * a Bridge may adjust the padding field such that
1243+ * the minimum size of a transmitted tagged frame is 68 octets (7.2).
1244+ * if_ether.h: ETH_ZLEN 60 - Min. octets in frame sans FCS
1245+ */
1246+ if (GET_BITMASK (EBT_VLAN_ENCAP)) {
1247+ if ((unsigned short) ntohs (info->encap) < ETH_ZLEN) {
1248+ DEBUG_MSG
1249+ ("encap packet length %d is less than minimal %d\n",
1250+ ntohs (info->encap), ETH_ZLEN);
1251+ return -EINVAL;
1252+ }
1253+ }
1254+
1255+ /*
1256+ * Otherwise is all correct
1257+ */
1258+ DEBUG_MSG ("802.1Q tagged frame checked (%s table, %d hook)\n",
1259+ tablename, hooknr);
1260+ return 0;
1261+}
1262+
1263+static struct ebt_match filter_vlan = {
1264+ {NULL, NULL},
1265+ EBT_VLAN_MATCH,
1266+ ebt_filter_vlan,
1267+ ebt_check_vlan,
1268+ NULL,
1269+ THIS_MODULE
1270+};
1271+
1272+/*
1273+ * Module initialization function.
1274+ * Called when module is loaded to kernelspace
1275+ */
1276+static int __init init (void)
1277+{
1278+ DEBUG_MSG ("ebtables 802.1Q extension module v"
1279+ MODULE_VERSION "\n");
1280+ DEBUG_MSG ("module debug=%d\n", !!debug);
1281+ return ebt_register_match (&filter_vlan);
1282+}
1283+
1284+/*
1285+ * Module "finalization" function
1286+ * Called when download module from kernelspace
1287+ */
1288+static void __exit fini (void)
1289+{
1290+ ebt_unregister_match (&filter_vlan);
1291+}
1292+
1293+module_init (init);
1294+module_exit (fini);
1295+
1296+EXPORT_NO_SYMBOLS;
1297--- /dev/null Thu Aug 24 11:00:32 2000
1298+++ linux-2.4.20-pre7-bcnt/net/bridge/netfilter/ebt_log.c Thu Oct 17 20:31:29 2002
1299@@ -0,0 +1,100 @@
1300+/*
1301+ * ebt_log
1302+ *
1303+ * Authors:
1304+ * Bart De Schuymer <bart.de.schuymer@pandora.be>
1305+ *
1306+ * April, 2002
1307+ *
1308+ */
1309+
1310+#include <linux/netfilter_bridge/ebtables.h>
1311+#include <linux/netfilter_bridge/ebt_log.h>
1312+#include <linux/module.h>
1313+#include <linux/ip.h>
1314+#include <linux/if_arp.h>
1315+#include <linux/spinlock.h>
1316+
1317+static spinlock_t ebt_log_lock = SPIN_LOCK_UNLOCKED;
1318+
1319+static int ebt_log_check(const char *tablename, unsigned int hookmask,
1320+ const struct ebt_entry *e, void *data, unsigned int datalen)
1321+{
1322+ struct ebt_log_info *info = (struct ebt_log_info *)data;
1323+
1324+ if (datalen != sizeof(struct ebt_log_info))
1325+ return -EINVAL;
1326+ if (info->bitmask & ~EBT_LOG_MASK)
1327+ return -EINVAL;
1328+ if (info->loglevel >= 8)
1329+ return -EINVAL;
1330+ info->prefix[EBT_LOG_PREFIX_SIZE - 1] = '\0';
1331+ return 0;
1332+}
1333+
1334+static void ebt_log(const struct sk_buff *skb, const struct net_device *in,
1335+ const struct net_device *out, const void *data, unsigned int datalen)
1336+{
1337+ struct ebt_log_info *info = (struct ebt_log_info *)data;
1338+ char level_string[4] = "< >";
1339+ level_string[1] = '0' + info->loglevel;
1340+
1341+ spin_lock_bh(&ebt_log_lock);
1342+ printk(level_string);
1343+ printk("%s IN=%s OUT=%s ", info->prefix, in ? in->name : "",
1344+ out ? out->name : "");
1345+
1346+ if (skb->dev->hard_header_len) {
1347+ int i;
1348+ unsigned char *p = (skb->mac.ethernet)->h_source;
1349+
1350+ printk("MAC source = ");
1351+ for (i = 0; i < ETH_ALEN; i++,p++)
1352+ printk("%02x%c", *p, i == ETH_ALEN - 1 ? ' ':':');
1353+ printk("MAC dest = ");
1354+ p = (skb->mac.ethernet)->h_dest;
1355+ for (i = 0; i < ETH_ALEN; i++,p++)
1356+ printk("%02x%c", *p, i == ETH_ALEN - 1 ? ' ':':');
1357+ }
1358+ printk("proto = 0x%04x", ntohs(((*skb).mac.ethernet)->h_proto));
1359+
1360+ if ((info->bitmask & EBT_LOG_IP) && skb->mac.ethernet->h_proto ==
1361+ htons(ETH_P_IP)){
1362+ struct iphdr *iph = skb->nh.iph;
1363+ printk(" IP SRC=%u.%u.%u.%u IP DST=%u.%u.%u.%u,",
1364+ NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
1365+ printk(" IP tos=0x%02X, IP proto=%d", iph->tos, iph->protocol);
1366+ }
1367+
1368+ if ((info->bitmask & EBT_LOG_ARP) &&
1369+ ((skb->mac.ethernet->h_proto == __constant_htons(ETH_P_ARP)) ||
1370+ (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_RARP)))) {
1371+ struct arphdr * arph = skb->nh.arph;
1372+ printk(" ARP HTYPE=%d, PTYPE=0x%04x, OPCODE=%d",
1373+ ntohs(arph->ar_hrd), ntohs(arph->ar_pro),
1374+ ntohs(arph->ar_op));
1375+ }
1376+ printk("\n");
1377+ spin_unlock_bh(&ebt_log_lock);
1378+}
1379+
1380+struct ebt_watcher log =
1381+{
1382+ {NULL, NULL}, EBT_LOG_WATCHER, ebt_log, ebt_log_check, NULL,
1383+ THIS_MODULE
1384+};
1385+
1386+static int __init init(void)
1387+{
1388+ return ebt_register_watcher(&log);
1389+}
1390+
1391+static void __exit fini(void)
1392+{
1393+ ebt_unregister_watcher(&log);
1394+}
1395+
1396+module_init(init);
1397+module_exit(fini);
1398+EXPORT_NO_SYMBOLS;
1399+MODULE_LICENSE("GPL");
1400--- /dev/null Thu Aug 24 11:00:32 2000
1401+++ linux-2.4.20-pre7-bcnt/net/bridge/netfilter/ebt_snat.c Thu Oct 17 20:31:29 2002
1402@@ -0,0 +1,64 @@
1403+/*
1404+ * ebt_snat
1405+ *
1406+ * Authors:
1407+ * Bart De Schuymer <bart.de.schuymer@pandora.be>
1408+ *
1409+ * June, 2002
1410+ *
1411+ */
1412+
1413+#include <linux/netfilter_bridge/ebtables.h>
1414+#include <linux/netfilter_bridge/ebt_nat.h>
1415+#include <linux/module.h>
1416+
1417+static int ebt_target_snat(struct sk_buff **pskb, unsigned int hooknr,
1418+ const struct net_device *in, const struct net_device *out,
1419+ const void *data, unsigned int datalen)
1420+{
1421+ struct ebt_nat_info *info = (struct ebt_nat_info *) data;
1422+
1423+ memcpy(((**pskb).mac.ethernet)->h_source, info->mac,
1424+ ETH_ALEN * sizeof(unsigned char));
1425+ return info->target;
1426+}
1427+
1428+static int ebt_target_snat_check(const char *tablename, unsigned int hookmask,
1429+ const struct ebt_entry *e, void *data, unsigned int datalen)
1430+{
1431+ struct ebt_nat_info *info = (struct ebt_nat_info *) data;
1432+
1433+ if (datalen != sizeof(struct ebt_nat_info))
1434+ return -EINVAL;
1435+ if (BASE_CHAIN && info->target == EBT_RETURN)
1436+ return -EINVAL;
1437+ CLEAR_BASE_CHAIN_BIT;
1438+ if (strcmp(tablename, "nat"))
1439+ return -EINVAL;
1440+ if (hookmask & ~(1 << NF_BR_POST_ROUTING))
1441+ return -EINVAL;
1442+ if (INVALID_TARGET)
1443+ return -EINVAL;
1444+ return 0;
1445+}
1446+
1447+static struct ebt_target snat =
1448+{
1449+ {NULL, NULL}, EBT_SNAT_TARGET, ebt_target_snat, ebt_target_snat_check,
1450+ NULL, THIS_MODULE
1451+};
1452+
1453+static int __init init(void)
1454+{
1455+ return ebt_register_target(&snat);
1456+}
1457+
1458+static void __exit fini(void)
1459+{
1460+ ebt_unregister_target(&snat);
1461+}
1462+
1463+module_init(init);
1464+module_exit(fini);
1465+EXPORT_NO_SYMBOLS;
1466+MODULE_LICENSE("GPL");
1467--- /dev/null Thu Aug 24 11:00:32 2000
1468+++ linux-2.4.20-pre7-bcnt/net/bridge/netfilter/ebt_dnat.c Thu Oct 17 20:31:29 2002
1469@@ -0,0 +1,65 @@
1470+/*
1471+ * ebt_dnat
1472+ *
1473+ * Authors:
1474+ * Bart De Schuymer <bart.de.schuymer@pandora.be>
1475+ *
1476+ * June, 2002
1477+ *
1478+ */
1479+
1480+#include <linux/netfilter_bridge/ebtables.h>
1481+#include <linux/netfilter_bridge/ebt_nat.h>
1482+#include <linux/module.h>
1483+#include <net/sock.h>
1484+
1485+static int ebt_target_dnat(struct sk_buff **pskb, unsigned int hooknr,
1486+ const struct net_device *in, const struct net_device *out,
1487+ const void *data, unsigned int datalen)
1488+{
1489+ struct ebt_nat_info *info = (struct ebt_nat_info *)data;
1490+
1491+ memcpy(((**pskb).mac.ethernet)->h_dest, info->mac,
1492+ ETH_ALEN * sizeof(unsigned char));
1493+ return info->target;
1494+}
1495+
1496+static int ebt_target_dnat_check(const char *tablename, unsigned int hookmask,
1497+ const struct ebt_entry *e, void *data, unsigned int datalen)
1498+{
1499+ struct ebt_nat_info *info = (struct ebt_nat_info *)data;
1500+
1501+ if (BASE_CHAIN && info->target == EBT_RETURN)
1502+ return -EINVAL;
1503+ CLEAR_BASE_CHAIN_BIT;
1504+ if ( (strcmp(tablename, "nat") ||
1505+ (hookmask & ~((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT)))) &&
1506+ (strcmp(tablename, "broute") || hookmask & ~(1 << NF_BR_BROUTING)) )
1507+ return -EINVAL;
1508+ if (datalen != sizeof(struct ebt_nat_info))
1509+ return -EINVAL;
1510+ if (INVALID_TARGET)
1511+ return -EINVAL;
1512+ return 0;
1513+}
1514+
1515+static struct ebt_target dnat =
1516+{
1517+ {NULL, NULL}, EBT_DNAT_TARGET, ebt_target_dnat, ebt_target_dnat_check,
1518+ NULL, THIS_MODULE
1519+};
1520+
1521+static int __init init(void)
1522+{
1523+ return ebt_register_target(&dnat);
1524+}
1525+
1526+static void __exit fini(void)
1527+{
1528+ ebt_unregister_target(&dnat);
1529+}
1530+
1531+module_init(init);
1532+module_exit(fini);
1533+EXPORT_NO_SYMBOLS;
1534+MODULE_LICENSE("GPL");
1535--- /dev/null Thu Aug 24 11:00:32 2000
1536+++ linux-2.4.20-pre7-bcnt/net/bridge/netfilter/ebtables.c Thu Oct 17 21:58:08 2002
1537@@ -0,0 +1,1489 @@
1538+/*
1539+ * ebtables
1540+ *
1541+ * Author:
1542+ * Bart De Schuymer <bart.de.schuymer@pandora.be>
1543+ *
1544+ * ebtables.c,v 2.0, July, 2002
1545+ *
1546+ * This code is stongly inspired on the iptables code which is
1547+ * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
1548+ *
1549+ * This program is free software; you can redistribute it and/or
1550+ * modify it under the terms of the GNU General Public License
1551+ * as published by the Free Software Foundation; either version
1552+ * 2 of the License, or (at your option) any later version.
1553+ */
1554+
1555+// used for print_string
1556+#include <linux/sched.h>
1557+#include <linux/tty.h>
1558+
1559+#include <linux/kmod.h>
1560+#include <linux/module.h>
1561+#include <linux/vmalloc.h>
1562+#include <linux/netfilter_bridge/ebtables.h>
1563+#include <linux/spinlock.h>
1564+#include <asm/uaccess.h>
1565+#include <linux/smp.h>
1566+#include <net/sock.h>
1567+// needed for logical [in,out]-dev filtering
1568+#include "../br_private.h"
1569+
1570+// list_named_find
1571+#define ASSERT_READ_LOCK(x)
1572+#define ASSERT_WRITE_LOCK(x)
1573+#include <linux/netfilter_ipv4/listhelp.h>
1574+
1575+#if 0 // use this for remote debugging
1576+// Copyright (C) 1998 by Ori Pomerantz
1577+// Print the string to the appropriate tty, the one
1578+// the current task uses
1579+static void print_string(char *str)
1580+{
1581+ struct tty_struct *my_tty;
1582+
1583+ /* The tty for the current task */
1584+ my_tty = current->tty;
1585+ if (my_tty != NULL) {
1586+ (*(my_tty->driver).write)(my_tty, 0, str, strlen(str));
1587+ (*(my_tty->driver).write)(my_tty, 0, "\015\012", 2);
1588+ }
1589+}
1590+
1591+#define BUGPRINT(args) print_string(args);
1592+#else
1593+#define BUGPRINT(format, args...) printk("kernel msg: ebtables bug: please "\
1594+ "report to author: "format, ## args)
1595+// #define BUGPRINT(format, args...)
1596+#endif
1597+#define MEMPRINT(format, args...) printk("kernel msg: ebtables "\
1598+ ": out of memory: "format, ## args)
1599+// #define MEMPRINT(format, args...)
1600+
1601+
1602+
1603+// Each cpu has its own set of counters, so there is no need for write_lock in
1604+// the softirq
1605+// For reading or updating the counters, the user context needs to
1606+// get a write_lock
1607+
1608+// The size of each set of counters is altered to get cache alignment
1609+#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
1610+#define COUNTER_OFFSET(n) (SMP_ALIGN(n * sizeof(struct ebt_counter)))
1611+#define COUNTER_BASE(c, n, cpu) ((struct ebt_counter *)(((char *)c) + \
1612+ COUNTER_OFFSET(n) * cpu))
1613+
1614+
1615+
1616+static DECLARE_MUTEX(ebt_mutex);
1617+static LIST_HEAD(ebt_tables);
1618+static LIST_HEAD(ebt_targets);
1619+static LIST_HEAD(ebt_matches);
1620+static LIST_HEAD(ebt_watchers);
1621+
1622+static struct ebt_target ebt_standard_target =
1623+{ {NULL, NULL}, EBT_STANDARD_TARGET, NULL, NULL, NULL, NULL};
1624+
1625+static inline int ebt_do_watcher (struct ebt_entry_watcher *w,
1626+ const struct sk_buff *skb, const struct net_device *in,
1627+ const struct net_device *out)
1628+{
1629+ w->u.watcher->watcher(skb, in, out, w->data,
1630+ w->watcher_size);
1631+ // watchers don't give a verdict
1632+ return 0;
1633+}
1634+
1635+static inline int ebt_do_match (struct ebt_entry_match *m,
1636+ const struct sk_buff *skb, const struct net_device *in,
1637+ const struct net_device *out)
1638+{
1639+ return m->u.match->match(skb, in, out, m->data,
1640+ m->match_size);
1641+}
1642+
1643+static inline int ebt_dev_check(char *entry, const struct net_device *device)
1644+{
1645+ if (*entry == '\0')
1646+ return 0;
1647+ if (!device)
1648+ return 1;
1649+ return !!strcmp(entry, device->name);
1650+}
1651+
1652+#define FWINV2(bool,invflg) ((bool) ^ !!(e->invflags & invflg))
1653+// process standard matches
1654+static inline int ebt_basic_match(struct ebt_entry *e, struct ethhdr *h,
1655+ const struct net_device *in, const struct net_device *out)
1656+{
1657+ int verdict, i;
1658+
1659+ if (e->bitmask & EBT_802_3) {
1660+ if (FWINV2(ntohs(h->h_proto) >= 1536, EBT_IPROTO))
1661+ return 1;
1662+ } else if (!(e->bitmask & EBT_NOPROTO) &&
1663+ FWINV2(e->ethproto != h->h_proto, EBT_IPROTO))
1664+ return 1;
1665+
1666+ if (FWINV2(ebt_dev_check(e->in, in), EBT_IIN))
1667+ return 1;
1668+ if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT))
1669+ return 1;
1670+ if ((!in || !in->br_port) ? 0 : FWINV2(ebt_dev_check(
1671+ e->logical_in, &in->br_port->br->dev), EBT_ILOGICALIN))
1672+ return 1;
1673+ if ((!out || !out->br_port) ? 0 : FWINV2(ebt_dev_check(
1674+ e->logical_out, &out->br_port->br->dev), EBT_ILOGICALOUT))
1675+ return 1;
1676+
1677+ if (e->bitmask & EBT_SOURCEMAC) {
1678+ verdict = 0;
1679+ for (i = 0; i < 6; i++)
1680+ verdict |= (h->h_source[i] ^ e->sourcemac[i]) &
1681+ e->sourcemsk[i];
1682+ if (FWINV2(verdict != 0, EBT_ISOURCE) )
1683+ return 1;
1684+ }
1685+ if (e->bitmask & EBT_DESTMAC) {
1686+ verdict = 0;
1687+ for (i = 0; i < 6; i++)
1688+ verdict |= (h->h_dest[i] ^ e->destmac[i]) &
1689+ e->destmsk[i];
1690+ if (FWINV2(verdict != 0, EBT_IDEST) )
1691+ return 1;
1692+ }
1693+ return 0;
1694+}
1695+
1696+// Do some firewalling
1697+unsigned int ebt_do_table (unsigned int hook, struct sk_buff **pskb,
1698+ const struct net_device *in, const struct net_device *out,
1699+ struct ebt_table *table)
1700+{
1701+ int i, nentries;
1702+ struct ebt_entry *point;
1703+ struct ebt_counter *counter_base, *cb_base;
1704+ struct ebt_entry_target *t;
1705+ int verdict, sp = 0;
1706+ struct ebt_chainstack *cs;
1707+ struct ebt_entries *chaininfo;
1708+ char *base;
1709+ struct ebt_table_info *private = table->private;
1710+
1711+ read_lock_bh(&table->lock);
1712+ cb_base = COUNTER_BASE(private->counters, private->nentries,
1713+ cpu_number_map(smp_processor_id()));
1714+ if (private->chainstack)
1715+ cs = private->chainstack[cpu_number_map(smp_processor_id())];
1716+ else
1717+ cs = NULL;
1718+ chaininfo = private->hook_entry[hook];
1719+ nentries = private->hook_entry[hook]->nentries;
1720+ point = (struct ebt_entry *)(private->hook_entry[hook]->data);
1721+ counter_base = cb_base + private->hook_entry[hook]->counter_offset;
1722+ // base for chain jumps
1723+ base = (char *)chaininfo;
1724+ i = 0;
1725+ while (i < nentries) {
1726+ if (ebt_basic_match(point, (**pskb).mac.ethernet, in, out))
1727+ goto letscontinue;
1728+
1729+ if (EBT_MATCH_ITERATE(point, ebt_do_match, *pskb, in, out) != 0)
1730+ goto letscontinue;
1731+
1732+ // increase counter
1733+ (*(counter_base + i)).pcnt++;
1734+ (*(counter_base + i)).bcnt+=(**pskb).len;
1735+
1736+ // these should only watch: not modify, nor tell us
1737+ // what to do with the packet
1738+ EBT_WATCHER_ITERATE(point, ebt_do_watcher, *pskb, in,
1739+ out);
1740+
1741+ t = (struct ebt_entry_target *)
1742+ (((char *)point) + point->target_offset);
1743+ // standard target
1744+ if (!t->u.target->target)
1745+ verdict = ((struct ebt_standard_target *)t)->verdict;
1746+ else
1747+ verdict = t->u.target->target(pskb, hook,
1748+ in, out, t->data, t->target_size);
1749+ if (verdict == EBT_ACCEPT) {
1750+ read_unlock_bh(&table->lock);
1751+ return NF_ACCEPT;
1752+ }
1753+ if (verdict == EBT_DROP) {
1754+ read_unlock_bh(&table->lock);
1755+ return NF_DROP;
1756+ }
1757+ if (verdict == EBT_RETURN) {
1758+letsreturn:
1759+#ifdef CONFIG_NETFILTER_DEBUG
1760+ if (sp == 0) {
1761+ BUGPRINT("RETURN on base chain");
1762+ // act like this is EBT_CONTINUE
1763+ goto letscontinue;
1764+ }
1765+#endif
1766+ sp--;
1767+ // put all the local variables right
1768+ i = cs[sp].n;
1769+ chaininfo = cs[sp].chaininfo;
1770+ nentries = chaininfo->nentries;
1771+ point = cs[sp].e;
1772+ counter_base = cb_base +
1773+ chaininfo->counter_offset;
1774+ continue;
1775+ }
1776+ if (verdict == EBT_CONTINUE)
1777+ goto letscontinue;
1778+#ifdef CONFIG_NETFILTER_DEBUG
1779+ if (verdict < 0) {
1780+ BUGPRINT("bogus standard verdict\n");
1781+ read_unlock_bh(&table->lock);
1782+ return NF_DROP;
1783+ }
1784+#endif
1785+ // jump to a udc
1786+ cs[sp].n = i + 1;
1787+ cs[sp].chaininfo = chaininfo;
1788+ cs[sp].e = (struct ebt_entry *)
1789+ (((char *)point) + point->next_offset);
1790+ i = 0;
1791+ chaininfo = (struct ebt_entries *) (base + verdict);
1792+#ifdef CONFIG_NETFILTER_DEBUG
1793+ if (chaininfo->distinguisher) {
1794+ BUGPRINT("jump to non-chain\n");
1795+ read_unlock_bh(&table->lock);
1796+ return NF_DROP;
1797+ }
1798+#endif
1799+ nentries = chaininfo->nentries;
1800+ point = (struct ebt_entry *)chaininfo->data;
1801+ counter_base = cb_base + chaininfo->counter_offset;
1802+ sp++;
1803+ continue;
1804+letscontinue:
1805+ point = (struct ebt_entry *)
1806+ (((char *)point) + point->next_offset);
1807+ i++;
1808+ }
1809+
1810+ // I actually like this :)
1811+ if (chaininfo->policy == EBT_RETURN)
1812+ goto letsreturn;
1813+ if (chaininfo->policy == EBT_ACCEPT) {
1814+ read_unlock_bh(&table->lock);
1815+ return NF_ACCEPT;
1816+ }
1817+ read_unlock_bh(&table->lock);
1818+ return NF_DROP;
1819+}
1820+
1821+// If it succeeds, returns element and locks mutex
1822+static inline void *
1823+find_inlist_lock_noload(struct list_head *head, const char *name, int *error,
1824+ struct semaphore *mutex)
1825+{
1826+ void *ret;
1827+
1828+ *error = down_interruptible(mutex);
1829+ if (*error != 0)
1830+ return NULL;
1831+
1832+ ret = list_named_find(head, name);
1833+ if (!ret) {
1834+ *error = -ENOENT;
1835+ up(mutex);
1836+ }
1837+ return ret;
1838+}
1839+
1840+#ifndef CONFIG_KMOD
1841+#define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m))
1842+#else
1843+static void *
1844+find_inlist_lock(struct list_head *head, const char *name, const char *prefix,
1845+ int *error, struct semaphore *mutex)
1846+{
1847+ void *ret;
1848+
1849+ ret = find_inlist_lock_noload(head, name, error, mutex);
1850+ if (!ret) {
1851+ char modulename[EBT_FUNCTION_MAXNAMELEN + strlen(prefix) + 1];
1852+ strcpy(modulename, prefix);
1853+ strcat(modulename, name);
1854+ request_module(modulename);
1855+ ret = find_inlist_lock_noload(head, name, error, mutex);
1856+ }
1857+ return ret;
1858+}
1859+#endif
1860+
1861+static inline struct ebt_table *
1862+find_table_lock(const char *name, int *error, struct semaphore *mutex)
1863+{
1864+ return find_inlist_lock(&ebt_tables, name, "ebtable_", error, mutex);
1865+}
1866+
1867+static inline struct ebt_match *
1868+find_match_lock(const char *name, int *error, struct semaphore *mutex)
1869+{
1870+ return find_inlist_lock(&ebt_matches, name, "ebt_", error, mutex);
1871+}
1872+
1873+static inline struct ebt_watcher *
1874+find_watcher_lock(const char *name, int *error, struct semaphore *mutex)
1875+{
1876+ return find_inlist_lock(&ebt_watchers, name, "ebt_", error, mutex);
1877+}
1878+
1879+static inline struct ebt_target *
1880+find_target_lock(const char *name, int *error, struct semaphore *mutex)
1881+{
1882+ return find_inlist_lock(&ebt_targets, name, "ebt_", error, mutex);
1883+}
1884+
1885+static inline int
1886+ebt_check_match(struct ebt_entry_match *m, struct ebt_entry *e,
1887+ const char *name, unsigned int hookmask, unsigned int *cnt)
1888+{
1889+ struct ebt_match *match;
1890+ int ret;
1891+
1892+ if (((char *)m) + m->match_size + sizeof(struct ebt_entry_match) >
1893+ ((char *)e) + e->watchers_offset)
1894+ return -EINVAL;
1895+ match = find_match_lock(m->u.name, &ret, &ebt_mutex);
1896+ if (!match)
1897+ return ret;
1898+ m->u.match = match;
1899+ if (match->me)
1900+ __MOD_INC_USE_COUNT(match->me);
1901+ up(&ebt_mutex);
1902+ if (match->check &&
1903+ match->check(name, hookmask, e, m->data, m->match_size) != 0) {
1904+ BUGPRINT("match->check failed\n");
1905+ if (match->me)
1906+ __MOD_DEC_USE_COUNT(match->me);
1907+ return -EINVAL;
1908+ }
1909+ (*cnt)++;
1910+ return 0;
1911+}
1912+
1913+static inline int
1914+ebt_check_watcher(struct ebt_entry_watcher *w, struct ebt_entry *e,
1915+ const char *name, unsigned int hookmask, unsigned int *cnt)
1916+{
1917+ struct ebt_watcher *watcher;
1918+ int ret;
1919+
1920+ if (((char *)w) + w->watcher_size + sizeof(struct ebt_entry_watcher) >
1921+ ((char *)e) + e->target_offset)
1922+ return -EINVAL;
1923+ watcher = find_watcher_lock(w->u.name, &ret, &ebt_mutex);
1924+ if (!watcher)
1925+ return ret;
1926+ w->u.watcher = watcher;
1927+ if (watcher->me)
1928+ __MOD_INC_USE_COUNT(watcher->me);
1929+ up(&ebt_mutex);
1930+ if (watcher->check &&
1931+ watcher->check(name, hookmask, e, w->data, w->watcher_size) != 0) {
1932+ BUGPRINT("watcher->check failed\n");
1933+ if (watcher->me)
1934+ __MOD_DEC_USE_COUNT(watcher->me);
1935+ return -EINVAL;
1936+ }
1937+ (*cnt)++;
1938+ return 0;
1939+}
1940+
1941+// this one is very careful, as it is the first function
1942+// to parse the userspace data
1943+static inline int
1944+ebt_check_entry_size_and_hooks(struct ebt_entry *e,
1945+ struct ebt_table_info *newinfo, char *base, char *limit,
1946+ struct ebt_entries **hook_entries, unsigned int *n, unsigned int *cnt,
1947+ unsigned int *totalcnt, unsigned int *udc_cnt, unsigned int valid_hooks)
1948+{
1949+ int i;
1950+
1951+ for (i = 0; i < NF_BR_NUMHOOKS; i++) {
1952+ if ((valid_hooks & (1 << i)) == 0)
1953+ continue;
1954+ if ( (char *)hook_entries[i] - base ==
1955+ (char *)e - newinfo->entries)
1956+ break;
1957+ }
1958+ // beginning of a new chain
1959+ // if i == NF_BR_NUMHOOKS it must be a user defined chain
1960+ if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
1961+ if ((e->bitmask & EBT_ENTRY_OR_ENTRIES) != 0) {
1962+ // we make userspace set this right,
1963+ // so there is no misunderstanding
1964+ BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set "
1965+ "in distinguisher\n");
1966+ return -EINVAL;
1967+ }
1968+ // this checks if the previous chain has as many entries
1969+ // as it said it has
1970+ if (*n != *cnt) {
1971+ BUGPRINT("nentries does not equal the nr of entries "
1972+ "in the chain\n");
1973+ return -EINVAL;
1974+ }
1975+ // before we look at the struct, be sure it is not too big
1976+ if ((char *)hook_entries[i] + sizeof(struct ebt_entries)
1977+ > limit) {
1978+ BUGPRINT("entries_size too small\n");
1979+ return -EINVAL;
1980+ }
1981+ if (((struct ebt_entries *)e)->policy != EBT_DROP &&
1982+ ((struct ebt_entries *)e)->policy != EBT_ACCEPT) {
1983+ // only RETURN from udc
1984+ if (i != NF_BR_NUMHOOKS ||
1985+ ((struct ebt_entries *)e)->policy != EBT_RETURN) {
1986+ BUGPRINT("bad policy\n");
1987+ return -EINVAL;
1988+ }
1989+ }
1990+ if (i == NF_BR_NUMHOOKS) // it's a user defined chain
1991+ (*udc_cnt)++;
1992+ else
1993+ newinfo->hook_entry[i] = (struct ebt_entries *)e;
1994+ if (((struct ebt_entries *)e)->counter_offset != *totalcnt) {
1995+ BUGPRINT("counter_offset != totalcnt");
1996+ return -EINVAL;
1997+ }
1998+ *n = ((struct ebt_entries *)e)->nentries;
1999+ *cnt = 0;
2000+ return 0;
2001+ }
2002+ // a plain old entry, heh
2003+ if (sizeof(struct ebt_entry) > e->watchers_offset ||
2004+ e->watchers_offset > e->target_offset ||
2005+ e->target_offset >= e->next_offset) {
2006+ BUGPRINT("entry offsets not in right order\n");
2007+ return -EINVAL;
2008+ }
2009+ // this is not checked anywhere else
2010+ if (e->next_offset - e->target_offset < sizeof(struct ebt_entry_target)) {
2011+ BUGPRINT("target size too small\n");
2012+ return -EINVAL;
2013+ }
2014+
2015+ (*cnt)++;
2016+ (*totalcnt)++;
2017+ return 0;
2018+}
2019+
2020+struct ebt_cl_stack
2021+{
2022+ struct ebt_chainstack cs;
2023+ int from;
2024+ unsigned int hookmask;
2025+};
2026+
2027+// we need these positions to check that the jumps to a different part of the
2028+// entries is a jump to the beginning of a new chain.
2029+static inline int
2030+ebt_get_udc_positions(struct ebt_entry *e, struct ebt_table_info *newinfo,
2031+ struct ebt_entries **hook_entries, unsigned int *n, unsigned int valid_hooks,
2032+ struct ebt_cl_stack *udc)
2033+{
2034+ int i;
2035+
2036+ // we're only interested in chain starts
2037+ if (e->bitmask & EBT_ENTRY_OR_ENTRIES)
2038+ return 0;
2039+ for (i = 0; i < NF_BR_NUMHOOKS; i++) {
2040+ if ((valid_hooks & (1 << i)) == 0)
2041+ continue;
2042+ if (newinfo->hook_entry[i] == (struct ebt_entries *)e)
2043+ break;
2044+ }
2045+ // only care about udc
2046+ if (i != NF_BR_NUMHOOKS)
2047+ return 0;
2048+
2049+ udc[*n].cs.chaininfo = (struct ebt_entries *)e;
2050+ // these initialisations are depended on later in check_chainloops()
2051+ udc[*n].cs.n = 0;
2052+ udc[*n].hookmask = 0;
2053+
2054+ (*n)++;
2055+ return 0;
2056+}
2057+
2058+static inline int
2059+ebt_cleanup_match(struct ebt_entry_match *m, unsigned int *i)
2060+{
2061+ if (i && (*i)-- == 0)
2062+ return 1;
2063+ if (m->u.match->destroy)
2064+ m->u.match->destroy(m->data, m->match_size);
2065+ if (m->u.match->me)
2066+ __MOD_DEC_USE_COUNT(m->u.match->me);
2067+
2068+ return 0;
2069+}
2070+
2071+static inline int
2072+ebt_cleanup_watcher(struct ebt_entry_watcher *w, unsigned int *i)
2073+{
2074+ if (i && (*i)-- == 0)
2075+ return 1;
2076+ if (w->u.watcher->destroy)
2077+ w->u.watcher->destroy(w->data, w->watcher_size);
2078+ if (w->u.watcher->me)
2079+ __MOD_DEC_USE_COUNT(w->u.watcher->me);
2080+
2081+ return 0;
2082+}
2083+
2084+static inline int
2085+ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt)
2086+{
2087+ struct ebt_entry_target *t;
2088+
2089+ if ((e->bitmask & EBT_ENTRY_OR_ENTRIES) == 0)
2090+ return 0;
2091+ // we're done
2092+ if (cnt && (*cnt)-- == 0)
2093+ return 1;
2094+ EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, NULL);
2095+ EBT_MATCH_ITERATE(e, ebt_cleanup_match, NULL);
2096+ t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
2097+ if (t->u.target->destroy)
2098+ t->u.target->destroy(t->data, t->target_size);
2099+ if (t->u.target->me)
2100+ __MOD_DEC_USE_COUNT(t->u.target->me);
2101+
2102+ return 0;
2103+}
2104+
2105+static inline int
2106+ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
2107+ const char *name, unsigned int *cnt, unsigned int valid_hooks,
2108+ struct ebt_cl_stack *cl_s, unsigned int udc_cnt)
2109+{
2110+ struct ebt_entry_target *t;
2111+ struct ebt_target *target;
2112+ unsigned int i, j, hook = 0, hookmask = 0;
2113+ int ret;
2114+
2115+ // Don't mess with the struct ebt_entries
2116+ if ((e->bitmask & EBT_ENTRY_OR_ENTRIES) == 0)
2117+ return 0;
2118+
2119+ if (e->bitmask & ~EBT_F_MASK) {
2120+ BUGPRINT("Unknown flag for bitmask\n");
2121+ return -EINVAL;
2122+ }
2123+ if (e->invflags & ~EBT_INV_MASK) {
2124+ BUGPRINT("Unknown flag for inv bitmask\n");
2125+ return -EINVAL;
2126+ }
2127+ if ( (e->bitmask & EBT_NOPROTO) && (e->bitmask & EBT_802_3) ) {
2128+ BUGPRINT("NOPROTO & 802_3 not allowed\n");
2129+ return -EINVAL;
2130+ }
2131+ // what hook do we belong to?
2132+ for (i = 0; i < NF_BR_NUMHOOKS; i++) {
2133+ if ((valid_hooks & (1 << i)) == 0)
2134+ continue;
2135+ if ((char *)newinfo->hook_entry[i] < (char *)e)
2136+ hook = i;
2137+ else
2138+ break;
2139+ }
2140+ // (1 << NF_BR_NUMHOOKS) tells the check functions the rule is on
2141+ // a base chain
2142+ if (i < NF_BR_NUMHOOKS)
2143+ hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
2144+ else {
2145+ for (i = 0; i < udc_cnt; i++)
2146+ if ((char *)(cl_s[i].cs.chaininfo) > (char *)e)
2147+ break;
2148+ if (i == 0)
2149+ hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
2150+ else
2151+ hookmask = cl_s[i - 1].hookmask;
2152+ }
2153+ i = 0;
2154+ ret = EBT_MATCH_ITERATE(e, ebt_check_match, e, name, hookmask, &i);
2155+ if (ret != 0)
2156+ goto cleanup_matches;
2157+ j = 0;
2158+ ret = EBT_WATCHER_ITERATE(e, ebt_check_watcher, e, name, hookmask, &j);
2159+ if (ret != 0)
2160+ goto cleanup_watchers;
2161+ t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
2162+ target = find_target_lock(t->u.name, &ret, &ebt_mutex);
2163+ if (!target)
2164+ goto cleanup_watchers;
2165+ if (target->me)
2166+ __MOD_INC_USE_COUNT(target->me);
2167+ up(&ebt_mutex);
2168+
2169+ t->u.target = target;
2170+ if (t->u.target == &ebt_standard_target) {
2171+ if (e->target_offset + sizeof(struct ebt_standard_target) >
2172+ e->next_offset) {
2173+ BUGPRINT("Standard target size too big\n");
2174+ ret = -EFAULT;
2175+ goto cleanup_watchers;
2176+ }
2177+ if (((struct ebt_standard_target *)t)->verdict <
2178+ -NUM_STANDARD_TARGETS) {
2179+ BUGPRINT("Invalid standard target\n");
2180+ ret = -EFAULT;
2181+ goto cleanup_watchers;
2182+ }
2183+ } else if ((e->target_offset + t->target_size +
2184+ sizeof(struct ebt_entry_target) > e->next_offset) ||
2185+ (t->u.target->check &&
2186+ t->u.target->check(name, hookmask, e, t->data, t->target_size) != 0)){
2187+ if (t->u.target->me)
2188+ __MOD_DEC_USE_COUNT(t->u.target->me);
2189+ ret = -EFAULT;
2190+ goto cleanup_watchers;
2191+ }
2192+ (*cnt)++;
2193+ return 0;
2194+cleanup_watchers:
2195+ EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, &j);
2196+cleanup_matches:
2197+ EBT_MATCH_ITERATE(e, ebt_cleanup_match, &i);
2198+ return ret;
2199+}
2200+
2201+// checks for loops and sets the hook mask for udc
2202+// the hook mask for udc tells us from which base chains the udc can be
2203+// accessed. This mask is a parameter to the check() functions of the extensions
2204+int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s,
2205+ unsigned int udc_cnt, unsigned int hooknr, char *base)
2206+{
2207+ int i, chain_nr = -1, pos = 0, nentries = chain->nentries, verdict;
2208+ struct ebt_entry *e = (struct ebt_entry *)chain->data;
2209+ struct ebt_entry_target *t;
2210+
2211+ while (pos < nentries || chain_nr != -1) {
2212+ // end of udc, go back one 'recursion' step
2213+ if (pos == nentries) {
2214+ // put back values of the time when this chain was called
2215+ e = cl_s[chain_nr].cs.e;
2216+ if (cl_s[chain_nr].from != -1)
2217+ nentries =
2218+ cl_s[cl_s[chain_nr].from].cs.chaininfo->nentries;
2219+ else
2220+ nentries = chain->nentries;
2221+ pos = cl_s[chain_nr].cs.n;
2222+ // make sure we won't see a loop that isn't one
2223+ cl_s[chain_nr].cs.n = 0;
2224+ chain_nr = cl_s[chain_nr].from;
2225+ if (pos == nentries)
2226+ continue;
2227+ }
2228+ t = (struct ebt_entry_target *)
2229+ (((char *)e) + e->target_offset);
2230+ if (strcmp(t->u.name, EBT_STANDARD_TARGET))
2231+ goto letscontinue;
2232+ if (e->target_offset + sizeof(struct ebt_standard_target) >
2233+ e->next_offset) {
2234+ BUGPRINT("Standard target size too big\n");
2235+ return -1;
2236+ }
2237+ verdict = ((struct ebt_standard_target *)t)->verdict;
2238+ if (verdict >= 0) { // jump to another chain
2239+ struct ebt_entries *hlp2 =
2240+ (struct ebt_entries *)(base + verdict);
2241+ for (i = 0; i < udc_cnt; i++)
2242+ if (hlp2 == cl_s[i].cs.chaininfo)
2243+ break;
2244+ // bad destination or loop
2245+ if (i == udc_cnt) {
2246+ BUGPRINT("bad destination\n");
2247+ return -1;
2248+ }
2249+ if (cl_s[i].cs.n) {
2250+ BUGPRINT("loop\n");
2251+ return -1;
2252+ }
2253+ // this can't be 0, so the above test is correct
2254+ cl_s[i].cs.n = pos + 1;
2255+ pos = 0;
2256+ cl_s[i].cs.e = ((void *)e + e->next_offset);
2257+ e = (struct ebt_entry *)(hlp2->data);
2258+ nentries = hlp2->nentries;
2259+ cl_s[i].from = chain_nr;
2260+ chain_nr = i;
2261+ // this udc is accessible from the base chain for hooknr
2262+ cl_s[i].hookmask |= (1 << hooknr);
2263+ continue;
2264+ }
2265+letscontinue:
2266+ e = (void *)e + e->next_offset;
2267+ pos++;
2268+ }
2269+ return 0;
2270+}
2271+
2272+// do the parsing of the table/chains/entries/matches/watchers/targets, heh
2273+static int translate_table(struct ebt_replace *repl,
2274+ struct ebt_table_info *newinfo)
2275+{
2276+ unsigned int i, j, k, udc_cnt;
2277+ int ret;
2278+ struct ebt_cl_stack *cl_s = NULL; // used in the checking for chain loops
2279+
2280+ i = 0;
2281+ while (i < NF_BR_NUMHOOKS && !(repl->valid_hooks & (1 << i)))
2282+ i++;
2283+ if (i == NF_BR_NUMHOOKS) {
2284+ BUGPRINT("No valid hooks specified\n");
2285+ return -EINVAL;
2286+ }
2287+ if (repl->hook_entry[i] != (struct ebt_entries *)repl->entries) {
2288+ BUGPRINT("Chains don't start at beginning\n");
2289+ return -EINVAL;
2290+ }
2291+ // make sure chains are ordered after each other in same order
2292+ // as their corresponding hooks
2293+ for (j = i + 1; j < NF_BR_NUMHOOKS; j++) {
2294+ if (!(repl->valid_hooks & (1 << j)))
2295+ continue;
2296+ if ( repl->hook_entry[j] <= repl->hook_entry[i] ) {
2297+ BUGPRINT("Hook order must be followed\n");
2298+ return -EINVAL;
2299+ }
2300+ i = j;
2301+ }
2302+
2303+ for (i = 0; i < NF_BR_NUMHOOKS; i++)
2304+ newinfo->hook_entry[i] = NULL;
2305+
2306+ newinfo->entries_size = repl->entries_size;
2307+ newinfo->nentries = repl->nentries;
2308+
2309+ // do some early checkings and initialize some things
2310+ i = 0; // holds the expected nr. of entries for the chain
2311+ j = 0; // holds the up to now counted entries for the chain
2312+ k = 0; // holds the total nr. of entries, should equal
2313+ // newinfo->nentries afterwards
2314+ udc_cnt = 0; // will hold the nr. of user defined chains (udc)
2315+ ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
2316+ ebt_check_entry_size_and_hooks, newinfo, repl->entries,
2317+ repl->entries + repl->entries_size, repl->hook_entry, &i, &j, &k,
2318+ &udc_cnt, repl->valid_hooks);
2319+
2320+ if (ret != 0)
2321+ return ret;
2322+
2323+ if (i != j) {
2324+ BUGPRINT("nentries does not equal the nr of entries in the "
2325+ "(last) chain\n");
2326+ return -EINVAL;
2327+ }
2328+ if (k != newinfo->nentries) {
2329+ BUGPRINT("Total nentries is wrong\n");
2330+ return -EINVAL;
2331+ }
2332+
2333+ // check if all valid hooks have a chain
2334+ for (i = 0; i < NF_BR_NUMHOOKS; i++) {
2335+ if (newinfo->hook_entry[i] == NULL &&
2336+ (repl->valid_hooks & (1 << i))) {
2337+ BUGPRINT("Valid hook without chain\n");
2338+ return -EINVAL;
2339+ }
2340+ }
2341+
2342+ // Get the location of the udc, put them in an array
2343+ // While we're at it, allocate the chainstack
2344+ if (udc_cnt) {
2345+ // this will get free'd in do_replace()/ebt_register_table()
2346+ // if an error occurs
2347+ newinfo->chainstack = (struct ebt_chainstack **)
2348+ vmalloc(smp_num_cpus * sizeof(struct ebt_chainstack));
2349+ if (!newinfo->chainstack)
2350+ return -ENOMEM;
2351+ for (i = 0; i < smp_num_cpus; i++) {
2352+ newinfo->chainstack[i] =
2353+ vmalloc(udc_cnt * sizeof(struct ebt_chainstack));
2354+ if (!newinfo->chainstack[i]) {
2355+ while (i)
2356+ vfree(newinfo->chainstack[--i]);
2357+ vfree(newinfo->chainstack);
2358+ newinfo->chainstack = NULL;
2359+ return -ENOMEM;
2360+ }
2361+ }
2362+
2363+ cl_s = (struct ebt_cl_stack *)
2364+ vmalloc(udc_cnt * sizeof(struct ebt_cl_stack));
2365+ if (!cl_s)
2366+ return -ENOMEM;
2367+ i = 0; // the i'th udc
2368+ EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
2369+ ebt_get_udc_positions, newinfo, repl->hook_entry, &i,
2370+ repl->valid_hooks, cl_s);
2371+ // sanity check
2372+ if (i != udc_cnt) {
2373+ BUGPRINT("i != udc_cnt\n");
2374+ vfree(cl_s);
2375+ return -EFAULT;
2376+ }
2377+ }
2378+
2379+ // Check for loops
2380+ for (i = 0; i < NF_BR_NUMHOOKS; i++)
2381+ if (repl->valid_hooks & (1 << i))
2382+ if (check_chainloops(newinfo->hook_entry[i],
2383+ cl_s, udc_cnt, i, newinfo->entries)) {
2384+ if (cl_s)
2385+ vfree(cl_s);
2386+ return -EINVAL;
2387+ }
2388+
2389