netfilter: ip6tables regression fix
[sfrench/cifs-2.6.git] / net / ipv6 / netfilter / ip6_tables.c
index 34af7bb8df5f8d6a3821288f0243f0b591bf3658..800ae854247163f8890ea244060835eccc5f0a99 100644 (file)
@@ -89,25 +89,6 @@ ip6t_ext_hdr(u8 nexthdr)
                 (nexthdr == IPPROTO_DSTOPTS) );
 }
 
-static unsigned long ifname_compare(const char *_a, const char *_b,
-                                   const unsigned char *_mask)
-{
-       const unsigned long *a = (const unsigned long *)_a;
-       const unsigned long *b = (const unsigned long *)_b;
-       const unsigned long *mask = (const unsigned long *)_mask;
-       unsigned long ret;
-
-       ret = (a[0] ^ b[0]) & mask[0];
-       if (IFNAMSIZ > sizeof(unsigned long))
-               ret |= (a[1] ^ b[1]) & mask[1];
-       if (IFNAMSIZ > 2 * sizeof(unsigned long))
-               ret |= (a[2] ^ b[2]) & mask[2];
-       if (IFNAMSIZ > 3 * sizeof(unsigned long))
-               ret |= (a[3] ^ b[3]) & mask[3];
-       BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long));
-       return ret;
-}
-
 /* Returns whether matches rule or not. */
 /* Performance critical - called for every packet */
 static inline bool
@@ -138,7 +119,7 @@ ip6_packet_match(const struct sk_buff *skb,
                return false;
        }
 
-       ret = ifname_compare(indev, ip6info->iniface, ip6info->iniface_mask);
+       ret = ifname_compare_aligned(indev, ip6info->iniface, ip6info->iniface_mask);
 
        if (FWINV(ret != 0, IP6T_INV_VIA_IN)) {
                dprintf("VIA in mismatch (%s vs %s).%s\n",
@@ -147,7 +128,7 @@ ip6_packet_match(const struct sk_buff *skb,
                return false;
        }
 
-       ret = ifname_compare(outdev, ip6info->outiface, ip6info->outiface_mask);
+       ret = ifname_compare_aligned(outdev, ip6info->outiface, ip6info->outiface_mask);
 
        if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
                dprintf("VIA out mismatch (%s vs %s).%s\n",
@@ -384,7 +365,7 @@ ip6t_do_table(struct sk_buff *skb,
 
        IP_NF_ASSERT(table->valid_hooks & (1 << hook));
 
-       rcu_read_lock();
+       rcu_read_lock_bh();
        private = rcu_dereference(table->private);
        table_base = rcu_dereference(private->entries[smp_processor_id()]);
 
@@ -485,7 +466,7 @@ ip6t_do_table(struct sk_buff *skb,
 #ifdef CONFIG_NETFILTER_DEBUG
        ((struct ip6t_entry *)table_base)->comefrom = NETFILTER_LINK_POISON;
 #endif
-       rcu_read_unlock();
+       rcu_read_unlock_bh();
 
 #ifdef DEBUG_ALLOW_ALL
        return NF_ACCEPT;
@@ -536,7 +517,9 @@ mark_source_chains(struct xt_table_info *newinfo,
                            && unconditional(&e->ipv6)) || visited) {
                                unsigned int oldpos, size;
 
-                               if (t->verdict < -NF_MAX_VERDICT - 1) {
+                               if ((strcmp(t->target.u.user.name,
+                                           IP6T_STANDARD_TARGET) == 0) &&
+                                   t->verdict < -NF_MAX_VERDICT - 1) {
                                        duprintf("mark_source_chains: bad "
                                                "negative verdict (%i)\n",
                                                                t->verdict);
@@ -1050,6 +1033,8 @@ static struct xt_counters *alloc_counters(struct xt_table *table)
 
        xt_free_table_info(info);
 
+       return counters;
+
  free_counters:
        vfree(counters);
  nomem: