* @fragoff:   packet is a fragment, this is the data offset
  * @thoff:     position of transport header relative to skb->data
  * @hotdrop:   drop packet if we had inspection problems
+ * @family:    Actual NFPROTO_* through which the function is invoked
+ *             (helpful when match->family == NFPROTO_UNSPEC)
  */
 struct xt_match_param {
        const struct net_device *in, *out;
        int fragoff;
        unsigned int thoff;
        bool *hotdrop;
+       u_int8_t family;
 };
 
 /**
        const struct xt_match *match;
        void *matchinfo;
        unsigned int hook_mask;
+       u_int8_t family;
 };
 
 /* Match destructor parameters */
 struct xt_mtdtor_param {
        const struct xt_match *match;
        void *matchinfo;
+       u_int8_t family;
 };
 
 /**
        unsigned int hooknum;
        const struct xt_target *target;
        const void *targinfo;
+       u_int8_t family;
 };
 
 /**
        const struct xt_target *target;
        void *targinfo;
        unsigned int hook_mask;
+       u_int8_t family;
 };
 
 /* Target destructor parameters */
 struct xt_tgdtor_param {
        const struct xt_target *target;
        void *targinfo;
+       u_int8_t family;
 };
 
 struct xt_match
 extern int xt_register_matches(struct xt_match *match, unsigned int n);
 extern void xt_unregister_matches(struct xt_match *match, unsigned int n);
 
