summaryrefslogtreecommitdiffstats
path: root/kernel/patches/incremental-patches
diff options
context:
space:
mode:
authorBart De Schuymer <bdschuym@pandora.be>2002-07-31 19:44:51 +0000
committerBart De Schuymer <bdschuym@pandora.be>2002-07-31 19:44:51 +0000
commitd6a5d8b6636b49b4ae54385661b434d1277c6d86 (patch)
treeddd81e65e9a91604c327eeb3653b933b94375703 /kernel/patches/incremental-patches
parent424ce46da34e4cfdf62ae60c9a2aa646cabf898f (diff)
*** empty log message ***
Diffstat (limited to 'kernel/patches/incremental-patches')
-rw-r--r--kernel/patches/incremental-patches/ebtables-v2.0_vs_2.4.18-rc1.001.diff1152
1 files changed, 1152 insertions, 0 deletions
diff --git a/kernel/patches/incremental-patches/ebtables-v2.0_vs_2.4.18-rc1.001.diff b/kernel/patches/incremental-patches/ebtables-v2.0_vs_2.4.18-rc1.001.diff
new file mode 100644
index 0000000..6e03a05
--- /dev/null
+++ b/kernel/patches/incremental-patches/ebtables-v2.0_vs_2.4.18-rc1.001.diff
@@ -0,0 +1,1152 @@
+--- linux/net/core/dev.c Wed Jul 31 19:15:22 2002
++++ ebt2.0-rc1/net/core/dev.c Wed Jul 31 19:04:30 2002
+@@ -1385,13 +1385,6 @@
+
+ #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
+ int (*br_handle_frame_hook)(struct sk_buff *skb) = NULL;
+-#if defined(CONFIG_BRIDGE_EBT_BROUTE) || \
+- defined(CONFIG_BRIDGE_EBT_BROUTE_MODULE)
+-unsigned int (*broute_decision) (unsigned int hook, struct sk_buff **pskb,
+- const struct net_device *in,
+- const struct net_device *out,
+- int (*okfn)(struct sk_buff *)) = NULL;
+-#endif
+ #endif
+
+ static __inline__ int handle_bridge(struct sk_buff *skb,
+--- linux/net/bridge/br.c Wed Jul 31 19:10:53 2002
++++ ebt2.0-rc1/net/bridge/br.c Wed Jul 31 19:04:30 2002
+@@ -28,6 +28,14 @@
+ #include "../atm/lec.h"
+ #endif
+
++#if defined(CONFIG_BRIDGE_EBT_BROUTE) || \
++ defined(CONFIG_BRIDGE_EBT_BROUTE_MODULE)
++unsigned int (*broute_decision) (unsigned int hook, struct sk_buff **pskb,
++ const struct net_device *in,
++ const struct net_device *out,
++ int (*okfn)(struct sk_buff *)) = NULL;
++#endif
++
+ void br_dec_use_count()
+ {
+ MOD_DEC_USE_COUNT;
+@@ -82,7 +90,12 @@
+ #endif
+ }
+
++#if defined(CONFIG_BRIDGE_EBT_BROUTE) || \
++ defined(CONFIG_BRIDGE_EBT_BROUTE_MODULE)
++EXPORT_SYMBOL(broute_decision);
++#else
+ EXPORT_NO_SYMBOLS;
++#endif
+
+ module_init(br_init)
+ module_exit(br_deinit)
+--- linux/net/bridge/Makefile Wed Jul 31 19:10:53 2002
++++ ebt2.0-rc1/net/bridge/Makefile Wed Jul 31 19:04:30 2002
+@@ -7,6 +7,12 @@
+ #
+ # Note 2! The CFLAGS definition is now in the main makefile...
+
++ifneq ($(CONFIG_BRIDGE_EBT_BROUTE),n)
++ifneq ($(CONFIG_BRIDGE_EBT_BROUTE),)
++export-objs := br.o
++endif
++endif
++
+ O_TARGET := bridge.o
+ obj-y := br.o br_device.o br_fdb.o br_forward.o br_if.o br_input.o \
+ br_ioctl.o br_notify.o br_stp.o br_stp_bpdu.o \
+--- linux/include/linux/netfilter_bridge.h Wed Jul 31 19:15:22 2002
++++ ebt2.0-rc1/include/linux/netfilter_bridge.h Wed Jul 31 19:04:30 2002
+@@ -28,8 +28,7 @@
+ NF_BR_PRI_FILTER_OTHER = 200,
+ NF_BR_PRI_NAT_DST_BRIDGED = -300,
+ NF_BR_PRI_NAT_DST_OTHER = 100,
+- NF_BR_PRI_NAT_SRC_BRIDGED = -100,
+- NF_BR_PRI_NAT_SRC_OTHER = 300,
++ NF_BR_PRI_NAT_SRC = 300,
+ NF_BR_PRI_LAST = INT_MAX,
+ };
+
+--- linux/net/netsyms.c Wed Jul 31 19:15:22 2002
++++ ebt2.0-rc1/net/netsyms.c Mon Feb 25 20:38:14 2002
+@@ -228,10 +228,6 @@
+
+ #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
+ EXPORT_SYMBOL(br_handle_frame_hook);
+-#if defined(CONFIG_BRIDGE_EBT_BROUTE) || \
+- defined(CONFIG_BRIDGE_EBT_BROUTE_MODULE)
+-EXPORT_SYMBOL(broute_decision);
+-#endif
+ #ifdef CONFIG_INET
+ EXPORT_SYMBOL(br_ioctl_hook);
+ #endif
+--- linux/net/Makefile Wed Jul 31 19:15:22 2002
++++ ebt2.0-rc1/net/Makefile Wed Jul 31 19:04:30 2002
+@@ -28,7 +28,7 @@
+ endif
+
+ ifneq ($(CONFIG_BRIDGE),n)
+-ifneq ($CONFIG_BRIDGE),)
++ifneq ($(CONFIG_BRIDGE),)
+ subdir-$(CONFIG_BRIDGE) += bridge/netfilter
+ endif
+ endif
+--- linux/net/bridge/netfilter/Makefile Wed Jul 31 19:15:22 2002
++++ ebt2.0-rc1/net/bridge/netfilter/Makefile Wed Jul 31 19:04:30 2002
+@@ -9,7 +9,7 @@
+
+ O_TARGET := netfilter.o
+
+-export-objs = ebtables.o
++export-objs := ebtables.o
+
+ obj-$(CONFIG_BRIDGE_EBT) += ebtables.o
+ obj-$(CONFIG_BRIDGE_EBT_T_FILTER) += ebtable_filter.o
+@@ -19,8 +19,10 @@
+ obj-$(CONFIG_BRIDGE_EBT_IPF) += ebt_ip.o
+ obj-$(CONFIG_BRIDGE_EBT_ARPF) += ebt_arp.o
+ obj-$(CONFIG_BRIDGE_EBT_VLANF) += ebt_vlan.o
++obj-$(CONFIG_BRIDGE_EBT_MARKF) += ebt_mark_m.o
+ obj-$(CONFIG_BRIDGE_EBT_LOG) += ebt_log.o
+ obj-$(CONFIG_BRIDGE_EBT_SNAT) += ebt_snat.o
+ obj-$(CONFIG_BRIDGE_EBT_DNAT) += ebt_dnat.o
+ obj-$(CONFIG_BRIDGE_EBT_REDIRECT) += ebt_redirect.o
++obj-$(CONFIG_BRIDGE_EBT_MARK_T) += ebt_mark.o
+ include $(TOPDIR)/Rules.make
+--- linux/net/bridge/netfilter/Config.in Wed Jul 31 19:15:22 2002
++++ ebt2.0-rc1/net/bridge/netfilter/Config.in Wed Jul 31 19:04:30 2002
+@@ -9,8 +9,10 @@
+ dep_tristate ' ebt: IP filter support' CONFIG_BRIDGE_EBT_IPF $CONFIG_BRIDGE_EBT
+ dep_tristate ' ebt: ARP filter support' CONFIG_BRIDGE_EBT_ARPF $CONFIG_BRIDGE_EBT
+ dep_tristate ' ebt: 802.1Q VLAN filter support (EXPERIMENTAL)' CONFIG_BRIDGE_EBT_VLANF $CONFIG_BRIDGE_EBT
++dep_tristate ' ebt: mark filter support' CONFIG_BRIDGE_EBT_MARKF $CONFIG_BRIDGE_EBT
+ dep_tristate ' ebt: snat target support' CONFIG_BRIDGE_EBT_SNAT $CONFIG_BRIDGE_EBT
+ dep_tristate ' ebt: dnat target support' CONFIG_BRIDGE_EBT_DNAT $CONFIG_BRIDGE_EBT
+ dep_tristate ' ebt: redirect target support' CONFIG_BRIDGE_EBT_REDIRECT $CONFIG_BRIDGE_EBT
++dep_tristate ' ebt: mark target support' CONFIG_BRIDGE_EBT_MARK_T $CONFIG_BRIDGE_EBT
+ dep_tristate ' Bridge: ethernet database' CONFIG_BRIDGE_DB $CONFIG_BRIDGE
+
+--- linux/net/bridge/netfilter/ebtable_nat.c Wed Jul 31 19:15:22 2002
++++ ebt2.0-rc1/net/bridge/netfilter/ebtable_nat.c Wed Jul 31 19:04:30 2002
+@@ -42,16 +42,6 @@
+ RW_LOCK_UNLOCKED, check, NULL
+ };
+
+-// used for snat to know if the frame comes from FORWARD or LOCAL_OUT.
+-// needed because of the bridge-nf patch (that allows use of iptables
+-// on bridged traffic)
+-// if the packet is routed, we want the ebtables stuff on POSTROUTING
+-// to be executed _after_ the iptables stuff. when it's bridged, it's
+-// the way around
+-static struct net_device __fake_net_device = {
+- hard_header_len: ETH_HLEN
+-};
+-
+ static unsigned int
+ ebt_nat_dst (unsigned int hook, struct sk_buff **pskb,
+ const struct net_device *in, const struct net_device *out,
+@@ -60,50 +50,11 @@
+ return ebt_do_table(hook, pskb, in, out, &frame_nat);
+ }
+
+-// let snat know this frame is routed
+-static unsigned int ebt_clear_physin (unsigned int hook, struct sk_buff **pskb,
+- const struct net_device *in, const struct net_device *out,
+- int (*okfn)(struct sk_buff *))
+-{
+- (*pskb)->physindev = NULL;
+- return NF_ACCEPT;
+-}
+-
+-// let snat know this frame is bridged
+-static unsigned int ebt_set_physin (unsigned int hook, struct sk_buff **pskb,
+- const struct net_device *in, const struct net_device *out,
+- int (*okfn)(struct sk_buff *))
+-{
+- (*pskb)->physindev = &__fake_net_device;
+- return NF_ACCEPT;
+-}
+-
+ static unsigned int ebt_nat_src (unsigned int hook, struct sk_buff **pskb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+ {
+- // this is a routed packet
+- if ((*pskb)->physindev == NULL)
+- return NF_ACCEPT;
+- if ((*pskb)->physindev != &__fake_net_device)
+- printk("ebtables (br_nat_src): physindev hack "
+- "doesn't work - BUG\n");
+-
+- return ebt_do_table(hook, pskb, in, out, &frame_nat);
+-}
+-
+-static unsigned int ebt_nat_src_route (unsigned int hook, struct sk_buff **pskb,
+- const struct net_device *in, const struct net_device *out,
+- int (*okfn)(struct sk_buff *))
+-{
+- // this is a bridged packet
+- if ((*pskb)->physindev == &__fake_net_device)
+- return NF_ACCEPT;
+- if ((*pskb)->physindev)
+- printk("ebtables (br_nat_src_route): physindev hack "
+- "doesn't work - BUG\n");
+-
+ return ebt_do_table(hook, pskb, in, out, &frame_nat);
+ }
+
+@@ -111,15 +62,9 @@
+ { { NULL, NULL }, ebt_nat_dst, PF_BRIDGE, NF_BR_LOCAL_OUT,
+ NF_BR_PRI_NAT_DST_OTHER},
+ { { NULL, NULL }, ebt_nat_src, PF_BRIDGE, NF_BR_POST_ROUTING,
+- NF_BR_PRI_NAT_SRC_BRIDGED},
+- { { NULL, NULL }, ebt_nat_src_route, PF_BRIDGE, NF_BR_POST_ROUTING,
+- NF_BR_PRI_NAT_SRC_OTHER},
++ NF_BR_PRI_NAT_SRC},
+ { { NULL, NULL }, ebt_nat_dst, PF_BRIDGE, NF_BR_PRE_ROUTING,
+ NF_BR_PRI_NAT_DST_BRIDGED},
+- { { NULL, NULL }, ebt_clear_physin, PF_BRIDGE, NF_BR_LOCAL_OUT,
+- NF_BR_PRI_FILTER_OTHER + 1},
+- { { NULL, NULL }, ebt_set_physin, PF_BRIDGE, NF_BR_FORWARD,
+- NF_BR_PRI_FILTER_OTHER + 1}
+ };
+
+ static int __init init(void)
+--- linux/net/bridge/netfilter/ebt_redirect.c Wed Jul 31 19:15:22 2002
++++ ebt2.0-rc1/net/bridge/netfilter/ebt_redirect.c Wed Jul 31 19:04:30 2002
+@@ -38,6 +38,10 @@
+ {
+ struct ebt_redirect_info *infostuff = (struct ebt_redirect_info *) data;
+
++ if ((hookmask & (1 << NF_BR_NUMHOOKS)) &&
++ infostuff->target == EBT_RETURN)
++ return -EINVAL;
++ hookmask &= ~(1 << NF_BR_NUMHOOKS);
+ if ( (strcmp(tablename, "nat") || hookmask & ~(1 << NF_BR_PRE_ROUTING)) &&
+ (strcmp(tablename, "broute") || hookmask & ~(1 << NF_BR_BROUTING)) )
+ return -EINVAL;
+--- /dev/null Thu Aug 24 11:00:32 2000
++++ ebt2.0-rc1/net/bridge/netfilter/ebt_mark.c Wed Jul 31 19:04:30 2002
+@@ -0,0 +1,73 @@
++/*
++ * ebt_mark_t
++ *
++ * Authors:
++ * Bart De Schuymer <bart.de.schuymer@pandora.be>
++ *
++ * July, 2002
++ *
++ */
++
++// The mark target can be used in any chain
++// I believe adding a mangle table just for marking is total overkill
++// Marking a frame doesn't really change anything in the frame anyway
++// The target member of the struct ebt_vlan_info provides the same
++// functionality as a separate table
++
++#include <linux/netfilter_bridge/ebtables.h>
++#include <linux/netfilter_bridge/ebt_mark_t.h>
++#include <linux/netfilter_bridge.h>
++#include <linux/skbuff.h>
++#include <linux/module.h>
++#include <net/sock.h>
++#include "../br_private.h"
++
++static int ebt_target_mark(struct sk_buff **pskb, unsigned int hooknr,
++ const struct net_device *in, const struct net_device *out,
++ const void *data, unsigned int datalen)
++{
++ struct ebt_mark_t_info *infostuff = (struct ebt_mark_t_info *) data;
++
++ if ((*pskb)->nfmark != infostuff->mark) {
++ (*pskb)->nfmark = infostuff->mark;
++ (*pskb)->nfcache |= NFC_ALTERED;
++ }
++ return infostuff->target;
++}
++
++static int ebt_target_mark_check(const char *tablename, unsigned int hookmask,
++ const struct ebt_entry *e, void *data, unsigned int datalen)
++{
++ struct ebt_mark_t_info *infostuff = (struct ebt_mark_t_info *) data;
++
++ if ((hookmask & (1 << NF_BR_NUMHOOKS)) &&
++ infostuff->target == EBT_RETURN)
++ return -EINVAL;
++ hookmask &= ~(1 << NF_BR_NUMHOOKS);
++ if (datalen != sizeof(struct ebt_mark_t_info))
++ return -EINVAL;
++ if (infostuff->target < -NUM_STANDARD_TARGETS || infostuff->target >= 0)
++ return -EINVAL;
++ return 0;
++}
++
++static struct ebt_target mark_target =
++{
++ {NULL, NULL}, EBT_MARK_TARGET, ebt_target_mark,
++ ebt_target_mark_check, NULL, THIS_MODULE
++};
++
++static int __init init(void)
++{
++ return ebt_register_target(&mark_target);
++}
++
++static void __exit fini(void)
++{
++ ebt_unregister_target(&mark_target);
++}
++
++module_init(init);
++module_exit(fini);
++EXPORT_NO_SYMBOLS;
++MODULE_LICENSE("GPL");
+--- /dev/null Thu Aug 24 11:00:32 2000
++++ ebt2.0-rc1/net/bridge/netfilter/ebt_mark_m.c Wed Jul 31 19:04:30 2002
+@@ -0,0 +1,62 @@
++/*
++ * ebt_mark_m
++ *
++ * Authors:
++ * Bart De Schuymer <bart.de.schuymer@pandora.be>
++ *
++ * July, 2002
++ *
++ */
++
++#include <linux/netfilter_bridge/ebtables.h>
++#include <linux/netfilter_bridge/ebt_mark_m.h>
++#include <linux/module.h>
++
++static int ebt_filter_mark(const struct sk_buff *skb,
++ const struct net_device *in, const struct net_device *out, const void *data,
++ unsigned int datalen, const struct ebt_counter *c)
++{
++ struct ebt_mark_m_info *info = (struct ebt_mark_m_info *) data;
++
++ if (info->bitmask & EBT_MARK_OR)
++ return !(!!(skb->nfmark & info->mask) ^ info->invert);
++ return !(((skb->nfmark & info->mask) == info->mark) ^ info->invert);
++}
++
++static int ebt_mark_check(const char *tablename, unsigned int hookmask,
++ const struct ebt_entry *e, void *data, unsigned int datalen)
++{
++ struct ebt_mark_m_info *info = (struct ebt_mark_m_info *) data;
++
++ if (info->bitmask & ~EBT_MARK_MASK)
++ return -EINVAL;
++ if ((info->bitmask & EBT_MARK_OR) && (info->bitmask & EBT_MARK_AND))
++ return -EINVAL;
++ if (!info->bitmask)
++ return -EINVAL;
++ if (datalen != sizeof(struct ebt_mark_m_info)) {
++ return -EINVAL;
++ }
++ return 0;
++}
++
++static struct ebt_match filter_mark =
++{
++ {NULL, NULL}, EBT_MARK_MATCH, ebt_filter_mark, ebt_mark_check, NULL,
++ THIS_MODULE
++};
++
++static int __init init(void)
++{
++ return ebt_register_match(&filter_mark);
++}
++
++static void __exit fini(void)
++{
++ ebt_unregister_match(&filter_mark);
++}
++
++module_init(init);
++module_exit(fini);
++EXPORT_NO_SYMBOLS;
++MODULE_LICENSE("GPL");
+--- linux/net/bridge/netfilter/ebt_snat.c Wed Jul 31 19:15:22 2002
++++ ebt2.0-rc1/net/bridge/netfilter/ebt_snat.c Wed Jul 31 19:04:30 2002
+@@ -31,6 +31,10 @@
+ {
+ struct ebt_nat_info *infostuff = (struct ebt_nat_info *) data;
+
++ if ((hookmask & (1 << NF_BR_NUMHOOKS)) &&
++ infostuff->target == EBT_RETURN)
++ return -EINVAL;
++ hookmask &= ~(1 << NF_BR_NUMHOOKS);
+ if (strcmp(tablename, "nat"))
+ return -EINVAL;
+ if (datalen != sizeof(struct ebt_nat_info))
+--- linux/net/bridge/netfilter/ebt_dnat.c Wed Jul 31 19:15:22 2002
++++ ebt2.0-rc1/net/bridge/netfilter/ebt_dnat.c Wed Jul 31 19:04:30 2002
+@@ -31,6 +31,10 @@
+ {
+ struct ebt_nat_info *infostuff = (struct ebt_nat_info *) data;
+
++ if ((hookmask & (1 << NF_BR_NUMHOOKS)) &&
++ infostuff->target == EBT_RETURN)
++ return -EINVAL;
++ hookmask &= ~(1 << NF_BR_NUMHOOKS);
+ if ( (strcmp(tablename, "nat") ||
+ (hookmask & ~((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT)))) &&
+ (strcmp(tablename, "broute") || hookmask & ~(1 << NF_BR_BROUTING)) )
+--- linux/net/bridge/netfilter/ebtables.c Wed Jul 31 19:15:22 2002
++++ ebt2.0-rc1/net/bridge/netfilter/ebtables.c Wed Jul 31 19:04:30 2002
+@@ -4,7 +4,7 @@
+ * Author:
+ * Bart De Schuymer <bart.de.schuymer@pandora.be>
+ *
+- * ebtables.c,v 2.0, April, 2002
++ * ebtables.c,v 2.0, July, 2002
+ *
+ * This code is stongly inspired on the iptables code which is
+ * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
+@@ -50,6 +50,21 @@
+ ": out of memory: "format, ## args)
+ // #define MEMPRINT(format, args...)
+
++
++
++// Each cpu has its own set of counters, so there is no need for write_lock in
++// the softirq
++// For reading or updating the counters, the user context needs to
++// get a write_lock
++
++// The size of each set of counters is altered to get cache alignment
++#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
++#define COUNTER_OFFSET(n) (SMP_ALIGN(n * sizeof(struct ebt_counter)))
++#define COUNTER_BASE(c, n, cpu) ((struct ebt_counter *)(((char *)c) + \
++ COUNTER_OFFSET(n) * cpu))
++
++
++
+ static void print_string(char *str);
+
+ static DECLARE_MUTEX(ebt_mutex);
+@@ -62,10 +77,8 @@
+ { {NULL, NULL}, EBT_STANDARD_TARGET, NULL, NULL, NULL, NULL};
+
+ static inline int ebt_do_watcher (struct ebt_entry_watcher *w,
+- const struct sk_buff *skb,
+- const struct net_device *in,
+- const struct net_device *out,
+- const struct ebt_counter *c)
++ const struct sk_buff *skb, const struct net_device *in,
++ const struct net_device *out, const struct ebt_counter *c)
+ {
+ w->u.watcher->watcher(skb, in, out, w->data,
+ w->watcher_size, c);
+@@ -74,10 +87,8 @@
+ }
+
+ static inline int ebt_do_match (struct ebt_entry_match *m,
+- const struct sk_buff *skb,
+- const struct net_device *in,
+- const struct net_device *out,
+- const struct ebt_counter *c)
++ const struct sk_buff *skb, const struct net_device *in,
++ const struct net_device *out, const struct ebt_counter *c)
+ {
+ return m->u.match->match(skb, in, out, m->data,
+ m->match_size, c);
+@@ -89,7 +100,51 @@
+ return 0;
+ if (!device)
+ return 1;
+- return strncmp(entry, device->name, IFNAMSIZ);
++ return !!strncmp(entry, device->name, IFNAMSIZ);
++}
++
++#define FWINV(bool,invflg) ((bool) ^ !!(p->invflags & invflg))
++// process standard matches
++static inline int ebt_basic_match(struct ebt_entry *p, struct ethhdr *h,
++ const struct net_device *in, const struct net_device *out)
++{
++ int verdict, i;
++
++ if (p->bitmask & EBT_802_3) {
++ if (FWINV(ntohs(h->h_proto) >= 1536, EBT_IPROTO))
++ return 1;
++ } else if (!(p->bitmask & EBT_NOPROTO) &&
++ FWINV(p->ethproto != h->h_proto, EBT_IPROTO))
++ return 1;
++
++ if (FWINV(ebt_dev_check(p->in, in), EBT_IIN))
++ return 1;
++ if (FWINV(ebt_dev_check(p->out, out), EBT_IOUT))
++ return 1;
++ if ((!in || !in->br_port) ? 0 : FWINV(ebt_dev_check(
++ p->logical_in, &in->br_port->br->dev), EBT_ILOGICALIN))
++ return 1;
++ if ((!out || !out->br_port) ? 0 : FWINV(ebt_dev_check(
++ (p->logical_out), &out->br_port->br->dev), EBT_ILOGICALOUT))
++ return 1;
++
++ if (p->bitmask & EBT_SOURCEMAC) {
++ verdict = 0;
++ for (i = 0; i < 6; i++)
++ verdict |= (h->h_source[i] ^ p->sourcemac[i]) &
++ p->sourcemsk[i];
++ if (FWINV(verdict != 0, EBT_ISOURCE) )
++ return 1;
++ }
++ if (p->bitmask & EBT_DESTMAC) {
++ verdict = 0;
++ for (i = 0; i < 6; i++)
++ verdict |= (h->h_dest[i] ^ p->destmac[i]) &
++ p->destmsk[i];
++ if (FWINV(verdict != 0, EBT_IDEST) )
++ return 1;
++ }
++ return 0;
+ }
+
+ // Do some firewalling
+@@ -97,9 +152,9 @@
+ const struct net_device *in, const struct net_device *out,
+ struct ebt_table *table)
+ {
+- int i, j, nentries;
++ int i, nentries;
+ struct ebt_entry *point;
+- struct ebt_counter *counter_base;
++ struct ebt_counter *counter_base, *cb_base;
+ struct ebt_entry_target *t;
+ int verdict, sp = 0;
+ struct ebt_chainstack *cs;
+@@ -108,6 +163,8 @@
+ struct ebt_table_info *private = table->private;
+
+ read_lock_bh(&table->lock);
++ cb_base = COUNTER_BASE(private->counters, private->nentries, \
++ cpu_number_map(smp_processor_id()));
+ if (private->chainstack)
+ cs = private->chainstack[cpu_number_map(smp_processor_id())];
+ else
+@@ -115,117 +172,83 @@
+ chaininfo = private->hook_entry[hook];
+ nentries = private->hook_entry[hook]->nentries;
+ point = (struct ebt_entry *)(private->hook_entry[hook]->data);
+- #define cb_base table->private->counters + \
+- cpu_number_map(smp_processor_id()) * table->private->nentries
+ counter_base = cb_base + private->hook_entry[hook]->counter_offset;
+- #define FWINV(bool,invflg) ((bool) ^ !!(point->invflags & invflg))
+ // base for chain jumps
+ base = (char *)chaininfo;
+ i = 0;
+- while (i < nentries) {
+- if ( ( point->bitmask & EBT_NOPROTO ||
+- FWINV(point->ethproto == ((**pskb).mac.ethernet)->h_proto,
+- EBT_IPROTO)
+- || FWINV(ntohs(((**pskb).mac.ethernet)->h_proto) < 1536 &&
+- (point->bitmask & EBT_802_3), EBT_IPROTO) )
+- && FWINV(!ebt_dev_check((char *)(point->in), in), EBT_IIN)
+- && FWINV(!ebt_dev_check((char *)(point->out), out), EBT_IOUT)
+- && ((!in || !in->br_port) ? 1 : FWINV(!ebt_dev_check((char *)
+- (point->logical_in), &in->br_port->br->dev), EBT_ILOGICALIN))
+- && ((!out || !out->br_port) ? 1 :
+- FWINV(!ebt_dev_check((char *)
+- (point->logical_out), &out->br_port->br->dev), EBT_ILOGICALOUT))
+-
+- ) {
+- if (point->bitmask & EBT_SOURCEMAC) {
+- verdict = 0;
+- for (j = 0; j < 6; j++)
+- verdict |= (((**pskb).mac.ethernet)->
+- h_source[j] ^ point->sourcemac[j]) &
+- point->sourcemsk[j];
+- if (FWINV(!!verdict, EBT_ISOURCE) )
+- goto letscontinue;
+- }
++ while (i < nentries) {
++ if (ebt_basic_match(point, (**pskb).mac.ethernet, in, out))
++ goto letscontinue;
+
+- if (point->bitmask & EBT_DESTMAC) {
+- verdict = 0;
+- for (j = 0; j < 6; j++)
+- verdict |= (((**pskb).mac.ethernet)->
+- h_dest[j] ^ point->destmac[j]) &
+- point->destmsk[j];
+- if (FWINV(!!verdict, EBT_IDEST) )
+- goto letscontinue;
+- }
++ if (EBT_MATCH_ITERATE(point, ebt_do_match, *pskb, in,
++ out, counter_base + i) != 0)
++ goto letscontinue;
+
+- if (EBT_MATCH_ITERATE(point, ebt_do_match, *pskb, in,
+- out, counter_base + i) != 0)
+- goto letscontinue;
++ // increase counter
++ (*(counter_base + i)).pcnt++;
+
+- // increase counter
+- (*(counter_base + i)).pcnt++;
++ // these should only watch: not modify, nor tell us
++ // what to do with the packet
++ EBT_WATCHER_ITERATE(point, ebt_do_watcher, *pskb, in,
++ out, counter_base + i);
+
+- // these should only watch: not modify, nor tell us
+- // what to do with the packet
+- EBT_WATCHER_ITERATE(point, ebt_do_watcher, *pskb, in,
+- out, counter_base + i);
+-
+- t = (struct ebt_entry_target *)
+- (((char *)point) + point->target_offset);
+- // standard target
+- if (!t->u.target->target)
+- verdict =
+- ((struct ebt_standard_target *)t)->verdict;
+- else
+- verdict = t->u.target->target(pskb, hook,
+- in, out, t->data, t->target_size);
+- if (verdict == EBT_ACCEPT) {
+- read_unlock_bh(&table->lock);
+- return NF_ACCEPT;
+- }
+- if (verdict == EBT_DROP) {
+- read_unlock_bh(&table->lock);
+- return NF_DROP;
+- }
+- if (verdict == EBT_RETURN) {
++ t = (struct ebt_entry_target *)
++ (((char *)point) + point->target_offset);
++ // standard target
++ if (!t->u.target->target)
++ verdict = ((struct ebt_standard_target *)t)->verdict;
++ else
++ verdict = t->u.target->target(pskb, hook,
++ in, out, t->data, t->target_size);
++ if (verdict == EBT_ACCEPT) {
++ read_unlock_bh(&table->lock);
++ return NF_ACCEPT;
++ }
++ if (verdict == EBT_DROP) {
++ read_unlock_bh(&table->lock);
++ return NF_DROP;
++ }
++ if (verdict == EBT_RETURN) {
+ letsreturn:
+- if (sp == 0)
+- // act like this is EBT_CONTINUE
+- goto letscontinue;
+- sp--;
+- // put all the local variables right
+- i = cs[sp].n;
+- chaininfo = cs[sp].chaininfo;
+- nentries = chaininfo->nentries;
+- point = cs[sp].e;
+- counter_base = cb_base +
+- chaininfo->counter_offset;
+- continue;
+- }
+- if (verdict == EBT_CONTINUE)
++ if (sp == 0) {
++ BUGPRINT("RETURN on base chain");
++ // act like this is EBT_CONTINUE
+ goto letscontinue;
+- if (verdict < 0) {
+- BUGPRINT("bogus standard verdict\n");
+- read_unlock_bh(&table->lock);
+- return NF_DROP;
+- }
+- // jump to a udc
+- cs[sp].n = i + 1;
+- cs[sp].chaininfo = chaininfo;
+- cs[sp].e = (struct ebt_entry *)
+- (((char *)point) + point->next_offset);
+- i = 0;
+- chaininfo = (struct ebt_entries *) (base + verdict);
+- if (chaininfo->distinguisher) {
+- BUGPRINT("jump to non-chain\n");
+- read_unlock_bh(&table->lock);
+- return NF_DROP;
+ }
++ sp--;
++ // put all the local variables right
++ i = cs[sp].n;
++ chaininfo = cs[sp].chaininfo;
+ nentries = chaininfo->nentries;
+- point = (struct ebt_entry *)chaininfo->data;
+- counter_base = cb_base + chaininfo->counter_offset;
+- sp++;
++ point = cs[sp].e;
++ counter_base = cb_base +
++ chaininfo->counter_offset;
+ continue;
+ }
++ if (verdict == EBT_CONTINUE)
++ goto letscontinue;
++ if (verdict < 0) {
++ BUGPRINT("bogus standard verdict\n");
++ read_unlock_bh(&table->lock);
++ return NF_DROP;
++ }
++ // jump to a udc
++ cs[sp].n = i + 1;
++ cs[sp].chaininfo = chaininfo;
++ cs[sp].e = (struct ebt_entry *)
++ (((char *)point) + point->next_offset);
++ i = 0;
++ chaininfo = (struct ebt_entries *) (base + verdict);
++ if (chaininfo->distinguisher) {
++ BUGPRINT("jump to non-chain\n");
++ read_unlock_bh(&table->lock);
++ return NF_DROP;
++ }
++ nentries = chaininfo->nentries;
++ point = (struct ebt_entry *)chaininfo->data;
++ counter_base = cb_base + chaininfo->counter_offset;
++ sp++;
++ continue;
+ letscontinue:
+ point = (struct ebt_entry *)
+ (((char *)point) + point->next_offset);
+@@ -284,7 +307,6 @@
+ request_module(modulename);
+ ret = find_inlist_lock_noload(head, name, error, mutex);
+ }
+-
+ return ret;
+ }
+ #endif
+@@ -320,9 +342,12 @@
+ struct ebt_match *match;
+ int ret;
+
++ if (((char *)m) + m->match_size + sizeof(struct ebt_entry_match) >
++ ((char *)e) + e->watchers_offset)
++ return -EINVAL;
+ m->u.name[EBT_FUNCTION_MAXNAMELEN - 1] = '\0';
+ match = find_match_lock(m->u.name, &ret, &ebt_mutex);
+- if (!match)
++ if (!match)
+ return ret;
+ m->u.match = match;
+ if (match->me)
+@@ -346,9 +371,12 @@
+ struct ebt_watcher *watcher;
+ int ret;
+
++ if (((char *)w) + w->watcher_size + sizeof(struct ebt_entry_watcher) >
++ ((char *)e) + e->target_offset)
++ return -EINVAL;
+ w->u.name[EBT_FUNCTION_MAXNAMELEN - 1] = '\0';
+ watcher = find_watcher_lock(w->u.name, &ret, &ebt_mutex);
+- if (!watcher)
++ if (!watcher)
+ return ret;
+ w->u.watcher = watcher;
+ if (watcher->me)
+@@ -547,14 +575,16 @@
+ else
+ break;
+ }
++ // (1 << NF_BR_NUMHOOKS) tells the check functions the rule is on
++ // a base chain
+ if (i < NF_BR_NUMHOOKS)
+- hookmask = (1 << hook);
++ hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
+ else {
+ for (i = 0; i < udc_cnt; i++)
+ if ((char *)(cl_s[i].cs.chaininfo) > (char *)e)
+ break;
+ if (i == 0)
+- hookmask = (1 << hook);
++ hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
+ else
+ hookmask = cl_s[i - 1].hookmask;
+ }
+@@ -589,9 +619,10 @@
+ ret = -EFAULT;
+ goto cleanup_watchers;
+ }
+- } else if (t->u.target->check &&
+- t->u.target->check(name, hookmask, e, t->data,
+- t->target_size) != 0) {
++ } else if ((e->target_offset + t->target_size +
++ sizeof(struct ebt_entry_target) > e->next_offset) ||
++ (t->u.target->check &&
++ t->u.target->check(name, hookmask, e, t->data, t->target_size) != 0)){
+ if (t->u.target->me)
+ __MOD_DEC_USE_COUNT(t->u.target->me);
+ ret = -EFAULT;
+@@ -611,7 +642,7 @@
+ {
+ struct ebt_entry_target *t;
+
+- if (e->bitmask == 0)
++ if ((e->bitmask & EBT_ENTRY_OR_ENTRIES) == 0)
+ return 0;
+ // we're done
+ if (cnt && (*cnt)-- == 0)
+@@ -643,7 +674,8 @@
+ // put back values of the time when this chain was called
+ e = cl_s[chain_nr].cs.e;
+ if (cl_s[chain_nr].from != -1)
+- nentries = cl_s[cl_s[chain_nr].from].cs.chaininfo->nentries;
++ nentries =
++ cl_s[cl_s[chain_nr].from].cs.chaininfo->nentries;
+ else
+ nentries = chain->nentries;
+ pos = cl_s[chain_nr].cs.n;
+@@ -679,6 +711,7 @@
+ BUGPRINT("loop\n");
+ return -1;
+ }
++ // this can't be 0, so the above test is correct
+ cl_s[i].cs.n = pos + 1;
+ pos = 0;
+ cl_s[i].cs.e = ((void *)e + e->next_offset);
+@@ -784,7 +817,7 @@
+ vfree(newinfo->chainstack[--i]);
+ vfree(newinfo->chainstack);
+ newinfo->chainstack = NULL;
+- break;
++ return -ENOMEM;
+ }
+ }
+
+@@ -824,7 +857,6 @@
+ // beginning of a chain. This can only occur in chains that
+ // are not accessible from any base chains, so we don't care.
+
+- // we just don't trust anything
+ repl->name[EBT_TABLE_MAXNAMELEN - 1] = '\0';
+ // used to know what we need to clean up if something goes wrong
+ i = 0;
+@@ -841,27 +873,27 @@
+ }
+
+ // called under write_lock
+-static inline void get_counters(struct ebt_counter *oldcounters,
++static void get_counters(struct ebt_counter *oldcounters,
+ struct ebt_counter *counters, unsigned int nentries)
+ {
+- int i, cpu, counter_base;
++ int i, cpu;
++ struct ebt_counter *counter_base;
+
+ // counters of cpu 0
+ memcpy(counters, oldcounters,
+ sizeof(struct ebt_counter) * nentries);
+ // add other counters to those of cpu 0
+ for (cpu = 1; cpu < smp_num_cpus; cpu++) {
+- counter_base = cpu * nentries;
++ counter_base = COUNTER_BASE(oldcounters, nentries, cpu);
+ for (i = 0; i < nentries; i++)
+- counters[i].pcnt +=
+- oldcounters[counter_base + i].pcnt;
++ counters[i].pcnt += counter_base[i].pcnt;
+ }
+ }
+
+ // replace the table
+ static int do_replace(void *user, unsigned int len)
+ {
+- int ret, i;
++ int ret, i, countersize;
+ struct ebt_table_info *newinfo;
+ struct ebt_replace tmp;
+ struct ebt_table *t;
+@@ -869,7 +901,7 @@
+ // used to be able to unlock earlier
+ struct ebt_table_info *table;
+
+- if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
++ if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
+ return -EFAULT;
+
+ if (len != sizeof(tmp) + tmp.entries_size) {
+@@ -881,28 +913,19 @@
+ BUGPRINT("Entries_size never zero\n");
+ return -EINVAL;
+ }
++ countersize = COUNTER_OFFSET(tmp.nentries) * smp_num_cpus;
+ newinfo = (struct ebt_table_info *)
+- vmalloc(sizeof(struct ebt_table_info));
++ vmalloc(sizeof(struct ebt_table_info) + countersize);
+ if (!newinfo)
+ return -ENOMEM;
+
+- if (tmp.nentries) {
+- newinfo->counters = (struct ebt_counter *)vmalloc(
+- sizeof(struct ebt_counter) * tmp.nentries * smp_num_cpus);
+- if (!newinfo->counters) {
+- ret = -ENOMEM;
+- goto free_newinfo;
+- }
+- memset(newinfo->counters, 0,
+- sizeof(struct ebt_counter) * tmp.nentries * smp_num_cpus);
+- }
+- else
+- newinfo->counters = NULL;
++ if (countersize)
++ memset(newinfo->counters, 0, countersize);
+
+ newinfo->entries = (char *)vmalloc(tmp.entries_size);
+ if (!newinfo->entries) {
+ ret = -ENOMEM;
+- goto free_counters;
++ goto free_newinfo;
+ }
+ if (copy_from_user(
+ newinfo->entries, tmp.entries, tmp.entries_size) != 0) {
+@@ -933,7 +956,7 @@
+
+ t = find_table_lock(tmp.name, &ret, &ebt_mutex);
+ if (!t)
+- goto free_unlock;
++ goto free_iterate;
+
+ // the table doesn't like it
+ if (t->check && (ret = t->check(newinfo, tmp.valid_hooks)))
+@@ -974,8 +997,6 @@
+ ebt_cleanup_entry, NULL);
+
+ vfree(table->entries);
+- if (table->counters)
+- vfree(table->counters);
+ if (table->chainstack) {
+ for (i = 0; i < smp_num_cpus; i++)
+ vfree(table->chainstack[i]);
+@@ -989,6 +1010,7 @@
+
+ free_unlock:
+ up(&ebt_mutex);
++free_iterate:
+ EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
+ ebt_cleanup_entry, NULL);
+ free_counterstmp:
+@@ -1003,9 +1025,6 @@
+ free_entries:
+ if (newinfo->entries)
+ vfree(newinfo->entries);
+-free_counters:
+- if (newinfo->counters)
+- vfree(newinfo->counters);
+ free_newinfo:
+ if (newinfo)
+ vfree(newinfo);
+@@ -1090,7 +1109,7 @@
+ int ebt_register_table(struct ebt_table *table)
+ {
+ struct ebt_table_info *newinfo;
+- int ret, i;
++ int ret, i, countersize;
+
+ if (!table || !table->table ||!table->table->entries ||
+ table->table->entries_size == 0 ||
+@@ -1099,8 +1118,9 @@
+ return -EINVAL;
+ }
+
++ countersize = COUNTER_OFFSET(table->table->nentries) * smp_num_cpus;
+ newinfo = (struct ebt_table_info *)
+- vmalloc(sizeof(struct ebt_table_info));
++ vmalloc(sizeof(struct ebt_table_info) + countersize);
+ ret = -ENOMEM;
+ if (!newinfo)
+ return -ENOMEM;
+@@ -1112,24 +1132,15 @@
+ memcpy(newinfo->entries, table->table->entries,
+ table->table->entries_size);
+
+- if (table->table->nentries) {
+- newinfo->counters = (struct ebt_counter *)
+- vmalloc(table->table->nentries *
+- sizeof(struct ebt_counter) * smp_num_cpus);
+- if (!newinfo->counters)
+- goto free_entries;
+- memset(newinfo->counters, 0, table->table->nentries *
+- sizeof(struct ebt_counter) * smp_num_cpus);
+- }
+- else
+- newinfo->counters = NULL;
++ if (countersize)
++ memset(newinfo->counters, 0, countersize);
+
+ // fill in newinfo and parse the entries
+ newinfo->chainstack = NULL;
+ ret = translate_table(table->table, newinfo);
+ if (ret != 0) {
+ BUGPRINT("Translate_table failed\n");
+- goto free_counters;
++ goto free_chainstack;
+ }
+
+ if (table->check && table->check(newinfo, table->valid_hooks)) {
+@@ -1141,7 +1152,7 @@
+ table->lock = RW_LOCK_UNLOCKED;
+ ret = down_interruptible(&ebt_mutex);
+ if (ret != 0)
+- goto free_counters;
++ goto free_chainstack;
+
+ if (list_named_find(&ebt_tables, table->name)) {
+ ret = -EEXIST;
+@@ -1155,15 +1166,12 @@
+ return 0;
+ free_unlock:
+ up(&ebt_mutex);
+-free_counters:
+- if (newinfo->counters)
+- vfree(newinfo->counters);
++free_chainstack:
+ if (newinfo->chainstack) {
+ for (i = 0; i < smp_num_cpus; i++)
+ vfree(newinfo->chainstack[i]);
+ vfree(newinfo->chainstack);
+ }
+-free_entries:
+ vfree(newinfo->entries);
+ free_newinfo:
+ vfree(newinfo);
+@@ -1183,8 +1191,6 @@
+ up(&ebt_mutex);
+ EBT_ENTRY_ITERATE(table->private->entries,
+ table->private->entries_size, ebt_cleanup_entry, NULL);
+- if (table->private->counters)
+- vfree(table->private->counters);
+ if (table->private->entries)
+ vfree(table->private->entries);
+ if (table->private->chainstack) {
+@@ -1219,7 +1225,6 @@
+ }
+
+ hlp.name[EBT_TABLE_MAXNAMELEN - 1] = '\0';
+-
+ t = find_table_lock(hlp.name, &ret, &ebt_mutex);
+ if (!t)
+ goto free_tmp;
+@@ -1344,7 +1349,7 @@
+ counterstmp = (struct ebt_counter *)
+ vmalloc(nentries * sizeof(struct ebt_counter));
+ if (!counterstmp) {
+- BUGPRINT("Couldn't copy counters, out of memory\n");
++ MEMPRINT("Couldn't copy counters, out of memory\n");
+ return -ENOMEM;
+ }
+ write_lock_bh(&t->lock);
+--- linux/include/linux/netfilter_bridge/ebtables.h Wed Jul 31 19:15:22 2002
++++ ebt2.0-rc1/include/linux/netfilter_bridge/ebtables.h Wed Jul 31 19:04:30 2002
+@@ -12,9 +12,9 @@
+
+ #ifndef __LINUX_BRIDGE_EFF_H
+ #define __LINUX_BRIDGE_EFF_H
+-#include <linux/if.h> // IFNAMSIZ
++#include <linux/if.h>
+ #include <linux/netfilter_bridge.h>
+-#include <linux/if_ether.h> // ETH_ALEN
++#include <linux/if_ether.h>
+
+ #define EBT_TABLE_MAXNAMELEN 32
+ #define EBT_CHAIN_MAXNAMELEN EBT_TABLE_MAXNAMELEN
+@@ -46,10 +46,10 @@
+ };
+
+ struct ebt_entries {
+- // this field is always set to zero (including userspace).
++ // this field is always set to zero
+ // See EBT_ENTRY_OR_ENTRIES.
+ // Must be same size as ebt_entry.bitmask
+- __u32 distinguisher;
++ unsigned int distinguisher;
+ // the chain name
+ char name[EBT_CHAIN_MAXNAMELEN];
+ // counter offset for this chain
+@@ -133,27 +133,27 @@
+ // one entry
+ struct ebt_entry {
+ // this needs to be the first field
+- __u32 bitmask;
+- __u32 invflags;
++ unsigned int bitmask;
++ unsigned int invflags;
+ __u16 ethproto;
+ // the physical in-dev
+- __u8 in[IFNAMSIZ];
++ char in[IFNAMSIZ];
+ // the logical in-dev
+- __u8 logical_in[IFNAMSIZ];
++ char logical_in[IFNAMSIZ];
+ // the physical out-dev
+- __u8 out[IFNAMSIZ];
++ char out[IFNAMSIZ];
+ // the logical out-dev
+- __u8 logical_out[IFNAMSIZ];
+- __u8 sourcemac[ETH_ALEN];
+- __u8 sourcemsk[ETH_ALEN];
+- __u8 destmac[ETH_ALEN];
+- __u8 destmsk[ETH_ALEN];
++ char logical_out[IFNAMSIZ];
++ unsigned char sourcemac[ETH_ALEN];
++ unsigned char sourcemsk[ETH_ALEN];
++ unsigned char destmac[ETH_ALEN];
++ unsigned char destmsk[ETH_ALEN];
+ // sizeof ebt_entry + matches
+- __u16 watchers_offset;
++ unsigned int watchers_offset;
+ // sizeof ebt_entry + matches + watchers
+- __u16 target_offset;
++ unsigned int target_offset;
+ // sizeof ebt_entry + matches + watchers + target
+- __u16 next_offset;
++ unsigned int next_offset;
+ unsigned char elems[0];
+ };
+
+@@ -238,10 +238,10 @@
+ unsigned int nentries;
+ // pointers to the start of the chains
+ struct ebt_entries *hook_entry[NF_BR_NUMHOOKS];
+- struct ebt_counter *counters;
+ // room to maintain the stack used for jumping from and into udc
+ struct ebt_chainstack **chainstack;
+ char *entries;
++ struct ebt_counter counters[0] __attribute__((aligned(SMP_CACHE_BYTES)));
+ };
+
+ struct ebt_table
+--- /dev/null Thu Aug 24 11:00:32 2000
++++ ebt2.0-rc1/include/linux/netfilter_bridge/ebt_mark_t.h Wed Jul 31 19:04:30 2002
+@@ -0,0 +1,12 @@
++#ifndef __LINUX_BRIDGE_EBT_MARK_T_H
++#define __LINUX_BRIDGE_EBT_MARK_T_H
++
++struct ebt_mark_t_info
++{
++ unsigned long mark;
++ // EBT_ACCEPT, EBT_DROP or EBT_CONTINUE or EBT_RETURN
++ int target;
++};
++#define EBT_MARK_TARGET "mark"
++
++#endif
+--- /dev/null Thu Aug 24 11:00:32 2000
++++ ebt2.0-rc1/include/linux/netfilter_bridge/ebt_mark_m.h Wed Jul 31 19:04:30 2002
+@@ -0,0 +1,15 @@
++#ifndef __LINUX_BRIDGE_EBT_MARK_M_H
++#define __LINUX_BRIDGE_EBT_MARK_M_H
++
++#define EBT_MARK_AND 0x01
++#define EBT_MARK_OR 0x02
++#define EBT_MARK_MASK (EBT_MARK_AND | EBT_MARK_OR)
++struct ebt_mark_m_info
++{
++ unsigned long mark, mask;
++ __u8 invert;
++ __u8 bitmask;
++};
++#define EBT_MARK_MATCH "mark_m"
++
++#endif