put reference to cc in each entry
authorBart De Schuymer <bdschuym@pandora.be>
Sun, 28 Aug 2005 13:16:25 +0000 (13:16 +0000)
committerBart De Schuymer <bdschuym@pandora.be>
Sun, 28 Aug 2005 13:16:25 +0000 (13:16 +0000)
communication.c
ebtables.c
include/ebtables_u.h
libebtc.c

index 01b69c9..472c7ed 100644 (file)
@@ -297,7 +297,7 @@ void ebt_deliver_counters(struct ebt_u_replace *u_repl, int exec_style)
        struct ebt_counter *old, *new, *newcounters;
        socklen_t optlen;
        struct ebt_replace repl;
-       struct ebt_cntchanges *cc = u_repl->counterchanges, *cc2, **cc3;
+       struct ebt_cntchanges *cc = u_repl->cc->next, *cc2;
        struct ebt_u_entries *entries;
        struct ebt_u_entry *next = NULL;
        int i, chainnr = 0;
@@ -312,13 +312,11 @@ void ebt_deliver_counters(struct ebt_u_replace *u_repl, int exec_style)
        memset(newcounters, 0, u_repl->nentries * sizeof(struct ebt_counter));
        old = u_repl->counters;
        new = newcounters;
-       while (cc) {
+       while (cc != u_repl->cc) {
                if (!next) {
-                       while (!(entries = u_repl->chains[chainnr++]))
-                               if (chainnr > NF_BR_NUMHOOKS)
-                                       goto letscontinue;/* Prevent infinite loop for -D x:-1 */
-                       if (!(next = entries->entries))
-                               continue;
+                       while (chainnr < u_repl->num_chains && (!(entries = u_repl->chains[chainnr++]) || !(next = entries->entries)));
+                       if (chainnr == u_repl->num_chains)
+                               break;
                }
                if (cc->type == CNT_NORM) {
                        /* 'Normal' rule, meaning we didn't do anything to it
@@ -326,17 +324,13 @@ void ebt_deliver_counters(struct ebt_u_replace *u_repl, int exec_style)
                        *new = *old;
                        next->cnt = *new;
                        next->cnt_surplus.pcnt = next->cnt_surplus.bcnt = 0;
-                       /* We've used an old counter */
-                       old++;
-                       /* We've set a new counter */
-                       new++;
+                       old++; /* We've used an old counter */
+                       new++; /* We've set a new counter */
                        next = next->next;
                } else if (cc->type == CNT_DEL) {
-                       /* Don't use this old counter */
-                       old++;
+                       old++; /* Don't use this old counter */
                } else {
                        if (cc->type == CNT_CHANGE) {
-                               new->pcnt = old->pcnt;
                                if (cc->change % 3 == 1)
                                        new->pcnt = old->pcnt + next->cnt_surplus.pcnt;
                                else if (cc->change % 3 == 2)
@@ -363,11 +357,29 @@ void ebt_deliver_counters(struct ebt_u_replace *u_repl, int exec_style)
                }
                cc = cc->next;
        }
-letscontinue:
 
        free(u_repl->counters);
        u_repl->counters = newcounters;
        u_repl->num_counters = u_repl->nentries;
+       /* Reset the counterchanges to CNT_NORM and delete the unused cc */
+       i = 0;
+       cc = u_repl->cc->next;
+       while (cc != u_repl->cc) {
+               if (cc->type == CNT_DEL) {
+                       cc->prev->next = cc->next;
+                       cc->next->prev = cc->prev;
+                       cc2 = cc->next;
+                       free(cc);
+                       cc = cc2;
+               } else {
+                       cc->type = CNT_NORM;
+                       cc->change = 0;
+                       i++;
+                       cc = cc->next;
+               }
+       }
+       if (i != u_repl->nentries)
+               ebt_print_bug("i != u_repl->nentries");
        if (u_repl->filename != NULL) {
                store_counters_in_file(u_repl->filename, u_repl);
                return;
@@ -386,20 +398,6 @@ letscontinue:
 
        if (exec_style != EXEC_STYLE_DAEMON)
                return;
-       /* Reset the counterchanges to CNT_NORM */
-       cc = u_repl->counterchanges;
-       for (i = 0; i < u_repl->nentries; i++) {
-               cc->type = CNT_NORM;
-               cc->change = 0;
-               cc3 = &cc->next;
-               cc = cc->next;
-       }
-       *cc3 = NULL;
-       while (cc) {
-               cc2 = cc->next;
-               free(cc);
-               cc = cc2;
-       }
 }
 
 static int
@@ -458,7 +456,7 @@ ebt_translate_watcher(struct ebt_entry_watcher *w,
 static int
 ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt,
    int *totalcnt, struct ebt_u_entry ***u_e, struct ebt_u_replace *u_repl,
-   unsigned int valid_hooks, char *base)
+   unsigned int valid_hooks, char *base, struct ebt_cntchanges **cc)
 {
        /* An entry */
        if (e->bitmask & EBT_ENTRY_OR_ENTRIES) {
@@ -490,6 +488,8 @@ ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt,
                        ebt_print_bug("*totalcnt >= u_repl->nentries");
                new->cnt = u_repl->counters[*totalcnt];
                new->cnt_surplus.pcnt = new->cnt_surplus.bcnt = 0;
+               new->cc = *cc;
+               *cc = (*cc)->next;
                new->m_list = NULL;
                new->w_list = NULL;
                new->next = NULL;
@@ -709,8 +709,7 @@ int ebt_get_table(struct ebt_u_replace *u_repl, int init)
        int i, j, k, hook;
        struct ebt_replace repl;
        struct ebt_u_entry **u_e;
-       struct ebt_cntchanges *new_cc;
-       struct ebt_cntchanges **prev_cc =  &(u_repl->counterchanges);
+       struct ebt_cntchanges *new_cc, *cc;
 
        strcpy(repl.name, u_repl->name);
        if (u_repl->filename != NULL) {
@@ -728,17 +727,24 @@ int ebt_get_table(struct ebt_u_replace *u_repl, int init)
        u_repl->nentries = repl.nentries;
        u_repl->num_counters = repl.num_counters;
        u_repl->counters = repl.counters;
-       u_repl->counterchanges = NULL;
+       u_repl->cc = (struct ebt_cntchanges *)malloc(sizeof(struct ebt_cntchanges));
+       if (!u_repl->cc)
+               ebt_print_memory();
+       u_repl->cc->next = u_repl->cc->prev = u_repl->cc;
+       cc = u_repl->cc;
        for (i = 0; i < repl.nentries; i++) {
-               new_cc = (struct ebt_cntchanges *)
-                        malloc(sizeof(struct ebt_cntchanges));
+               new_cc = (struct ebt_cntchanges *)malloc(sizeof(struct ebt_cntchanges));
                if (!new_cc)
                        ebt_print_memory();
                new_cc->type = CNT_NORM;
                new_cc->change = 0;
-               new_cc->next = NULL;
-               *prev_cc = new_cc;
-               prev_cc = &(new_cc->next);
+               new_cc->prev = cc;
+               cc->next = new_cc;
+               cc = new_cc;
+       }
+       if (repl.nentries) {
+               new_cc->next = u_repl->cc;
+               u_repl->cc->prev = new_cc;
        }
        u_repl->chains = (struct ebt_u_entries **)calloc(EBT_ORI_MAX_CHAINS, sizeof(void *));
        u_repl->max_chains = EBT_ORI_MAX_CHAINS;
@@ -753,10 +759,11 @@ int ebt_get_table(struct ebt_u_replace *u_repl, int init)
        i = 0; /* Holds the expected nr. of entries for the chain */
        j = 0; /* Holds the up to now counted entries for the chain */
        k = 0; /* Holds the total nr. of entries, should equal u_repl->nentries afterwards */
+       cc = u_repl->cc->next;
        hook = -1;
        EBT_ENTRY_ITERATE((char *)repl.entries, repl.entries_size,
           ebt_translate_entry, &hook, &i, &j, &k, &u_e, u_repl,
-          u_repl->valid_hooks, (char *)repl.entries);
+          u_repl->valid_hooks, (char *)repl.entries, &cc);
        if (k != u_repl->nentries)
                ebt_print_bug("Wrong total nentries");
        return 0;
index 717c66b..dc04f4e 100644 (file)
@@ -182,7 +182,7 @@ static void print_iface(const char *iface)
 #define LIST_MAC2 0x20
 
 /* Helper function for list_rules() */
-static void list_em(struct ebt_u_entries *entries, struct ebt_cntchanges *cc)
+static void list_em(struct ebt_u_entries *entries)
 {
        int i, j, space = 0, digits;
        struct ebt_u_entry *hlp;
@@ -320,13 +320,6 @@ static void list_em(struct ebt_u_entries *entries, struct ebt_cntchanges *cc)
                        uint64_t pcnt = hlp->cnt.pcnt;
                        uint64_t bcnt = hlp->cnt.bcnt;
 
-#ifdef EBT_DEBUG
-                       while (cc->type == CNT_DEL)
-                               cc = cc->next;
-                       if (cc->change != 0) /* In daemon mode, only change==0 is allowed */
-                               ebt_print_bug("cc->change != 0");
-                       cc = cc->next;
-#endif
                        if (replace->flags & LIST_X)
                                printf("-c %llu %llu", pcnt, bcnt);
                        else
@@ -406,12 +399,11 @@ ATOMIC_ENV_VARIABLE "          : if set <FILE> (see above) will equal its value"
 static void list_rules()
 {
        int i;
-       struct ebt_cntchanges *cc = replace->counterchanges;
 
        if (!(replace->flags & LIST_X))
                printf("Bridge table: %s\n", table->name);
        if (replace->selected_chain != -1)
-               list_em(ebt_to_chain(replace), cc);
+               list_em(ebt_to_chain(replace));
        else {
                /* Create new chains and rename standard chains when necessary */
                if (replace->flags & LIST_X && replace->num_chains > NF_BR_NUMHOOKS) {
@@ -423,7 +415,7 @@ static void list_rules()
                }
                for (i = 0; i < replace->num_chains; i++)
                        if (replace->chains[i])
-                               list_em(replace->chains[i], cc);
+                               list_em(replace->chains[i]);
        }
 }
 
@@ -1215,7 +1207,7 @@ delete_the_rule:
        if (exec_style == EXEC_STYLE_PRG) {/* Implies ebt_errormsg[0] == '\0' */
                ebt_deliver_table(replace);
 
-               if (replace->counterchanges)
+               if (replace->cc)
                        ebt_deliver_counters(replace, EXEC_STYLE_PRG);
        }
        return 0;
index c74118b..1c87117 100644 (file)
@@ -52,6 +52,7 @@ struct ebt_cntchanges
 {
        unsigned short type;
        unsigned short change; /* determines incremental/decremental/change */
+       struct ebt_cntchanges *prev;
        struct ebt_cntchanges *next;
 };
 
@@ -82,8 +83,8 @@ struct ebt_u_replace
        int selected_chain;
        /* used for the atomic option */
        char *filename;
-       /* tells what happened to the old rules */
-       struct ebt_cntchanges *counterchanges;
+       /* tells what happened to the old rules (counter changes) */
+       struct ebt_cntchanges *cc;
 };
 
 struct ebt_u_table
@@ -125,6 +126,7 @@ struct ebt_u_entry
        struct ebt_u_entry *next;
        struct ebt_counter cnt;
        struct ebt_counter cnt_surplus; /* for increasing/decreasing a counter and for option 'C' */
+       struct ebt_cntchanges *cc;
        /* the standard target needs this to know the name of a udc when
         * printing out rules. */
        struct ebt_u_replace *replace;
@@ -236,7 +238,6 @@ void ebt_double_chains(struct ebt_u_replace *replace);
 void ebt_free_u_entry(struct ebt_u_entry *e);
 struct ebt_u_entries *ebt_name_to_chain(const struct ebt_u_replace *replace,
                                    const char* arg);
-struct ebt_u_entries *ebt_to_chain(const struct ebt_u_replace *replace);
 struct ebt_u_entries *ebt_name_to_chain(const struct ebt_u_replace *replace,
                                    const char* arg);
 int ebt_get_chainnr(const struct ebt_u_replace *replace, const char* arg);
@@ -294,7 +295,11 @@ int do_command(int argc, char *argv[], int exec_style,
 
 struct ethertypeent *parseethertypebynumber(int type);
 
-#define ebt_to_chain(repl) repl->chains[repl->selected_chain]
+#define ebt_to_chain(repl)                             \
+({struct ebt_u_entries *_ch = NULL;                    \
+if (repl->selected_chain != -1)                                        \
+       _ch = repl->chains[repl->selected_chain];       \
+_ch;})
 #define ebt_print_bug(format, args...) \
    __ebt_print_bug(__FILE__, __LINE__, format, ##args)
 #define ebt_print_error(format,args...) __ebt_print_error(format, ##args);
@@ -320,9 +325,7 @@ __ret;})
 #define CNT_NORM       0
 #define CNT_DEL        1
 #define CNT_ADD        2
-#define CNT_OWRITE     3
-#define CNT_ZERO       4
-#define CNT_CHANGE     5
+#define CNT_CHANGE     3
 
 extern const char *ebt_hooknames[NF_BR_NUMHOOKS];
 extern const char *ebt_standard_targets[NUM_STANDARD_TARGETS];
index 451e9c2..9f93ee1 100644 (file)
--- a/libebtc.c
+++ b/libebtc.c
@@ -207,13 +207,13 @@ void ebt_cleanup_replace(struct ebt_u_replace *replace)
                free(entries);
                replace->chains[i] = NULL;
        }
-       cc1 = replace->counterchanges;
-       while (cc1) {
+       cc1 = replace->cc->next;
+       while (cc1 != replace->cc) {
                cc2 = cc1->next;
                free(cc1);
                cc1 = cc2;
        }
-       replace->counterchanges = NULL;
+       replace->cc->next = replace->cc->prev = replace->cc;
 }
 
 /* Should be called, e.g., between 2 rule adds */
@@ -399,15 +399,23 @@ void ebt_change_policy(struct ebt_u_replace *replace, int policy)
        entries->policy = policy;
 }
 
+void ebt_delete_cc(struct ebt_cntchanges *cc)
+{
+       if (cc->type == CNT_ADD) {
+               cc->prev->next = cc->next;
+               cc->next->prev = cc->prev;
+               free(cc);
+       }
+       cc->type = CNT_DEL;
+}
+
 /* Flush one chain or the complete table
  * If selected_chain == -1 then flush the complete table */
 void ebt_flush_chains(struct ebt_u_replace *replace)
 {
-       int i, j, numdel;
+       int i, numdel;
        struct ebt_u_entry *u_e, *tmp;
        struct ebt_u_entries *entries = ebt_to_chain(replace);
-       struct ebt_cntchanges *cc = replace->counterchanges;
-       struct ebt_cntchanges **prev_cc =  &(replace->counterchanges);
 
        /* Flush whole table */
        if (!entries) {
@@ -424,24 +432,13 @@ void ebt_flush_chains(struct ebt_u_replace *replace)
                        u_e = entries->entries;
                        entries->entries = NULL;
                        while (u_e) {
+                               ebt_delete_cc(u_e->cc);
                                ebt_free_u_entry(u_e);
                                tmp = u_e->next;
                                free(u_e);
                                u_e = tmp;
                        }
                }
-               /* Update the counters */
-               while (cc) {
-                       if (cc->type == CNT_ADD) {
-                               *prev_cc = cc->next;
-                               free(cc);
-                               cc = *prev_cc;
-                               continue;
-                       }
-                       cc->type = CNT_DEL;
-                       prev_cc = &(cc->next);
-                       cc = cc->next;
-               }
                return;
        }
 
@@ -450,41 +447,18 @@ void ebt_flush_chains(struct ebt_u_replace *replace)
        replace->nentries -= entries->nentries;
        numdel = entries->nentries;
 
-       /* Delete the counters belonging to the specified chain,
-        * update counter_offset */
-       for (i = 0; i < replace->num_chains; i++) {
+       /* Update counter_offset */
+       for (i = replace->selected_chain+1; i < replace->num_chains; i++) {
                if (!(entries = replace->chains[i]))
                        continue;
-               if (i > replace->selected_chain) {
-                       entries->counter_offset -= numdel;
-                       continue;
-               }
-               j = entries->nentries;
-               while (j) {
-                       /* Don't count deleted entries */
-                       if (cc->type == CNT_DEL)
-                               goto letscontinue;
-                       if (i == replace->selected_chain) {
-                               if (cc->type == CNT_ADD) {
-                                       *prev_cc = cc->next;
-                                       free(cc);
-                                       cc = *prev_cc;
-                                       j--;
-                                       continue;
-                               }
-                               cc->type = CNT_DEL;
-                       }
-                       j--;
-letscontinue:
-                       prev_cc = &(cc->next);
-                       cc = cc->next;
-               }
+               entries->counter_offset -= numdel;
        }
 
        entries = ebt_to_chain(replace);
        entries->nentries = 0;
        u_e = entries->entries;
        while (u_e) {
+               ebt_delete_cc(u_e->cc);
                ebt_free_u_entry(u_e);
                tmp = u_e->next;
                free(u_e);
@@ -607,13 +581,12 @@ letscontinue:;
  * don't reuse the new_entry after a successful call to ebt_add_rule() */
 void ebt_add_rule(struct ebt_u_replace *replace, struct ebt_u_entry *new_entry, int rule_nr)
 {
-       int i, j;
+       int i;
        struct ebt_u_entry **u_e;
        struct ebt_u_match_list *m_l;
        struct ebt_u_watcher_list *w_l;
        struct ebt_u_entries *entries = ebt_to_chain(replace);
-       struct ebt_cntchanges *cc = replace->counterchanges, *new_cc;
-       struct ebt_cntchanges **prev_cc =  &(replace->counterchanges);
+       struct ebt_cntchanges *cc, *new_cc;
 
        if (rule_nr <= 0)
                rule_nr += entries->nentries;
@@ -626,37 +599,6 @@ void ebt_add_rule(struct ebt_u_replace *replace, struct ebt_u_entry *new_entry,
        /* We're adding one rule */
        replace->nentries++;
        entries->nentries++;
-
-       /* Handle counter stuff */
-       for (i = 0; i < replace->selected_chain; i++) {
-               if (!(replace->chains[i]))
-                       continue;
-               j = replace->chains[i]->nentries;
-               while (j) {
-                       if (cc->type != CNT_DEL)
-                               j--;
-                       prev_cc = &(cc->next);
-                       cc = cc->next;
-               }
-       }
-       j = rule_nr;
-       while (j) {
-               if (cc->type != CNT_DEL)
-                       j--;
-               prev_cc = &(cc->next);
-               cc = cc->next;
-       }
-       if (cc && cc->type == CNT_DEL)
-               cc->type = CNT_OWRITE;
-       else {
-               new_cc = (struct ebt_cntchanges *)malloc(sizeof(struct ebt_cntchanges));
-               if (!new_cc)
-                       ebt_print_memory();
-               new_cc->type = CNT_ADD;
-               new_cc->change = 0;
-               new_cc->next = cc;
-               *prev_cc = new_cc;
-       }
        /* Go to the right position in the chain */
        u_e = &entries->entries;
        for (i = 0; i < rule_nr; i++)
@@ -664,6 +606,27 @@ void ebt_add_rule(struct ebt_u_replace *replace, struct ebt_u_entry *new_entry,
        /* Insert the rule */
        new_entry->next = *u_e;
        *u_e = new_entry;
+       new_cc = (struct ebt_cntchanges *)malloc(sizeof(struct ebt_cntchanges));
+       if (!new_cc)
+               ebt_print_memory();
+       new_cc->type = CNT_ADD;
+       new_cc->change = 0;
+       if (!new_entry->next) {
+               for (i = replace->selected_chain+1; i < replace->num_chains; i++)
+                       if (!replace->chains[i] || replace->chains[i]->nentries == 0)
+                               continue;
+                       else
+                               break;
+               if (i == replace->num_chains)
+                       cc = replace->cc;
+               else
+                       cc = replace->chains[i]->entries->cc;
+       } else
+               cc = new_entry->next->cc;
+       new_cc->next = cc;
+       new_cc->prev = cc->prev;
+       cc->prev->next = new_cc;
+       cc->prev = new_cc;
 
        /* Put the ebt_{match, watcher, target} pointers in place */
        m_l = new_entry->m_list;
@@ -730,73 +693,32 @@ static int check_and_change_rule_number(struct ebt_u_replace *replace,
 void ebt_delete_rule(struct ebt_u_replace *replace,
                     struct ebt_u_entry *new_entry, int begin, int end)
 {
-       int i, j,  nr_deletes;
+       int i,  nr_deletes;
        struct ebt_u_entry **u_e, *u_e2;
        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;
-
        /* We're deleting rules */
        nr_deletes = end - begin + 1;
        replace->nentries -= nr_deletes;
        entries->nentries -= nr_deletes;
-
-       /* Handle counter stuff */
-       for (i = 0; i < replace->selected_chain; i++) {
-               if (!(replace->chains[i]))
-                       continue;
-               j = replace->chains[i]->nentries;
-               while (j) {
-                       if (cc->type != CNT_DEL)
-                               j--;
-                       prev_cc = &(cc->next);
-                       cc = cc->next;
-               }
-       }
-       j = begin;
-       while (j) {
-               if (cc->type != CNT_DEL)
-                       j--;
-               prev_cc = &(cc->next);
-               cc = cc->next;
-       }
-       j = nr_deletes;
-       while (j) {
-               if (cc->type != CNT_DEL) {
-                       j--;
-                       if (cc->type == CNT_ADD) {
-                               *prev_cc = cc->next;
-                               free(cc);
-                               cc = *prev_cc;
-                               continue;
-                       }
-                       cc->type = CNT_DEL;
-               }
-               prev_cc = &(cc->next);
-               cc = cc->next;
-       }
-
        /* Go to the right position in the chain */
        u_e = &entries->entries;
-       for (j = 0; j < begin; j++)
+       for (i = 0; i < begin; i++)
                u_e = &(*u_e)->next;
        /* Remove the rules */
-       j = nr_deletes;
-       while (j--) {
+       for (i = 0; i < nr_deletes; i++) {
                u_e2 = *u_e;
+               ebt_delete_cc(u_e2->cc);
                *u_e = (*u_e)->next;
                /* Free everything */
                ebt_free_u_entry(u_e2);
                free(u_e2);
        }
-
        /* Update the counter_offset of chains behind this one */
-       j = replace->selected_chain;
-       for (j = replace->selected_chain+1; j < replace->num_chains; j++) {
-               if (!(entries = replace->chains[j]))
+       for (i = replace->selected_chain+1; i < replace->num_chains; i++) {
+               if (!(entries = replace->chains[i]))
                        continue;
                entries->counter_offset -= nr_deletes;
        }
@@ -816,64 +738,41 @@ void ebt_change_counters(struct ebt_u_replace *replace,
                     struct ebt_u_entry *new_entry, int begin, int end,
                     struct ebt_counter *cnt, int mask)
 {
-       int i, j;
+       int i;
        struct ebt_u_entry *u_e;
        struct ebt_u_entries *entries = ebt_to_chain(replace);
-       struct ebt_cntchanges *cc = replace->counterchanges;
 
        if (check_and_change_rule_number(replace, new_entry, &begin, &end))
                return;
-
-       for (i = 0; i < replace->selected_chain; i++) {
-               if (!(replace->chains[i]))
-                       continue;
-               j = replace->chains[i]->nentries;
-               while (j) {
-                       if (cc->type != CNT_DEL)
-                               j--;
-                       cc = cc->next;
-               }
-       }
-       i = begin;
-       while (i) {
-               if (cc->type != CNT_DEL)
-                       i--;
-               cc = cc->next;
-       }
        u_e = entries->entries;
        for (i = 0; i < begin; i++)
                u_e = u_e->next;
-       i = end - begin + 1;
-       while (i) {
-               if (cc->type != CNT_DEL) {
-                       i--;
-                       if (mask % 3 == 0) {
-                               u_e->cnt.pcnt = (*cnt).pcnt;
-                               u_e->cnt_surplus.pcnt = 0;
-                       } else {
+       for (i = end-begin+1; i > 0; i--) {
+               if (mask % 3 == 0) {
+                       u_e->cnt.pcnt = (*cnt).pcnt;
+                       u_e->cnt_surplus.pcnt = 0;
+               } else {
 #ifdef EBT_DEBUG
-                               if (cc->type != CNT_NORM)
-                                       ebt_print_bug("cc->type != CNT_NORM");
+                       if (u_e->cc->type != CNT_NORM)
+                               ebt_print_bug("cc->type != CNT_NORM");
 #endif
-                               u_e->cnt_surplus.pcnt = (*cnt).pcnt;
-                       }
+                       u_e->cnt_surplus.pcnt = (*cnt).pcnt;
+               }
 
-                       if (mask / 3 == 0) {
-                               u_e->cnt.bcnt = (*cnt).bcnt;
-                               u_e->cnt_surplus.bcnt = 0;
-                       } else {
+               if (mask / 3 == 0) {
+                       u_e->cnt.bcnt = (*cnt).bcnt;
+                       u_e->cnt_surplus.bcnt = 0;
+               } else {
 #ifdef EBT_DEBUG
-                               if (cc->type != CNT_NORM)
-                                       ebt_print_bug("cc->type != CNT_NORM");
+                       if (u_e->cc->type != CNT_NORM)
+                               ebt_print_bug("cc->type != CNT_NORM");
 #endif
-                               u_e->cnt_surplus.bcnt = (*cnt).bcnt;
-                       }
-                       if (cc->type == CNT_NORM || cc->type == CNT_ZERO)
-                               cc->type = CNT_CHANGE;
-                       cc->change = mask;
-                       u_e = u_e->next;
+                       u_e->cnt_surplus.bcnt = (*cnt).bcnt;
                }
-               cc = cc->next;
+               if (u_e->cc->type != CNT_ADD)
+                       u_e->cc->type = CNT_CHANGE;
+               u_e->cc->change = mask;
+               u_e = u_e->next;
        }
 }
 
@@ -882,22 +781,19 @@ void ebt_change_counters(struct ebt_u_replace *replace,
 void ebt_zero_counters(struct ebt_u_replace *replace)
 {
        struct ebt_u_entries *entries = ebt_to_chain(replace);
-       struct ebt_cntchanges *cc = replace->counterchanges;
        struct ebt_u_entry *next;
-       int i, j;
+       int i;
 
        if (!entries) {
-               while (cc) {
-                       if (cc->type == CNT_NORM)
-                               cc->type = CNT_ZERO;
-                       cc = cc->next;
-               }
                for (i = 0; i < replace->num_chains; i++) {
                        if (!(entries = replace->chains[i]))
                                continue;
                        next = entries->entries;
                        while (next) {
+                               if (next->cc->type == CNT_NORM)
+                                       next->cc->type = CNT_CHANGE;
                                next->cnt.bcnt = next->cnt.pcnt = 0;
+                               next->cc->change = 0;
                                next = next->next;
                        }
                }
@@ -905,27 +801,10 @@ void ebt_zero_counters(struct ebt_u_replace *replace)
                if (entries->nentries == 0)
                        return;
 
-               for (i = 0; i < replace->selected_chain; i++) {
-                       if (!(replace->chains[i]))
-                               continue;
-                       j = replace->chains[i]->nentries;
-                       while (j) {
-                               if (cc->type != CNT_DEL)
-                                       j--;
-                               cc = cc->next;
-                       }
-               }
-               j = entries->nentries;
-               while (j) {
-                       if (cc->type != CNT_DEL) {
-                               j--;
-                               if (cc->type == CNT_NORM)
-                                       cc->type = CNT_ZERO;
-                       }
-                       cc = cc->next;
-               }
                next = entries->entries;
                while (next) {
+                       if (next->cc->type == CNT_NORM)
+                               next->cc->type = CNT_CHANGE;
                        next->cnt.bcnt = next->cnt.pcnt = 0;
                        next = next->next;
                }