-extern int xt_check_match(struct xt_mtchk_param *, u_int8_t family,
+extern int xt_check_match(struct xt_mtchk_param *,
                          unsigned int size, u_int8_t proto, bool inv_proto);
-extern int xt_check_target(struct xt_tgchk_param *, u_int8_t family,
+extern int xt_check_target(struct xt_tgchk_param *,
                           unsigned int size, u_int8_t proto, bool inv_proto);
 
 extern struct xt_table *xt_register_table(struct net *net,
 
        struct xt_match_param mtpar;
        struct xt_target_param tgpar;
 
+       mtpar.family  = tgpar.family = NFPROTO_BRIDGE;
        mtpar.in      = tgpar.in  = in;
        mtpar.out     = tgpar.out = out;
        mtpar.hotdrop = &hotdrop;
 
        par->match     = match;
        par->matchinfo = m->data;
-       ret = xt_check_match(par, NFPROTO_BRIDGE, m->match_size,
+       ret = xt_check_match(par, m->match_size,
              e->ethproto, e->invflags & EBT_IPROTO);
        if (ret < 0) {
                module_put(match->me);
 
        par->target   = watcher;
        par->targinfo = w->data;
-       ret = xt_check_target(par, NFPROTO_BRIDGE, w->watcher_size,
+       ret = xt_check_target(par, w->watcher_size,
              e->ethproto, e->invflags & EBT_IPROTO);
        if (ret < 0) {
                module_put(watcher->me);
 
        par.match     = m->u.match;
        par.matchinfo = m->data;
+       par.family    = NFPROTO_BRIDGE;
        if (par.match->destroy != NULL)
                par.match->destroy(&par);
        module_put(par.match->me);
 
        par.target   = w->u.watcher;
        par.targinfo = w->data;
+       par.family   = NFPROTO_BRIDGE;
        if (par.target->destroy != NULL)
                par.target->destroy(&par);
        module_put(par.target->me);
 
        par.target   = t->u.target;
        par.targinfo = t->data;
+       par.family   = NFPROTO_BRIDGE;
        if (par.target->destroy != NULL)
                par.target->destroy(&par);
        module_put(par.target->me);
        mtpar.table     = tgpar.table     = name;
        mtpar.entryinfo = tgpar.entryinfo = e;
        mtpar.hook_mask = tgpar.hook_mask = hookmask;
+       mtpar.family    = tgpar.family    = NFPROTO_BRIDGE;
        ret = EBT_MATCH_ITERATE(e, ebt_check_match, &mtpar, &i);
        if (ret != 0)
                goto cleanup_matches;
 
        tgpar.target   = target;
        tgpar.targinfo = t->data;
-       ret = xt_check_target(&tgpar, NFPROTO_BRIDGE, t->target_size,
+       ret = xt_check_target(&tgpar, t->target_size,
              e->ethproto, e->invflags & EBT_IPROTO);
        if (ret < 0) {
                module_put(target->me);
 
        tgpar.in      = in;
        tgpar.out     = out;
        tgpar.hooknum = hook;
+       tgpar.family  = NFPROTO_ARP;
 
        arp = arp_hdr(skb);
        do {
                .target    = t->u.kernel.target,
                .targinfo  = t->data,
                .hook_mask = e->comefrom,
+               .family    = NFPROTO_ARP,
        };
 
-       ret = xt_check_target(&par, NFPROTO_ARP,
-             t->u.target_size - sizeof(*t), 0, false);
+       ret = xt_check_target(&par, t->u.target_size - sizeof(*t), 0, false);
        if (ret < 0) {
                duprintf("arp_tables: check failed for `%s'.\n",
                         t->u.kernel.target->name);
        t = arpt_get_target(e);
        par.target   = t->u.kernel.target;
        par.targinfo = t->data;
+       par.family   = NFPROTO_ARP;
        if (par.target->destroy != NULL)
                par.target->destroy(&par);
        module_put(par.target->me);
 
        mtpar.hotdrop = &hotdrop;
        mtpar.in      = tgpar.in  = in;
        mtpar.out     = tgpar.out = out;
+       mtpar.family  = tgpar.family = NFPROTO_IPV4;
        tgpar.hooknum = hook;
 
        read_lock_bh(&table->lock);
 
        par.match     = m->u.kernel.match;
        par.matchinfo = m->data;
+       par.family    = NFPROTO_IPV4;
        if (par.match->destroy != NULL)
                par.match->destroy(&par);
        module_put(par.match->me);
        par->match     = m->u.kernel.match;
        par->matchinfo = m->data;
 
-       ret = xt_check_match(par, NFPROTO_IPV4, m->u.match_size - sizeof(*m),
+       ret = xt_check_match(par, m->u.match_size - sizeof(*m),
              ip->proto, ip->invflags & IPT_INV_PROTO);
        if (ret < 0) {
                duprintf("ip_tables: check failed for `%s'.\n",
                .target    = t->u.kernel.target,
                .targinfo  = t->data,
                .hook_mask = e->comefrom,
+               .family    = NFPROTO_IPV4,
        };
        int ret;
 
-       ret = xt_check_target(&par, NFPROTO_IPV4, t->u.target_size - sizeof(*t),
+       ret = xt_check_target(&par, t->u.target_size - sizeof(*t),
              e->ip.proto, e->ip.invflags & IPT_INV_PROTO);
        if (ret < 0) {
                duprintf("ip_tables: check failed for `%s'.\n",
        mtpar.table     = name;
        mtpar.entryinfo = &e->ip;
        mtpar.hook_mask = e->comefrom;
+       mtpar.family    = NFPROTO_IPV4;
        ret = IPT_MATCH_ITERATE(e, find_check_match, &mtpar, &j);
        if (ret != 0)
                goto cleanup_matches;
 
        par.target   = t->u.kernel.target;
        par.targinfo = t->data;
+       par.family   = NFPROTO_IPV4;
        if (par.target->destroy != NULL)
                par.target->destroy(&par);
        module_put(par.target->me);
        mtpar.table     = name;
        mtpar.entryinfo = &e->ip;
        mtpar.hook_mask = e->comefrom;
+       mtpar.family    = NFPROTO_IPV4;
        ret = IPT_MATCH_ITERATE(e, check_match, &mtpar, &j);
        if (ret)
                goto cleanup_matches;
 
        mtpar.hotdrop = &hotdrop;
        mtpar.in      = tgpar.in  = in;
        mtpar.out     = tgpar.out = out;
+       mtpar.family  = tgpar.family = NFPROTO_IPV6;
        tgpar.hooknum = hook;
 
        read_lock_bh(&table->lock);
 
        par.match     = m->u.kernel.match;
        par.matchinfo = m->data;
+       par.family    = NFPROTO_IPV6;
        if (par.match->destroy != NULL)
                par.match->destroy(&par);
        module_put(par.match->me);
        par->match     = m->u.kernel.match;
        par->matchinfo = m->data;
 
-       ret = xt_check_match(par, NFPROTO_IPV6, m->u.match_size - sizeof(*m),
+       ret = xt_check_match(par, m->u.match_size - sizeof(*m),
                             ipv6->proto, ipv6->invflags & IP6T_INV_PROTO);
        if (ret < 0) {
                duprintf("ip_tables: check failed for `%s'.\n",
                .target    = t->u.kernel.target,
                .targinfo  = t->data,
                .hook_mask = e->comefrom,
+               .family    = NFPROTO_IPV6,
        };
        int ret;
 
        t = ip6t_get_target(e);
-       ret = xt_check_target(&par, NFPROTO_IPV6, t->u.target_size - sizeof(*t),
+       ret = xt_check_target(&par, t->u.target_size - sizeof(*t),
              e->ipv6.proto, e->ipv6.invflags & IP6T_INV_PROTO);
        if (ret < 0) {
                duprintf("ip_tables: check failed for `%s'.\n",
        mtpar.table     = name;
        mtpar.entryinfo = &e->ipv6;
        mtpar.hook_mask = e->comefrom;
+       mtpar.family    = NFPROTO_IPV6;
        ret = IP6T_MATCH_ITERATE(e, find_check_match, &mtpar, &j);
        if (ret != 0)
                goto cleanup_matches;
 
        par.target   = t->u.kernel.target;
        par.targinfo = t->data;
+       par.family   = NFPROTO_IPV6;
        if (par.target->destroy != NULL)
                par.target->destroy(&par);
        module_put(par.target->me);
        mtpar.table     = name;
        mtpar.entryinfo = &e->ipv6;
        mtpar.hook_mask = e->comefrom;
+       mtpar.family    = NFPROTO_IPV6;
        ret = IP6T_MATCH_ITERATE(e, check_match, &mtpar, &j);
        if (ret)
                goto cleanup_matches;
 
 }
 EXPORT_SYMBOL_GPL(xt_find_revision);
 
-int xt_check_match(struct xt_mtchk_param *par, u_int8_t family,
+int xt_check_match(struct xt_mtchk_param *par,
                   unsigned int size, u_int8_t proto, bool inv_proto)
 {
        if (XT_ALIGN(par->match->matchsize) != size &&
                 * because it uses a dynamic-size data set.
                 */
                printk("%s_tables: %s match: invalid size %Zu != %u\n",
-                      xt_prefix[family], par->match->name,
+                      xt_prefix[par->family], par->match->name,
                       XT_ALIGN(par->match->matchsize), size);
                return -EINVAL;
        }
        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], par->match->name,
+                      xt_prefix[par->family], par->match->name,
                       par->match->table, par->table);
                return -EINVAL;
        }
        if (par->match->hooks && (par->hook_mask & ~par->match->hooks) != 0) {
                printk("%s_tables: %s match: bad hook_mask %#x/%#x\n",
-                      xt_prefix[family], par->match->name,
+                      xt_prefix[par->family], par->match->name,
                       par->hook_mask, par->match->hooks);
                return -EINVAL;
        }
        if (par->match->proto && (par->match->proto != proto || inv_proto)) {
                printk("%s_tables: %s match: only valid for protocol %u\n",
-                      xt_prefix[family], par->match->name, par->match->proto);
+                      xt_prefix[par->family], par->match->name,
+                      par->match->proto);
                return -EINVAL;
        }
        if (par->match->checkentry != NULL && !par->match->checkentry(par))
 EXPORT_SYMBOL_GPL(xt_compat_match_to_user);
 #endif /* CONFIG_COMPAT */
 
-int xt_check_target(struct xt_tgchk_param *par, u_int8_t family,
+int xt_check_target(struct xt_tgchk_param *par,
                    unsigned int size, u_int8_t proto, bool inv_proto)
 {
        if (XT_ALIGN(par->target->targetsize) != size) {
                printk("%s_tables: %s target: invalid size %Zu != %u\n",
-                      xt_prefix[family], par->target->name,
+                      xt_prefix[par->family], par->target->name,
                       XT_ALIGN(par->target->targetsize), size);
                return -EINVAL;
        }
        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], par->target->name,
+                      xt_prefix[par->family], par->target->name,
                       par->target->table, par->table);
                return -EINVAL;
        }
        if (par->target->hooks && (par->hook_mask & ~par->target->hooks) != 0) {
                printk("%s_tables: %s target: bad hook_mask %#x/%#x\n",
-                      xt_prefix[family], par->target->name, par->hook_mask,
-                      par->target->hooks);
+                      xt_prefix[par->family], par->target->name,
+                      par->hook_mask, par->target->hooks);
                return -EINVAL;
        }
        if (par->target->proto && (par->target->proto != proto || inv_proto)) {
                printk("%s_tables: %s target: only valid for protocol %u\n",
-                      xt_prefix[family], par->target->name,
+                      xt_prefix[par->family], par->target->name,
                       par->target->proto);
                return -EINVAL;
        }
 
        par.target    = target;
        par.targinfo  = t->data;
        par.hook_mask = hook;
+       par.family    = NFPROTO_IPV4;
 
-       ret = xt_check_target(&par, NFPROTO_IPV4,
-             t->u.target_size - sizeof(*t), 0, false);
+       ret = xt_check_target(&par, t->u.target_size - sizeof(*t), 0, false);
        if (ret < 0) {
                module_put(t->u.kernel.target->me);
                return ret;