general cleanup + add -C and -c
diff --git a/ChangeLog b/ChangeLog
index af1fe66..3507924 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -5,6 +5,8 @@
 	* added the ebtablesd/ebtablesu scheme to allow faster
 	  addition of rules (and to test the modular code).
 	* some small fixes
+	* added -c option (initialize counters)
+	* added -C option (change counters)
 20031102
 	Since last entry:
 	* <grzes_at_gnu.univ.gda.pl> added arpreply and among modules
diff --git a/communication.c b/communication.c
index f712b2b..e93217a 100644
--- a/communication.c
+++ b/communication.c
@@ -362,6 +362,7 @@
 			old++;
 			/* We've set a new counter */
 			new++;
+			next = next->next;
 		} else if (cc->type == CNT_DEL) {
 			/* Don't use this old counter */
 			old++;
@@ -373,9 +374,9 @@
 				old++;
 				new++;
 			}
+			next = next->next;
 		}
 		cc = cc->next;
-		next = next->next;
 	}
 
 	free(u_repl->counters);
diff --git a/ebtables.c b/ebtables.c
index 8723e66..f3e8cdd 100644
--- a/ebtables.c
+++ b/ebtables.c
@@ -58,6 +58,7 @@
 	{ "help"          , no_argument      , 0, 'h' },
 	{ "jump"          , required_argument, 0, 'j' },
 	{ "set-counter"   , required_argument, 0, 'c' },
+	{ "change-counter", required_argument, 0, 'C' },
 	{ "proto"         , required_argument, 0, 'p' },
 	{ "protocol"      , required_argument, 0, 'p' },
 	{ "db"            , required_argument, 0, 'b' },
@@ -442,6 +443,33 @@
 	return 0;
 }
 
+static int parse_change_counters_rule(int argc, char **argv, int *rule_nr, int *rule_nr_end)
+{
+	char *buffer;
+
+	if (optind + 1 >= argc || (argv[optind][0] == '-' && (argv[optind][1] < '0' || argv[optind][1] > '9')) ||
+	    (argv[optind + 1][0] == '-' && (argv[optind + 1][1] < '0'  && argv[optind + 1][1] > '9')))
+		ebt_print_error2("The command -C needs at least 3 arguments");
+	if (optind + 2 < argc && (argv[optind + 2][0] != '-' || (argv[optind][1] >= '0' && argv[optind][1] <= '9'))) {
+		if (optind + 3 != argc)
+			ebt_print_error2("No extra options allowed with -C start_nr[:end_nr] pcnt bcnt");
+		if (parse_delete_rule(argv[optind], rule_nr, rule_nr_end))
+			ebt_print_error2("Something is wrong with the rule number specification '%s'", argv[optind]);
+		optind++;
+	}
+
+	new_entry->cnt.pcnt = strtoull(argv[optind], &buffer, 10);
+	if (*buffer != '\0')
+		ebt_print_error2("Packet counter '%s' invalid", argv[optind])
+	optind++;
+	new_entry->cnt.bcnt = strtoull(argv[optind], &buffer, 10);
+	if (*buffer != '\0')
+		ebt_print_error2("Packet counter '%s' invalid", argv[optind])
+
+	optind++;
+	return 0;
+}
+
 static int parse_iface(char *iface, char *option)
 {
 	char *c;
@@ -464,19 +492,6 @@
 	ebt_iterate_targets(merge_target);
 }
 
-#define ebt_print_error2(format, args...) {__ebt_print_error(format, ##args); \
-   return -1;}
-#define ebt_check_option2(flags,mask)	\
-({ebt_check_option(flags,mask);		\
- if (ebt_errormsg[0] != '\0')		\
-	return -1;})
-#define ebt_check_inverse2(option)				\
-({int __ret = ebt_check_inverse(option);			\
-if (ebt_errormsg[0] != '\0')					\
-	return -1;						\
-if (!optarg)							\
-	__ebt_print_error("Option without (mandatory) argument");	\
-__ret;})
 #define OPT_COMMANDS (replace->flags & OPT_COMMAND || replace->flags & OPT_ZERO)
 
 #define OPT_COMMAND	0x01
