Merge branch 'topic/hda' into for-linus
[safe/jmp/linux-2.6] / net / netfilter / x_tables.c
index 2a7eb1d..bfbf521 100644 (file)
@@ -30,7 +30,7 @@
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
-MODULE_DESCRIPTION("[ip,ip6,arp]_tables backend module");
+MODULE_DESCRIPTION("{ip,ip6,arp,eb}_tables backend module");
 
 #define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
 
@@ -209,6 +209,11 @@ struct xt_match *xt_find_match(u8 af, const char *name, u8 revision)
                }
        }
        mutex_unlock(&xt[af].mutex);
+
+       if (af != NFPROTO_UNSPEC)
+               /* Try searching again in the family-independent list */
+               return xt_find_match(NFPROTO_UNSPEC, name, revision);
+
        return ERR_PTR(err);
 }
 EXPORT_SYMBOL(xt_find_match);
@@ -234,6 +239,11 @@ struct xt_target *xt_find_target(u8 af, const char *name, u8 revision)
                }
        }
        mutex_unlock(&xt[af].mutex);
+
+       if (af != NFPROTO_UNSPEC)
+               /* Try searching again in the family-independent list */
+               return xt_find_target(NFPROTO_UNSPEC, name, revision);
+
        return ERR_PTR(err);
 }
 EXPORT_SYMBOL(xt_find_target);
@@ -263,6 +273,10 @@ static int match_revfn(u8 af, const char *name, u8 revision, int *bestp)
                                have_rev = 1;
                }
        }
+
+       if (af != NFPROTO_UNSPEC && !have_rev)
+               return match_revfn(NFPROTO_UNSPEC, name, revision, bestp);
+
        return have_rev;
 }
 
@@ -279,6 +293,10 @@ static int target_revfn(u8 af, const char *name, u8 revision, int *bestp)
                                have_rev = 1;
                }
        }
+
+       if (af != NFPROTO_UNSPEC && !have_rev)
+               return target_revfn(NFPROTO_UNSPEC, name, revision, bestp);
+
        return have_rev;
 }
 
@@ -311,31 +329,41 @@ int xt_find_revision(u8 af, const char *name, u8 revision, int target,
 }
 EXPORT_SYMBOL_GPL(xt_find_revision);
 
-int xt_check_match(const struct xt_match *match, unsigned short family,
-                  unsigned int size, const char *table, unsigned int hook_mask,
-                  unsigned short proto, int inv_proto)
+int xt_check_match(struct xt_mtchk_param *par,
+                  unsigned int size, u_int8_t proto, bool inv_proto)
 {
-       if (XT_ALIGN(match->matchsize) != size) {
+       if (XT_ALIGN(par->match->matchsize) != size &&
+           par->match->matchsize != -1) {
+               /*
+                * ebt_among is exempt from centralized matchsize checking
+                * because it uses a dynamic-size data set.
+                */
                printk("%s_tables: %s match: invalid size %Zu != %u\n",
-                      xt_prefix[family], match->name,
-                      XT_ALIGN(match->matchsize), size);
+                      xt_prefix[par->family], par->match->name,
+                      XT_ALIGN(par->match->matchsize), size);
                return -EINVAL;
        }
-       if (match->table && strcmp(match->table, table)) {
+       if (par->match->table != NULL &&
+           strcmp(par->match->table, par->table) != 0) {
                printk("%s_tables: %s match: only valid in %s table, not %s\n",
-                      xt_prefix[family], match->name, match->table, table);
+                      xt_prefix[par->family], par->match->name,
+                      par->match->table, par->table);
                return -EINVAL;
        }
-       if (match->hooks && (hook_mask & ~match->hooks) != 0) {
-               printk("%s_tables: %s match: bad hook_mask %u/%u\n",
-                      xt_prefix[family], match->name, hook_mask, match->hooks);
+       if (par->match->hooks && (par->hook_mask & ~par->match->hooks) != 0) {
+               printk("%s_tables: %s match: bad hook_mask %#x/%#x\n",
+                      xt_prefix[par->family], par->match->name,
+                      par->hook_mask, par->match->hooks);
                return -EINVAL;
        }
-       if (match->proto && (match->proto != proto || inv_proto)) {
+       if (par->match->proto && (par->match->proto != proto || inv_proto)) {
                printk("%s_tables: %s match: only valid for protocol %u\n",
-                      xt_prefix[family], match->name, match->proto);
+                      xt_prefix[par->family], par->match->name,
+                      par->match->proto);
                return -EINVAL;
        }
+       if (par->match->checkentry != NULL && !par->match->checkentry(par))
+               return -EINVAL;
        return 0;
 }
 EXPORT_SYMBOL_GPL(xt_check_match);
@@ -452,32 +480,36 @@ int xt_compat_match_to_user(struct xt_entry_match *m, void __user **dstptr,
 EXPORT_SYMBOL_GPL(xt_compat_match_to_user);
 #endif /* CONFIG_COMPAT */
 
-int xt_check_target(const struct xt_target *target, unsigned short family,
-                   unsigned int size, const char *table, unsigned int hook_mask,
-                   unsigned short proto, int inv_proto)
+int xt_check_target(struct xt_tgchk_param *par,
+                   unsigned int size, u_int8_t proto, bool inv_proto)
 {
-       if (XT_ALIGN(target->targetsize) != size) {
+       if (XT_ALIGN(par->target->targetsize) != size) {
                printk("%s_tables: %s target: invalid size %Zu != %u\n",
-                      xt_prefix[family], target->name,
-                      XT_ALIGN(target->targetsize), size);
+                      xt_prefix[par->family], par->target->name,
+                      XT_ALIGN(par->target->targetsize), size);
                return -EINVAL;
        }
-       if (target->table && strcmp(target->table, table)) {
+       if (par->target->table != NULL &&
+           strcmp(par->target->table, par->table) != 0) {
                printk("%s_tables: %s target: only valid in %s table, not %s\n",
-                      xt_prefix[family], target->name, target->table, table);
+                      xt_prefix[par->family], par->target->name,
+                      par->target->table, par->table);
                return -EINVAL;
        }
-       if (target->hooks && (hook_mask & ~target->hooks) != 0) {
-               printk("%s_tables: %s target: bad hook_mask %u/%u\n",
-                      xt_prefix[family], target->name, hook_mask,
-                      target->hooks);
+       if (par->target->hooks && (par->hook_mask & ~par->target->hooks) != 0) {
+               printk("%s_tables: %s target: bad hook_mask %#x/%#x\n",
+                      xt_prefix[par->family], par->target->name,
+                      par->hook_mask, par->target->hooks);
                return -EINVAL;
        }
-       if (target->proto && (target->proto != proto || inv_proto)) {
+       if (par->target->proto && (par->target->proto != proto || inv_proto)) {
                printk("%s_tables: %s target: only valid for protocol %u\n",
-                      xt_prefix[family], target->name, target->proto);
+                      xt_prefix[par->family], par->target->name,
+                      par->target->proto);
                return -EINVAL;
        }
+       if (par->target->checkentry != NULL && !par->target->checkentry(par))
+               return -EINVAL;
        return 0;
 }
 EXPORT_SYMBOL_GPL(xt_check_target);