]> err.no Git - linux-2.6/blobdiff - net/bridge/netfilter/ebtables.c
[EBTABLES]: translate_table(): switch direct uses of repl->hook_info to newinfo
[linux-2.6] / net / bridge / netfilter / ebtables.c
index 84b9af76f0a2390763ef878b365cbe75d12a4fcc..3e1bf716509a99117400dc3ad25758acf9eff9d3 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/vmalloc.h>
 #include <linux/netfilter_bridge/ebtables.h>
 #include <linux/spinlock.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 #include <linux/smp.h>
 #include <linux/cpumask.h>
 /* needed for logical [in,out]-dev filtering */
 #include "../br_private.h"
 
-/* list_named_find */
-#define ASSERT_READ_LOCK(x)
-#define ASSERT_WRITE_LOCK(x)
-#include <linux/netfilter_ipv4/listhelp.h>
-#include <linux/mutex.h>
-
-#if 0
-/* use this for remote debugging
- * Copyright (C) 1998 by Ori Pomerantz
- * Print the string to the appropriate tty, the one
- * the current task uses
- */
-static void print_string(char *str)
-{
-       struct tty_struct *my_tty;
-
-       /* The tty for the current task */
-       my_tty = current->signal->tty;
-       if (my_tty != NULL) {
-               my_tty->driver->write(my_tty, 0, str, strlen(str));
-               my_tty->driver->write(my_tty, 0, "\015\012", 2);
-       }
-}
-
-#define BUGPRINT(args) print_string(args);
-#else
 #define BUGPRINT(format, args...) printk("kernel msg: ebtables bug: please "\
                                          "report to author: "format, ## args)
 /* #define BUGPRINT(format, args...) */
-#endif
 #define MEMPRINT(format, args...) printk("kernel msg: ebtables "\
                                          ": out of memory: "format, ## args)
 /* #define MEMPRINT(format, args...) */
@@ -112,7 +86,7 @@ static inline int ebt_do_match (struct ebt_entry_match *m,
 static inline int ebt_dev_check(char *entry, const struct net_device *device)
 {
        int i = 0;
-       char *devname = device->name;
+       const char *devname = device->name;
 
        if (*entry == '\0')
                return 0;
@@ -299,18 +273,22 @@ static inline void *
 find_inlist_lock_noload(struct list_head *head, const char *name, int *error,
    struct mutex *mutex)
 {
-       void *ret;
+       struct {
+               struct list_head list;
+               char name[EBT_FUNCTION_MAXNAMELEN];
+       } *e;
 
        *error = mutex_lock_interruptible(mutex);
        if (*error != 0)
                return NULL;
 
-       ret = list_named_find(head, name);
-       if (!ret) {
-               *error = -ENOENT;
-               mutex_unlock(mutex);
+       list_for_each_entry(e, head, list) {
+               if (strcmp(e->name, name) == 0)
+                       return e;
        }
-       return ret;
+       *error = -ENOENT;
+       mutex_unlock(mutex);
+       return NULL;
 }
 
 #ifndef CONFIG_KMOD
@@ -360,10 +338,11 @@ ebt_check_match(struct ebt_entry_match *m, struct ebt_entry *e,
    const char *name, unsigned int hookmask, unsigned int *cnt)
 {
        struct ebt_match *match;
+       size_t left = ((char *)e + e->watchers_offset) - (char *)m;
        int ret;
 
-       if (((char *)m) + m->match_size + sizeof(struct ebt_entry_match) >
-          ((char *)e) + e->watchers_offset)
+       if (left < sizeof(struct ebt_entry_match) ||
+           left - sizeof(struct ebt_entry_match) < m->match_size)
                return -EINVAL;
        match = find_match_lock(m->u.name, &ret, &ebt_mutex);
        if (!match)
@@ -389,10 +368,11 @@ ebt_check_watcher(struct ebt_entry_watcher *w, struct ebt_entry *e,
    const char *name, unsigned int hookmask, unsigned int *cnt)
 {
        struct ebt_watcher *watcher;
+       size_t left = ((char *)e + e->target_offset) - (char *)w;
        int ret;
 
-       if (((char *)w) + w->watcher_size + sizeof(struct ebt_entry_watcher) >
-          ((char *)e) + e->target_offset)
+       if (left < sizeof(struct ebt_entry_watcher) ||
+          left - sizeof(struct ebt_entry_watcher) < w->watcher_size)
                return -EINVAL;
        watcher = find_watcher_lock(w->u.name, &ret, &ebt_mutex);
        if (!watcher)
@@ -413,35 +393,93 @@ ebt_check_watcher(struct ebt_entry_watcher *w, struct ebt_entry *e,
        return 0;
 }
 
+static int ebt_verify_pointers(struct ebt_replace *repl,
+                              struct ebt_table_info *newinfo)
+{
+       unsigned int limit = repl->entries_size;
+       unsigned int valid_hooks = repl->valid_hooks;
+       unsigned int offset = 0;
+       int i;
+
+       for (i = 0; i < NF_BR_NUMHOOKS; i++)
+               newinfo->hook_entry[i] = NULL;
+
+       newinfo->entries_size = repl->entries_size;
+       newinfo->nentries = repl->nentries;
+
+       while (offset < limit) {
+               size_t left = limit - offset;
+               struct ebt_entry *e = (void *)newinfo->entries + offset;
+
+               if (left < sizeof(unsigned int))
+                       break;
+
+               for (i = 0; i < NF_BR_NUMHOOKS; i++) {
+                       if ((valid_hooks & (1 << i)) == 0)
+                               continue;
+                       if ((char *)repl->hook_entry[i] == repl->entries + offset)
+                               break;
+               }
+
+               if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
+                       if (e->bitmask != 0) {
+                               /* we make userspace set this right,
+                                  so there is no misunderstanding */
+                               BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set "
+                                        "in distinguisher\n");
+                               return -EINVAL;
+                       }
+                       if (i != NF_BR_NUMHOOKS)
+                               newinfo->hook_entry[i] = (struct ebt_entries *)e;
+                       if (left < sizeof(struct ebt_entries))
+                               break;
+                       offset += sizeof(struct ebt_entries);
+               } else {
+                       if (left < sizeof(struct ebt_entry))
+                               break;
+                       if (left < e->next_offset)
+                               break;
+                       offset += e->next_offset;
+               }
+       }
+       if (offset != limit) {
+               BUGPRINT("entries_size too small\n");
+               return -EINVAL;
+       }
+
+       /* check if all valid hooks have a chain */
+       for (i = 0; i < NF_BR_NUMHOOKS; i++) {
+               if (!newinfo->hook_entry[i] &&
+                  (valid_hooks & (1 << i))) {
+                       BUGPRINT("Valid hook without chain\n");
+                       return -EINVAL;
+               }
+       }
+       return 0;
+}
+
 /*
  * this one is very careful, as it is the first function
  * to parse the userspace data
  */
 static inline int
 ebt_check_entry_size_and_hooks(struct ebt_entry *e,
-   struct ebt_table_info *newinfo, char *base, char *limit,
+   struct ebt_table_info *newinfo, char *base,
    struct ebt_entries **hook_entries, unsigned int *n, unsigned int *cnt,
    unsigned int *totalcnt, unsigned int *udc_cnt, unsigned int valid_hooks)
 {
+       unsigned int offset = (char *)e - newinfo->entries;
        int i;
 
        for (i = 0; i < NF_BR_NUMHOOKS; i++) {
                if ((valid_hooks & (1 << i)) == 0)
                        continue;
-               if ( (char *)hook_entries[i] - base ==
-                  (char *)e - newinfo->entries)
+               if ((char *)hook_entries[i] == base + offset)
                        break;
        }
        /* beginning of a new chain
           if i == NF_BR_NUMHOOKS it must be a user defined chain */
-       if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
-               if ((e->bitmask & EBT_ENTRY_OR_ENTRIES) != 0) {
-                       /* we make userspace set this right,
-                          so there is no misunderstanding */
-                       BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set "
-                                "in distinguisher\n");
-                       return -EINVAL;
-               }
+       if (i != NF_BR_NUMHOOKS || !e->bitmask) {
                /* this checks if the previous chain has as many entries
                   as it said it has */
                if (*n != *cnt) {
@@ -449,12 +487,6 @@ ebt_check_entry_size_and_hooks(struct ebt_entry *e,
                                 "in the chain\n");
                        return -EINVAL;
                }
-               /* before we look at the struct, be sure it is not too big */
-               if ((char *)hook_entries[i] + sizeof(struct ebt_entries)
-                  > limit) {
-                       BUGPRINT("entries_size too small\n");
-                       return -EINVAL;
-               }
                if (((struct ebt_entries *)e)->policy != EBT_DROP &&
                   ((struct ebt_entries *)e)->policy != EBT_ACCEPT) {
                        /* only RETURN from udc */
@@ -466,8 +498,6 @@ ebt_check_entry_size_and_hooks(struct ebt_entry *e,
                }
                if (i == NF_BR_NUMHOOKS) /* it's a user defined chain */
                        (*udc_cnt)++;
-               else
-                       newinfo->hook_entry[i] = (struct ebt_entries *)e;
                if (((struct ebt_entries *)e)->counter_offset != *totalcnt) {
                        BUGPRINT("counter_offset != totalcnt");
                        return -EINVAL;
@@ -488,7 +518,6 @@ ebt_check_entry_size_and_hooks(struct ebt_entry *e,
                BUGPRINT("target size too small\n");
                return -EINVAL;
        }
-
        (*cnt)++;
        (*totalcnt)++;
        return 0;
@@ -513,7 +542,7 @@ ebt_get_udc_positions(struct ebt_entry *e, struct ebt_table_info *newinfo,
        int i;
 
        /* we're only interested in chain starts */
-       if (e->bitmask & EBT_ENTRY_OR_ENTRIES)
+       if (e->bitmask)
                return 0;
        for (i = 0; i < NF_BR_NUMHOOKS; i++) {
                if ((valid_hooks & (1 << i)) == 0)
@@ -563,7 +592,7 @@ ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt)
 {
        struct ebt_entry_target *t;
 
-       if ((e->bitmask & EBT_ENTRY_OR_ENTRIES) == 0)
+       if (e->bitmask == 0)
                return 0;
        /* we're done */
        if (cnt && (*cnt)-- == 0)
@@ -586,10 +615,11 @@ ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
        struct ebt_entry_target *t;
        struct ebt_target *target;
        unsigned int i, j, hook = 0, hookmask = 0;
+       size_t gap = e->next_offset - e->target_offset;
        int ret;
 
        /* don't mess with the struct ebt_entries */
-       if ((e->bitmask & EBT_ENTRY_OR_ENTRIES) == 0)
+       if (e->bitmask == 0)
                return 0;
 
        if (e->bitmask & ~EBT_F_MASK) {
@@ -647,8 +677,7 @@ ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
 
        t->u.target = target;
        if (t->u.target == &ebt_standard_target) {
-               if (e->target_offset + sizeof(struct ebt_standard_target) >
-                  e->next_offset) {
+               if (gap < sizeof(struct ebt_standard_target)) {
                        BUGPRINT("Standard target size too big\n");
                        ret = -EFAULT;
                        goto cleanup_watchers;
@@ -659,8 +688,7 @@ ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
                        ret = -EFAULT;
                        goto cleanup_watchers;
                }
-       } else if ((e->target_offset + t->target_size +
-          sizeof(struct ebt_entry_target) > e->next_offset) ||
+       } else if (t->target_size > gap - sizeof(struct ebt_entry_target) ||
           (t->u.target->check &&
           t->u.target->check(name, hookmask, e, t->data, t->target_size) != 0)){
                module_put(t->u.target->me);
@@ -730,7 +758,9 @@ static int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s
                                BUGPRINT("loop\n");
                                return -1;
                        }
-                       /* this can't be 0, so the above test is correct */
+                       if (cl_s[i].hookmask & (1 << hooknr))
+                               goto letscontinue;
+                       /* this can't be 0, so the loop test is correct */
                        cl_s[i].cs.n = pos + 1;
                        pos = 0;
                        cl_s[i].cs.e = ((void *)e + e->next_offset);
@@ -757,35 +787,33 @@ static int translate_table(struct ebt_replace *repl,
        int ret;
        struct ebt_cl_stack *cl_s = NULL; /* used in the checking for chain loops */
 
+       ret = ebt_verify_pointers(repl, newinfo);
+       if (ret != 0)
+               return ret;
+
        i = 0;
-       while (i < NF_BR_NUMHOOKS && !(repl->valid_hooks & (1 << i)))
+       while (i < NF_BR_NUMHOOKS && !newinfo->hook_entry[i])
                i++;
        if (i == NF_BR_NUMHOOKS) {
                BUGPRINT("No valid hooks specified\n");
                return -EINVAL;
        }
-       if (repl->hook_entry[i] != (struct ebt_entries *)repl->entries) {
+       if (newinfo->hook_entry[i] != (struct ebt_entries *)newinfo->entries) {
                BUGPRINT("Chains don't start at beginning\n");
                return -EINVAL;
        }
        /* make sure chains are ordered after each other in same order
           as their corresponding hooks */
        for (j = i + 1; j < NF_BR_NUMHOOKS; j++) {
-               if (!(repl->valid_hooks & (1 << j)))
+               if (!newinfo->hook_entry[j])
                        continue;
-               if ( repl->hook_entry[j] <= repl->hook_entry[i] ) {
+               if (newinfo->hook_entry[j] <= newinfo->hook_entry[i]) {
                        BUGPRINT("Hook order must be followed\n");
                        return -EINVAL;
                }
                i = j;
        }
 
-       for (i = 0; i < NF_BR_NUMHOOKS; i++)
-               newinfo->hook_entry[i] = NULL;
-
-       newinfo->entries_size = repl->entries_size;
-       newinfo->nentries = repl->nentries;
-
        /* do some early checkings and initialize some things */
        i = 0; /* holds the expected nr. of entries for the chain */
        j = 0; /* holds the up to now counted entries for the chain */
@@ -794,7 +822,7 @@ static int translate_table(struct ebt_replace *repl,
        udc_cnt = 0; /* will hold the nr. of user defined chains (udc) */
        ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
           ebt_check_entry_size_and_hooks, newinfo, repl->entries,
-          repl->entries + repl->entries_size, repl->hook_entry, &i, &j, &k,
+          repl->hook_entry, &i, &j, &k,
           &udc_cnt, repl->valid_hooks);
 
        if (ret != 0)
@@ -810,15 +838,6 @@ static int translate_table(struct ebt_replace *repl,
                return -EINVAL;
        }
 
-       /* check if all valid hooks have a chain */
-       for (i = 0; i < NF_BR_NUMHOOKS; i++) {
-               if (newinfo->hook_entry[i] == NULL &&
-                  (repl->valid_hooks & (1 << i))) {
-                       BUGPRINT("Valid hook without chain\n");
-                       return -EINVAL;
-               }
-       }
-
        /* get the location of the udc, put them in an array
           while we're at it, allocate the chainstack */
        if (udc_cnt) {
@@ -831,7 +850,7 @@ static int translate_table(struct ebt_replace *repl,
                        return -ENOMEM;
                for_each_possible_cpu(i) {
                        newinfo->chainstack[i] =
-                          vmalloc(udc_cnt * sizeof(struct ebt_chainstack));
+                         vmalloc(udc_cnt * sizeof(*(newinfo->chainstack[0])));
                        if (!newinfo->chainstack[i]) {
                                while (i)
                                        vfree(newinfo->chainstack[--i]);
@@ -841,8 +860,7 @@ static int translate_table(struct ebt_replace *repl,
                        }
                }
 
-               cl_s = (struct ebt_cl_stack *)
-                  vmalloc(udc_cnt * sizeof(struct ebt_cl_stack));
+               cl_s = vmalloc(udc_cnt * sizeof(*cl_s));
                if (!cl_s)
                        return -ENOMEM;
                i = 0; /* the i'th udc */
@@ -859,7 +877,7 @@ static int translate_table(struct ebt_replace *repl,
 
        /* Check for loops */
        for (i = 0; i < NF_BR_NUMHOOKS; i++)
-               if (repl->valid_hooks & (1 << i))
+               if (newinfo->hook_entry[i])
                        if (check_chainloops(newinfo->hook_entry[i],
                           cl_s, udc_cnt, i, newinfo->entries)) {
                                vfree(cl_s);
@@ -944,8 +962,7 @@ static int do_replace(void __user *user, unsigned int len)
 
        countersize = COUNTER_OFFSET(tmp.nentries) * 
                                        (highest_possible_processor_id()+1);
-       newinfo = (struct ebt_table_info *)
-          vmalloc(sizeof(struct ebt_table_info) + countersize);
+       newinfo = vmalloc(sizeof(*newinfo) + countersize);
        if (!newinfo)
                return -ENOMEM;
 
@@ -967,8 +984,7 @@ static int do_replace(void __user *user, unsigned int len)
        /* the user wants counters back
           the check on the size is done later, when we have the lock */
        if (tmp.num_counters) {
-               counterstmp = (struct ebt_counter *)
-                  vmalloc(tmp.num_counters * sizeof(struct ebt_counter));
+               counterstmp = vmalloc(tmp.num_counters * sizeof(*counterstmp));
                if (!counterstmp) {
                        ret = -ENOMEM;
                        goto free_entries;
@@ -1067,15 +1083,19 @@ free_newinfo:
 
 int ebt_register_target(struct ebt_target *target)
 {
+       struct ebt_target *t;
        int ret;
 
        ret = mutex_lock_interruptible(&ebt_mutex);
        if (ret != 0)
                return ret;
-       if (!list_named_insert(&ebt_targets, target)) {
-               mutex_unlock(&ebt_mutex);
-               return -EEXIST;
+       list_for_each_entry(t, &ebt_targets, list) {
+               if (strcmp(t->name, target->name) == 0) {
+                       mutex_unlock(&ebt_mutex);
+                       return -EEXIST;
+               }
        }
+       list_add(&target->list, &ebt_targets);
        mutex_unlock(&ebt_mutex);
 
        return 0;
@@ -1084,21 +1104,25 @@ int ebt_register_target(struct ebt_target *target)
 void ebt_unregister_target(struct ebt_target *target)
 {
        mutex_lock(&ebt_mutex);
-       LIST_DELETE(&ebt_targets, target);
+       list_del(&target->list);
        mutex_unlock(&ebt_mutex);
 }
 
 int ebt_register_match(struct ebt_match *match)
 {
+       struct ebt_match *m;
        int ret;
 
        ret = mutex_lock_interruptible(&ebt_mutex);
        if (ret != 0)
                return ret;
-       if (!list_named_insert(&ebt_matches, match)) {
-               mutex_unlock(&ebt_mutex);
-               return -EEXIST;
+       list_for_each_entry(m, &ebt_matches, list) {
+               if (strcmp(m->name, match->name) == 0) {
+                       mutex_unlock(&ebt_mutex);
+                       return -EEXIST;
+               }
        }
+       list_add(&match->list, &ebt_matches);
        mutex_unlock(&ebt_mutex);
 
        return 0;
@@ -1107,21 +1131,25 @@ int ebt_register_match(struct ebt_match *match)
 void ebt_unregister_match(struct ebt_match *match)
 {
        mutex_lock(&ebt_mutex);
-       LIST_DELETE(&ebt_matches, match);
+       list_del(&match->list);
        mutex_unlock(&ebt_mutex);
 }
 
 int ebt_register_watcher(struct ebt_watcher *watcher)
 {
+       struct ebt_watcher *w;
        int ret;
 
        ret = mutex_lock_interruptible(&ebt_mutex);
        if (ret != 0)
                return ret;
-       if (!list_named_insert(&ebt_watchers, watcher)) {
-               mutex_unlock(&ebt_mutex);
-               return -EEXIST;
+       list_for_each_entry(w, &ebt_watchers, list) {
+               if (strcmp(w->name, watcher->name) == 0) {
+                       mutex_unlock(&ebt_mutex);
+                       return -EEXIST;
+               }
        }
+       list_add(&watcher->list, &ebt_watchers);
        mutex_unlock(&ebt_mutex);
 
        return 0;
@@ -1130,13 +1158,14 @@ int ebt_register_watcher(struct ebt_watcher *watcher)
 void ebt_unregister_watcher(struct ebt_watcher *watcher)
 {
        mutex_lock(&ebt_mutex);
-       LIST_DELETE(&ebt_watchers, watcher);
+       list_del(&watcher->list);
        mutex_unlock(&ebt_mutex);
 }
 
 int ebt_register_table(struct ebt_table *table)
 {
        struct ebt_table_info *newinfo;
+       struct ebt_table *t;
        int ret, i, countersize;
 
        if (!table || !table->table ||!table->table->entries ||
@@ -1148,8 +1177,7 @@ int ebt_register_table(struct ebt_table *table)
 
        countersize = COUNTER_OFFSET(table->table->nentries) *
                                        (highest_possible_processor_id()+1);
-       newinfo = (struct ebt_table_info *)
-          vmalloc(sizeof(struct ebt_table_info) + countersize);
+       newinfo = vmalloc(sizeof(*newinfo) + countersize);
        ret = -ENOMEM;
        if (!newinfo)
                return -ENOMEM;
@@ -1183,10 +1211,12 @@ int ebt_register_table(struct ebt_table *table)
        if (ret != 0)
                goto free_chainstack;
 
-       if (list_named_find(&ebt_tables, table->name)) {
-               ret = -EEXIST;
-               BUGPRINT("Table name already exists\n");
-               goto free_unlock;
+       list_for_each_entry(t, &ebt_tables, list) {
+               if (strcmp(t->name, table->name) == 0) {
+                       ret = -EEXIST;
+                       BUGPRINT("Table name already exists\n");
+                       goto free_unlock;
+               }
        }
 
        /* Hold a reference count if the chains aren't empty */
@@ -1194,7 +1224,7 @@ int ebt_register_table(struct ebt_table *table)
                ret = -ENOENT;
                goto free_unlock;
        }
-       list_prepend(&ebt_tables, table);
+       list_add(&table->list, &ebt_tables);
        mutex_unlock(&ebt_mutex);
        return 0;
 free_unlock:
@@ -1220,7 +1250,7 @@ void ebt_unregister_table(struct ebt_table *table)
                return;
        }
        mutex_lock(&ebt_mutex);
-       LIST_DELETE(&ebt_tables, table);
+       list_del(&table->list);
        mutex_unlock(&ebt_mutex);
        vfree(table->private->entries);
        if (table->private->chainstack) {
@@ -1247,8 +1277,7 @@ static int update_counters(void __user *user, unsigned int len)
        if (hlp.num_counters == 0)
                return -EINVAL;
 
-       if ( !(tmp = (struct ebt_counter *)
-          vmalloc(hlp.num_counters * sizeof(struct ebt_counter))) ){
+       if (!(tmp = vmalloc(hlp.num_counters * sizeof(*tmp)))) {
                MEMPRINT("Update_counters && nomemory\n");
                return -ENOMEM;
        }
@@ -1312,7 +1341,7 @@ static inline int ebt_make_names(struct ebt_entry *e, char *base, char *ubase)
        char *hlp;
        struct ebt_entry_target *t;
 
-       if ((e->bitmask & EBT_ENTRY_OR_ENTRIES) == 0)
+       if (e->bitmask == 0)
                return 0;
 
        hlp = ubase - base + (char *)e + e->target_offset;
@@ -1377,8 +1406,7 @@ static int copy_everything_to_user(struct ebt_table *t, void __user *user,
                        BUGPRINT("Num_counters wrong\n");
                        return -EINVAL;
                }
-               counterstmp = (struct ebt_counter *)
-                  vmalloc(nentries * sizeof(struct ebt_counter));
+               counterstmp = vmalloc(nentries * sizeof(*counterstmp));
                if (!counterstmp) {
                        MEMPRINT("Couldn't copy counters, out of memory\n");
                        return -ENOMEM;
@@ -1492,7 +1520,7 @@ static int __init ebtables_init(void)
        int ret;
 
        mutex_lock(&ebt_mutex);
-       list_named_insert(&ebt_targets, &ebt_standard_target);
+       list_add(&ebt_standard_target.list, &ebt_targets);
        mutex_unlock(&ebt_mutex);
        if ((ret = nf_register_sockopt(&ebt_sockopts)) < 0)
                return ret;