@@ -545,11 +560,12 @@
 
 	/* Getopt saves the day */
 	while ((c = getopt_long(argc, argv,
-	   "-A:D:I:N:E:X::L::Z::F::P:Vhi:o:j:c:p:s:d:t:M:", ebt_options, NULL)) != -1) {
+	   "-A:D:C:I:N:E:X::L::Z::F::P:Vhi:o:j:c:p:s:d:t:M:", ebt_options, NULL)) != -1) {
 		switch (c) {
 
 		case 'A': /* Add a rule */
 		case 'D': /* Delete a rule */
+		case 'C': /* Change counters */
 		case 'P': /* Define policy */
 		case 'I': /* Insert a rule */
 		case 'N': /* Make a user defined chain */
@@ -614,8 +630,11 @@
 				if (optind != argc - 1)
 					ebt_print_error2("No extra options allowed with -D start_nr[:end_nr]");
 				if (parse_delete_rule(argv[optind], &rule_nr, &rule_nr_end))
-					ebt_print_error2("Problem with the specified rule number(s)");
+					ebt_print_error2("Problem with the specified rule number(s) '%s'", argv[optind]);
 				optind++;
+			} else if (c == 'C') {
+				if (parse_change_counters_rule(argc, argv, &rule_nr, &rule_nr_end))
+					return -1;
 			} else if (c == 'I') {
 				if (optind >= argc || (argv[optind][0] == '-' && (argv[optind][1] < '0' || argv[optind][1] > '9')))
 					ebt_print_error2("No rulenr for -I specified");
@@ -996,8 +1015,11 @@
 		default:
 			/* Is it a target option? */
 			t = (struct ebt_u_target *)new_entry->t;
-			if ((t->parse(c - t->option_offset, argv, argc, new_entry, &t->flags, &t->t)))
+			if ((t->parse(c - t->option_offset, argv, argc, new_entry, &t->flags, &t->t))) {
+				if (ebt_errormsg[0] != '\0')
+					return -1;
 				goto check_extension;
+			}
 
 			/* Is it a match_option? */
 			for (m = ebt_matches; m; m = m->next)
@@ -1005,6 +1027,8 @@
 					break;
 
 			if (m != NULL) {
+				if (ebt_errormsg[0] != '\0')
+					return -1;
 				if (m->used == 0) {
 					ebt_add_match(new_entry, m);
 					m->used = 1;
@@ -1019,6 +1043,8 @@
 
 			if (w == NULL)
 				ebt_print_error2("Unknown argument: '%s', %c, '%c'", argv[optind - 1], (char)optopt, (char)c);
+			if (ebt_errormsg[0] != '\0')
+				return -1;
 			if (w->used == 0) {
 				ebt_add_watcher(new_entry, w);
 				w->used = 1;
@@ -1045,7 +1071,7 @@
 
 	/* Do the final checks */
 	if (replace->command == 'A' || replace->command == 'I' ||
-	   replace->command == 'D') {
+	   replace->command == 'D' || replace->command == 'C') {
 		/* This will put the hook_mask right for the chains */
 		ebt_check_for_loops(replace);
 		if (ebt_errormsg[0] != '\0')
@@ -1135,9 +1161,16 @@
 		}
 		/* Don't reuse the added rule */
 		new_entry = NULL;
-	} else if (replace->command == 'D')
-delete_the_rule: /* This needs to be followed by a check on ebt_errormsg[0] */
+	} else if (replace->command == 'D') {
+delete_the_rule:
 		ebt_delete_rule(replace, new_entry, rule_nr, rule_nr_end);
+		if (ebt_errormsg[0] != '\0')
+			return -1;
+	} else if (replace->command == 'C') {
+		ebt_change_counters(replace, new_entry, rule_nr, rule_nr_end, &(new_entry->cnt));
+		if (ebt_errormsg[0] != '\0')
+			return -1;
+	}
 	/* Commands -N, -E, -X, --atomic-commit, --atomic-commit, --atomic-save,
 	 * --init-table fall through */
 
diff --git a/extensions/ebt_802_3.c b/extensions/ebt_802_3.c
index e0b65ee..a43d060 100644
--- a/extensions/ebt_802_3.c
+++ b/extensions/ebt_802_3.c
@@ -1,3 +1,11 @@
+/* 802_3
+ *
+ * Author:
+ * Chris Vitale <csv@bluetail.com>
+ *
+ * May 2003
+ */
+
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
@@ -43,28 +51,23 @@
 
 	switch (c) {
 		case _802_3_SAP:
-			ebt_check_option(flags, _802_3_SAP);
-			if (ebt_check_inverse(optarg))
+			ebt_check_option2(flags, _802_3_SAP);
+			if (ebt_check_inverse2(optarg))
 				info->invflags |= EBT_802_3_SAP;
-
-			if (optind > argc)
-				ebt_print_error("Missing 802.3-sap argument");
-			i = strtoul(argv[optind - 1], &end, 16);
+			i = strtoul(optarg, &end, 16);
 			if (i > 255 || *end != '\0') 
-				ebt_print_error("Problem with specified "
+				ebt_print_error2("Problem with specified "
 						"sap hex value, %x",i);
 			info->sap = i; /* one byte, so no byte order worries */
 			info->bitmask |= EBT_802_3_SAP;
 			break;
 		case _802_3_TYPE:
-			ebt_check_option(flags, _802_3_TYPE);
-			if (ebt_check_inverse(optarg))
+			ebt_check_option2(flags, _802_3_TYPE);
+			if (ebt_check_inverse2(optarg))
 				info->invflags |= EBT_802_3_TYPE;
-			if (optind > argc)
-				ebt_print_error("Missing 802.3-type argument");
-			i = strtoul(argv[optind - 1], &end, 16);
+			i = strtoul(optarg, &end, 16);
 			if (i > 65535 || *end != '\0') {
-				ebt_print_error("Problem with the specified "
+				ebt_print_error2("Problem with the specified "
 						"type hex value, %x",i);
 			}
 			info->type = htons(i);
diff --git a/extensions/ebt_among.c b/extensions/ebt_among.c
index 1756e44..65ce481 100644
--- a/extensions/ebt_among.c
+++ b/extensions/ebt_among.c
@@ -1,3 +1,11 @@
+/* ebt_among
+ *
+ * Authors:
+ * Grzegorz Borowiak <grzes@gnu.univ.gda.pl>
+ *
+ * August, 2003
+ */
+
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
@@ -9,8 +17,6 @@
 #include <linux/if_ether.h>
 #include <linux/netfilter_bridge/ebt_among.h>
 
-#define NODEBUG
-
 #define AMONG_DST '1'
 #define AMONG_SRC '2'
 
@@ -69,6 +75,8 @@
 	struct ebt_mac_wormhash *result =
 	    (struct ebt_mac_wormhash *) malloc(size);
 
+	if (!result)
+		ebt_print_memory();
 	memset(result, 0, size);
 	result->poolsize = n;
 	return result;
@@ -181,54 +189,53 @@
 		for (i = 0; i < 5; i++) {
 			if (read_until(&pc, ":", token, 2) < 0
 			    || token[0] == 0) {
-				ebt_print_error("MAC parse error: %.20s",
-						anchor);
+				ebt_print_error("MAC parse error: %.20s", anchor);
+				return NULL;
 			}
 			mac[i] = strtol(token, &endptr, 16);
 			if (*endptr) {
-				ebt_print_error("MAC parse error: %.20s",
-						anchor);
+				ebt_print_error("MAC parse error: %.20s", anchor);
+				return NULL;
 			}
 			pc++;
 		}
 		if (read_until(&pc, "=,", token, 2) == -2 || token[0] == 0) {
 			ebt_print_error("MAC parse error: %.20s", anchor);
+			return NULL;
 		}
 		mac[i] = strtol(token, &endptr, 16);
 		if (*endptr) {
 			ebt_print_error("MAC parse error: %.20s", anchor);
+			return NULL;
 		}
 		if (*pc == '=') {
 			/* an IP follows the MAC; collect similarly to MAC */
 			pc++;
 			anchor = pc;
 			for (i = 0; i < 3; i++) {
-				if (read_until(&pc, ".", token, 3) < 0
-				    || token[0] == 0) {
-					ebt_print_error
-					    ("IP parse error: %.20s",
-					     anchor);
+				if (read_until(&pc, ".", token, 3) < 0 || token[0] == 0) {
+					ebt_print_error("IP parse error: %.20s", anchor);
+					return NULL;
 				}
 				ip[i] = strtol(token, &endptr, 10);
 				if (*endptr) {
-					ebt_print_error
-					    ("IP parse error: %.20s",
-					     anchor);
+					ebt_print_error("IP parse error: %.20s", anchor);
+					return NULL;
 				}
 				pc++;
 			}
-			if (read_until(&pc, ",", token, 3) == -2
-			    || token[0] == 0) {
-				ebt_print_error("IP parse error: %.20s",
-					    anchor);
+			if (read_until(&pc, ",", token, 3) == -2 || token[0] == 0) {
+				ebt_print_error("IP parse error: %.20s", anchor);
+				return NULL;
 			}
 			ip[3] = strtol(token, &endptr, 10);
 			if (*endptr) {
-				ebt_print_error("IP parse error: %.20s",
-					    anchor);
+				ebt_print_error("IP parse error: %.20s", anchor);
+				return NULL;
 			}
 			if (*(uint32_t*)ip == 0) {
 				ebt_print_error("Illegal IP 0.0.0.0");
+				return NULL;
 			}
 		} else {
 			/* no IP, we set it to 0.0.0.0 */
@@ -260,6 +267,7 @@
 		/* but first assert :-> */
 		if (*pc != ',') {
 			ebt_print_error("Something went wrong; no comma...\n");
+			return NULL;
 		}
 		pc++;
 
@@ -295,30 +303,33 @@
 	switch (c) {
 	case AMONG_DST:
 	case AMONG_SRC:
-		if (ebt_check_inverse(optarg)) {
+		if (c == AMONG_DST) {
+			ebt_check_option2(flags, OPT_DST);
+		} else {
+			ebt_check_option2(flags, OPT_SRC);
+		}
+		if (ebt_check_inverse2(optarg)) {
 			if (c == AMONG_DST)
 				info->bitmask |= EBT_AMONG_DST_NEG;
 			else
 				info->bitmask |= EBT_AMONG_SRC_NEG;
 		}
-		if (optind > argc)
-			ebt_print_error("No MAC list specified\n");
-		wh = create_wormhash(argv[optind - 1]);
-		old_size = sizeof(struct ebt_entry_match) +
-				(**match).match_size;
-		h = malloc((new_size =
-			    old_size + ebt_mac_wormhash_size(wh)));
+		wh = create_wormhash(optarg);
+		if (ebt_errormsg[0] != '\0')
+			break;
+
+		old_size = sizeof(struct ebt_entry_match) + (**match).match_size;
+		h = malloc((new_size = old_size + ebt_mac_wormhash_size(wh)));
+		if (!h)
+			ebt_print_memory();
 		memcpy(h, *match, old_size);
-		memcpy((char *) h + old_size, wh,
-		       ebt_mac_wormhash_size(wh));
+		memcpy((char *) h + old_size, wh, ebt_mac_wormhash_size(wh));
 		h->match_size = new_size - sizeof(struct ebt_entry_match);
 		info = (struct ebt_among_info *) h->data;
 		if (c == AMONG_DST) {
-			ebt_check_option(flags, OPT_DST);
 			info->wh_dst_ofs =
 			    old_size - sizeof(struct ebt_entry_match);
 		} else {
-			ebt_check_option(flags, OPT_SRC);
 			info->wh_src_ofs =
 			    old_size - sizeof(struct ebt_entry_match);
 		}
diff --git a/extensions/ebt_arp.c b/extensions/ebt_arp.c
index c38eec6..9eed645 100644
--- a/extensions/ebt_arp.c
+++ b/extensions/ebt_arp.c
@@ -1,3 +1,12 @@
+/* ebt_arp
+ *
+ * Authors:
+ * Bart De Schuymer <bdschuym@pandora.be>
+ * Tim Gardner <timg@tpi.com>
+ *
+ * April, 2002
+ */
+
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
@@ -92,20 +101,16 @@
 
 	switch (c) {
 	case ARP_OPCODE:
-		ebt_check_option(flags, OPT_OPCODE);
-		if (ebt_check_inverse(optarg))
+		ebt_check_option2(flags, OPT_OPCODE);
+		if (ebt_check_inverse2(optarg))
 			arpinfo->invflags |= EBT_ARP_OPCODE;
-
-		if (optind > argc)
-			ebt_print_error("Missing ARP opcode argument");
-		i = strtol(argv[optind - 1], &end, 10);
+		i = strtol(optarg, &end, 10);
 		if (i < 0 || i >= (0x1 << 16) || *end !='\0') {
 			for (i = 0; i < NUMOPCODES; i++)
 				if (!strcasecmp(opcodes[i], optarg))
 					break;
 			if (i == NUMOPCODES)
-				ebt_print_error("Problem with specified "
-						"ARP opcode");
+				ebt_print_error2("Problem with specified ARP opcode");
 			i++;
 		}
 		arpinfo->opcode = htons(i);
@@ -113,19 +118,15 @@
 		break;
 
 	case ARP_HTYPE:
-		ebt_check_option(flags, OPT_HTYPE);
-		if (ebt_check_inverse(optarg))
+		ebt_check_option2(flags, OPT_HTYPE);
+		if (ebt_check_inverse2(optarg))
 			arpinfo->invflags |= EBT_ARP_HTYPE;
-
-		if (optind > argc)
-			ebt_print_error("Missing ARP hardware type argument");
-		i = strtol(argv[optind - 1], &end, 10);
+		i = strtol(optarg, &end, 10);
 		if (i < 0 || i >= (0x1 << 16) || *end !='\0') {
 			if (!strcasecmp("Ethernet", argv[optind - 1]))
 				i = 1;
 			else
-				ebt_print_error("Problem with specified ARP "
-						"hardware type");
+				ebt_print_error2("Problem with specified ARP hardware type");
 		}
 		arpinfo->htype = htons(i);
 		arpinfo->bitmask |= EBT_ARP_HTYPE;
@@ -135,19 +136,17 @@
 	{
 		uint16_t proto;
 
-		ebt_check_option(flags, OPT_PTYPE);
-		if (ebt_check_inverse(optarg))
+		ebt_check_option2(flags, OPT_PTYPE);
+		if (ebt_check_inverse2(optarg))
 			arpinfo->invflags |= EBT_ARP_PTYPE;
 
-		if (optind > argc)
-			ebt_print_error("Missing ARP protocol type argument");
-		i = strtol(argv[optind - 1], &end, 16);
+		i = strtol(optarg, &end, 16);
 		if (i < 0 || i >= (0x1 << 16) || *end !='\0') {
 			struct ethertypeent *ent;
 
 			ent = getethertypebyname(argv[optind - 1]);
 			if (!ent)
-				ebt_print_error("Problem with specified ARP "
+				ebt_print_error2("Problem with specified ARP "
 						"protocol type");
 			proto = ent->e_ethertype;
 
@@ -161,51 +160,46 @@
 	case ARP_IP_S:
 	case ARP_IP_D:
 		if (c == ARP_IP_S) {
-			ebt_check_option(flags, OPT_IP_S);
+			ebt_check_option2(flags, OPT_IP_S);
 			addr = &arpinfo->saddr;
 			mask = &arpinfo->smsk;
 			arpinfo->bitmask |= EBT_ARP_SRC_IP;
 		} else {
-			ebt_check_option(flags, OPT_IP_D);
+			ebt_check_option2(flags, OPT_IP_D);
 			addr = &arpinfo->daddr;
 			mask = &arpinfo->dmsk;
 			arpinfo->bitmask |= EBT_ARP_DST_IP;
 		}
-		if (ebt_check_inverse(optarg)) {
+		if (ebt_check_inverse2(optarg)) {
 			if (c == ARP_IP_S)
 				arpinfo->invflags |= EBT_ARP_SRC_IP;
 			else
 				arpinfo->invflags |= EBT_ARP_DST_IP;
 		}
-		if (optind > argc)
-			ebt_print_error("Missing ARP IP address argument");
-		ebt_parse_ip_address(argv[optind - 1], addr, mask);
+		ebt_parse_ip_address(optarg, addr, mask);
 		break;
 
 	case ARP_MAC_S:
 	case ARP_MAC_D:
 		if (c == ARP_MAC_S) {
-			ebt_check_option(flags, OPT_MAC_S);
+			ebt_check_option2(flags, OPT_MAC_S);
 			maddr = arpinfo->smaddr;
 			mmask = arpinfo->smmsk;
 			arpinfo->bitmask |= EBT_ARP_SRC_MAC;
 		} else {
-			ebt_check_option(flags, OPT_MAC_D);
+			ebt_check_option2(flags, OPT_MAC_D);
 			maddr = arpinfo->dmaddr;
 			mmask = arpinfo->dmmsk;
 			arpinfo->bitmask |= EBT_ARP_DST_MAC;
 		}
-		if (ebt_check_inverse(optarg)) {
+		if (ebt_check_inverse2(optarg)) {
 			if (c == ARP_MAC_S)
 				arpinfo->invflags |= EBT_ARP_SRC_MAC;
 			else
 				arpinfo->invflags |= EBT_ARP_DST_MAC;
 		}
-		if (optind > argc)
-			ebt_print_error("Missing ARP MAC address argument");
-		if (ebt_get_mac_and_mask(argv[optind - 1], maddr, mmask))
-			ebt_print_error("Problem with ARP MAC address "
-					"argument");
+		if (ebt_get_mac_and_mask(optarg, maddr, mmask))
+			ebt_print_error2("Problem with ARP MAC address argument");
 		break;
 
 	default:
@@ -220,8 +214,7 @@
 {
 	if ((entry->ethproto != ETH_P_ARP && entry->ethproto != ETH_P_RARP) ||
 	    entry->invflags & EBT_IPROTO)
-		ebt_print_error("For (R)ARP filtering the protocol must be "
-				"specified as ARP or RARP");
+		ebt_print_error("For (R)ARP filtering the protocol must be specified as ARP or RARP");
 }
 
 static void print(const struct ebt_u_entry *entry,
diff --git a/extensions/ebt_arpreply.c b/extensions/ebt_arpreply.c
index 9c50519..32e50b4 100644
--- a/extensions/ebt_arpreply.c
+++ b/extensions/ebt_arpreply.c
@@ -1,3 +1,12 @@
+/* ebt_arpreply
+ *
+ * Authors:
+ * Grzegorz Borowiak <grzes@gnu.univ.gda.pl>
+ * Bart De Schuymer <bdschuym@pandora.be>
+ *
+ *  August, 2003
+ */
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -48,17 +57,16 @@
 
 	switch (c) {
 	case REPLY_MAC:
-		ebt_check_option(flags, OPT_REPLY_MAC);
+		ebt_check_option2(flags, OPT_REPLY_MAC);
 		if (!(addr = ether_aton(optarg)))
-			ebt_print_error("Problem with specified "
-					"--arpreply-mac mac");
+			ebt_print_error2("Problem with specified --arpreply-mac mac");
 		memcpy(replyinfo->mac, addr, ETH_ALEN);
 		mac_supplied = 1;
 		break;
 	case REPLY_TARGET:
-		ebt_check_option(flags, OPT_REPLY_TARGET);
+		ebt_check_option2(flags, OPT_REPLY_TARGET);
 		if (FILL_TARGET(optarg, replyinfo->target))
-			ebt_print_error("Illegal --arpreply-target target");
+			ebt_print_error2("Illegal --arpreply-target target");
 		break;
 
 	default:
@@ -74,17 +82,17 @@
 	struct ebt_arpreply_info *replyinfo =
 	   (struct ebt_arpreply_info *)target->data;
 
-	if (entry->ethproto != ETH_P_ARP || entry->invflags & EBT_IPROTO)
-		ebt_print_error("For ARP replying the protocol must be "
-				"specified as ARP");
-	if (time == 0 && mac_supplied == 0)
+	if (entry->ethproto != ETH_P_ARP || entry->invflags & EBT_IPROTO) {
+		ebt_print_error("For ARP replying the protocol must be specified as ARP");
+	} else if (time == 0 && mac_supplied == 0) {
 		ebt_print_error("No arpreply mac supplied");
-	if (BASE_CHAIN && replyinfo->target == EBT_RETURN)
-		ebt_print_error("--arpreply-target RETURN not allowed on "
-				"base chain");
-	CLEAR_BASE_CHAIN_BIT;
-	if (strcmp(name, "nat") || hookmask & ~(1 << NF_BR_PRE_ROUTING))
-		ebt_print_error("arpreply only allowed in PREROUTING");
+	} else if (BASE_CHAIN && replyinfo->target == EBT_RETURN) {
+		ebt_print_error("--arpreply-target RETURN not allowed on base chain");
+	} else {
+		CLEAR_BASE_CHAIN_BIT;
+		if (strcmp(name, "nat") || hookmask & ~(1 << NF_BR_PRE_ROUTING))
+			ebt_print_error("arpreply only allowed in PREROUTING");
+	}
 }
 
 static void print(const struct ebt_u_entry *entry,
diff --git a/extensions/ebt_inat.c b/extensions/ebt_inat.c
index aae5cab..1aa9435 100644
--- a/extensions/ebt_inat.c
+++ b/extensions/ebt_inat.c
@@ -1,3 +1,11 @@
+/* ebt_inat
+ *
+ * Authors:
+ * Grzegorz Borowiak <grzes@gnu.univ.gda.pl>
+ *
+ * August, 2003
+ */
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
diff --git a/extensions/ebt_ip.c b/extensions/ebt_ip.c
index c81e687..8e45171 100644
--- a/extensions/ebt_ip.c
+++ b/extensions/ebt_ip.c
@@ -1,29 +1,13 @@
-/*
- *  ebtables ebt_ip: IP extension module for userspace
+/* ebt_ip
  * 
- *  Authors:
- *   Bart De Schuymer <bdschuym@pandora.be>
+ * Authors:
+ * Bart De Schuymer <bdschuym@pandora.be>
  *
- *  Changes:
+ * Changes:
  *    added ip-sport and ip-dport; parsing of port arguments is
  *    based on code from iptables-1.2.7a
  *    Innominate Security Technologies AG <mhopf@innominate.com>
  *    September, 2002
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
  */
 
 #include <stdio.h>
@@ -76,7 +60,7 @@
 	}
 	ebt_print_error("Problem with specified %s port '%s'", 
 			protocol?protocol:"", name);
-	return 0; /* never reached */
+	return 0;
 }
 
 static void
@@ -92,7 +76,11 @@
 		*cp = '\0';
 		cp++;
 		ports[0] = buffer[0] ? parse_port(protocol, buffer) : 0;
+		if (ebt_errormsg[0] != '\0')
+			return;
 		ports[1] = cp[0] ? parse_port(protocol, cp) : 0xFFFF;
+		if (ebt_errormsg[0] != '\0')
+			return;
 		
 		if (ports[0] > ports[1])
 			ebt_print_error("Invalid portrange (min > max)");
@@ -143,81 +131,67 @@
 
 	switch (c) {
 	case IP_SOURCE:
-		ebt_check_option(flags, OPT_SOURCE);
+		ebt_check_option2(flags, OPT_SOURCE);
 		ipinfo->bitmask |= EBT_IP_SOURCE;
 
 	case IP_DEST:
 		if (c == IP_DEST) {
-			ebt_check_option(flags, OPT_DEST);
+			ebt_check_option2(flags, OPT_DEST);
 			ipinfo->bitmask |= EBT_IP_DEST;
 		}
-		if (ebt_check_inverse(optarg)) {
+		if (ebt_check_inverse2(optarg)) {
 			if (c == IP_SOURCE)
 				ipinfo->invflags |= EBT_IP_SOURCE;
 			else
 				ipinfo->invflags |= EBT_IP_DEST;
 		}
-
-		if (optind > argc)
-			ebt_print_error("Missing IP address argument");
 		if (c == IP_SOURCE)
-			ebt_parse_ip_address(argv[optind - 1], &ipinfo->saddr,
-			   &ipinfo->smsk);
+			ebt_parse_ip_address(optarg, &ipinfo->saddr, &ipinfo->smsk);
 		else
-			ebt_parse_ip_address(argv[optind - 1], &ipinfo->daddr,
-			   &ipinfo->dmsk);
+			ebt_parse_ip_address(optarg, &ipinfo->daddr, &ipinfo->dmsk);
 		break;
 
 	case IP_SPORT:
 	case IP_DPORT:
 		if (c == IP_SPORT) {
-			ebt_check_option(flags, OPT_SPORT);
+			ebt_check_option2(flags, OPT_SPORT);
 			ipinfo->bitmask |= EBT_IP_SPORT;
-			if (ebt_check_inverse(optarg))
+			if (ebt_check_inverse2(optarg))
 				ipinfo->invflags |= EBT_IP_SPORT;
 		} else {
-			ebt_check_option(flags, OPT_DPORT);
+			ebt_check_option2(flags, OPT_DPORT);
 			ipinfo->bitmask |= EBT_IP_DPORT;
-			if (ebt_check_inverse(optarg))
+			if (ebt_check_inverse2(optarg))
 				ipinfo->invflags |= EBT_IP_DPORT;
 		}
-		if (optind > argc)
-			ebt_print_error("Missing port argument");
 		if (c == IP_SPORT)
-			parse_port_range(NULL, argv[optind - 1], ipinfo->sport);
+			parse_port_range(NULL, optarg, ipinfo->sport);
 		else
-			parse_port_range(NULL, argv[optind - 1], ipinfo->dport);
+			parse_port_range(NULL, optarg, ipinfo->dport);
 		break;
 
 	case IP_myTOS:
-		ebt_check_option(flags, OPT_TOS);
-		if (ebt_check_inverse(optarg))
+		ebt_check_option2(flags, OPT_TOS);
+		if (ebt_check_inverse2(optarg))
 			ipinfo->invflags |= EBT_IP_TOS;
-
-		if (optind > argc)
-			ebt_print_error("Missing IP tos argument");
-		i = strtol(argv[optind - 1], &end, 16);
+		i = strtol(optarg, &end, 16);
 		if (i < 0 || i > 255 || *end != '\0')
-			ebt_print_error("Problem with specified IP tos");
+			ebt_print_error2("Problem with specified IP tos");
 		ipinfo->tos = i;
 		ipinfo->bitmask |= EBT_IP_TOS;
 		break;
 
 	case IP_PROTO:
-		ebt_check_option(flags, OPT_PROTO);
-		if (ebt_check_inverse(optarg))
+		ebt_check_option2(flags, OPT_PROTO);
+		if (ebt_check_inverse2(optarg))
 			ipinfo->invflags |= EBT_IP_PROTO;
-		if (optind > argc)
-			ebt_print_error("Missing IP protocol argument");
-		i = strtoul(argv[optind - 1], &end, 10);
+		i = strtoul(optarg, &end, 10);
 		if (*end != '\0') {
 			struct protoent *pe;
 
-			pe = getprotobyname(argv[optind - 1]);
+			pe = getprotobyname(optarg);
 			if (pe == NULL)
-				ebt_print_error
-				    ("Unknown specified IP protocol - %s",
-				     argv[optind - 1]);
+				ebt_print_error("Unknown specified IP protocol - %s", argv[optind - 1]);
 			ipinfo->protocol = pe->p_proto;
 		} else {
 			ipinfo->protocol = (unsigned char) i;
@@ -236,11 +210,10 @@
 {
  	struct ebt_ip_info *ipinfo = (struct ebt_ip_info *)match->data;
 
-	if (entry->ethproto != ETH_P_IP || entry->invflags & EBT_IPROTO)
+	if (entry->ethproto != ETH_P_IP || entry->invflags & EBT_IPROTO) {
 		ebt_print_error("For IP filtering the protocol must be "
 		            "specified as IPv4");
-
-	if (ipinfo->bitmask & (EBT_IP_SPORT|EBT_IP_DPORT) &&
+	} else if (ipinfo->bitmask & (EBT_IP_SPORT|EBT_IP_DPORT) &&
 		(!(ipinfo->bitmask & EBT_IP_PROTO) || 
 		ipinfo->invflags & EBT_IP_PROTO ||
 		(ipinfo->protocol!=IPPROTO_TCP && 
@@ -294,16 +267,14 @@
 	}
 	if (ipinfo->bitmask & EBT_IP_SPORT) {
 		printf("--ip-sport ");
-		if (ipinfo->invflags & EBT_IP_SPORT) {
+		if (ipinfo->invflags & EBT_IP_SPORT)
 			printf("! ");
-		}
 		print_port_range(ipinfo->sport);
 	}
 	if (ipinfo->bitmask & EBT_IP_DPORT) {
 		printf("--ip-dport ");
-		if (ipinfo->invflags & EBT_IP_DPORT) {
+		if (ipinfo->invflags & EBT_IP_DPORT)
 			printf("! ");
-		}
 		print_port_range(ipinfo->dport);
 	}
 }
diff --git a/extensions/ebt_limit.c b/extensions/ebt_limit.c
index 6dcd50d..5655b59 100644
--- a/extensions/ebt_limit.c
+++ b/extensions/ebt_limit.c
@@ -1,32 +1,33 @@
-/* Shared library add-on to ebtables to add limit support.
+/* ebt_limit
  *
- * Swipted from iptables' limit match.
+ * Authors:
+ * Tom Marshall <tommy@home.tig-grr.com>
+ *
+ * Mostly copied from iptables' limit match.
+ *
+ * September, 2003
  */
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <getopt.h>
+#include <errno.h>
 #include "../include/ebtables_u.h"
 #include <linux/netfilter_bridge/ebt_limit.h>
 
 #define EBT_LIMIT_AVG	"3/hour"
 #define EBT_LIMIT_BURST	5
 
-/* from iptables.c */
-#include <errno.h>
-int
-string_to_number(const char *s, unsigned int min, unsigned int max,
-		 unsigned int *ret)
+int string_to_number(const char *s, unsigned int min, unsigned int max,
+   unsigned int *ret)
 {
 	long number;
 	char *end;
 
-	/* Handle hex, octal, etc. */
 	errno = 0;
 	number = strtol(s, &end, 0);
 	if (*end == '\0' && end != s) {
-		/* we parsed a number, let's see if we want this */
 		if (errno != ERANGE && min <= number && number <= max) {
 			*ret = number;
 			return 0;
@@ -37,7 +38,6 @@
 
 #define FLAG_LIMIT		0x01
 #define FLAG_LIMIT_BURST	0x02
-
 #define ARG_LIMIT		'1'
 #define ARG_LIMIT_BURST		'2'
 
@@ -52,12 +52,11 @@
 {
 	printf(
 "limit options:\n"
-"--limit avg			max average match rate: default "EBT_LIMIT_AVG"\n"
+"--limit avg                   : max average match rate: default "EBT_LIMIT_AVG"\n"
 "                                [Packets per second unless followed by \n"
 "                                /sec /minute /hour /day postfixes]\n"
-"--limit-burst number		number to match in a burst, -1 < number < 10001,\n"
-"                                default %u\n"
-"\n", EBT_LIMIT_BURST);
+"--limit-burst number          : number to match in a burst, -1 < number < 10001,\n"
+"                                default %u\n", EBT_LIMIT_BURST);
 }
 
 static int parse_rate(const char *rate, u_int32_t *val)
@@ -120,20 +119,19 @@
 
 	switch(c) {
 	case ARG_LIMIT:
-		ebt_check_option(flags, FLAG_LIMIT);
-		if (ebt_check_inverse(optarg))
-			ebt_print_error("Unexpected `!' after --limit");
+		ebt_check_option2(flags, FLAG_LIMIT);
+		if (ebt_check_inverse2(optarg))
+			ebt_print_error2("Unexpected `!' after --limit");
 		if (!parse_rate(optarg, &r->avg))
-			ebt_print_error("bad rate `%s'", optarg);
+			ebt_print_error2("bad rate `%s'", optarg);
 		break;
 
 	case ARG_LIMIT_BURST:
-		ebt_check_option(flags, FLAG_LIMIT_BURST);
-		if (ebt_check_inverse(optarg))
-			ebt_print_error("Unexpected `!' after --limit-burst");
-
+		ebt_check_option2(flags, FLAG_LIMIT_BURST);
+		if (ebt_check_inverse2(optarg))
+			ebt_print_error2("Unexpected `!' after --limit-burst");
 		if (string_to_number(optarg, 0, 10000, &num) == -1)
-			ebt_print_error("bad --limit-burst `%s'", optarg);
+			ebt_print_error2("bad --limit-burst `%s'", optarg);
 		r->burst = num;
 		break;
 
@@ -148,7 +146,6 @@
    const struct ebt_entry_match *match, const char *name,
    unsigned int hookmask, unsigned int time)
 {
-	/* empty */
 }
 
 struct rates
@@ -177,17 +174,18 @@
 	printf("%u/%s ", g_rates[i-1].mult / period, g_rates[i-1].name);
 }
 
-/* Prints out the matchinfo. */
-static void
-print(const struct ebt_u_entry *entry, const struct ebt_entry_match *match)
+static void print(const struct ebt_u_entry *entry,
+   const struct ebt_entry_match *match)
 {
 	struct ebt_limit_info *r = (struct ebt_limit_info *)match->data;
 
-	printf("limit: avg "); print_rate(r->avg);
-	printf("burst %u ", r->burst);
+	printf("--limit ");
+	print_rate(r->avg);
+	printf("--limit-burst %u ", r->burst);
 }
 
-static int compare(const struct ebt_entry_match* m1, const struct ebt_entry_match *m2)
+static int compare(const struct ebt_entry_match* m1,
+   const struct ebt_entry_match *m2)
 {
 	struct ebt_limit_info* li1 = (struct ebt_limit_info*)m1->data;
 	struct ebt_limit_info* li2 = (struct ebt_limit_info*)m2->data;
diff --git a/extensions/ebt_log.c b/extensions/ebt_log.c
index f455f9f..07a5fe9 100644
--- a/extensions/ebt_log.c
+++ b/extensions/ebt_log.c
@@ -1,3 +1,11 @@
+/* ebt_log
+ *
+ * Authors:
+ * Bart De Schuymer <bdschuym@pandora.be>
+ *
+ * April, 2002
+ */
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -103,35 +111,43 @@
 
 	switch (c) {
 	case LOG_PREFIX:
-		ebt_check_option(flags, OPT_PREFIX);
+		ebt_check_option2(flags, OPT_PREFIX);
+		if (ebt_check_inverse(optarg))
+			ebt_print_error2("Unexpected `!' after --log-prefix");
 		if (strlen(optarg) > sizeof(loginfo->prefix) - 1)
-			ebt_print_error("Prefix too long");
+			ebt_print_error2("Prefix too long");
 		strcpy(loginfo->prefix, optarg);
 		break;
 
 	case LOG_LEVEL:
-		ebt_check_option(flags, OPT_LEVEL);
+		ebt_check_option2(flags, OPT_LEVEL);
 		i = strtol(optarg, &end, 16);
 		if (*end != '\0' || i < 0 || i > 7)
 			loginfo->loglevel = name_to_loglevel(optarg);
 		else
 			loginfo->loglevel = i;
 		if (loginfo->loglevel == 9)
-			ebt_print_error("Problem with the log-level");
+			ebt_print_error2("Problem with the log-level");
 		break;
 
 	case LOG_IP:
-		ebt_check_option(flags, OPT_IP);
+		ebt_check_option2(flags, OPT_IP);
+		if (ebt_check_inverse(optarg))
+			ebt_print_error2("Unexpected `!' after --log-ip");
 		loginfo->bitmask |= EBT_LOG_IP;
 		break;
 
 	case LOG_ARP:
-		ebt_check_option(flags, OPT_ARP);
+		ebt_check_option2(flags, OPT_ARP);
+		if (ebt_check_inverse(optarg))
+			ebt_print_error2("Unexpected `!' after --log-arp");
 		loginfo->bitmask |= EBT_LOG_ARP;
 		break;
 
 	case LOG_LOG:
-		ebt_check_option(flags, OPT_LOG);
+		ebt_check_option2(flags, OPT_LOG);
+		if (ebt_check_inverse(optarg))
+			ebt_print_error2("Unexpected `!' after --log");
 		break;
 	default:
 		return 0;
@@ -143,7 +159,6 @@
    const struct ebt_entry_watcher *watcher, const char *name,
    unsigned int hookmask, unsigned int time)
 {
-	return;
 }
 
 static void print(const struct ebt_u_entry *entry,
diff --git a/extensions/ebt_mark.c b/extensions/ebt_mark.c
index 11bcc12..c7c79aa 100644
--- a/extensions/ebt_mark.c
+++ b/extensions/ebt_mark.c
@@ -1,3 +1,11 @@
+/* ebt_mark
+ *
+ * Authors:
+ * Bart De Schuymer <bdschuym@pandora.be>
+ *
+ * July, 2002
+ */
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -49,15 +57,15 @@
 
 	switch (c) {
 	case MARK_TARGET:
-		ebt_check_option(flags, OPT_MARK_TARGET);
+		ebt_check_option2(flags, OPT_MARK_TARGET);
 		if (FILL_TARGET(optarg, markinfo->target))
-			ebt_print_error("Illegal --mark-target target");
+			ebt_print_error2("Illegal --mark-target target");
 		break;
 	case MARK_SETMARK:
-		ebt_check_option(flags, OPT_MARK_SETMARK);
+		ebt_check_option2(flags, OPT_MARK_SETMARK);
 		markinfo->mark = strtoul(optarg, &end, 0);
 		if (*end != '\0' || end == optarg)
-			ebt_print_error("Bad MARK value '%s'", optarg);
+			ebt_print_error2("Bad MARK value '%s'", optarg);
 		mark_supplied = 1;
                 break;
 	 default:
@@ -73,11 +81,10 @@
 	struct ebt_mark_t_info *markinfo =
 	   (struct ebt_mark_t_info *)target->data;
 
-	if (time == 0 && mark_supplied == 0)
+	if (time == 0 && mark_supplied == 0) {
 		ebt_print_error("No mark value supplied");
-	if (BASE_CHAIN && markinfo->target == EBT_RETURN)
-		ebt_print_error("--mark-target RETURN not allowed on base "
-				"chain");
+	} else if (BASE_CHAIN && markinfo->target == EBT_RETURN)
+		ebt_print_error("--mark-target RETURN not allowed on base chain");
 }
 
 static void print(const struct ebt_u_entry *entry,
diff --git a/extensions/ebt_mark_m.c b/extensions/ebt_mark_m.c
index 2cc371a..8c5913e 100644
--- a/extensions/ebt_mark_m.c
+++ b/extensions/ebt_mark_m.c
@@ -1,3 +1,11 @@
+/* ebt_mark_m
+ *
+ * Authors:
+ * Bart De Schuymer <bdschuym@pandora.be>
+ *
+ * July, 2002
+ */
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -40,22 +48,19 @@
 
 	switch (c) {
 	case MARK:
-		ebt_check_option(flags, MARK);
-		if (ebt_check_inverse(optarg))
+		ebt_check_option2(flags, MARK);
+		if (ebt_check_inverse2(optarg))
 			markinfo->invert = 1;
-		if (optind > argc)
-			ebt_print_error("No mark specified");
-		markinfo->mark = strtoul(argv[optind - 1], &end, 0);
+		markinfo->mark = strtoul(optarg, &end, 0);
 		markinfo->bitmask = EBT_MARK_AND;
 		if (*end == '/') {
-			if (end == argv[optind - 1])
+			if (end == optarg)
 				markinfo->bitmask = EBT_MARK_OR;
 			markinfo->mask = strtoul(end+1, &end, 0);
 		} else
 			markinfo->mask = 0xffffffff;
-		if ( *end != '\0' || end == argv[optind - 1])
-			ebt_print_error("Bad mark value '%s'",
-					argv[optind - 1]);
+		if ( *end != '\0' || end == optarg)
+			ebt_print_error2("Bad mark value '%s'", optarg);
 		break;
 	default:
 		return 0;
diff --git a/extensions/ebt_nat.c b/extensions/ebt_nat.c
index f2e79ca..5906ac4 100644
--- a/extensions/ebt_nat.c
+++ b/extensions/ebt_nat.c
@@ -1,3 +1,11 @@
+/* ebt_nat
+ *
+ * Authors:
+ * Bart De Schuymer <bdschuym@pandora.be>
+ *
+ * June, 2002
+ */
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -73,17 +81,16 @@
 
 	switch (c) {
 	case NAT_S:
-		ebt_check_option(flags, OPT_SNAT);
+		ebt_check_option2(flags, OPT_SNAT);
 		to_source_supplied = 1;
 		if (!(addr = ether_aton(optarg)))
-			ebt_print_error("Problem with specified --to-source "
-					"mac");
+			ebt_print_error2("Problem with specified --to-source mac");
 		memcpy(natinfo->mac, addr, ETH_ALEN);
 		break;
 	case NAT_S_TARGET:
-		ebt_check_option(flags, OPT_SNAT_TARGET);
+		ebt_check_option2(flags, OPT_SNAT_TARGET);
 		if (FILL_TARGET(optarg, natinfo->target))
-			ebt_print_error("Illegal --snat-target target");
+			ebt_print_error2("Illegal --snat-target target");
 		break;
 	default:
 		return 0;
@@ -102,17 +109,16 @@
 
 	switch (c) {
 	case NAT_D:
-		ebt_check_option(flags, OPT_DNAT);
+		ebt_check_option2(flags, OPT_DNAT);
 		to_dest_supplied = 1;
 		if (!(addr = ether_aton(optarg)))
-			ebt_print_error("Problem with specified "
-					"--to-destination mac");
+			ebt_print_error2("Problem with specified --to-destination mac");
 		memcpy(natinfo->mac, addr, ETH_ALEN);
 		break;
 	case NAT_D_TARGET:
-		ebt_check_option(flags, OPT_DNAT_TARGET);
+		ebt_check_option2(flags, OPT_DNAT_TARGET);
 		if (FILL_TARGET(optarg, natinfo->target))
-			ebt_print_error("Illegal --dnat-target target");
+			ebt_print_error2("Illegal --dnat-target target");
 		break;
 	default:
 		return 0;
@@ -126,13 +132,14 @@
 {
 	struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data;
 
-	if (BASE_CHAIN && natinfo->target == EBT_RETURN)
-		ebt_print_error("--snat-target RETURN not allowed on base "
-				"chain");
+	if (BASE_CHAIN && natinfo->target == EBT_RETURN) {
+		ebt_print_error("--snat-target RETURN not allowed on base chain");
+		return;
+	}
 	CLEAR_BASE_CHAIN_BIT;
-	if ((hookmask & ~(1 << NF_BR_POST_ROUTING)) || strcmp(name, "nat"))
+	if ((hookmask & ~(1 << NF_BR_POST_ROUTING)) || strcmp(name, "nat")) {
 		ebt_print_error("Wrong chain for snat");
-	if (time == 0 && to_source_supplied == 0)
+	} else if (time == 0 && to_source_supplied == 0)
 		ebt_print_error("No snat address supplied");
 }
 
@@ -142,15 +149,16 @@
 {
 	struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data;
 
-	if (BASE_CHAIN && natinfo->target == EBT_RETURN)
-		ebt_print_error("--dnat-target RETURN not allowed on base "
-				"chain");
+	if (BASE_CHAIN && natinfo->target == EBT_RETURN) {
+		ebt_print_error("--dnat-target RETURN not allowed on base chain");
+		return;
+	}
 	CLEAR_BASE_CHAIN_BIT;
 	if (((hookmask & ~((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT)))
 	   || strcmp(name, "nat")) &&
-	   ((hookmask & ~(1 << NF_BR_BROUTING)) || strcmp(name, "broute")))
+	   ((hookmask & ~(1 << NF_BR_BROUTING)) || strcmp(name, "broute"))) {
 		ebt_print_error("Wrong chain for dnat");
-	if (time == 0 && to_dest_supplied == 0)
+	} if (time == 0 && to_dest_supplied == 0)
 		ebt_print_error("No dnat address supplied");
 }
 
diff --git a/extensions/ebt_pkttype.c b/extensions/ebt_pkttype.c
index f7893bb..7894d0d 100644
--- a/extensions/ebt_pkttype.c
+++ b/extensions/ebt_pkttype.c
@@ -1,9 +1,9 @@
-/*
- *  ebtables ebt_pkttype
+/* ebt_pkttype
  *
- *  Authors:
- *   Bart De Schuymer <bdschuym@pandora.be>
+ * Authors:
+ * Bart De Schuymer <bdschuym@pandora.be>
  *
+ * April, 2003
  */
 
 #include <stdio.h>
@@ -38,7 +38,7 @@
 	printf(
 "pkttype options:\n"
 "--pkttype-type    [!] type: class the packet belongs to\n"
-"Possible values: broadcast, multicast, host, otherhost any byte value.\n");
+"Possible values: broadcast, multicast, host, otherhost, or any other byte value (which would be pretty useless).\n");
 }
 
 static void init(struct ebt_entry_match *match)
@@ -58,25 +58,21 @@
 	switch (c) {
 	case '1':
 		ebt_check_option(flags, 1);
-		if (ebt_check_inverse(optarg))
+		if (ebt_check_inverse2(optarg))
 			ptinfo->invert = 1;
-		if (optind > argc)
-			ebt_print_error("Missing pkttype class specification");
-
-		i = strtol(argv[optind - 1], &end, 16);
+		i = strtol(optarg, &end, 16);
 		if (*end != '\0') {
 			int j = 0;
 			i = -1;
 			while (classes[j][0])
-				if (!strcasecmp(argv[optind - 1], classes[j++])) {
+				if (!strcasecmp(optarg, classes[j++])) {
 					i = j - 1;
 					break;
 				}
 		}
 		if (i < 0 || i > 255)
-			ebt_print_error("Problem with specified pkttype class");
+			ebt_print_error2("Problem with specified pkttype class");
 		ptinfo->pkt_type = (uint8_t)i;
-
 		break;
 	default:
 		return 0;
diff --git a/extensions/ebt_redirect.c b/extensions/ebt_redirect.c
index ba7f6b1..8630254 100644
--- a/extensions/ebt_redirect.c
+++ b/extensions/ebt_redirect.c
@@ -1,3 +1,11 @@
+/* ebt_redirect
+ *
+ * Authors:
+ * Bart De Schuymer <bdschuym@pandora.be>
+ *
+ * April, 2002
+ */
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -38,9 +46,9 @@
 
 	switch (c) {
 	case REDIRECT_TARGET:
-		ebt_check_option(flags, OPT_REDIRECT_TARGET);
+		ebt_check_option2(flags, OPT_REDIRECT_TARGET);
 		if (FILL_TARGET(optarg, redirectinfo->target))
-			ebt_print_error("Illegal --redirect-target target");
+			ebt_print_error2("Illegal --redirect-target target");
 		break;
 	default:
 		return 0;
@@ -55,9 +63,10 @@
 	struct ebt_redirect_info *redirectinfo =
 	   (struct ebt_redirect_info *)target->data;
 
-	if (BASE_CHAIN && redirectinfo->target == EBT_RETURN)
-		ebt_print_error("--redirect-target RETURN not allowed on "
-				"base chain");
+	if (BASE_CHAIN && redirectinfo->target == EBT_RETURN) {
+		ebt_print_error("--redirect-target RETURN not allowed on base chain");
+		return;
+	}
 	CLEAR_BASE_CHAIN_BIT;
 	if ( ((hookmask & ~(1 << NF_BR_PRE_ROUTING)) || strcmp(name, "nat")) &&
 	   ((hookmask & ~(1 << NF_BR_BROUTING)) || strcmp(name, "broute")) )
diff --git a/extensions/ebt_standard.c b/extensions/ebt_standard.c
index 4ac3dc0..1420d1d 100644
--- a/extensions/ebt_standard.c
+++ b/extensions/ebt_standard.c
@@ -1,3 +1,11 @@
+/* ebt_standard
+ *
+ * Authors:
+ * Bart De Schuymer <bdschuym@pandora.be>
+ *
+ * April, 2002
+ */
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <getopt.h>
diff --git a/extensions/ebt_stp.c b/extensions/ebt_stp.c
index 8ed4c47..307131f 100644
--- a/extensions/ebt_stp.c
+++ b/extensions/ebt_stp.c
@@ -1,3 +1,11 @@
+/* ebt_stp
+ *
+ * Authors:
+ * Bart De Schuymer <bdschuym@pandora.be>
+ *
+ * July, 2003
+ */
+
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
@@ -157,38 +165,32 @@
 	if (c < 'a' || c > ('a' + STP_NUMOPS - 1))
 		return 0;
 	flag = 1 << (c - 'a');
-	ebt_check_option(flags, flag);
-	if (ebt_check_inverse(optarg))
+	ebt_check_option2(flags, flag);
+	if (ebt_check_inverse2(optarg))
 		stpinfo->invflags |= flag;
-	if (optind > argc)
-		ebt_print_error("Missing argument for --%s", opts[c-'a'].name);
 	stpinfo->bitmask |= flag;
 	switch (flag) {
 	case EBT_STP_TYPE:
-		i = strtol(argv[optind - 1], &end, 0);
+		i = strtol(optarg, &end, 0);
 		if (i < 0 || i > 255 || *end != '\0') {
-			if (!strcasecmp(argv[optind - 1],
-			    BPDU_TYPE_CONFIG_STRING))
+			if (!strcasecmp(optarg, BPDU_TYPE_CONFIG_STRING))
 				stpinfo->type = BPDU_TYPE_CONFIG;
-			else if (!strcasecmp(argv[optind - 1],
-			           BPDU_TYPE_TCN_STRING))
+			else if (!strcasecmp(optarg, BPDU_TYPE_TCN_STRING))
 				stpinfo->type = BPDU_TYPE_TCN;
 			else
-				ebt_print_error("Bad --stp-type argument");
+				ebt_print_error2("Bad --stp-type argument");
 		} else
 			stpinfo->type = i;
 		break;
 	case EBT_STP_FLAGS:
-		i = strtol(argv[optind - 1], &end, 0);
+		i = strtol(optarg, &end, 0);
 		if (i < 0 || i > 255 || *end != '\0') {
-			if (!strcasecmp(argv[optind - 1],
-			    FLAG_TC_STRING))
+			if (!strcasecmp(optarg, FLAG_TC_STRING))
 				stpinfo->config.flags = FLAG_TC;
-			else if (!strcasecmp(argv[optind - 1],
-			           FLAG_TC_ACK_STRING))
+			else if (!strcasecmp(optarg, FLAG_TC_ACK_STRING))
 				stpinfo->config.flags = FLAG_TC_ACK;
 			else
-				ebt_print_error("Bad --stp-flags argument");
+				ebt_print_error2("Bad --stp-flags argument");
 		} else
 			stpinfo->config.flags = i;
 		break;
diff --git a/extensions/ebt_ulog.c b/extensions/ebt_ulog.c
index 4af42e2..5c762b2 100644
--- a/extensions/ebt_ulog.c
+++ b/extensions/ebt_ulog.c
@@ -1,3 +1,11 @@
+/* ebt_ulog
+ *
+ * Authors:
+ * Bart De Schuymer <bdschuym@pandora.be>
+ *
+ * November, 2004
+ */
+
 #define __need_time_t
 #define __need_suseconds_t
 #include <stdio.h>
@@ -65,59 +73,54 @@
 	uloginfo = (struct ebt_ulog_info *)(*watcher)->data;
 	switch (c) {
 	case ULOG_PREFIX:
-		if (ebt_check_inverse(optarg))
+		if (ebt_check_inverse2(optarg))
 			goto inverse_invalid;
-		ebt_check_option(flags, OPT_PREFIX);
+		ebt_check_option2(flags, OPT_PREFIX);
 		if (strlen(optarg) > EBT_ULOG_PREFIX_LEN - 1)
 			ebt_print_error("Prefix too long for ulog-prefix");
 		strcpy(uloginfo->prefix, optarg);
 		break;
 
 	case ULOG_NLGROUP:
-		if (ebt_check_inverse(optarg))
+		if (ebt_check_inverse2(optarg))
 			goto inverse_invalid;
-		ebt_check_option(flags, OPT_NLGROUP);
+		ebt_check_option2(flags, OPT_NLGROUP);
 		i = strtoul(optarg, &end, 10);
 		if (*end != '\0')
-			ebt_print_error("Problem with ulog-nlgroup: %s", optarg);
+			ebt_print_error2("Problem with ulog-nlgroup: %s", optarg);
 		if (i < 1 || i > EBT_ULOG_MAXNLGROUPS)
-			ebt_print_error("the ulog-nlgroup number must be "
-			                "between 1 and 32");
+			ebt_print_error2("the ulog-nlgroup number must be between 1 and 32");
 		uloginfo->nlgroup = i - 1;
 		break;
 
 	case ULOG_CPRANGE:
-		if (ebt_check_inverse(optarg))
+		if (ebt_check_inverse2(optarg))
 			goto inverse_invalid;
-		ebt_check_option(flags, OPT_CPRANGE);
+		ebt_check_option2(flags, OPT_CPRANGE);
 		i = strtoul(optarg, &end, 10);
 		if (*end != '\0') {
 			if (strcasecmp(optarg, CP_NO_LIMIT_S))
-				ebt_print_error("Problem with ulog-cprange: "
-				                "%s", optarg);
+				ebt_print_error2("Problem with ulog-cprange: %s", optarg);
 			i = CP_NO_LIMIT_N;
 		}
 		uloginfo->cprange = i;
 		break;
 
 	case ULOG_QTHRESHOLD:
-		if (ebt_check_inverse(optarg))
+		if (ebt_check_inverse2(optarg))
 			goto inverse_invalid;
-		ebt_check_option(flags, OPT_QTHRESHOLD);
+		ebt_check_option2(flags, OPT_QTHRESHOLD);
 		i = strtoul(optarg, &end, 10);
 		if (*end != '\0')
-			ebt_print_error("Problem with ulog-qthreshold: %s",
-			                optarg);
+			ebt_print_error2("Problem with ulog-qthreshold: %s", optarg);
 		if (i > EBT_ULOG_MAX_QLEN)
-			ebt_print_error("ulog-qthreshold argument %d exceeds "
-			                "the maximum of %d", i,
-			                EBT_ULOG_MAX_QLEN);
+			ebt_print_error2("ulog-qthreshold argument %d exceeds the maximum of %d", i, EBT_ULOG_MAX_QLEN);
 		uloginfo->qthreshold = i;
 		break;
 	case ULOG_ULOG:
-		if (ebt_check_inverse(optarg))
+		if (ebt_check_inverse2(optarg))
 			goto inverse_invalid;
-		ebt_check_option(flags, OPT_ULOG);
+		ebt_check_option2(flags, OPT_ULOG);
 		break;
 
 	default:
@@ -127,14 +130,13 @@
 
 inverse_invalid:
 	ebt_print_error("The use of '!' makes no sense for the ulog watcher");
-	return 0;
+	return 1;
 }
 
 static void final_check(const struct ebt_u_entry *entry,
    const struct ebt_entry_watcher *watcher, const char *name,
    unsigned int hookmask, unsigned int time)
 {
-	return;
 }
 
 static void print(const struct ebt_u_entry *entry,
diff --git a/extensions/ebt_vlan.c b/extensions/ebt_vlan.c
index 0c94a66..21f2e22 100644
--- a/extensions/ebt_vlan.c
+++ b/extensions/ebt_vlan.c
@@ -1,33 +1,10 @@
-/*
- * Summary: ebt_vlan - IEEE 802.1Q extension module for userspace
- *
- * Description: 802.1Q Virtual LAN match support module for ebtables project. 
- * Enables to match 802.1Q:
- * 1) VLAN-tagged frames by VLAN numeric identifier (12 - bits field)
- * 2) Priority-tagged frames by user_priority (3 bits field)
- * 3) Encapsulated Frame by ethernet protocol type/length
+/* ebt_vlan
  * 
  * Authors:
- * Bart De Schuymer <bart.de.schuymer@pandora.be>
+ * Bart De Schuymer <bdschuym@pandora.be>
  * Nick Fedchik <nick@fedchik.org.ua> 
+ *
  * June, 2002
- *
- * License: GNU GPL 
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
  */
 
 #include <stdio.h>
@@ -40,30 +17,19 @@
 #include <linux/netfilter_bridge/ebt_vlan.h>
 #include <linux/if_ether.h>
 
-
-#define GET_BITMASK(_MASK_) vlaninfo->bitmask & _MASK_
-#define SET_BITMASK(_MASK_) vlaninfo->bitmask |= _MASK_
-#define INV_FLAG(_inv_flag_) (vlaninfo->invflags & _inv_flag_) ? "! " : ""
-#define CHECK_IF_MISSING_VALUE if (optind > argc) ebt_print_error ("Missing %s value", opts[c].name);
-#define CHECK_INV_FLAG(_INDEX_) if (ebt_check_inverse (optarg)) vlaninfo->invflags |= _INDEX_;
-#define CHECK_RANGE(_RANGE_) if (_RANGE_) ebt_print_error ("Invalid %s range", opts[c].name);
-
 #define NAME_VLAN_ID    "id"
 #define NAME_VLAN_PRIO  "prio"
 #define NAME_VLAN_ENCAP "encap"
 
-#define VLAN_ID    0
-#define VLAN_PRIO  1
-#define VLAN_ENCAP 2
+#define VLAN_ID    '1'
+#define VLAN_PRIO  '2'
+#define VLAN_ENCAP '3'
 
 static struct option opts[] = {
-	{EBT_VLAN_MATCH "-" NAME_VLAN_ID, required_argument, NULL,
-	 VLAN_ID},
-	{EBT_VLAN_MATCH "-" NAME_VLAN_PRIO, required_argument, NULL,
-	 VLAN_PRIO},
-	{EBT_VLAN_MATCH "-" NAME_VLAN_ENCAP, required_argument, NULL,
-	 VLAN_ENCAP},
-	{NULL}
+	{"vlan-id"   , required_argument, NULL, VLAN_ID},
+	{"vlan-prio" , required_argument, NULL, VLAN_PRIO},
+	{"vlan-encap", required_argument, NULL, VLAN_ENCAP},
+	{ 0 }
 };
 
 /*
@@ -76,104 +42,67 @@
 
 struct ethertypeent *ethent;
 
-/*
- * Print out local help by "ebtables -h <match name>" 
- */
-
 static void print_help()
 {
-#define HELP_TITLE "802.1Q VLAN extension"
-
-	printf(HELP_TITLE " options:\n");
-	printf("--" EBT_VLAN_MATCH "-" NAME_VLAN_ID " %s" NAME_VLAN_ID
-	       " : VLAN-tagged frame identifier, 0,1-4096 (integer), default 1\n",
-	       OPT_VLAN_FLAGS & OPT_VLAN_ID ? "[!] " : "");
-	printf("--" EBT_VLAN_MATCH "-" NAME_VLAN_PRIO " %s" NAME_VLAN_PRIO
-	       " : Priority-tagged frame user_priority, 0-7 (integer), default 0\n",
-	       OPT_VLAN_FLAGS & OPT_VLAN_PRIO ? "[!] " : "");
-	printf("--" EBT_VLAN_MATCH "-" NAME_VLAN_ENCAP " %s"
-	       NAME_VLAN_ENCAP
-	       " : Encapsulated frame type (hexadecimal), default IP (0800)\n",
-	       OPT_VLAN_FLAGS & OPT_VLAN_ENCAP ? "[!] " : "");
+	printf(
+"vlan options:\n"
+"--vlan-id [!] id       : vlan-tagged frame identifier, 0,1-4096 (integer)\n"
+"--vlan-prio [!] prio   : Priority-tagged frame's user priority, 0-7 (integer)\n"
+"--vlan-encap [!] encap : Encapsulated frame protocol (hexadecimal or name)\n");
 }
 
-/*
- * Initialization function 
- */
 static void init(struct ebt_entry_match *match)
 {
-	struct ebt_vlan_info *vlaninfo =
-	    (struct ebt_vlan_info *) match->data;
-	/*
-	 * Set initial values 
-	 */
-	vlaninfo->id = 1;	/* Default VID for VLAN-tagged 802.1Q frames */
-	vlaninfo->prio = 0;
-	vlaninfo->encap = 0;
+	struct ebt_vlan_info *vlaninfo = (struct ebt_vlan_info *) match->data;
 	vlaninfo->invflags = 0;
 	vlaninfo->bitmask = 0;
 }
 
 
-/*
- * Parse passed arguments values (ranges, flags, etc...)
- * int c - parameter number from static struct option opts[]
- * int argc - total amout of arguments (std argc value)
- * int argv - arguments (std argv value)
- * const struct ebt_u_entry *entry - default ebtables entry set
- * unsigned int *flags -
- * struct ebt_entry_match **match - 
- */
-static int
-parse(int c,
-      char **argv,
-      int argc,
-      const struct ebt_u_entry *entry,
-      unsigned int *flags, struct ebt_entry_match **match)
+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_vlan_info *vlaninfo =
-	    (struct ebt_vlan_info *) (*match)->data;
+	struct ebt_vlan_info *vlaninfo = (struct ebt_vlan_info *) (*match)->data;
 	char *end;
 	struct ebt_vlan_info local;
 
 	switch (c) {
 	case VLAN_ID:
-		ebt_check_option(flags, OPT_VLAN_ID);
-		CHECK_INV_FLAG(EBT_VLAN_ID);
-		CHECK_IF_MISSING_VALUE;
-		local.id = strtoul(argv[optind - 1], &end, 10);
-		CHECK_RANGE(local.id > 4094 || *end != '\0');
+		ebt_check_option2(flags, OPT_VLAN_ID);
+		if (ebt_check_inverse2(optarg))
+			vlaninfo->invflags |= EBT_VLAN_ID;
+		local.id = strtoul(optarg, &end, 10);
+		if (local.id > 4094 || *end != '\0')
+			ebt_print_error2("Invalid --vlan-id range ('%s')", optarg);
 		vlaninfo->id = local.id;
-		SET_BITMASK(EBT_VLAN_ID);
+		vlaninfo->bitmask |= EBT_VLAN_ID;
 		break;
-
 	case VLAN_PRIO:
-		ebt_check_option(flags, OPT_VLAN_PRIO);
-		CHECK_INV_FLAG(EBT_VLAN_PRIO);
-		CHECK_IF_MISSING_VALUE;
-		local.prio = strtoul(argv[optind - 1], &end, 10);
-		CHECK_RANGE(local.prio >= 8 || *end != '\0');
+		ebt_check_option2(flags, OPT_VLAN_PRIO);
+		if (ebt_check_inverse2(optarg))
+			vlaninfo->invflags |= EBT_VLAN_PRIO;
+		local.prio = strtoul(optarg, &end, 10);
+		if (local.prio >= 8 || *end != '\0')
+			ebt_print_error2("Invalid --vlan-prio range ('%s')", optarg);
 		vlaninfo->prio = local.prio;
-		SET_BITMASK(EBT_VLAN_PRIO);
+		vlaninfo->bitmask |= EBT_VLAN_PRIO;
 		break;
-
 	case VLAN_ENCAP:
-		ebt_check_option(flags, OPT_VLAN_ENCAP);
-		CHECK_INV_FLAG(EBT_VLAN_ENCAP);
-		CHECK_IF_MISSING_VALUE;
-		local.encap = strtoul(argv[optind - 1], &end, 16);
+		ebt_check_option2(flags, OPT_VLAN_ENCAP);
+		if (ebt_check_inverse2(optarg))
+			vlaninfo->invflags |= EBT_VLAN_ENCAP;
+		local.encap = strtoul(optarg, &end, 16);
 		if (*end != '\0') {
-			ethent = getethertypebyname(argv[optind - 1]);
+			ethent = getethertypebyname(optarg);
 			if (ethent == NULL)
-				ebt_print_error("Unknown %s encap",
-						opts[c].name);
+				ebt_print_error("Unknown --vlan-encap value ('%s')", optarg);
 			local.encap = ethent->e_ethertype;
 		}
-		CHECK_RANGE(local.encap < ETH_ZLEN);
+		if (local.encap < ETH_ZLEN)
+			ebt_print_error2("Invalid --vlan-encap range ('%s')", optarg);
 		vlaninfo->encap = htons(local.encap);
-		SET_BITMASK(EBT_VLAN_ENCAP);
+		vlaninfo->bitmask |= EBT_VLAN_ENCAP;
 		break;
-
 	default:
 		return 0;
 
@@ -181,75 +110,34 @@
 	return 1;
 }
 
-/*
- * Final check - logical conditions
- */
-static void
-final_check(const struct ebt_u_entry *entry,
-	    const struct ebt_entry_match *match,
-	    const char *name, unsigned int hookmask, unsigned int time)
+static void final_check(const struct ebt_u_entry *entry,
+   const struct ebt_entry_match *match,
+   const char *name, unsigned int hookmask, unsigned int time)
 {
-
-	struct ebt_vlan_info *vlaninfo =
-	    (struct ebt_vlan_info *) match->data;
-	/*
-	 * Specified proto isn't 802.1Q?
-	 */
 	if (entry->ethproto != ETH_P_8021Q || entry->invflags & EBT_IPROTO)
-		ebt_print_error("For use 802.1Q extension the protocol "
-				"must be specified as 802_1Q");
-	/*
-	 * Check if specified vlan-encap=0x8100 (802.1Q Frame) 
-	 * when vlan-encap specified.
-	 */
-	if (GET_BITMASK(EBT_VLAN_ENCAP)) {
-		if (vlaninfo->encap == htons(0x8100))
-			ebt_print_error("Encapsulated frame type can not be "
-				"802.1Q (0x8100)");
-	}
+		ebt_print_error("For vlan filtering the protocol must be specified as 802_1Q");
 
-	/*
-	 * Check if specified vlan-id=0 (priority-tagged frame condition) 
-	 * when vlan-prio was specified.
-	 */
-	if (GET_BITMASK(EBT_VLAN_PRIO)) {
-		if (vlaninfo->id && GET_BITMASK(EBT_VLAN_ID))
-			ebt_print_error("For use user_priority the specified "
-					"vlan-id must be 0");
-	}
+	/* Check if specified vlan-id=0 (priority-tagged frame condition) 
+	 * when vlan-prio was specified. */
+	/* I see no reason why a user should be prohibited to match on a perhaps impossible situation <BDS>
+	if (vlaninfo->bitmask & EBT_VLAN_PRIO &&
+	    vlaninfo->id && vlaninfo->bitmask & EBT_VLAN_ID)
+		ebt_print_error("When setting --vlan-prio the specified --vlan-id must be 0");*/
 }
 
-/*
- * Print line when listing rules by ebtables -L 
- */
-static void
-print(const struct ebt_u_entry *entry, const struct ebt_entry_match *match)
+static void print(const struct ebt_u_entry *entry,
+   const struct ebt_entry_match *match)
 {
-	struct ebt_vlan_info *vlaninfo =
-	    (struct ebt_vlan_info *) match->data;
+	struct ebt_vlan_info *vlaninfo = (struct ebt_vlan_info *) match->data;
 
-	/*
-	 * Print VLAN ID if they are specified 
-	 */
-	if (GET_BITMASK(EBT_VLAN_ID)) {
-		printf("--%s %s%d ",
-		       opts[VLAN_ID].name,
-		       INV_FLAG(EBT_VLAN_ID), vlaninfo->id);
+	if (vlaninfo->bitmask & EBT_VLAN_ID) {
+		printf("--vlan-id %s%d ", (vlaninfo->invflags & EBT_VLAN_ID) ? "! " : "", vlaninfo->id);
 	}
-	/*
-	 * Print user priority if they are specified 
-	 */
-	if (GET_BITMASK(EBT_VLAN_PRIO)) {
-		printf("--%s %s%d ",
-		       opts[VLAN_PRIO].name,
-		       INV_FLAG(EBT_VLAN_PRIO), vlaninfo->prio);
+	if (vlaninfo->bitmask & EBT_VLAN_PRIO) {
+		printf("--vlan-prio %s%d ", (vlaninfo->invflags & EBT_VLAN_PRIO) ? "! " : "", vlaninfo->prio);
 	}
-	/*
-	 * Print encapsulated frame type if they are specified 
-	 */
-	if (GET_BITMASK(EBT_VLAN_ENCAP)) {
-		printf("--%s %s",
-		       opts[VLAN_ENCAP].name, INV_FLAG(EBT_VLAN_ENCAP));
+	if (vlaninfo->bitmask & EBT_VLAN_ENCAP) {
+		printf("--vlan-encap %s", (vlaninfo->invflags & EBT_VLAN_ENCAP) ? "! " : "");
 		ethent = getethertypebynumber(ntohs(vlaninfo->encap));
 		if (ethent != NULL) {
 			printf("%s ", ethent->e_name);
@@ -259,47 +147,25 @@
 	}
 }
 
-
-static int
-compare(const struct ebt_entry_match *vlan1,
-	const struct ebt_entry_match *vlan2)
+static int compare(const struct ebt_entry_match *vlan1,
+   const struct ebt_entry_match *vlan2)
 {
-	struct ebt_vlan_info *vlaninfo1 =
-	    (struct ebt_vlan_info *) vlan1->data;
-	struct ebt_vlan_info *vlaninfo2 =
-	    (struct ebt_vlan_info *) vlan2->data;
-	/*
-	 * Compare argc 
-	 */
+	struct ebt_vlan_info *vlaninfo1 = (struct ebt_vlan_info *) vlan1->data;
+	struct ebt_vlan_info *vlaninfo2 = (struct ebt_vlan_info *) vlan2->data;
+
 	if (vlaninfo1->bitmask != vlaninfo2->bitmask)
 		return 0;
-	/*
-	 * Compare inv flags  
-	 */
 	if (vlaninfo1->invflags != vlaninfo2->invflags)
 		return 0;
-	/*
-	 * Compare VLAN ID if they are present 
-	 */
-	if (vlaninfo1->bitmask & EBT_VLAN_ID) {
-		if (vlaninfo1->id != vlaninfo2->id)
-			return 0;
-	};
-	/*
-	 * Compare VLAN Prio if they are present 
-	 */
-	if (vlaninfo1->bitmask & EBT_VLAN_PRIO) {
-		if (vlaninfo1->prio != vlaninfo2->prio)
-			return 0;
-	};
-	/*
-	 * Compare VLAN Encap if they are present 
-	 */
-	if (vlaninfo1->bitmask & EBT_VLAN_ENCAP) {
-		if (vlaninfo1->encap != vlaninfo2->encap)
-			return 0;
-	};
-
+	if (vlaninfo1->bitmask & EBT_VLAN_ID &&
+	    vlaninfo1->id != vlaninfo2->id)
+		return 0;
+	if (vlaninfo1->bitmask & EBT_VLAN_PRIO &&
+	    vlaninfo1->prio != vlaninfo2->prio)
+		return 0;
+	if (vlaninfo1->bitmask & EBT_VLAN_ENCAP &&
+	    vlaninfo1->encap != vlaninfo2->encap)
+		return 0;
 	return 1;
 }
 
diff --git a/extensions/ebtable_broute.c b/extensions/ebtable_broute.c
index 3c00962..5259355 100644
--- a/extensions/ebtable_broute.c
+++ b/extensions/ebtable_broute.c
@@ -1,3 +1,11 @@
+/* ebtable_broute
+ *
+ * Authors:
+ * Bart De Schuymer <bdschuym@pandora.be>
+ *
+ * April, 2002
+ */
+
 #include <stdio.h>
 #include "../include/ebtables_u.h"
 
diff --git a/extensions/ebtable_filter.c b/extensions/ebtable_filter.c
index 08f5033..e41fb84 100644
--- a/extensions/ebtable_filter.c
+++ b/extensions/ebtable_filter.c
@@ -1,3 +1,11 @@
+/* ebtable_filter
+ *
+ * Authors:
+ * Bart De Schuymer <bdschuym@pandora.be>
+ *
+ * April, 2002
+ */
+
 #include <stdio.h>
 #include "../include/ebtables_u.h"
 
diff --git a/extensions/ebtable_nat.c b/extensions/ebtable_nat.c
index d64e21d..b21c9dd 100644
--- a/extensions/ebtable_nat.c
+++ b/extensions/ebtable_nat.c
@@ -1,3 +1,11 @@
+/* ebtable_nat
+ *
+ * Authors:
+ * Bart De Schuymer <bdschuym@pandora.be>
+ *
+ * April, 2002
+ */
+
 #include <stdio.h>
 #include "../include/ebtables_u.h"
 
diff --git a/include/ebtables_u.h b/include/ebtables_u.h
index 5632ec1..24c5045 100644
--- a/include/ebtables_u.h
+++ b/include/ebtables_u.h
@@ -256,6 +256,9 @@
 void ebt_delete_rule(struct ebt_u_replace *replace,
 		     struct ebt_u_entry *new_entry, int begin, int end);
 void ebt_zero_counters(struct ebt_u_replace *replace);
+void ebt_change_counters(struct ebt_u_replace *replace,
+		     struct ebt_u_entry *new_entry, int begin, int end,
+		     struct ebt_counter *cnt);
 void ebt_new_chain(struct ebt_u_replace *replace, const char *name, int policy);
 void ebt_delete_chain(struct ebt_u_replace *replace);
 void ebt_rename_chain(struct ebt_u_replace *replace, const char *name);
@@ -284,7 +287,8 @@
 
 extern int ebt_invert;
 void ebt_check_option(unsigned int *flags, unsigned int mask);
-int ebt_check_inverse(const char option[]);
+#define ebt_check_inverse(arg) _ebt_check_inverse(arg, argc, argv)
+int _ebt_check_inverse(const char option[], int argc, char **argv);
 void ebt_print_mac(const char *mac);
 void ebt_print_mac_and_mask(const char *mac, const char *mask);
 int ebt_get_mac_and_mask(char *from, char *to, char *mask);
@@ -299,6 +303,21 @@
 #define ebt_print_bug(format, args...) \
    __ebt_print_bug(__FILE__, __LINE__, format, ##args)
 #define ebt_print_error(format,args...) __ebt_print_error(format, ##args);
+#define ebt_print_error2(format, args...) {__ebt_print_error(format, ##args); \
+   return -1;}
+#define ebt_check_option2(flags,mask)	\
+({ebt_check_option(flags,mask);		\
+ if (ebt_errormsg[0] != '\0')		\
+	return -1;})
+#define ebt_check_inverse2(option)					\
+({int __ret = ebt_check_inverse(option);				\
+if (ebt_errormsg[0] != '\0')						\
+	return -1;							\
+if (!optarg) {								\
+	__ebt_print_error("Option without (mandatory) argument");	\
+	return -1;							\
+}									\
+__ret;})
 #define ebt_print_memory() {printf("Ebtables: " __FILE__ \
    " %s %d :Out of memory.\n", __FUNCTION__, __LINE__); exit(-1);}
 
@@ -308,6 +327,7 @@
 #define CNT_ADD 	2
 #define CNT_OWRITE 	3
 #define CNT_ZERO 	4
+#define CNT_CHANGE 	5
 
 extern const char *ebt_hooknames[NF_BR_NUMHOOKS];
 extern const char *ebt_standard_targets[NUM_STANDARD_TARGETS];
diff --git a/libebtc.c b/libebtc.c
index ff1e14c..a0dabde 100644
--- a/libebtc.c
+++ b/libebtc.c
@@ -1,4 +1,3 @@
-
 /*
  * libebtc.c, January 2004
  *
@@ -260,8 +259,8 @@
 			strcpy(m->m->u.name, m->name);
 			m->m->match_size = EBT_ALIGN(m->size);
 			m->used = 0;
-			m->flags = 0;
 		}
+		m->flags = 0; /* An error can occur before used is set, while flags is changed. */
 		m->init(m->m);
 	}
 	for (w = ebt_watchers; w; w = w->next) {
@@ -273,8 +272,8 @@
 			strcpy(w->w->u.name, w->name);
 			w->w->watcher_size = EBT_ALIGN(w->size);
 			w->used = 0;
-			w->flags = 0;
 		}
+		w->flags = 0;
 		w->init(w->w);
 	}
 	for (t = ebt_targets; t; t = t->next) {
@@ -286,8 +285,8 @@
 			strcpy(t->t->u.name, t->name);
 			t->t->target_size = EBT_ALIGN(t->size);
 			t->used = 0;
-			t->flags = 0;
 		}
+		t->flags = 0;
 		t->init(t->t);
 	}
 }
@@ -777,6 +776,38 @@
 	}
 }
 
+static int check_and_change_rule_number(struct ebt_u_replace *replace,
+   struct ebt_u_entry *new_entry, int *begin, int *end)
+{
+	struct ebt_u_entries *entries = ebt_to_chain(replace);
+
+	if (*begin < 0)
+		*begin += entries->nentries + 1;
+	if (*end < 0)
+		*end += entries->nentries + 1;
+
+	if (*begin < 0 || *begin > *end || *end > entries->nentries) {
+		ebt_print_error("Sorry, wrong rule numbers");
+		return -1;
+	}
+
+	if ((*begin * *end == 0) && (*begin + *end != 0))
+		ebt_print_bug("begin and end should be either both zero, "
+			      "either both non-zero");
+	if (*begin != 0 && *end != 0) {
+		(*begin)--;
+		(*end)--;
+	} else {
+		*begin = ebt_check_rule_exists(replace, new_entry);
+		*end = *begin;
+		if (*begin == -1) {
+			ebt_print_error("Sorry, rule does not exist");
+			return -1;
+		}
+	}
+	return 0;
+}
+
 /* Delete a rule or rules
  * begin == end == 0: delete the rule corresponding to new_entry
  *
@@ -792,30 +823,8 @@
 	struct ebt_cntchanges *cc = replace->counterchanges;
 	struct ebt_cntchanges **prev_cc =  &(replace->counterchanges);
 
-	if (begin < 0)
-		begin += entries->nentries + 1;
-	if (end < 0)
-		end += entries->nentries + 1;
-
-	if (begin < 0 || begin > end || end > entries->nentries) {
-		ebt_print_error("Sorry, wrong rule numbers");
+	if (check_and_change_rule_number(replace, new_entry, &begin, &end))
 		return;
-	}
-
-	if ((begin * end == 0) && (begin + end != 0))
-		ebt_print_bug("begin and end should be either both zero, "
-			      "either both non-zero");
-	if (begin != 0 && end != 0) {
-		begin--;
-		end--;
-	} else {
-		begin = ebt_check_rule_exists(replace, new_entry);
-		end = begin;
-		if (begin == -1) {
-			ebt_print_error("Sorry, rule does not exist");
-			return;
-		}
-	}
 
 	/* We're deleting rules */
 	nr_deletes = end - begin + 1;
@@ -886,6 +895,64 @@
 	}
 }
 
+/* Change the counters of a rule or rules
+ * begin == end == 0: change counters of the rule corresponding to new_entry
+ *
+ * The first rule has rule nr 1, the last rule has rule nr -1, etc.
+ * This function expects the ebt_{match,watcher,target} members of new_entry
+ * to contain pointers to ebt_u_{match,watcher,target}. */
+void ebt_change_counters(struct ebt_u_replace *replace,
+		     struct ebt_u_entry *new_entry, int begin, int end,
+		     struct ebt_counter *cnt)
+{
+	int i, j;
+	struct ebt_u_entry *u_e;
+	struct ebt_u_entries *entries = ebt_to_chain(replace);
+	struct ebt_cntchanges *cc = replace->counterchanges;
+	struct ebt_cntchanges **prev_cc =  &(replace->counterchanges);
+
+	if (check_and_change_rule_number(replace, new_entry, &begin, &end))
+		return;
+
+	for (i = 0; i < replace->selected_chain; i++) {
+		if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i)))
+			continue;
+		j = ebt_nr_to_chain(replace, i)->nentries;
+		while (j) {
+			if (cc->type != CNT_DEL)
+				j--;
+			prev_cc = &(cc->next);
+			cc = cc->next;
+		}
+	}
+	i = begin;
+	while (i) {
+		if (cc->type != CNT_DEL)
+			i--;
+		prev_cc = &(cc->next);
+		cc = cc->next;
+	}
+	i = end - begin + 1;
+	while (i) {
+		if (cc->type != CNT_DEL) {
+			i--;
+			/* A -C after a -A remains a -A */
+			if (cc->type != CNT_ADD && cc->type != CNT_OWRITE)
+				cc->type = CNT_CHANGE;
+		}
+		prev_cc = &(cc->next);
+		cc = cc->next;
+	}
+	u_e = entries->entries;
+	for (i = 0; i < begin; i++)
+		u_e = u_e->next;
+	i = end - begin + 1;
+	while(i--) {
+		u_e->cnt = *cnt;
+		u_e = u_e->next;
+	}
+}
+
 /* Selected_chain == -1 : zero all counters
  * Otherwise, zero the counters of selected_chain */
 void ebt_zero_counters(struct ebt_u_replace *replace)
diff --git a/useful_functions.c b/useful_functions.c
index a36062e..0cd3d51 100644
--- a/useful_functions.c
+++ b/useful_functions.c
@@ -39,11 +39,9 @@
 const unsigned char mac_type_bridge_group[ETH_ALEN] = {0x01,0x80,0xc2,0,0,0};
 const unsigned char msk_type_bridge_group[ETH_ALEN] = {255,255,255,255,255,255};
 
-/*
- * 0: default, print only 2 digits if necessary
+/* 0: default, print only 2 digits if necessary
  * 2: always print 2 digits, a printed mac address
- * then always has the same length
- */
+ * then always has the same length */
 int ebt_printstyle_mac;
 
 void ebt_print_mac(const char *mac)
@@ -82,9 +80,7 @@
 	}
 }
 
-/*
- * Checks the type for validity and calls getethertypebynumber()
- */
+/* Checks the type for validity and calls getethertypebynumber(). */
 struct ethertypeent *parseethertypebynumber(int type)
 {
 	if (type < 1536)
@@ -94,10 +90,7 @@
 	return getethertypebynumber(type);
 }
 
-/*
- * put the mac address into 6 (ETH_ALEN) bytes
- * returns 0 on success
- */
+/* Put the mac address into 6 (ETH_ALEN) bytes returns 0 on success. */
 int ebt_get_mac_and_mask(char *from, char *to, char *mask)
 {
 	char *p;
@@ -139,23 +132,25 @@
 	return 0;
 }
 
-/*
- * 0: default
- * 1: the inverse '!' of the option has already been specified
- */
+/* 0: default
+ * 1: the inverse '!' of the option has already been specified */
 int ebt_invert = 0;
 
 /*
  * Check if the inverse of the option is specified. This is used
- * in the parse functions of the extensions and ebtables.c.
+ * in the parse functions of the extensions and ebtables.c
  */
-int ebt_check_inverse(const char option[])
+int _ebt_check_inverse(const char option[], int argc, char **argv)
 {
 	if (!option)
 		return ebt_invert;
 	if (strcmp(option, "!") == 0) {
 		if (ebt_invert == 1)
-			ebt_print_error("double use of '!' not allowed");
+			ebt_print_error("Double use of '!' not allowed");
+		if (optind >= argc)
+			optarg = NULL;
+		else
+			optarg = argv[optind];
 		optind++;
 		ebt_invert = 1;
 		return 1;
@@ -163,10 +158,8 @@
 	return ebt_invert;
 }
 
-/*
- * Make sure the same option wasn't specified twice. This is used
- * in the parse functions of the extensions and ebtables.c.
- */
+/* Make sure the same option wasn't specified twice. This is used
+ * in the parse functions of the extensions and ebtables.c */
 void ebt_check_option(unsigned int *flags, unsigned int mask)
 {
 	if (*flags & mask)
@@ -174,9 +167,7 @@
 	*flags |= mask;
 }
 
-/*
- * put the ip string into 4 bytes
- */
+/* Put the ip string into 4 bytes. */
 static int undot_ip(char *ip, unsigned char *ip2)
 {
 	char *p, *q, *end;
@@ -206,9 +197,7 @@
 	return 0;
 }
 
-/*
- * put the mask into 4 bytes
- */
+/* Put the mask into 4 bytes. */
 static int ip_mask(char *mask, unsigned char *mask2)
 {
 	char *end;
@@ -231,9 +220,8 @@
 	return 0;
 }
 
-/*
- * set the ip mask and ip address
- */
+/* Set the ip mask and ip address. Callers should check ebt_errormsg[0].
+ * The string pointed to by address can be altered. */
 void ebt_parse_ip_address(char *address, uint32_t *addr, uint32_t *msk)
 {
 	char *p;
@@ -241,19 +229,21 @@
 	/* first the mask */
 	if ((p = strrchr(address, '/')) != NULL) {
 		*p = '\0';
-		if (ip_mask(p + 1, (unsigned char *)msk))
-			ebt_print_error("Problem with the IP mask");
+		if (ip_mask(p + 1, (unsigned char *)msk)) {
+			ebt_print_error("Problem with the IP mask '%s'", p + 1);
+			return;
+		}
 	} else
 		*msk = 0xFFFFFFFF;
 
-	if (undot_ip(address, (unsigned char *)addr))
-		ebt_print_error("Problem with the IP address");
+	if (undot_ip(address, (unsigned char *)addr)) {
+		ebt_print_error("Problem with the IP address '%s'", address);
+		return;
+	}
 	*addr = *addr & *msk;
 }
 
-/*
- * transform the ip mask into a string ready for output
- */
+/* Transform the ip mask into a string ready for output. */
 char *ebt_mask_to_dotted(uint32_t mask)
 {
 	int i;
@@ -269,7 +259,7 @@
 	}
 
 	i = 32;
-	bits = 0xFFFFFFFEL; /* case 0xFFFFFFFF has just been dealt with */
+	bits = 0xFFFFFFFEL; /* Case 0xFFFFFFFF has just been dealt with */
 	while (--i >= 0 && maskaddr != bits)
 		bits <<= 1;
 
@@ -278,7 +268,7 @@
 	else if (!i)
 		*buf = '\0';
 	else
-		/* mask was not a decent combination of 1's and 0's */
+		/* Mask was not a decent combination of 1's and 0's */
 		sprintf(buf, "/%d.%d.%d.%d", ((unsigned char *)&mask)[0], 
 		   ((unsigned char *)&mask)[1], ((unsigned char *)&mask)[2],
 		   ((unsigned char *)&mask)[3]);