summaryrefslogtreecommitdiffstats
path: root/userspace/patches/incremental-patches/ebtables-v2.0-rc1.001.diff
diff options
context:
space:
mode:
Diffstat (limited to 'userspace/patches/incremental-patches/ebtables-v2.0-rc1.001.diff')
-rw-r--r--userspace/patches/incremental-patches/ebtables-v2.0-rc1.001.diff1764
1 files changed, 1764 insertions, 0 deletions
diff --git a/userspace/patches/incremental-patches/ebtables-v2.0-rc1.001.diff b/userspace/patches/incremental-patches/ebtables-v2.0-rc1.001.diff
new file mode 100644
index 0000000..b6ee40f
--- /dev/null
+++ b/userspace/patches/incremental-patches/ebtables-v2.0-rc1.001.diff
@@ -0,0 +1,1764 @@
+--- ebtables-v2.0pre10/Makefile Wed Jul 10 22:12:36 2002
++++ ebtables-v2.0-rc1.001/Makefile Wed Jul 31 19:48:25 2002
+@@ -2,7 +2,7 @@
+
+ KERNEL_DIR?=/usr/src/linux
+ PROGNAME:=ebtables
+-PROGVERSION:="2.0pre10 (July 2002)"
++PROGVERSION:="2.0-rc1 (July 2002)"
+
+ MANDIR?=/usr/local/man
+ CFLAGS:=-Wall -Wunused
+--- ebtables-v2.0pre10/ebtables.c Tue Jul 16 20:36:50 2002
++++ ebtables-v2.0-rc1.001/ebtables.c Thu Jul 25 16:02:43 2002
+@@ -1,5 +1,5 @@
+ /*
+- * ebtables.c, v2.0 April 2002
++ * ebtables.c, v2.0 July 2002
+ *
+ * Author: Bart De Schuymer
+ *
+@@ -32,13 +32,12 @@
+ #include <linux/br_db.h> // the database
+ #include <netinet/in.h>
+ #include <netinet/ether.h>
+-#include <asm/types.h>
+ #include "include/ebtables_u.h"
+ #include <unistd.h>
+ #include <fcntl.h>
+ #include <sys/wait.h>
+
+-// here are the number-name correspondences kept for the ethernet
++// here are the number-name correspondences kept for the Ethernet
+ // frame type field
+ #define PROTOCOLFILE "/etc/ethertypes"
+
+@@ -123,8 +122,6 @@
+ unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
+ unsigned char msk_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
+
+-// tells what happened to the old rules
+-static unsigned short *counterchanges;
+ // holds all the data
+ static struct ebt_u_replace replace;
+
+@@ -228,8 +225,7 @@
+ struct ebt_u_match_list **m_list, *new;
+
+ m->used = 1;
+- for (m_list = &new_entry->m_list;
+- *m_list; m_list = &(*m_list)->next);
++ for (m_list = &new_entry->m_list; *m_list; m_list = &(*m_list)->next);
+ new = (struct ebt_u_match_list *)
+ malloc(sizeof(struct ebt_u_match_list));
+ if (!new)
+@@ -245,8 +241,7 @@
+ struct ebt_u_watcher_list *new;
+
+ w->used = 1;
+- for (w_list = &new_entry->w_list;
+- *w_list; w_list = &(*w_list)->next);
++ for (w_list = &new_entry->w_list; *w_list; w_list = &(*w_list)->next);
+ new = (struct ebt_u_watcher_list *)
+ malloc(sizeof(struct ebt_u_watcher_list));
+ if (!new)
+@@ -340,6 +335,7 @@
+ ebt_options = merge_options
+ (ebt_options, t->extra_ops, &(t->option_offset));
+ t->init(t->t);
++
+ for (i = &targets; *i; i = &((*i)->next));
+ t->next = NULL;
+ *i = t;
+@@ -379,7 +375,6 @@
+ return NULL;
+ }
+
+-// I hate stealing, really... Lets call it a tribute.
+ int ebtables_insmod(const char *modname, const char *modprobe)
+ {
+ char *buf = NULL;
+@@ -413,86 +408,26 @@
+ return 0;
+ }
+
+-
+-// used to parse /etc/ethertypes
+-static int disregard_whitespace(char *buffer, FILE *ifp)
+-{
+- int hlp;
+-
+- buffer[0] = '\t';
+- while (buffer[0] == '\t' || buffer[0] == '\n' || buffer[0] == ' ') {
+- hlp = fscanf(ifp, "%c", buffer);
+- if (hlp == EOF || hlp == 0) return -1;
+- }
+- return 0;
+-}
+-
+-// used to parse /etc/ethertypes
+-static int disregard_tabspace(char *buffer, FILE *ifp)
+-{
+- int hlp;
+-
+- buffer[0] = '\t';
+- while (buffer[0] == '\t' || buffer[0] == ' ') {
+- hlp = fscanf(ifp, "%c", buffer);
+- if (hlp == EOF || hlp == 0) return -1;
+- }
+- return 0;
+-}
+-
+ // helper function: processes a line of data from the file /etc/ethertypes
+ static int get_a_line(char *buffer, char *value, FILE *ifp)
+ {
+- int i, hlp;
+- char anotherhlp;
++ char line[80], *p;
++ const char delim[] = " \t\n";
+
+- // discard comment lines and whitespace
+- while (1) {
+- if (disregard_whitespace(buffer, ifp))
+- return -1;
+- if (buffer[0] == '#')
+- while (1) {
+- hlp = fscanf(ifp, "%c", &anotherhlp);
+- if (!hlp || hlp == EOF)
+- return -1;
+- if (anotherhlp == '\n')
+- break;
+- }
+- else
+- break;
+- }
+-
+- // buffer[0] already contains the first letter
+- for (i = 1; i < 21; i++) {
+- hlp = fscanf(ifp, "%c", buffer + i);
+- if (hlp == EOF || hlp == 0)
+- return -1;
+- if (buffer[i] == '\t' || buffer[i] == ' ')
+- break;
+- }
+- if (i == 21)
+- return -1;
+- buffer[i] = '\0';
+- if (disregard_tabspace(value, ifp))
+- return -1;
+- // maybe I should allow 0x0800 instead of 0800, but I'm feeling lazy
+- // buffer[0] already contains the first letter
+- for (i = 1; i < 5; i++) {
+- hlp = fscanf(ifp, "%c", value+i);
+- if (value[i] == '\n' || value[i] == '\t' ||
+- value[i] == ' ' || hlp == EOF)
+- break;
++ while (fgets(line, sizeof(line), ifp)) {
++ p = strtok(line, delim);
++ if (!p || p[0] == '#')
++ continue;
++ if (strlen(p) > 20)
++ continue;
++ strcpy(buffer, p);
++ p = strtok(NULL, delim);
++ if (!p || strlen(p) > 10)
++ continue;
++ strcpy(value, p);
++ return 0;
+ }
+- if (i == 5) return -1;
+- // discard comments at the end of a line
+- if (value[i] == '\t' || value[i] == ' ')
+- while (1) {
+- hlp = fscanf(ifp, "%c", &anotherhlp);
+- if (!hlp || hlp == EOF || anotherhlp == '\n')
+- break;
+- }
+- value[i] = '\0';
+- return 0;
++ return -1;
+ }
+
+ // translate a hexadecimal number to a protocol name, parsing /etc/ethertypes
+@@ -500,7 +435,7 @@
+ int number_to_name(unsigned short proto, char *name)
+ {
+ FILE *ifp;
+- char buffer[21], value[5], *bfr;
++ char buffer[21], value[11], *bfr;
+ unsigned short i;
+
+ if ( !(ifp = fopen(PROTOCOLFILE, "r")) )
+@@ -768,7 +703,9 @@
+ if (!(replace.valid_hooks & (1 << i)))
+ continue;
+ entries = nr_to_chain(i);
+- entries->hook_mask = (1 << i);
++ // (1 << NF_BR_NUMHOOKS) implies it's a standard chain
++ // (usefull in the final_check() funtions)
++ entries->hook_mask = (1 << i) | (1 << NF_BR_NUMHOOKS);
+ chain_nr = i;
+
+ e = entries->entries;
+@@ -784,7 +721,8 @@
+ for (k = 0; k < sp; k++)
+ if (stack[k].chain_nr == verdict + NF_BR_NUMHOOKS)
+ print_error("Loop from chain %s to chain %s",
+- nr_to_chain(chain_nr)->name, nr_to_chain(stack[k].chain_nr)->name);
++ nr_to_chain(chain_nr)->name,
++ nr_to_chain(stack[k].chain_nr)->name);
+ // jump to the chain, make sure we know how to get back
+ stack[sp].chain_nr = chain_nr;
+ stack[sp].n = j;
+@@ -960,16 +898,16 @@
+ replace.num_counters = replace.nentries;
+ if (replace.nentries) {
+ // '+ 1' for the CNT_END
+- if (!(counterchanges = (unsigned short *) malloc(
++ if (!(replace.counterchanges = (unsigned short *) malloc(
+ (replace.nentries + 1) * sizeof(unsigned short))))
+ print_memory();
+ // done nothing special to the rules
+ for (i = 0; i < replace.nentries; i++)
+- counterchanges[i] = CNT_NORM;
+- counterchanges[replace.nentries] = CNT_END;
++ replace.counterchanges[i] = CNT_NORM;
++ replace.counterchanges[replace.nentries] = CNT_END;
+ }
+ else
+- counterchanges = NULL;
++ replace.counterchanges = NULL;
+ }
+ else
+ exit(0);
+@@ -1026,14 +964,14 @@
+
+ if (replace.nentries) {
+ // +1 for CNT_END
+- if ( !(counterchanges = (unsigned short *)
++ if ( !(replace.counterchanges = (unsigned short *)
+ malloc((oldnentries + 1) * sizeof(unsigned short))) )
+ print_memory();
+ }
+ // delete the counters belonging to the specified chain,
+ // update counter_offset
+ i = -1;
+- cnt = counterchanges;
++ cnt = replace.counterchanges;
+ while (1) {
+ i++;
+ entries = nr_to_chain(i);
+@@ -1101,73 +1039,74 @@
+ for (i = 0; i < entries->nentries; i++, u_e = u_e->next) {
+ if (!u_e)
+ print_bug("Hmm, trouble");
+- if ( u_e->ethproto == new_entry->ethproto
+- && !strcmp(u_e->in, new_entry->in)
+- && !strcmp(u_e->out, new_entry->out)) {
+- if (strcmp(u_e->logical_in, new_entry->logical_in) ||
+- strcmp(u_e->logical_out, new_entry->logical_out))
+- continue;
+- if (new_entry->bitmask & EBT_SOURCEMAC &&
+- memcmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN))
+- continue;
+- if (new_entry->bitmask & EBT_DESTMAC &&
+- memcmp(u_e->destmac, new_entry->destmac, ETH_ALEN))
+- continue;
+- if (new_entry->bitmask != u_e->bitmask ||
+- new_entry->invflags != u_e->invflags)
+- continue;
+- // compare all matches
+- m_l = new_entry->m_list;
+- j = 0;
+- while (m_l) {
+- m = (struct ebt_u_match *)(m_l->m);
+- m_l2 = u_e->m_list;
+- while (m_l2 &&
+- strcmp(m_l2->m->u.name, m->m->u.name))
+- m_l2 = m_l2->next;
+- if (!m_l2 || !m->compare(m->m, m_l2->m))
+- goto letscontinue;
+- j++;
+- m_l = m_l->next;
+- }
+- // now be sure they have the same nr of matches
+- k = 0;
+- m_l = u_e->m_list;
+- while (m_l) {
+- k++;
+- m_l = m_l->next;
+- }
+- if (j != k)
+- continue;
++ if (u_e->ethproto != new_entry->ethproto)
++ continue;
++ if (strcmp(u_e->in, new_entry->in))
++ continue;
++ if (strcmp(u_e->out, new_entry->out))
++ continue;
++ if (strcmp(u_e->logical_in, new_entry->logical_in))
++ continue;
++ if (strcmp(u_e->logical_out, new_entry->logical_out))
++ continue;
++ if (new_entry->bitmask & EBT_SOURCEMAC &&
++ memcmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN))
++ continue;
++ if (new_entry->bitmask & EBT_DESTMAC &&
++ memcmp(u_e->destmac, new_entry->destmac, ETH_ALEN))
++ continue;
++ if (new_entry->bitmask != u_e->bitmask ||
++ new_entry->invflags != u_e->invflags)
++ continue;
++ // compare all matches
++ m_l = new_entry->m_list;
++ j = 0;
++ while (m_l) {
++ m = (struct ebt_u_match *)(m_l->m);
++ m_l2 = u_e->m_list;
++ while (m_l2 && strcmp(m_l2->m->u.name, m->m->u.name))
++ m_l2 = m_l2->next;
++ if (!m_l2 || !m->compare(m->m, m_l2->m))
++ goto letscontinue;
++ j++;
++ m_l = m_l->next;
++ }
++ // now be sure they have the same nr of matches
++ k = 0;
++ m_l = u_e->m_list;
++ while (m_l) {
++ k++;
++ m_l = m_l->next;
++ }
++ if (j != k)
++ continue;
+
+- // compare all watchers
+- w_l = new_entry->w_list;
+- j = 0;
+- while (w_l) {
+- w = (struct ebt_u_watcher *)(w_l->w);
+- w_l2 = u_e->w_list;
+- while (w_l2 &&
+- strcmp(w_l2->w->u.name, w->w->u.name))
+- w_l2 = w_l2->next;
+- if (!w_l2 || !w->compare(w->w, w_l2->w))
+- goto letscontinue;
+- j++;
+- w_l = w_l->next;
+- }
+- k = 0;
+- w_l = u_e->w_list;
+- while (w_l) {
+- k++;
+- w_l = w_l->next;
+- }
+- if (j != k)
+- continue;
+- if (strcmp(t->t->u.name, u_e->t->u.name))
+- continue;
+- if (!t->compare(t->t, u_e->t))
+- continue;
+- return i;
++ // compare all watchers
++ w_l = new_entry->w_list;
++ j = 0;
++ while (w_l) {
++ w = (struct ebt_u_watcher *)(w_l->w);
++ w_l2 = u_e->w_list;
++ while (w_l2 && strcmp(w_l2->w->u.name, w->w->u.name))
++ w_l2 = w_l2->next;
++ if (!w_l2 || !w->compare(w->w, w_l2->w))
++ goto letscontinue;
++ j++;
++ w_l = w_l->next;
++ }
++ k = 0;
++ w_l = u_e->w_list;
++ while (w_l) {
++ k++;
++ w_l = w_l->next;
+ }
++ if (j != k)
++ continue;
++ if (strcmp(t->t->u.name, u_e->t->u.name))
++ continue;
++ if (!t->compare(t->t, u_e->t))
++ continue;
++ return i;
+ letscontinue:
+ }
+ return -1;
+@@ -1177,7 +1116,7 @@
+ static void add_rule(int rule_nr)
+ {
+ int i, j;
+- struct ebt_u_entry *u_e, *u_e2;
++ struct ebt_u_entry **u_e;
+ unsigned short *cnt;
+ struct ebt_u_match_list *m_l;
+ struct ebt_u_watcher_list *w_l;
+@@ -1196,10 +1135,10 @@
+
+ // handle counter stuff
+ // +1 for CNT_END
+- if ( !(counterchanges = (unsigned short *)
++ if ( !(replace.counterchanges = (unsigned short *)
+ malloc((replace.nentries + 1) * sizeof(unsigned short))) )
+ print_memory();
+- cnt = counterchanges;
++ cnt = replace.counterchanges;
+ for (i = 0; i < replace.selected_hook; i++) {
+ if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
+ continue;
+@@ -1215,25 +1154,19 @@
+ }
+ *cnt = CNT_ADD;
+ cnt++;
+- while (cnt != counterchanges + replace.nentries) {
++ while (cnt != replace.counterchanges + replace.nentries) {
+ *cnt = CNT_NORM;
+ cnt++;
+ }
+ *cnt = CNT_END;
+
+ // go to the right position in the chain
+- u_e2 = NULL;
+- u_e = entries->entries;
+- for (i = 0; i < rule_nr; i++) {
+- u_e2 = u_e;
+- u_e = u_e->next;
+- }
++ u_e = &entries->entries;
++ for (i = 0; i < rule_nr; i++)
++ u_e = &(*u_e)->next;
+ // insert the rule
+- if (u_e2)
+- u_e2->next = new_entry;
+- else
+- entries->entries = new_entry;
+- new_entry->next = u_e;
++ new_entry->next = *u_e;
++ *u_e = new_entry;
+
+ // put the ebt_[match, watcher, target] pointers in place
+ m_l = new_entry->m_list;
+@@ -1268,7 +1201,7 @@
+ {
+ int i, j, lentmp = 0;
+ unsigned short *cnt;
+- struct ebt_u_entry *u_e, *u_e2;
++ struct ebt_u_entry **u_e, *u_e2;
+ struct ebt_u_entries *entries = to_chain(), *entries2;
+
+ if ( (i = check_rule_exists(rule_nr)) == -1 )
+@@ -1277,6 +1210,7 @@
+ // we're deleting a rule
+ replace.num_counters = replace.nentries;
+ replace.nentries--;
++ entries->nentries--;
+
+ if (replace.nentries) {
+ for (j = 0; j < replace.selected_hook; j++) {
+@@ -1288,10 +1222,10 @@
+ }
+ lentmp += i;
+ // +1 for CNT_END
+- if ( !(counterchanges = (unsigned short *)malloc(
++ if ( !(replace.counterchanges = (unsigned short *)malloc(
+ (replace.num_counters + 1) * sizeof(unsigned short))) )
+ print_memory();
+- cnt = counterchanges;
++ cnt = replace.counterchanges;
+ for (j = 0; j < lentmp; j++) {
+ *cnt = CNT_NORM;
+ cnt++;
+@@ -1308,23 +1242,16 @@
+ replace.num_counters = 0;
+
+ // go to the right position in the chain
+- u_e2 = NULL;
+- u_e = entries->entries;
+- for (j = 0; j < i; j++) {
+- u_e2 = u_e;
+- u_e = u_e->next;
+- }
+-
+- // remove from the chain
+- if (u_e2)
+- u_e2->next = u_e->next;
+- else
+- entries->entries = u_e->next;
+-
+- entries->nentries--;
++ u_e = &entries->entries;
++ for (j = 0; j < i; j++)
++ u_e = &(*u_e)->next;
++ // remove the rule
++ u_e2 = *u_e;
++ *u_e = (*u_e)->next;
+ // free everything
+- free_u_entry(u_e);
+- free(u_e);
++ free_u_entry(u_e2);
++ free(u_e2);
++
+ // update the counter_offset of chains behind this one
+ i = replace.selected_hook;
+ while (1) {
+@@ -1348,7 +1275,7 @@
+ // tell main() we don't update the counters
+ // this results in tricking the kernel to zero its counters,
+ // naively expecting userspace to update its counters. Muahahaha
+- counterchanges = NULL;
++ replace.counterchanges = NULL;
+ replace.num_counters = 0;
+ } else {
+ int i, j;
+@@ -1357,11 +1284,11 @@
+
+ if (entries->nentries == 0)
+ exit(0);
+- counterchanges = (unsigned short *)
++ replace.counterchanges = (unsigned short *)
+ malloc((replace.nentries + 1) * sizeof(unsigned short));
+- if (!counterchanges)
++ if (!replace.counterchanges)
+ print_memory();
+- cnt = counterchanges;
++ cnt = replace.counterchanges;
+ for (i = 0; i < zerochain; i++) {
+ if (i < NF_BR_NUMHOOKS &&
+ !(replace.valid_hooks & (1 << i)))
+@@ -1376,7 +1303,7 @@
+ *cnt = CNT_ZERO;
+ cnt++;
+ }
+- while (cnt != counterchanges + replace.nentries) {
++ while (cnt != replace.counterchanges + replace.nentries) {
+ *cnt = CNT_NORM;
+ cnt++;
+ }
+@@ -1450,7 +1377,7 @@
+ int name_to_number(char *name, __u16 *proto)
+ {
+ FILE *ifp;
+- char buffer[21], value[5], *bfr;
++ char buffer[21], value[11], *bfr;
+ unsigned short i;
+
+ if (!strcasecmp("LENGTH", name)) {
+@@ -1461,14 +1388,15 @@
+ if ( !(ifp = fopen(PROTOCOLFILE, "r")) )
+ return -1;
+ while (1) {
+- if (get_a_line(buffer, value, ifp)) return -1;
++ if (get_a_line(buffer, value, ifp))
++ return -1;
+ if (strcasecmp(buffer, name))
+ continue;
++ fclose(ifp);
+ i = (unsigned short) strtol(value, &bfr, 16);
+ if (*bfr != '\0')
+ return -1;
+ *proto = i;
+- fclose(ifp);
+ return 0;
+ }
+ return -1;
+@@ -1587,6 +1515,19 @@
+ *flags |= mask;
+ }
+
++static void get_kernel_table(const char *modprobe)
++{
++ if ( !(table = find_table(replace.name)) )
++ print_error("Bad table name");
++ // get the kernel's information
++ if (get_table(&replace)) {
++ ebtables_insmod("ebtables", modprobe);
++ if (get_table(&replace))
++ print_error("The kernel doesn't support the ebtables "
++ "%s table", replace.name);
++ }
++}
++
+ #define OPT_COMMAND 0x01
+ #define OPT_TABLE 0x02
+ #define OPT_IN 0x04
+@@ -1606,7 +1547,7 @@
+ // this special one for the -Z option (we can have -Z <this> -L <that>)
+ int zerochain = -1;
+ int policy = 0;
+- int rule_nr = -1;// used for -D chain number
++ int rule_nr = -1;// used for -[D,I] chain number
+ struct ebt_u_target *t;
+ struct ebt_u_match *m;
+ struct ebt_u_watcher *w;
+@@ -1621,6 +1562,7 @@
+ replace.selected_hook = -1;
+ replace.command = 'h';
+ replace.filename = NULL;
++ replace.counterchanges = NULL;
+
+ new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
+ if (!new_entry)
+@@ -1648,16 +1590,8 @@
+ if (replace.flags & OPT_COMMAND)
+ print_error("Multiple commands not allowed");
+ replace.flags |= OPT_COMMAND;
+- if ( !(table = find_table(replace.name)) )
+- print_error("Bad table name");
+- // get the kernel's information
+- if (get_table(&replace)) {
+- ebtables_insmod("ebtables", modprobe);
+- if (get_table(&replace))
+- print_error("can't initialize ebtables "
+- "table %s", replace.name);
+- }
+- if (optarg[0] == '-')
++ get_kernel_table(modprobe);
++ if (optarg[0] == '-' || !strcmp(optarg, "!"))
+ print_error("No chain name specified");
+ if (c == 'N') {
+ struct ebt_u_chain_list *cl, **cl2;
+@@ -1697,7 +1631,8 @@
+ if ((replace.selected_hook = get_hooknr(optarg)) == -1)
+ print_error("Chain %s doesn't exist", optarg);
+ if (c == 'E') {
+- if (optind >= argc || argv[optind][0] == '-')
++ if (optind >= argc || argv[optind][0] == '-' ||
++ !strcmp(argv[optind], "!"))
+ print_error("No new chain name specified");
+ if (strlen(argv[optind]) >= EBT_CHAIN_MAXNAMELEN)
+ print_error("Chain name len can't exceed %d",
+@@ -1705,6 +1640,9 @@
+ if (get_hooknr(argv[optind]) != -1)
+ print_error("Chain %s already exists",
+ argv[optind]);
++ if (find_target(argv[optind]))
++ print_error("Target with name %s exists"
++ , argv[optind]);
+ entries = to_chain();
+ strcpy(entries->name, argv[optind]);
+ optind++;
+@@ -1719,25 +1657,21 @@
+ check_for_references(replace.selected_hook - NF_BR_NUMHOOKS);
+ flush_chains();
+ entries = to_chain();
+- if (replace.udc->udc == entries) {
+- cl = replace.udc;
+- replace.udc = replace.udc->next;
+- free(cl->udc);
+- free(cl);
+- break;
+- }
+ cl2 = &(replace.udc);
+- while ((*cl2)->next->udc != entries)
++ while ((*cl2)->udc != entries)
+ cl2 = &((*cl2)->next);
+- cl = (*cl2)->next;
+- (*cl2)->next = (*cl2)->next->next;
++ cl = (*cl2);
++ (*cl2) = (*cl2)->next;
+ free(cl->udc);
+ free(cl);
+ break;
+ }
+
+- if (c == 'D' && optind < argc &&
+- argv[optind][0] != '-') {
++ if ( (c == 'D' && optind < argc &&
++ argv[optind][0] != '-') || c == 'I') {
++ if (optind >= argc || argv[optind][0] == '-')
++ print_error("No rulenr for -I"
++ " specified");
+ rule_nr = strtol(argv[optind], &buffer, 10);
+ if (*buffer != '\0' || rule_nr < 0)
+ print_error("Problem with the "
+@@ -1760,16 +1694,6 @@
+ print_error("Wrong policy");
+ optind++;
+ }
+- if (c == 'I') {
+- if (optind >= argc)
+- print_error("No rulenr for -I"
+- " specified");
+- rule_nr = strtol(argv[optind], &buffer, 10);
+- if (*buffer != '\0' || rule_nr < 0)
+- print_error("Problem with the specified"
+- " rule number");
+- optind++;
+- }
+ break;
+
+ case 'L': // list
+@@ -1791,23 +1715,14 @@
+ " not allowed");
+ replace.flags |= OPT_COMMAND;
+ }
+- if ( !(table = find_table(replace.name)) )
+- print_error("Bad table name");
+- // get the kernel's information
+- if (get_table(&replace)) {
+- ebtables_insmod("ebtables", modprobe);
+- if (get_table(&replace))
+- print_error("can't initialize ebtables "
+- "table %s", replace.name);
+- }
++ get_kernel_table(modprobe);
+ i = -1;
+ if (optarg) {
+ if ( (i = get_hooknr(optarg)) == -1 )
+ print_error("Bad chain");
+ } else
+ if (optind < argc && argv[optind][0] != '-') {
+- if ((i = get_hooknr(argv[optind]))
+- == -1)
++ if ((i = get_hooknr(argv[optind])) == -1)
+ print_error("Bad chain");
+ optind++;
+ }
+@@ -2054,7 +1969,7 @@
+ if (new_entry->ethproto < 1536 &&
+ !(new_entry->bitmask & EBT_802_3))
+ print_error("Sorry, protocols have values above"
+- " or equal to 1536 (0x0600)");
++ " or equal to 0x0600");
+ break;
+
+ case 'b': // allow database?
+@@ -2104,17 +2019,24 @@
+ if (replace.flags & OPT_COMMAND)
+ print_error("Multiple commands not allowed");
+ replace.flags |= OPT_COMMAND;
++ if (replace.filename)
++ print_error("--atomic incompatible with "
++ "command");
+ replace.filename = (char *)malloc(strlen(optarg) + 1);
+ strcpy(replace.filename, optarg);
+ // get the information from the file
+ get_table(&replace);
+ if (replace.nentries) {
+- counterchanges = (unsigned short *)
++ replace.counterchanges = (unsigned short *)
+ malloc(sizeof(unsigned short) * (replace.nentries + 1));
+ for (i = 0; i < replace.nentries; i++)
+- counterchanges[i] = CNT_NORM;
+- counterchanges[i] = CNT_END;
++ replace.counterchanges[i] = CNT_NORM;
++ replace.counterchanges[i] = CNT_END;
+ }
++ // we don't want the kernel giving us its counters, they would
++ // overwrite the counters extracted from the file
++ replace.num_counters = 0;
++ // make sure the table will be written to the kernel
+ free(replace.filename);
+ replace.filename = NULL;
+ break;
+@@ -2125,24 +2047,23 @@
+ if (replace.flags & OPT_COMMAND)
+ print_error("Multiple commands not allowed");
+ replace.flags |= OPT_COMMAND;
+- if ( !(table = find_table(replace.name)) )
+- print_error("Bad table name");
+- if (get_table(&replace)) {
+- ebtables_insmod("ebtables", modprobe);
+- if (get_table(&replace))
+- print_error("can't initialize ebtables "
+- "table %s", replace.name);
+- }
++ if (replace.filename)
++ print_error("--atomic incompatible with "
++ "command");
++ get_kernel_table(modprobe);
+ if (replace.nentries) {
+- counterchanges = (unsigned short *)
++ replace.counterchanges = (unsigned short *)
+ malloc(sizeof(unsigned short) * (replace.nentries + 1));
+ for (i = 0; i < replace.nentries; i++)
+- counterchanges[i] = CNT_NORM;
+- counterchanges[i] = CNT_END;
++ replace.counterchanges[i] = CNT_NORM;
++ replace.counterchanges[i] = CNT_END;
+ }
+ if (c == 11)
+ break;
+ case 9 : // atomic
++ if (c == 9 && (replace.flags & OPT_COMMAND))
++ print_error("--atomic has to come before"
++ " the command");
+ replace.filename = (char *)malloc(strlen(optarg) + 1);
+ strcpy(replace.filename, optarg);
+ break;
+@@ -2179,7 +2100,7 @@
+ check_extension:
+ if (replace.command != 'A' && replace.command != 'I' &&
+ replace.command != 'D')
+- print_error("extensions only for -A, -I and -D");
++ print_error("Extensions only for -A, -I and -D");
+ }
+ }
+
+@@ -2195,12 +2116,6 @@
+ replace.flags & OPT_ZERO )
+ print_error("Command -Z only allowed together with command -L");
+
+- if (replace.command == 'A' || replace.command == 'I' ||
+- replace.command == 'D') {
+- if (replace.selected_hook == -1)
+- print_error("Not enough information");
+- }
+-
+ // do this after parsing everything, so we can print specific info
+ if (replace.command == 'h' && !(replace.flags & OPT_ZERO))
+ print_help();
+@@ -2283,7 +2198,7 @@
+
+ deliver_table(&replace);
+
+- if (counterchanges)
+- deliver_counters(&replace, counterchanges);
++ if (replace.counterchanges)
++ deliver_counters(&replace);
+ return 0;
+ }
+--- ebtables-v2.0pre10/communication.c Mon Jul 15 22:35:14 2002
++++ ebtables-v2.0-rc1.001/communication.c Fri Jul 26 13:33:02 2002
+@@ -1,5 +1,5 @@
+ /*
+- * communication.c, v2.0 April 2002
++ * communication.c, v2.0 July 2002
+ *
+ * Author: Bart De Schuymer
+ *
+@@ -18,9 +18,8 @@
+ #include <stdlib.h>
+ #include <sys/socket.h>
+ #include <linux/netfilter_bridge/ebtables.h>
+-#include <linux/br_db.h> // the database
++#include <linux/br_db.h>
+ #include <netinet/in.h> // IPPROTO_IP
+-#include <asm/types.h>
+ #include "include/ebtables_u.h"
+
+ extern char* hooknames[NF_BR_NUMHOOKS];
+@@ -32,7 +31,8 @@
+ if (sockfd == -1) {
+ sockfd = socket(AF_INET, SOCK_RAW, PF_INET);
+ if (sockfd < 0)
+- print_error("Problem getting a socket");
++ print_error("Problem getting a socket, "
++ "do you have the right permissions?");
+ }
+ }
+
+@@ -52,7 +52,7 @@
+ if (!new)
+ print_memory();
+ new->valid_hooks = u_repl->valid_hooks;
+- memcpy(new->name, u_repl->name, sizeof(new->name));
++ strcpy(new->name, u_repl->name);
+ new->nentries = u_repl->nentries;
+ new->num_counters = u_repl->num_counters;
+ new->counters = u_repl->counters;
+@@ -150,12 +150,10 @@
+ tmp->bitmask = e->bitmask | EBT_ENTRY_OR_ENTRIES;
+ tmp->invflags = e->invflags;
+ tmp->ethproto = e->ethproto;
+- memcpy(tmp->in, e->in, sizeof(tmp->in));
+- memcpy(tmp->out, e->out, sizeof(tmp->out));
+- memcpy(tmp->logical_in, e->logical_in,
+- sizeof(tmp->logical_in));
+- memcpy(tmp->logical_out, e->logical_out,
+- sizeof(tmp->logical_out));
++ strcpy(tmp->in, e->in);
++ strcpy(tmp->out, e->out);
++ strcpy(tmp->logical_in, e->logical_in);
++ strcpy(tmp->logical_out, e->logical_out);
+ memcpy(tmp->sourcemac, e->sourcemac,
+ sizeof(tmp->sourcemac));
+ memcpy(tmp->sourcemsk, e->sourcemsk,
+@@ -190,7 +188,8 @@
+ (struct ebt_standard_target *)p;
+ // translate the jump to a udc
+ if (st->verdict >= 0)
+- st->verdict = chain_offsets[st->verdict + NF_BR_NUMHOOKS];
++ st->verdict = chain_offsets
++ [st->verdict + NF_BR_NUMHOOKS];
+ }
+ p += e->t->target_size +
+ sizeof(struct ebt_entry_target);
+@@ -257,23 +256,23 @@
+
+ // translate the struct ebt_u_replace to a struct ebt_replace
+ repl = translate_user2kernel(u_repl);
+- // give the data to the kernel
+- optlen = sizeof(struct ebt_replace) + repl->entries_size;
+ if (u_repl->filename != NULL) {
+ store_table_in_file(u_repl->filename, repl);
+ return;
+ }
++ // give the data to the kernel
++ optlen = sizeof(struct ebt_replace) + repl->entries_size;
+ get_sockfd();
+ if (setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_ENTRIES, repl, optlen))
+ print_error("The kernel doesn't support a certain ebtables"
+ " extension, consider recompiling your kernel or insmod"
+- " the extension");
++ " the extension");
+ }
+
+ static void store_counters_in_file(char *filename, struct ebt_u_replace *repl)
+ {
+ int size = repl->nentries * sizeof(struct ebt_counter);
+- int entries_size;
++ unsigned int entries_size;
+ struct ebt_replace hlp;
+ FILE *file;
+
+@@ -296,12 +295,13 @@
+
+ // gets executed after deliver_table
+ void
+-deliver_counters(struct ebt_u_replace *u_repl, unsigned short *counterchanges)
++deliver_counters(struct ebt_u_replace *u_repl)
+ {
+ unsigned short *point;
+ struct ebt_counter *old, *new, *newcounters;
+ socklen_t optlen;
+ struct ebt_replace repl;
++ unsigned short *counterchanges = u_repl->counterchanges;
+
+ if (u_repl->nentries == 0)
+ return;
+@@ -323,16 +323,14 @@
+ old++;
+ // we've set a new counter
+ new++;
+- } else
+- if (*point == CNT_DEL) {
++ } else if (*point == CNT_DEL) {
+ // don't use this old counter
+ old++;
+ } else if (*point == CNT_ADD) {
+ // new counter, let it stay 0
+ new++;
+ } else {
+- // zero it
+- new->pcnt = 0;
++ // zero it (let it stay 0)
+ old++;
+ new++;
+ }
+@@ -355,7 +353,7 @@
+
+ get_sockfd();
+ if (setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_COUNTERS, &repl, optlen))
+- print_bug("couldn't update kernel counters");
++ print_bug("Couldn't update kernel counters");
+ }
+
+ static int
+@@ -425,12 +423,10 @@
+ new->bitmask &= ~EBT_ENTRY_OR_ENTRIES;
+ new->invflags = e->invflags;
+ new->ethproto = e->ethproto;
+- memcpy(new->in, e->in, sizeof(new->in));
+- memcpy(new->out, e->out, sizeof(new->out));
+- memcpy(new->logical_in, e->logical_in,
+- sizeof(new->logical_in));
+- memcpy(new->logical_out, e->logical_out,
+- sizeof(new->logical_out));
++ strcpy(new->in, e->in);
++ strcpy(new->out, e->out);
++ strcpy(new->logical_in, e->logical_in);
++ strcpy(new->logical_out, e->logical_out);
+ memcpy(new->sourcemac, e->sourcemac, sizeof(new->sourcemac));
+ memcpy(new->sourcemsk, e->sourcemsk, sizeof(new->sourcemsk));
+ memcpy(new->destmac, e->destmac, sizeof(new->destmac));
+@@ -500,9 +496,8 @@
+ while (i-- > 0)
+ cl = cl->next;
+ *u_e = &(cl->udc->entries);
+- } else {
++ } else
+ *u_e = &(u_repl->hook_entry[*hook]->entries);
+- }
+ return 0;
+ }
+ }
+@@ -568,7 +563,7 @@
+ print_error("Could not open file %s", filename);
+ // make sure table name is right if command isn't -L or --atomic-commit
+ if (command != 'L' && command != 8) {
+- hlp = (char *)malloc(strlen(repl->name));
++ hlp = (char *)malloc(strlen(repl->name) + 1);
+ if (!hlp)
+ print_memory();
+ strcpy(hlp, repl->name);
+@@ -580,12 +575,11 @@
+ fclose(file);
+ print_error("File %s contains wrong table name or is corrupt",
+ filename);
+- } else
+- if (!find_table(repl->name)) {
+- fclose(file);
+- print_error("File %s contains invalid table name",
+- filename);
+- }
++ free(hlp);
++ } else if (!find_table(repl->name)) {
++ fclose(file);
++ print_error("File %s contains invalid table name", filename);
++ }
+
+ size = sizeof(struct ebt_replace) +
+ repl->nentries * sizeof(struct ebt_counter) + repl->entries_size;
+@@ -633,7 +627,7 @@
+ if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
+ return -1;
+
+- if ( !(repl->entries = (char *) malloc(repl->entries_size)) )
++ if ( !(repl->entries = (char *)malloc(repl->entries_size)) )
+ print_memory();
+ if (repl->nentries) {
+ if (!(repl->counters = (struct ebt_counter *)
+@@ -657,7 +651,6 @@
+ return 0;
+ }
+
+-// talk with kernel to receive the kernel's table
+ int get_table(struct ebt_u_replace *u_repl)
+ {
+ int i, j, k, hook;
+@@ -667,12 +660,10 @@
+ strcpy(repl.name, u_repl->name);
+ if (u_repl->filename != NULL)
+ retrieve_from_file(u_repl->filename, &repl, u_repl->command);
+- else
+- if (retrieve_from_kernel(&repl, u_repl->command) == -1)
+- return -1;
++ else if (retrieve_from_kernel(&repl, u_repl->command) == -1)
++ return -1;
+
+ // translate the struct ebt_replace to a struct ebt_u_replace
+- memcpy(u_repl->name, repl.name, sizeof(u_repl->name));
+ u_repl->valid_hooks = repl.valid_hooks;
+ u_repl->nentries = repl.nentries;
+ u_repl->num_counters = repl.num_counters;
+--- ebtables-v2.0pre10/extensions/ebt_redirect.c Thu Jun 27 18:53:55 2002
++++ ebtables-v2.0-rc1.001/extensions/ebt_redirect.c Thu Jul 25 19:28:52 2002
+@@ -12,7 +12,7 @@
+ #define REDIRECT_TARGET '1'
+ static struct option opts[] =
+ {
+- { "redirect-target" , required_argument, 0, REDIRECT_TARGET },
++ { "redirect-target", required_argument, 0, REDIRECT_TARGET },
+ { 0 }
+ };
+
+@@ -20,7 +20,7 @@
+ {
+ printf(
+ "redirect option:\n"
+- " --redirect-target target : ACCEPT, DROP or CONTINUE\n");
++ " --redirect-target target : ACCEPT, DROP, RETURN or CONTINUE\n");
+ }
+
+ static void init(struct ebt_entry_target *target)
+@@ -62,6 +62,13 @@
+ const struct ebt_entry_target *target, const char *name,
+ unsigned int hook_mask, unsigned int time)
+ {
++ struct ebt_redirect_info *redirectinfo =
++ (struct ebt_redirect_info *)target->data;
++
++ if ((hook_mask & (1 << NF_BR_NUMHOOKS)) &&
++ redirectinfo->target == EBT_RETURN)
++ print_error("--redirect-target RETURN not allowed on base chain");
++ hook_mask &= ~(1 << NF_BR_NUMHOOKS);
+ if ( ((hook_mask & ~(1 << NF_BR_PRE_ROUTING)) || strcmp(name, "nat")) &&
+ ((hook_mask & ~(1 << NF_BR_BROUTING)) || strcmp(name, "broute")) )
+ print_error("Wrong chain for redirect");
+--- ebtables-v2.0pre10/extensions/ebtable_broute.c Thu Jun 27 18:53:55 2002
++++ ebtables-v2.0-rc1.001/extensions/ebtable_broute.c Wed Jul 24 20:44:43 2002
+@@ -5,7 +5,7 @@
+
+ static void print_help(char **hn)
+ {
+- printf("Supported chain for the nat table:\n");
++ printf("Supported chain for the broute table:\n");
+ printf("%s\n",hn[NF_BR_BROUTING]);
+ }
+
+--- ebtables-v2.0pre10/extensions/ebt_nat.c Thu Jun 27 18:53:55 2002
++++ ebtables-v2.0-rc1.001/extensions/ebt_nat.c Thu Jul 25 16:31:01 2002
+@@ -37,7 +37,7 @@
+ printf(
+ "snat options:\n"
+ " --to-src address : MAC address to map source to\n"
+- " --snat-target target : ACCEPT, DROP or CONTINUE\n");
++ " --snat-target target : ACCEPT, DROP, RETURN or CONTINUE\n");
+ }
+
+ static void print_help_d()
+@@ -45,7 +45,7 @@
+ printf(
+ "dnat options:\n"
+ " --to-dst address : MAC address to map destination to\n"
+- " --dnat-target target : ACCEPT, DROP or CONTINUE\n");
++ " --dnat-target target : ACCEPT, DROP, RETURN or CONTINUE\n");
+ }
+
+ static void init_s(struct ebt_entry_target *target)
+@@ -81,7 +81,7 @@
+ check_option(flags, OPT_SNAT);
+ to_source_supplied = 1;
+ if (!(addr = ether_aton(optarg)))
+- print_error("Problem with specified to-source mac");
++ print_error("Problem with specified --to-source mac");
+ memcpy(natinfo->mac, addr, ETH_ALEN);
+ break;
+ case NAT_S_TARGET:
+@@ -116,7 +116,7 @@
+ to_dest_supplied = 1;
+ if (!(addr = ether_aton(optarg)))
+ print_error("Problem with specified "
+- "to-destination mac");
++ "--to-destination mac");
+ memcpy(natinfo->mac, addr, ETH_ALEN);
+ break;
+ case NAT_D_TARGET:
+@@ -139,6 +139,11 @@
+ const struct ebt_entry_target *target, const char *name,
+ unsigned int hook_mask, unsigned int time)
+ {
++ struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data;
++
++ if ((hook_mask & (1 << NF_BR_NUMHOOKS)) && natinfo->target == EBT_RETURN)
++ print_error("--snat-target RETURN not allowed on base chain");
++ hook_mask &= ~(1 << NF_BR_NUMHOOKS);
+ if (!(hook_mask & (1 << NF_BR_POST_ROUTING)) || strcmp(name, "nat"))
+ print_error("Wrong chain for snat");
+ if (time == 0 && to_source_supplied == 0)
+@@ -149,6 +154,11 @@
+ const struct ebt_entry_target *target, const char *name,
+ unsigned int hook_mask, unsigned int time)
+ {
++ struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data;
++
++ if ((hook_mask & (1 << NF_BR_NUMHOOKS)) && natinfo->target == EBT_RETURN)
++ print_error("--dnat-target RETURN not allowed on base chain");
++ hook_mask &= ~(1 << NF_BR_NUMHOOKS);
+ if (((hook_mask & ~((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT))) ||
+ strcmp(name, "nat")) &&
+ ((hook_mask & ~(1 << NF_BR_BROUTING)) || strcmp(name, "broute")))
+--- ebtables-v2.0pre10/extensions/ebt_vlan.c Thu Jun 27 18:53:55 2002
++++ ebtables-v2.0-rc1.001/extensions/ebt_vlan.c Wed Jul 24 12:18:25 2002
+@@ -41,7 +41,7 @@
+
+ #define GET_BITMASK(_MASK_) vlaninfo->bitmask & _MASK_
+ #define SET_BITMASK(_MASK_) vlaninfo->bitmask |= _MASK_
+-#define INV_FLAG(_inv_flag_) (vlaninfo->invflags & _inv_flag_) ? "!" : ""
++#define INV_FLAG(_inv_flag_) (vlaninfo->invflags & _inv_flag_) ? "! " : ""
+
+ #define VLAN_ID 0
+ #define VLAN_PRIO 1
+@@ -60,9 +60,9 @@
+ static void print_help ()
+ {
+ printf ("802.1Q VLAN extension options:\n"
+- "--vlan-id [!]id : VLAN-tagged frame identifier, 0,1-4094 (integer)\n"
+- "--vlan-prio [!]prio : Priority-tagged frame user_priority, 0-7 (integer)\n"
+- "--vlan-encap [!]proto : Encapsulated protocol (hexadecimal)\n");
++ "--vlan-id [!] id : VLAN-tagged frame identifier, 0,1-4094 (integer)\n"
++ "--vlan-prio [!] prio : Priority-tagged frame user_priority, 0-7 (integer)\n"
++ "--vlan-encap [!] proto : Encapsulated protocol (hexadecimal)\n");
+ }
+
+ /*
+@@ -124,7 +124,7 @@
+ * Check arg value presence
+ */
+ if (optind > argc)
+- print_error ("Missing VLAN ID argument value\n");
++ print_error ("Missing VLAN ID argument value");
+ /*
+ * Convert argv to long int,
+ * set *end to end of argv string,
+@@ -136,7 +136,7 @@
+ */
+ if (i > 4094 || *end != '\0')
+ print_error
+- ("Specified VLAN ID is out of range (0-4094)\n");
++ ("Specified VLAN ID is out of range (0-4094)");
+ /*
+ * Set up parameter value
+ */
+@@ -153,7 +153,7 @@
+ vlaninfo->invflags |= EBT_VLAN_PRIO;
+ if (optind > argc)
+ print_error
+- ("Missing user_priority argument value\n");
++ ("Missing user_priority argument value");
+ /*
+ * Convert argv to long int,
+ * set *end to end of argv string,
+@@ -165,7 +165,7 @@
+ */
+ if (i >= 8 || *end != '\0')
+ print_error
+- ("Specified user_priority is out of range (0-7)\n");
++ ("Specified user_priority is out of range (0-7)");
+ /*
+ * Set up parameter value
+ */
+@@ -182,7 +182,7 @@
+ vlaninfo->invflags |= EBT_VLAN_ENCAP;
+ if (optind > argc)
+ print_error
+- ("Missing encapsulated frame type argument value\n");
++ ("Missing encapsulated frame type argument value");
+ /*
+ * Parameter can be decimal, hexadecimal, or string.
+ * Check arg val range (still raw area)
+@@ -190,12 +190,12 @@
+ (unsigned short) encap = strtol (argv[optind - 1], &end, 16);
+ if (*end == '\0' && (encap < ETH_ZLEN || encap > 0xFFFF))
+ print_error
+- ("Specified encapsulated frame type is out of range\n");
++ ("Specified encapsulated frame type is out of range");
+ if (*end != '\0')
+ if (name_to_number (argv[optind - 1], &encap) == -1)
+ print_error
+ ("Problem with the specified encapsulated"
+- "protocol\n");
++ "protocol");
+ /*
+ * Set up parameter value (network notation)
+ */
+@@ -227,7 +227,7 @@
+ */
+ if (entry->bitmask & EBT_NOPROTO || entry->ethproto != ETH_P_8021Q)
+ print_error
+- ("For use 802.1Q extension the protocol must be specified as 802_1Q\n");
++ ("For use 802.1Q extension the protocol must be specified as 802_1Q");
+ /*
+ * Check if specified vlan-id=0 (priority-tagged frame condition)
+ * when vlan-prio was specified.
+@@ -235,7 +235,7 @@
+ if (GET_BITMASK (EBT_VLAN_PRIO)) {
+ if (vlaninfo->id && GET_BITMASK (EBT_VLAN_ID))
+ print_error
+- ("For use user_priority the specified vlan-id must be 0\n");
++ ("For use user_priority the specified vlan-id must be 0");
+ }
+ }
+
+--- /dev/null Thu Aug 24 11:00:32 2000
++++ ebtables-v2.0-rc1.001/extensions/ebt_mark.c Thu Jul 25 16:51:14 2002
+@@ -0,0 +1,132 @@
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include <getopt.h>
++#include "../include/ebtables_u.h"
++#include <linux/netfilter_bridge/ebt_mark_t.h>
++
++extern char *standard_targets[NUM_STANDARD_TARGETS];
++
++int mark_supplied;
++
++#define MARK_TARGET '1'
++#define MARK_SETMARK '2'
++static struct option opts[] =
++{
++ { "mark-target" , required_argument, 0, MARK_TARGET },
++ { "set-mark" , required_argument, 0, MARK_SETMARK },
++ { 0 }
++};
++
++static void print_help()
++{
++ printf(
++ "mark target options:\n"
++ " --set-mark value : Set nfmark value\n"
++ " --mark-target target : ACCEPT, DROP, RETURN or CONTINUE\n");
++}
++
++static void init(struct ebt_entry_target *target)
++{
++ struct ebt_mark_t_info *markinfo =
++ (struct ebt_mark_t_info *)target->data;
++
++ markinfo->target = EBT_ACCEPT;
++ markinfo->mark = 0;
++ mark_supplied = 0;
++ return;
++}
++
++#define OPT_MARK_TARGET 0x01
++#define OPT_MARK_SETMARK 0x02
++static int parse(int c, char **argv, int argc,
++ const struct ebt_u_entry *entry, unsigned int *flags,
++ struct ebt_entry_target **target)
++{
++ int i;
++ struct ebt_mark_t_info *markinfo =
++ (struct ebt_mark_t_info *)(*target)->data;
++ char *end;
++
++ switch (c) {
++ case MARK_TARGET:
++ check_option(flags, OPT_MARK_TARGET);
++ for (i = 0; i < NUM_STANDARD_TARGETS; i++)
++ if (!strcmp(optarg, standard_targets[i])) {
++ markinfo->target = -i - 1;
++ break;
++ }
++ if (i == NUM_STANDARD_TARGETS)
++ print_error("Illegal --mark-target target");
++ break;
++ case MARK_SETMARK:
++ check_option(flags, OPT_MARK_SETMARK);
++ markinfo->mark = strtoul(optarg, &end, 0);
++ if (*end != '\0' || end == optarg)
++ print_error("Bad MARK value '%s'", optarg);
++ mark_supplied = 1;
++ break;
++ default:
++ return 0;
++ }
++ return 1;
++}
++
++static void final_check(const struct ebt_u_entry *entry,
++ const struct ebt_entry_target *target, const char *name,
++ unsigned int hook_mask, unsigned int time)
++{
++ struct ebt_mark_t_info *markinfo =
++ (struct ebt_mark_t_info *)target->data;
++
++ if (time == 0 && mark_supplied == 0)
++ print_error("No mark value supplied");
++ if ((hook_mask & (1 << NF_BR_NUMHOOKS)) && markinfo->target == EBT_RETURN)
++ print_error("--mark-target RETURN not allowed on base chain");
++}
++
++static void print(const struct ebt_u_entry *entry,
++ const struct ebt_entry_target *target)
++{
++ struct ebt_mark_t_info *markinfo =
++ (struct ebt_mark_t_info *)target->data;
++
++ printf("--set-mark 0x%lx", markinfo->mark);
++ if (markinfo->target == EBT_ACCEPT)
++ return;
++ printf(" --mark-target %s",
++ standard_targets[-markinfo->target - 1]);
++}
++
++static int compare(const struct ebt_entry_target *t1,
++ const struct ebt_entry_target *t2)
++{
++ struct ebt_mark_t_info *markinfo1 =
++ (struct ebt_mark_t_info *)t1->data;
++ struct ebt_mark_t_info *markinfo2 =
++ (struct ebt_mark_t_info *)t2->data;
++
++ return markinfo1->target == markinfo2->target &&
++ markinfo1->mark == markinfo2->mark;
++}
++
++static struct ebt_u_target mark_target =
++{
++ EBT_MARK_TARGET,
++ sizeof(struct ebt_mark_t_info),
++ print_help,
++ init,
++ parse,
++ final_check,
++ print,
++ compare,
++ opts,
++};
++
++static void _init(void) __attribute__ ((constructor));
++static void _init(void)
++{
++ register_target(&mark_target);
++}
+--- /dev/null Thu Aug 24 11:00:32 2000
++++ ebtables-v2.0-rc1.001/extensions/ebt_mark_m.c Sun Jul 21 17:12:04 2002
+@@ -0,0 +1,123 @@
++#include <stdio.h>
++#include <stdlib.h>
++#include <sys/socket.h>
++#include <string.h>
++#include <getopt.h>
++#include "../include/ebtables_u.h"
++#include <linux/netfilter_bridge/ebt_mark_m.h>
++
++#define MARK '1'
++
++static struct option opts[] =
++{
++ { "mark" , required_argument, 0, MARK },
++ { 0 }
++};
++
++static void print_help()
++{
++ printf(
++"mark option:\n"
++"--mark [!] [value][/mask]: Match nfmask value (see man page)\n");
++}
++
++static void init(struct ebt_entry_match *match)
++{
++ struct ebt_mark_m_info *markinfo = (struct ebt_mark_m_info *)match->data;
++
++ markinfo->mark = 0;
++ markinfo->mask = 0;
++ markinfo->invert = 0;
++ markinfo->bitmask = 0;
++}
++
++#define OPT_MARK 0x01
++static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry,
++ unsigned int *flags, struct ebt_entry_match **match)
++{
++ struct ebt_mark_m_info *markinfo = (struct ebt_mark_m_info *)
++ (*match)->data;
++ char *end;
++
++ switch (c) {
++ case MARK:
++ check_option(flags, MARK);
++ if (check_inverse(optarg))
++ markinfo->invert = 1;
++ if (optind > argc)
++ print_error("No mark specified");
++ markinfo->mark = strtoul(argv[optind - 1], &end, 0);
++ markinfo->bitmask = EBT_MARK_AND;
++ if (*end == '/') {
++ if (end == argv[optind - 1])
++ markinfo->bitmask = EBT_MARK_OR;
++ markinfo->mask = strtoul(end+1, &end, 0);
++ } else
++ markinfo->mask = 0xffffffff;
++ if ( *end != '\0' || end == argv[optind - 1])
++ print_error("Bad mark value '%s'", argv[optind - 1]);
++ break;
++ default:
++ return 0;
++ }
++ return 1;
++}
++
++static void final_check(const struct ebt_u_entry *entry,
++ const struct ebt_entry_match *match, const char *name,
++ unsigned int hook_mask, unsigned int time)
++{
++}
++
++static void print(const struct ebt_u_entry *entry,
++ const struct ebt_entry_match *match)
++{
++ struct ebt_mark_m_info *markinfo =
++ (struct ebt_mark_m_info *)match->data;
++
++ printf("--mark ");
++ if (markinfo->invert)
++ printf("! ");
++ if (markinfo->bitmask == EBT_MARK_OR)
++ printf("/0x%lx ", markinfo->mask);
++ else if(markinfo->mask != 0xffffffff)
++ printf("0x%lx/0x%lx ", markinfo->mark, markinfo->mask);
++ else
++ printf("0x%lx ", markinfo->mark);
++}
++
++static int compare(const struct ebt_entry_match *m1,
++ const struct ebt_entry_match *m2)
++{
++ struct ebt_mark_m_info *markinfo1 = (struct ebt_mark_m_info *)m1->data;
++ struct ebt_mark_m_info *markinfo2 = (struct ebt_mark_m_info *)m2->data;
++
++ if (markinfo1->invert != markinfo2->invert)
++ return 0;
++ if (markinfo1->mark != markinfo2->mark)
++ return 0;
++ if (markinfo1->mask != markinfo2->mask)
++ return 0;
++ if (markinfo1->bitmask != markinfo2->bitmask)
++ return 0;
++ return 1;
++}
++
++static struct ebt_u_match mark_match =
++{
++ EBT_MARK_MATCH,
++ sizeof(struct ebt_mark_m_info),
++ print_help,
++ init,
++ parse,
++ final_check,
++ print,
++ compare,
++ opts,
++};
++
++static void _init(void) __attribute((constructor));
++static void _init(void)
++{
++ register_match(&mark_match);
++}
+--- ebtables-v2.0pre10/extensions/Makefile Thu Jun 27 18:53:55 2002
++++ ebtables-v2.0-rc1.001/extensions/Makefile Sat Jul 20 15:34:51 2002
+@@ -1,6 +1,6 @@
+ #! /usr/bin/make
+
+-EXT_FUNC+=nat arp ip standard log redirect vlan
++EXT_FUNC+=nat arp ip standard log redirect vlan mark_m mark
+ EXT_TABLES+=filter nat broute
+ EXT_OBJS+=$(foreach T,$(EXT_FUNC), extensions/ebt_$(T).o)
+ EXT_OBJS+=$(foreach T,$(EXT_TABLES), extensions/ebtable_$(T).o)
+--- ebtables-v2.0pre10/ChangeLog Sun Jul 14 21:30:18 2002
++++ ebtables-v2.0-rc1.001/ChangeLog Tue Jul 30 23:05:30 2002
+@@ -1,3 +1,16 @@
++20020730
++ * other things done before 2.0-rc1 that I can think of,
++ including kernel:
++ * cache align counters for better smp performance
++ * simplify snat code
++ * check for --xxxx-target RETURN on base chain
++ * cleanup code
++ * minor bugfixes
++20020724
++ * code cleanup
++ * bugfix for --atomic-commit
++20020720
++ * added mark target+match
+ 20020714
+ * added --atomic options
+ 20020710
+--- ebtables-v2.0pre10/ebtables.8 Mon Jul 15 21:45:55 2002
++++ ebtables-v2.0-rc1.001/ebtables.8 Thu Jul 25 17:01:17 2002
+@@ -1,4 +1,4 @@
+-.TH EBTABLES 8 "26 June 2002"
++.TH EBTABLES 8 "23 July 2002"
+ .\"
+ .\" Man page written by Bart De Schuymer <bart.de.schuymer@pandora.be>
+ .\" It is based on the iptables man page.
+@@ -21,7 +21,7 @@
+ .\"
+ .\"
+ .SH NAME
+-ebtables (v.2.0) \- ethernet bridge packet table administration
++ebtables (v.2.0) \- Ethernet bridge packet table administration
+ .SH SYNOPSIS
+ .BR "ebtables -[ADI] " "chain rule-specification " [ options ]
+ .br
+@@ -335,7 +335,7 @@
+ .B ebtables
+ will try to write help about those extensions. E.g. ebtables -h snat log ip arp.
+ .TP
+-.BR "-b --db [" "y/n" "]"
++.BR "-b --db " [ "y/n" ]
+ Enable (y) or disable (n) the database.
+ .TP
+ .BR "-j, --jump " "\fItarget\fP"
+@@ -346,13 +346,13 @@
+ or a target extension, see
+ .BR "TARGET EXTENSIONS" .
+ .TP
+-.BR "--atomic " file
++.B --atomic file
+ Let the command operate on the specified file. The data of the table to
+ operate on will be extracted from the file and the result of the operation
+ will be saved back into the file. If specified, this option should come
+ before the command specification.
+ .TP
+-.BR "-M, --modprobe " "program"
++.B -M, --modprobe program
+ When talking to the kernel, use this program to try to automatically load
+ missing kernel modules.
+ .SH MATCH EXTENSIONS
+@@ -390,7 +390,8 @@
+ .BR ARP " or " RARP .
+ .TP
+ .BR "--arp-opcode " "[!] \fIopcode\fP"
+-The (r)arp opcode (decimal or a string, for more details see ebtables -h arp).
++The (r)arp opcode (decimal or a string, for more details see
++.BR "ebtables -h arp" ).
+ .TP
+ .BR "--arp-htype " "[!] \fIhardware type\fP"
+ The hardware type, this can be a decimal or the string "Ethernet". This
+@@ -419,13 +420,24 @@
+ Required VID to be 0 (null VID) or not specified vlan-id parameter (in this case VID deliberately be set to 0).
+ .TP
+ .BR "--vlan-encap " "[!] \fItype\fP"
+-The encapsulated ethernet frame type/length, this can be a hexadecimal number from 0x0000 to 0xFFFF.
++The encapsulated Ethernet frame type/length, this can be a hexadecimal
++number from 0x0000 to 0xFFFF.
+ Usually it's 0x0800 (IPv4). See also
+ .B /etc/ethertypes
+ file.
++.SS mark_m
++.TP
++.BR "--mark " "[!] [\fIvalue\fP][/\fImask\fP]"
++Matches frames with the given unsigned mark value. If a mark value and
++mask is specified, the logical AND of the mark value of the frame and
++the user specified mask is taken before comparing with the user specified
++mark value. If only a mask is specified (start with '/') the logical AND
++of the mark value of the frame and the user specified mark is taken and
++the result is compared with zero.
++
+ .SH WATCHER EXTENSION(S)
+-Watchers are things that only look at frames passing by. These watchers only see the
+-frame if the frame passes all the matches of the rule.
++Watchers are things that only look at frames passing by. These watchers only
++see the frame if the frame passes all the matches of the rule.
+ .SS log
+ The fact that the log module is a watcher lets us log stuff while giving a target
+ by choice. Note that the log module therefore is not a target.
+@@ -478,7 +490,7 @@
+ The default target is ACCEPT. Making it CONTINUE could let you use
+ multiple target extensions on the same frame. Making it DROP doesn't
+ make sense, but you could do that too. RETURN is also allowed. Note
+-that using RETURN in a base chain will result in the CONTINUE behaviour.
++that using RETURN in a base chain is not allowed.
+ .TP
+ .B dnat
+ The
+@@ -504,7 +516,7 @@
+ multiple target extensions on the same frame. Making it DROP only makes
+ sense in the BROUTING chain but using the redirect target is more logical
+ there. RETURN is also allowed. Note
+-that using RETURN in a base chain will result in the CONTINUE behaviour.
++that using RETURN in a base chain is not allowed.
+ .TP
+ .B redirect
+ The
+@@ -523,7 +535,28 @@
+ The default target is ACCEPT. Making it CONTINUE could let you use
+ multiple target extensions on the same frame. Making it DROP in the
+ BROUTING chain will let the frames be routed. RETURN is also allowed. Note
+-that using RETURN in a base chain will result in the CONTINUE behaviour.
++that using RETURN in a base chain is not allowed.
++.TP
++.B mark
++The mark target can be used in every chain of every table. It is possible
++to use the marking of a frame/packet in both ebtables and iptables,
++if the br-nf code is compiled into the kernel. Both put the marking at the
++same place. So, you can consider this fact as a feature, or as something to
++watch out for.
++.br
++.BR "--mark-target " "\fItarget\fP"
++.br
++Specifies the standard target. After marking the frame, the rule
++still has to give a standard target so
++.B ebtables
++knows what to do.
++The default target is ACCEPT. Making it CONTINUE can let you do other
++things with the frame in other rules of the chain.
++.br
++.BR "--set-mark " "\fIvalue\fP"
++.br
++Mark the frame with the specified unsigned value.
++.br
+ .SH FILES
+ .I /etc/ethertypes
+ .SH BUGS
+--- ebtables-v2.0pre10/ethertypes Thu Jun 27 18:53:55 2002
++++ ebtables-v2.0-rc1.001/ethertypes Fri Jul 19 20:44:25 2002
+@@ -3,15 +3,14 @@
+ # all protocol numbers are in hexadecimal form
+ # maximum namesize = 20 characters
+ # always put tabs or spaces between the name and the protocol number
+-# don't use more than 4 digits for the protocol number
++# anything on a line after the protocol number is ignored
+ # programs using this file should not be case sensitive
+-# that's all :-))
+-IPV4 0800 put your comments behind, on the same line, after a tab
+-X25 0805 or whitespace
++IPv4 0800
++X25 0805
+ ARP 0806
+ 802_1Q 8100 802.1Q Virtual LAN tagged frame
+ IPX 8137
+-IPV6 86DD
++IPv6 86DD
+ NetBEUI 8191
+ BPQ 08FF G8BPQ AX.25 Ethernet Packet
+ DEC 6000 DEC Assigned proto
+--- ebtables-v2.0pre10/include/ebtables_u.h Sat Jul 13 21:13:46 2002
++++ ebtables-v2.0-rc1.001/include/ebtables_u.h Fri Jul 26 14:03:04 2002
+@@ -29,7 +29,7 @@
+ struct ebt_u_entries
+ {
+ int policy;
+- __u32 nentries;
++ unsigned int nentries;
+ // counter offset for this chain
+ unsigned int counter_offset;
+ // used for udc
+@@ -42,7 +42,7 @@
+ {
+ struct ebt_u_entries *udc;
+ struct ebt_u_chain_list *next;
+- // this is only used internally, in communications.c
++ // this is only used internally, in communication.c
+ char *kernel_start;
+ };
+
+@@ -68,6 +68,8 @@
+ int selected_hook;
+ // used for the atomic option
+ char *filename;
++ // tells what happened to the old rules
++ unsigned short *counterchanges;
+ };
+
+ struct ebt_u_table
+@@ -92,17 +94,17 @@
+
+ struct ebt_u_entry
+ {
+- __u32 bitmask;
+- __u32 invflags;
++ unsigned int bitmask;
++ unsigned int invflags;
+ __u16 ethproto;
+- __u8 in[IFNAMSIZ];
+- __u8 logical_in[IFNAMSIZ];
+- __u8 out[IFNAMSIZ];
+- __u8 logical_out[IFNAMSIZ];
+- __u8 sourcemac[ETH_ALEN];
+- __u8 sourcemsk[ETH_ALEN];
+- __u8 destmac[ETH_ALEN];
+- __u8 destmsk[ETH_ALEN];
++ char in[IFNAMSIZ];
++ char logical_in[IFNAMSIZ];
++ char out[IFNAMSIZ];
++ char logical_out[IFNAMSIZ];
++ unsigned char sourcemac[ETH_ALEN];
++ unsigned char sourcemsk[ETH_ALEN];
++ unsigned char destmac[ETH_ALEN];
++ unsigned char destmsk[ETH_ALEN];
+ struct ebt_u_match_list *m_list;
+ struct ebt_u_watcher_list *w_list;
+ struct ebt_entry_target *t;
+@@ -194,8 +196,7 @@
+ struct ebt_u_match *find_match(const char *name);
+ struct ebt_u_watcher *find_watcher(const char *name);
+ struct ebt_u_table *find_table(char *name);
+-void deliver_counters(struct ebt_u_replace *repl,
+- unsigned short * counterchanges);
++void deliver_counters(struct ebt_u_replace *repl);
+ void deliver_table(struct ebt_u_replace *repl);
+ void get_dbinfo(struct brdb_dbinfo *nr);
+ void get_db(int len, struct brdb_dbentry *db);