x_tables.c revision 739674fb7febf116e7d647031fab16989a08a965
12e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/*
22e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * x_tables core - Backend for {ip,ip6,arp}_tables
32e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *
42e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * Copyright (C) 2006-2006 Harald Welte <laforge@netfilter.org>
52e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *
62e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * Based on existing ip_tables code which is
72e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *   Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
82e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *   Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org>
92e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *
102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * This program is free software; you can redistribute it and/or modify
112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * it under the terms of the GNU General Public License version 2 as
122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * published by the Free Software Foundation.
132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *
142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte */
152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/kernel.h>
172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/socket.h>
182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/net.h>
192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/proc_fs.h>
202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/seq_file.h>
212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/string.h>
222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/vmalloc.h>
239e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar#include <linux/mutex.h>
24d7fe0f241dceade9c8d4af75498765c5ff7f27e6Al Viro#include <linux/mm.h>
25457c4cbc5a3dde259d2a1f15d5f9785290397267Eric W. Biederman#include <net/net_namespace.h>
262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/netfilter/x_tables.h>
282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/netfilter_arp.h>
29e3eaa9910b380530cfd2c0670fcd3f627674da8aJan Engelhardt#include <linux/netfilter_ipv4/ip_tables.h>
30e3eaa9910b380530cfd2c0670fcd3f627674da8aJan Engelhardt#include <linux/netfilter_ipv6/ip6_tables.h>
31e3eaa9910b380530cfd2c0670fcd3f627674da8aJan Engelhardt#include <linux/netfilter_arp/arp_tables.h>
329e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar
332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteMODULE_LICENSE("GPL");
342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteMODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
35043ef46c7690bfdbd5b012e15812a14a19ca5604Jan EngelhardtMODULE_DESCRIPTION("{ip,ip6,arp,eb}_tables backend module");
362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
39b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardystruct compat_delta {
40b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	struct compat_delta *next;
41b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	unsigned int offset;
42b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	short delta;
43b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy};
44b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_af {
469e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	struct mutex mutex;
472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct list_head match;
482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct list_head target;
49b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy#ifdef CONFIG_COMPAT
502722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	struct mutex compat_mutex;
51b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	struct compat_delta *compat_offsets;
52b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy#endif
532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte};
542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic struct xt_af *xt;
562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef DEBUG_IP_FIREWALL_USER
582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define duprintf(format, args...) printk(format , ## args)
592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#else
602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define duprintf(format, args...)
612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif
622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
637e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardtstatic const char *const xt_prefix[NFPROTO_NUMPROTO] = {
647e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	[NFPROTO_UNSPEC] = "x",
657e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	[NFPROTO_IPV4]   = "ip",
667e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	[NFPROTO_ARP]    = "arp",
677e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	[NFPROTO_BRIDGE] = "eb",
687e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	[NFPROTO_IPV6]   = "ip6",
6937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy};
7037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy
712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Registration hooks for targets. */
722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteint
73a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_register_target(struct xt_target *target)
742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
7576108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	u_int8_t af = target->family;
7676108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	int ret;
772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
789e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	ret = mutex_lock_interruptible(&xt[af].mutex);
792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (ret != 0)
802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ret;
812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_add(&target->list, &xt[af].target);
829e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ret;
842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_register_target);
862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid
88a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_unregister_target(struct xt_target *target)
892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
9076108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	u_int8_t af = target->family;
91a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayuso
929e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_lock(&xt[af].mutex);
93df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy	list_del(&target->list);
949e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_unregister_target);
972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteint
9952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyxt_register_targets(struct xt_target *target, unsigned int n)
10052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy{
10152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	unsigned int i;
10252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	int err = 0;
10352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
10452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	for (i = 0; i < n; i++) {
10552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		err = xt_register_target(&target[i]);
10652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		if (err)
10752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy			goto err;
10852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	}
10952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	return err;
11052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
11152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyerr:
11252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	if (i > 0)
11352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		xt_unregister_targets(target, i);
11452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	return err;
11552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy}
11652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyEXPORT_SYMBOL(xt_register_targets);
11752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
11852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyvoid
11952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyxt_unregister_targets(struct xt_target *target, unsigned int n)
12052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy{
12152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	unsigned int i;
12252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
12352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	for (i = 0; i < n; i++)
12452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		xt_unregister_target(&target[i]);
12552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy}
12652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyEXPORT_SYMBOL(xt_unregister_targets);
12752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
12852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyint
129a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_register_match(struct xt_match *match)
1302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
13176108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	u_int8_t af = match->family;
13276108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	int ret;
1332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1349e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	ret = mutex_lock_interruptible(&xt[af].mutex);
1352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (ret != 0)
1362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ret;
1372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_add(&match->list, &xt[af].match);
1399e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
1402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ret;
1422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
1432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_register_match);
1442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid
146a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_unregister_match(struct xt_match *match)
1472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
14876108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	u_int8_t af = match->family;
149a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayuso
1509e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_lock(&xt[af].mutex);
151df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy	list_del(&match->list);
1529e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
1532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
1542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_unregister_match);
1552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
15652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyint
15752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyxt_register_matches(struct xt_match *match, unsigned int n)
15852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy{
15952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	unsigned int i;
16052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	int err = 0;
16152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
16252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	for (i = 0; i < n; i++) {
16352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		err = xt_register_match(&match[i]);
16452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		if (err)
16552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy			goto err;
16652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	}
16752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	return err;
16852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
16952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyerr:
17052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	if (i > 0)
17152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		xt_unregister_matches(match, i);
17252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	return err;
17352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy}
17452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyEXPORT_SYMBOL(xt_register_matches);
17552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
17652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyvoid
17752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyxt_unregister_matches(struct xt_match *match, unsigned int n)
17852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy{
17952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	unsigned int i;
18052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
18152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	for (i = 0; i < n; i++)
18252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		xt_unregister_match(&match[i]);
18352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy}
18452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyEXPORT_SYMBOL(xt_unregister_matches);
18552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
1862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/*
1882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * These are weird, but module loading must not be done with mutex
1892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * held (since they will register), and we have to have a single
1902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * function to use try_then_request_module().
1912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte */
1922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Find match, grabs ref.  Returns ERR_PTR() on error. */
19476108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstruct xt_match *xt_find_match(u8 af, const char *name, u8 revision)
1952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
1962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_match *m;
1972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int err = 0;
1982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1999e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	if (mutex_lock_interruptible(&xt[af].mutex) != 0)
2002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ERR_PTR(-EINTR);
2012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(m, &xt[af].match, list) {
2032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(m->name, name) == 0) {
2042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (m->revision == revision) {
2052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				if (try_module_get(m->me)) {
2069e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar					mutex_unlock(&xt[af].mutex);
2072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte					return m;
2082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				}
2092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			} else
2102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				err = -EPROTOTYPE; /* Found something. */
2112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
2122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
2139e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
21455b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt
21555b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt	if (af != NFPROTO_UNSPEC)
21655b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt		/* Try searching again in the family-independent list */
21755b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt		return xt_find_match(NFPROTO_UNSPEC, name, revision);
21855b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt
2192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ERR_PTR(err);
2202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
2212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_find_match);
2222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Find target, grabs ref.  Returns ERR_PTR() on error. */
22476108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstruct xt_target *xt_find_target(u8 af, const char *name, u8 revision)
2252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
2262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_target *t;
2272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int err = 0;
2282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2299e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	if (mutex_lock_interruptible(&xt[af].mutex) != 0)
2302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ERR_PTR(-EINTR);
2312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(t, &xt[af].target, list) {
2332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(t->name, name) == 0) {
2342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (t->revision == revision) {
2352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				if (try_module_get(t->me)) {
2369e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar					mutex_unlock(&xt[af].mutex);
2372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte					return t;
2382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				}
2392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			} else
2402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				err = -EPROTOTYPE; /* Found something. */
2412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
2422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
2439e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
24455b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt
24555b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt	if (af != NFPROTO_UNSPEC)
24655b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt		/* Try searching again in the family-independent list */
24755b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt		return xt_find_target(NFPROTO_UNSPEC, name, revision);
24855b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt
2492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ERR_PTR(err);
2502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
2512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_find_target);
2522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
25376108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstruct xt_target *xt_request_find_target(u8 af, const char *name, u8 revision)
2542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
2552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_target *target;
2562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	target = try_then_request_module(xt_find_target(af, name, revision),
25837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy					 "%st_%s", xt_prefix[af], name);
2592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (IS_ERR(target) || !target)
2602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
2612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return target;
2622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
2632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_request_find_target);
2642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
26576108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstatic int match_revfn(u8 af, const char *name, u8 revision, int *bestp)
2662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
2675452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt	const struct xt_match *m;
2682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int have_rev = 0;
2692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(m, &xt[af].match, list) {
2712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(m->name, name) == 0) {
2722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (m->revision > *bestp)
2732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				*bestp = m->revision;
2742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (m->revision == revision)
2752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				have_rev = 1;
2762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
2772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
278656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy
279656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy	if (af != NFPROTO_UNSPEC && !have_rev)
280656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy		return match_revfn(NFPROTO_UNSPEC, name, revision, bestp);
281656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy
2822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return have_rev;
2832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
2842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
28576108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstatic int target_revfn(u8 af, const char *name, u8 revision, int *bestp)
2862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
2875452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt	const struct xt_target *t;
2882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int have_rev = 0;
2892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(t, &xt[af].target, list) {
2912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(t->name, name) == 0) {
2922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (t->revision > *bestp)
2932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				*bestp = t->revision;
2942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (t->revision == revision)
2952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				have_rev = 1;
2962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
2972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
298656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy
299656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy	if (af != NFPROTO_UNSPEC && !have_rev)
300656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy		return target_revfn(NFPROTO_UNSPEC, name, revision, bestp);
301656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy
3022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return have_rev;
3032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
3042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Returns true or false (if no such extension at all) */
30676108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtint xt_find_revision(u8 af, const char *name, u8 revision, int target,
3072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		     int *err)
3082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
3092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int have_rev, best = -1;
3102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3119e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	if (mutex_lock_interruptible(&xt[af].mutex) != 0) {
3122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		*err = -EINTR;
3132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return 1;
3142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
3152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (target == 1)
3162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		have_rev = target_revfn(af, name, revision, &best);
3172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	else
3182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		have_rev = match_revfn(af, name, revision, &best);
3199e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
3202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Nothing at all?  Return 0 to try loading module. */
3222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (best == -1) {
3232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		*err = -ENOENT;
3242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return 0;
3252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
3262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	*err = best;
3282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!have_rev)
3292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		*err = -EPROTONOSUPPORT;
3302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return 1;
3312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
3322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_find_revision);
3332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
334451853645f3cb804b523227eca054701e4cbc589Jan Engelhardtstatic char *textify_hooks(char *buf, size_t size, unsigned int mask)
335451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt{
336451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	static const char *const names[] = {
337451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		"PREROUTING", "INPUT", "FORWARD",
338451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		"OUTPUT", "POSTROUTING", "BROUTING",
339451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	};
340451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	unsigned int i;
341451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	char *p = buf;
342451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	bool np = false;
343451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	int res;
344451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt
345451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	*p = '\0';
346451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	for (i = 0; i < ARRAY_SIZE(names); ++i) {
347451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		if (!(mask & (1 << i)))
348451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt			continue;
349451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		res = snprintf(p, size, "%s%s", np ? "/" : "", names[i]);
350451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		if (res > 0) {
351451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt			size -= res;
352451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt			p += res;
353451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		}
354451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		np = true;
355451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	}
356451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt
357451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	return buf;
358451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt}
359451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt
360916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardtint xt_check_match(struct xt_mtchk_param *par,
3619b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt		   unsigned int size, u_int8_t proto, bool inv_proto)
36237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy{
3639b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt	if (XT_ALIGN(par->match->matchsize) != size &&
3649b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt	    par->match->matchsize != -1) {
365043ef46c7690bfdbd5b012e15812a14a19ca5604Jan Engelhardt		/*
366043ef46c7690bfdbd5b012e15812a14a19ca5604Jan Engelhardt		 * ebt_among is exempt from centralized matchsize checking
367043ef46c7690bfdbd5b012e15812a14a19ca5604Jan Engelhardt		 * because it uses a dynamic-size data set.
368043ef46c7690bfdbd5b012e15812a14a19ca5604Jan Engelhardt		 */
369b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt		pr_err("%s_tables: %s.%u match: invalid size "
370b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt		       "%u (kernel) != (user) %u\n",
371916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt		       xt_prefix[par->family], par->match->name,
372b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt		       par->match->revision,
3739b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt		       XT_ALIGN(par->match->matchsize), size);
37437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
37537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
3769b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt	if (par->match->table != NULL &&
3779b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt	    strcmp(par->match->table, par->table) != 0) {
3783dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches		pr_err("%s_tables: %s match: only valid in %s table, not %s\n",
379916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt		       xt_prefix[par->family], par->match->name,
3809b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt		       par->match->table, par->table);
38137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
38237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
3839b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt	if (par->match->hooks && (par->hook_mask & ~par->match->hooks) != 0) {
384451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		char used[64], allow[64];
385451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt
3863dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches		pr_err("%s_tables: %s match: used from hooks %s, but only "
387451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		       "valid from %s\n",
388916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt		       xt_prefix[par->family], par->match->name,
389451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		       textify_hooks(used, sizeof(used), par->hook_mask),
390451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		       textify_hooks(allow, sizeof(allow), par->match->hooks));
39137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
39237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
3939b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt	if (par->match->proto && (par->match->proto != proto || inv_proto)) {
3943dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches		pr_err("%s_tables: %s match: only valid for protocol %u\n",
395916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt		       xt_prefix[par->family], par->match->name,
396916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt		       par->match->proto);
39737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
39837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
3999b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt	if (par->match->checkentry != NULL && !par->match->checkentry(par))
400367c679007fa4f990eb7ee381326ec59d8148b0eJan Engelhardt		return -EINVAL;
40137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	return 0;
40237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy}
40337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardyEXPORT_SYMBOL_GPL(xt_check_match);
40437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy
4052722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT
40676108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtint xt_compat_add_offset(u_int8_t af, unsigned int offset, short delta)
407b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy{
408b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	struct compat_delta *tmp;
409b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
410b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	tmp = kmalloc(sizeof(struct compat_delta), GFP_KERNEL);
411b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	if (!tmp)
412b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		return -ENOMEM;
413b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
414b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	tmp->offset = offset;
415b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	tmp->delta = delta;
416b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
417b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	if (xt[af].compat_offsets) {
418b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		tmp->next = xt[af].compat_offsets->next;
419b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		xt[af].compat_offsets->next = tmp;
420b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	} else {
421b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		xt[af].compat_offsets = tmp;
422b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		tmp->next = NULL;
423b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	}
424b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	return 0;
425b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy}
426b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_add_offset);
427b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
42876108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtvoid xt_compat_flush_offsets(u_int8_t af)
429b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy{
430b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	struct compat_delta *tmp, *next;
431b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
432b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	if (xt[af].compat_offsets) {
433b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		for (tmp = xt[af].compat_offsets; tmp; tmp = next) {
434b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy			next = tmp->next;
435b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy			kfree(tmp);
436b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		}
437b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		xt[af].compat_offsets = NULL;
438b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	}
439b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy}
440b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_flush_offsets);
441b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
44276108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtshort xt_compat_calc_jump(u_int8_t af, unsigned int offset)
443b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy{
444b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	struct compat_delta *tmp;
445b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	short delta;
446b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
447b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	for (tmp = xt[af].compat_offsets, delta = 0; tmp; tmp = tmp->next)
448b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		if (tmp->offset < offset)
449b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy			delta += tmp->delta;
450b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	return delta;
451b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy}
452b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_calc_jump);
453b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
4545452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardtint xt_compat_match_offset(const struct xt_match *match)
4552722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{
4569fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	u_int16_t csize = match->compatsize ? : match->matchsize;
4579fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	return XT_ALIGN(match->matchsize) - COMPAT_XT_ALIGN(csize);
4589fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy}
4599fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_match_offset);
4609fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
4618956695131b8a7878891667469899d667eb5892bPatrick McHardyint xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr,
462b0a6363c2418c93f25dd30b8ffcd3fdd4ce23ad6Patrick McHardy			      unsigned int *size)
4639fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy{
4645452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt	const struct xt_match *match = m->u.kernel.match;
4659fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	struct compat_xt_entry_match *cm = (struct compat_xt_entry_match *)m;
4669fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	int pad, off = xt_compat_match_offset(match);
4679fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	u_int16_t msize = cm->u.user.match_size;
4689fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
4699fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	m = *dstptr;
4709fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	memcpy(m, cm, sizeof(*cm));
4719fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (match->compat_from_user)
4729fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		match->compat_from_user(m->data, cm->data);
4739fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	else
4749fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		memcpy(m->data, cm->data, msize - sizeof(*cm));
4759fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	pad = XT_ALIGN(match->matchsize) - match->matchsize;
4769fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (pad > 0)
4779fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		memset(m->data + match->matchsize, 0, pad);
4789fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
4799fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	msize += off;
4809fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	m->u.user.match_size = msize;
4819fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
4829fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*size += off;
4839fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*dstptr += msize;
4848956695131b8a7878891667469899d667eb5892bPatrick McHardy	return 0;
4859fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy}
4869fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_match_from_user);
4879fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
488739674fb7febf116e7d647031fab16989a08a965Jan Engelhardtint xt_compat_match_to_user(const struct xt_entry_match *m,
489739674fb7febf116e7d647031fab16989a08a965Jan Engelhardt			    void __user **dstptr, unsigned int *size)
4909fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy{
4915452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt	const struct xt_match *match = m->u.kernel.match;
4929fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	struct compat_xt_entry_match __user *cm = *dstptr;
4939fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	int off = xt_compat_match_offset(match);
4949fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	u_int16_t msize = m->u.user.match_size - off;
4959fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
4969fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (copy_to_user(cm, m, sizeof(*cm)) ||
497a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy	    put_user(msize, &cm->u.user.match_size) ||
498a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy	    copy_to_user(cm->u.user.name, m->u.kernel.match->name,
499a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy			 strlen(m->u.kernel.match->name) + 1))
500601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki		return -EFAULT;
5019fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
5029fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (match->compat_to_user) {
5039fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		if (match->compat_to_user((void __user *)cm->data, m->data))
5049fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy			return -EFAULT;
5059fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	} else {
5069fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		if (copy_to_user(cm->data, m->data, msize - sizeof(*cm)))
5079fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy			return -EFAULT;
5082722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	}
5099fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
5109fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*size -= off;
5119fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*dstptr += msize;
5129fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	return 0;
5132722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin}
5149fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_match_to_user);
5159fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy#endif /* CONFIG_COMPAT */
5162722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin
517916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardtint xt_check_target(struct xt_tgchk_param *par,
518af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt		    unsigned int size, u_int8_t proto, bool inv_proto)
51937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy{
520af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt	if (XT_ALIGN(par->target->targetsize) != size) {
521b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt		pr_err("%s_tables: %s.%u target: invalid size "
522b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt		       "%u (kernel) != (user) %u\n",
523916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt		       xt_prefix[par->family], par->target->name,
524b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt		       par->target->revision,
525af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt		       XT_ALIGN(par->target->targetsize), size);
52637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
52737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
528af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt	if (par->target->table != NULL &&
529af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt	    strcmp(par->target->table, par->table) != 0) {
5303dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches		pr_err("%s_tables: %s target: only valid in %s table, not %s\n",
531916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt		       xt_prefix[par->family], par->target->name,
532af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt		       par->target->table, par->table);
53337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
53437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
535af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt	if (par->target->hooks && (par->hook_mask & ~par->target->hooks) != 0) {
536451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		char used[64], allow[64];
537451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt
5383dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches		pr_err("%s_tables: %s target: used from hooks %s, but only "
539451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		       "usable from %s\n",
540916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt		       xt_prefix[par->family], par->target->name,
541451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		       textify_hooks(used, sizeof(used), par->hook_mask),
542451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		       textify_hooks(allow, sizeof(allow), par->target->hooks));
54337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
54437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
545af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt	if (par->target->proto && (par->target->proto != proto || inv_proto)) {
5463dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches		pr_err("%s_tables: %s target: only valid for protocol %u\n",
547916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt		       xt_prefix[par->family], par->target->name,
548af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt		       par->target->proto);
54937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
55037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
551af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt	if (par->target->checkentry != NULL && !par->target->checkentry(par))
552367c679007fa4f990eb7ee381326ec59d8148b0eJan Engelhardt		return -EINVAL;
55337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	return 0;
55437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy}
55537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardyEXPORT_SYMBOL_GPL(xt_check_target);
55637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy
5572722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT
5585452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardtint xt_compat_target_offset(const struct xt_target *target)
5592722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{
5609fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	u_int16_t csize = target->compatsize ? : target->targetsize;
5619fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	return XT_ALIGN(target->targetsize) - COMPAT_XT_ALIGN(csize);
5629fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy}
5639fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_target_offset);
5649fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
5659fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyvoid xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr,
566b0a6363c2418c93f25dd30b8ffcd3fdd4ce23ad6Patrick McHardy				unsigned int *size)
5679fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy{
5685452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt	const struct xt_target *target = t->u.kernel.target;
5699fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	struct compat_xt_entry_target *ct = (struct compat_xt_entry_target *)t;
5709fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	int pad, off = xt_compat_target_offset(target);
5719fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	u_int16_t tsize = ct->u.user.target_size;
5729fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
5739fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	t = *dstptr;
5749fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	memcpy(t, ct, sizeof(*ct));
5759fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (target->compat_from_user)
5769fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		target->compat_from_user(t->data, ct->data);
5779fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	else
5789fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		memcpy(t->data, ct->data, tsize - sizeof(*ct));
5799fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	pad = XT_ALIGN(target->targetsize) - target->targetsize;
5809fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (pad > 0)
5819fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		memset(t->data + target->targetsize, 0, pad);
5829fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
5839fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	tsize += off;
5849fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	t->u.user.target_size = tsize;
5859fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
5869fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*size += off;
5879fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*dstptr += tsize;
5889fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy}
5899fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_target_from_user);
5909fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
591739674fb7febf116e7d647031fab16989a08a965Jan Engelhardtint xt_compat_target_to_user(const struct xt_entry_target *t,
592739674fb7febf116e7d647031fab16989a08a965Jan Engelhardt			     void __user **dstptr, unsigned int *size)
5939fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy{
5945452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt	const struct xt_target *target = t->u.kernel.target;
5959fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	struct compat_xt_entry_target __user *ct = *dstptr;
5969fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	int off = xt_compat_target_offset(target);
5979fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	u_int16_t tsize = t->u.user.target_size - off;
5989fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
5999fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (copy_to_user(ct, t, sizeof(*ct)) ||
600a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy	    put_user(tsize, &ct->u.user.target_size) ||
601a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy	    copy_to_user(ct->u.user.name, t->u.kernel.target->name,
602a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy			 strlen(t->u.kernel.target->name) + 1))
603601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki		return -EFAULT;
6049fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
6059fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (target->compat_to_user) {
6069fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		if (target->compat_to_user((void __user *)ct->data, t->data))
6079fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy			return -EFAULT;
6089fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	} else {
6099fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		if (copy_to_user(ct->data, t->data, tsize - sizeof(*ct)))
6109fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy			return -EFAULT;
6112722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	}
6129fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
6139fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*size -= off;
6149fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*dstptr += tsize;
6159fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	return 0;
6162722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin}
6179fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_target_to_user);
6182722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#endif
6192722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin
6202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_table_info *xt_alloc_table_info(unsigned int size)
6212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
6222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table_info *newinfo;
6232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int cpu;
6242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
6264481374ce88ba8f460c8b89f2572027bd27057d0Jan Beulich	if ((SMP_ALIGN(size) >> PAGE_SHIFT) + 2 > totalram_pages)
6272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
6282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
629259d4e41f3ec25f22169daece42729f597b89f9aEric Dumazet	newinfo = kzalloc(XT_TABLE_INFO_SZ, GFP_KERNEL);
6302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!newinfo)
6312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
6322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	newinfo->size = size;
6342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6356f912042256c12b0927438122594f5379b364f5dKAMEZAWA Hiroyuki	for_each_possible_cpu(cpu) {
6362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (size <= PAGE_SIZE)
6372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			newinfo->entries[cpu] = kmalloc_node(size,
6382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte							GFP_KERNEL,
6392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte							cpu_to_node(cpu));
6402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		else
6412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			newinfo->entries[cpu] = vmalloc_node(size,
6422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte							cpu_to_node(cpu));
6432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (newinfo->entries[cpu] == NULL) {
6452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			xt_free_table_info(newinfo);
6462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			return NULL;
6472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
6482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
6492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return newinfo;
6512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
6522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_alloc_table_info);
6532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid xt_free_table_info(struct xt_table_info *info)
6552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
6562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int cpu;
6572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6586f912042256c12b0927438122594f5379b364f5dKAMEZAWA Hiroyuki	for_each_possible_cpu(cpu) {
6592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (info->size <= PAGE_SIZE)
6602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			kfree(info->entries[cpu]);
6612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		else
6622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			vfree(info->entries[cpu]);
6632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
6642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	kfree(info);
6652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
6662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_free_table_info);
6672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Find table by name, grabs mutex & ref.  Returns ERR_PTR() on error. */
66976108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstruct xt_table *xt_find_table_lock(struct net *net, u_int8_t af,
67076108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt				    const char *name)
6712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
6722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table *t;
6732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6749e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	if (mutex_lock_interruptible(&xt[af].mutex) != 0)
6752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ERR_PTR(-EINTR);
6762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6778d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	list_for_each_entry(t, &net->xt.tables[af], list)
6782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(t->name, name) == 0 && try_module_get(t->me))
6792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			return t;
6809e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
6812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return NULL;
6822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
6832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_find_table_lock);
6842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid xt_table_unlock(struct xt_table *table)
6862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
6879e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[table->af].mutex);
6882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
6892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_table_unlock);
6902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6912722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT
69276108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtvoid xt_compat_lock(u_int8_t af)
6932722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{
6942722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	mutex_lock(&xt[af].compat_mutex);
6952722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin}
6962722971cbe831117686039d5c334f2c0f560be13Dmitry MishinEXPORT_SYMBOL_GPL(xt_compat_lock);
6972722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin
69876108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtvoid xt_compat_unlock(u_int8_t af)
6992722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{
7002722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	mutex_unlock(&xt[af].compat_mutex);
7012722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin}
7022722971cbe831117686039d5c334f2c0f560be13Dmitry MishinEXPORT_SYMBOL_GPL(xt_compat_unlock);
7032722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#endif
7042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
705942e4a2bd680c606af0211e64eb216be2e19bf61Stephen HemmingerDEFINE_PER_CPU(struct xt_info_lock, xt_info_locks);
706942e4a2bd680c606af0211e64eb216be2e19bf61Stephen HemmingerEXPORT_PER_CPU_SYMBOL_GPL(xt_info_locks);
707942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger
708942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger
7092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_table_info *
7102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltext_replace_table(struct xt_table *table,
7112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	      unsigned int num_counters,
7122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	      struct xt_table_info *newinfo,
7132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	      int *error)
7142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
715942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	struct xt_table_info *private;
7162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Do the substitution. */
718942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	local_bh_disable();
7192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	private = table->private;
720942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger
7212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Check inside lock: is the old number correct? */
7222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (num_counters != private->number) {
7232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		duprintf("num_counters != table->private->number (%u/%u)\n",
7242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			 num_counters, private->number);
725942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger		local_bh_enable();
7262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		*error = -EAGAIN;
7272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
7282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
7292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
730942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	table->private = newinfo;
731942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	newinfo->initial_entries = private->initial_entries;
732942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger
733942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	/*
734942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	 * Even though table entries have now been swapped, other CPU's
735942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	 * may still be using the old entries. This is okay, because
736942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	 * resynchronization happens because of the locking done
737942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	 * during the get_counters() routine.
738942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	 */
739942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	local_bh_enable();
740942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger
741942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	return private;
7422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
7432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_replace_table);
7442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
74535aad0ffdf548617940ca1e78be1f2e0bafc4496Jan Engelhardtstruct xt_table *xt_register_table(struct net *net,
74635aad0ffdf548617940ca1e78be1f2e0bafc4496Jan Engelhardt				   const struct xt_table *input_table,
747a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan				   struct xt_table_info *bootstrap,
748a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan				   struct xt_table_info *newinfo)
7492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
7502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int ret;
7512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table_info *private;
75235aad0ffdf548617940ca1e78be1f2e0bafc4496Jan Engelhardt	struct xt_table *t, *table;
7532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
75444d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan	/* Don't add one object to multiple lists. */
75535aad0ffdf548617940ca1e78be1f2e0bafc4496Jan Engelhardt	table = kmemdup(input_table, sizeof(struct xt_table), GFP_KERNEL);
75644d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan	if (!table) {
75744d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan		ret = -ENOMEM;
75844d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan		goto out;
75944d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan	}
76044d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan
7619e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	ret = mutex_lock_interruptible(&xt[table->af].mutex);
7622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (ret != 0)
76344d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan		goto out_free;
7642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Don't autoload: we'd eat our tail... */
7668d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	list_for_each_entry(t, &net->xt.tables[table->af], list) {
767df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy		if (strcmp(t->name, table->name) == 0) {
768df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy			ret = -EEXIST;
769df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy			goto unlock;
770df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy		}
7712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
7722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Simplifies replace_table code. */
7742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	table->private = bootstrap;
775784544739a25c30637397ace5489eeb6e15d7d49Stephen Hemminger
7762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!xt_replace_table(table, 0, newinfo, &ret))
7772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto unlock;
7782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	private = table->private;
7802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	duprintf("table->private->number = %u\n", private->number);
7812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* save number of initial entries */
7832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	private->initial_entries = private->number;
7842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7858d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	list_add(&table->list, &net->xt.tables[table->af]);
786a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan	mutex_unlock(&xt[table->af].mutex);
787a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan	return table;
7882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte unlock:
7909e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[table->af].mutex);
79144d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyanout_free:
79244d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan	kfree(table);
793a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyanout:
794a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan	return ERR_PTR(ret);
7952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
7962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_register_table);
7972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid *xt_unregister_table(struct xt_table *table)
7992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
8002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table_info *private;
8012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8029e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_lock(&xt[table->af].mutex);
8032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	private = table->private;
804df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy	list_del(&table->list);
8059e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[table->af].mutex);
80644d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan	kfree(table);
8072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return private;
8092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
8102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_unregister_table);
8112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
813715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyanstruct xt_names_priv {
814715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	struct seq_net_private p;
81576108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	u_int8_t af;
816715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan};
817025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void *xt_table_seq_start(struct seq_file *seq, loff_t *pos)
8182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
819715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	struct xt_names_priv *priv = seq->private;
8201218854afa6f659be90b748cf1bc7badee954a35YOSHIFUJI Hideaki	struct net *net = seq_file_net(seq);
82176108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	u_int8_t af = priv->af;
8222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
823025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	mutex_lock(&xt[af].mutex);
824715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	return seq_list_start(&net->xt.tables[af], *pos);
825025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
8262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
827025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void *xt_table_seq_next(struct seq_file *seq, void *v, loff_t *pos)
828025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
829715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	struct xt_names_priv *priv = seq->private;
8301218854afa6f659be90b748cf1bc7badee954a35YOSHIFUJI Hideaki	struct net *net = seq_file_net(seq);
83176108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	u_int8_t af = priv->af;
8322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
833715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	return seq_list_next(v, &net->xt.tables[af], pos);
8342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
8352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
836025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void xt_table_seq_stop(struct seq_file *seq, void *v)
8372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
838715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	struct xt_names_priv *priv = seq->private;
83976108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	u_int8_t af = priv->af;
8402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
841025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	mutex_unlock(&xt[af].mutex);
842025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
8432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
844025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_table_seq_show(struct seq_file *seq, void *v)
845025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
846025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	struct xt_table *table = list_entry(v, struct xt_table, list);
8472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
848025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	if (strlen(table->name))
849025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan		return seq_printf(seq, "%s\n", table->name);
850025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	else
851025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan		return 0;
852025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
853601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki
854025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct seq_operations xt_table_seq_ops = {
855025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.start	= xt_table_seq_start,
856025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.next	= xt_table_seq_next,
857025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.stop	= xt_table_seq_stop,
858025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.show	= xt_table_seq_show,
859025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan};
860025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
861025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_table_open(struct inode *inode, struct file *file)
862025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
863025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	int ret;
864715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	struct xt_names_priv *priv;
865025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
866715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	ret = seq_open_net(inode, file, &xt_table_seq_ops,
867715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan			   sizeof(struct xt_names_priv));
868025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	if (!ret) {
869715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan		priv = ((struct seq_file *)file->private_data)->private;
870715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan		priv->af = (unsigned long)PDE(inode)->data;
871025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	}
872025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	return ret;
8732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
8742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
875025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct file_operations xt_table_ops = {
876025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.owner	 = THIS_MODULE,
877025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.open	 = xt_table_open,
878025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.read	 = seq_read,
879025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.llseek	 = seq_lseek,
8800e93bb9459f56b50a2f71f2c230f4ad00ec40a73Pavel Emelyanov	.release = seq_release_net,
881025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan};
882025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
883eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt/*
884eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt * Traverse state for ip{,6}_{tables,matches} for helping crossing
885eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt * the multi-AF mutexes.
886eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt */
887eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstruct nf_mttg_trav {
888eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	struct list_head *head, *curr;
889eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	uint8_t class, nfproto;
890eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt};
891eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt
892eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtenum {
893eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	MTTG_TRAV_INIT,
894eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	MTTG_TRAV_NFP_UNSPEC,
895eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	MTTG_TRAV_NFP_SPEC,
896eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	MTTG_TRAV_DONE,
897eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt};
898eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt
899eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void *xt_mttg_seq_next(struct seq_file *seq, void *v, loff_t *ppos,
900eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt    bool is_target)
9012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
902eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	static const uint8_t next_class[] = {
903eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		[MTTG_TRAV_NFP_UNSPEC] = MTTG_TRAV_NFP_SPEC,
904eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		[MTTG_TRAV_NFP_SPEC]   = MTTG_TRAV_DONE,
905eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	};
906eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	struct nf_mttg_trav *trav = seq->private;
907eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt
908eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	switch (trav->class) {
909eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	case MTTG_TRAV_INIT:
910eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		trav->class = MTTG_TRAV_NFP_UNSPEC;
911eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		mutex_lock(&xt[NFPROTO_UNSPEC].mutex);
912eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		trav->head = trav->curr = is_target ?
913eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt			&xt[NFPROTO_UNSPEC].target : &xt[NFPROTO_UNSPEC].match;
914eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt 		break;
915eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	case MTTG_TRAV_NFP_UNSPEC:
916eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		trav->curr = trav->curr->next;
917eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		if (trav->curr != trav->head)
918eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt			break;
919eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		mutex_unlock(&xt[NFPROTO_UNSPEC].mutex);
920eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		mutex_lock(&xt[trav->nfproto].mutex);
921eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		trav->head = trav->curr = is_target ?
922eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt			&xt[trav->nfproto].target : &xt[trav->nfproto].match;
923eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		trav->class = next_class[trav->class];
924eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		break;
925eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	case MTTG_TRAV_NFP_SPEC:
926eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		trav->curr = trav->curr->next;
927eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		if (trav->curr != trav->head)
928eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt			break;
929eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		/* fallthru, _stop will unlock */
930eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	default:
931eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		return NULL;
932eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	}
9332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
934eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	if (ppos != NULL)
935eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		++*ppos;
936eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return trav;
937025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
938601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki
939eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void *xt_mttg_seq_start(struct seq_file *seq, loff_t *pos,
940eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt    bool is_target)
941025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
942eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	struct nf_mttg_trav *trav = seq->private;
943eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	unsigned int j;
9442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
945eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	trav->class = MTTG_TRAV_INIT;
946eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	for (j = 0; j < *pos; ++j)
947eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		if (xt_mttg_seq_next(seq, NULL, NULL, is_target) == NULL)
948eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt			return NULL;
949eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return trav;
9502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
9512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
952eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void xt_mttg_seq_stop(struct seq_file *seq, void *v)
9532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
954eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	struct nf_mttg_trav *trav = seq->private;
955eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt
956eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	switch (trav->class) {
957eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	case MTTG_TRAV_NFP_UNSPEC:
958eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		mutex_unlock(&xt[NFPROTO_UNSPEC].mutex);
959eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		break;
960eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	case MTTG_TRAV_NFP_SPEC:
961eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		mutex_unlock(&xt[trav->nfproto].mutex);
962eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		break;
963eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	}
964eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt}
9652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
966eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void *xt_match_seq_start(struct seq_file *seq, loff_t *pos)
967eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt{
968eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return xt_mttg_seq_start(seq, pos, false);
9692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
9702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
971eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void *xt_match_seq_next(struct seq_file *seq, void *v, loff_t *ppos)
9722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
973eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return xt_mttg_seq_next(seq, v, ppos, false);
974eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt}
9752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
976eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic int xt_match_seq_show(struct seq_file *seq, void *v)
977eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt{
978eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	const struct nf_mttg_trav *trav = seq->private;
979eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	const struct xt_match *match;
980eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt
981eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	switch (trav->class) {
982eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	case MTTG_TRAV_NFP_UNSPEC:
983eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	case MTTG_TRAV_NFP_SPEC:
984eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		if (trav->curr == trav->head)
985eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt			return 0;
986eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		match = list_entry(trav->curr, struct xt_match, list);
987eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		return (*match->name == '\0') ? 0 :
988eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		       seq_printf(seq, "%s\n", match->name);
989eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	}
990eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return 0;
9912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
9922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
993025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct seq_operations xt_match_seq_ops = {
994025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.start	= xt_match_seq_start,
995025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.next	= xt_match_seq_next,
996eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	.stop	= xt_mttg_seq_stop,
997025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.show	= xt_match_seq_show,
9982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte};
9992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1000025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_match_open(struct inode *inode, struct file *file)
10012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
1002eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	struct seq_file *seq;
1003eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	struct nf_mttg_trav *trav;
10042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int ret;
10052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1006eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	trav = kmalloc(sizeof(*trav), GFP_KERNEL);
1007eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	if (trav == NULL)
1008eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		return -ENOMEM;
10092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1010eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	ret = seq_open(file, &xt_match_seq_ops);
1011eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	if (ret < 0) {
1012eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		kfree(trav);
1013eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		return ret;
10142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
1015eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt
1016eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	seq = file->private_data;
1017eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	seq->private = trav;
1018eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	trav->nfproto = (unsigned long)PDE(inode)->data;
1019eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return 0;
1020025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
1021025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
1022025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct file_operations xt_match_ops = {
1023025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.owner	 = THIS_MODULE,
1024025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.open	 = xt_match_open,
1025025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.read	 = seq_read,
1026025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.llseek	 = seq_lseek,
1027eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	.release = seq_release_private,
1028025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan};
10292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1030025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void *xt_target_seq_start(struct seq_file *seq, loff_t *pos)
1031025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
1032eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return xt_mttg_seq_start(seq, pos, true);
1033025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
1034025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
1035eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void *xt_target_seq_next(struct seq_file *seq, void *v, loff_t *ppos)
1036025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
1037eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return xt_mttg_seq_next(seq, v, ppos, true);
1038025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
1039025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
1040025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_target_seq_show(struct seq_file *seq, void *v)
1041025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
1042eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	const struct nf_mttg_trav *trav = seq->private;
1043eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	const struct xt_target *target;
1044eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt
1045eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	switch (trav->class) {
1046eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	case MTTG_TRAV_NFP_UNSPEC:
1047eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	case MTTG_TRAV_NFP_SPEC:
1048eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		if (trav->curr == trav->head)
1049eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt			return 0;
1050eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		target = list_entry(trav->curr, struct xt_target, list);
1051eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		return (*target->name == '\0') ? 0 :
1052eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		       seq_printf(seq, "%s\n", target->name);
1053eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	}
1054eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return 0;
1055025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
1056025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
1057025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct seq_operations xt_target_seq_ops = {
1058025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.start	= xt_target_seq_start,
1059025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.next	= xt_target_seq_next,
1060eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	.stop	= xt_mttg_seq_stop,
1061025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.show	= xt_target_seq_show,
1062025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan};
1063025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
1064025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_target_open(struct inode *inode, struct file *file)
1065025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
1066eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	struct seq_file *seq;
1067eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	struct nf_mttg_trav *trav;
1068025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	int ret;
1069025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
1070eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	trav = kmalloc(sizeof(*trav), GFP_KERNEL);
1071eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	if (trav == NULL)
1072eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		return -ENOMEM;
1073025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
1074eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	ret = seq_open(file, &xt_target_seq_ops);
1075eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	if (ret < 0) {
1076eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		kfree(trav);
1077eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		return ret;
1078025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	}
1079eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt
1080eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	seq = file->private_data;
1081eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	seq->private = trav;
1082eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	trav->nfproto = (unsigned long)PDE(inode)->data;
1083eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return 0;
10842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
10852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1086025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct file_operations xt_target_ops = {
10872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.owner	 = THIS_MODULE,
1088025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.open	 = xt_target_open,
10892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.read	 = seq_read,
10902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.llseek	 = seq_lseek,
1091eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	.release = seq_release_private,
10922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte};
10932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
10942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define FORMAT_TABLES	"_tables_names"
10952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define	FORMAT_MATCHES	"_tables_matches"
10962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define FORMAT_TARGETS 	"_tables_targets"
10972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
10982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif /* CONFIG_PROC_FS */
10992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
11002b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt/**
11012b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * xt_hook_link - set up hooks for a new table
11022b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * @table:	table with metadata needed to set up hooks
11032b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * @fn:		Hook function
11042b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt *
11052b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * This function will take care of creating and registering the necessary
11062b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * Netfilter hooks for XT tables.
11072b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt */
11082b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardtstruct nf_hook_ops *xt_hook_link(const struct xt_table *table, nf_hookfn *fn)
11092b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt{
11102b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	unsigned int hook_mask = table->valid_hooks;
11112b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	uint8_t i, num_hooks = hweight32(hook_mask);
11122b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	uint8_t hooknum;
11132b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	struct nf_hook_ops *ops;
11142b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	int ret;
11152b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt
11162b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	ops = kmalloc(sizeof(*ops) * num_hooks, GFP_KERNEL);
11172b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	if (ops == NULL)
11182b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		return ERR_PTR(-ENOMEM);
11192b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt
11202b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	for (i = 0, hooknum = 0; i < num_hooks && hook_mask != 0;
11212b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	     hook_mask >>= 1, ++hooknum) {
11222b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		if (!(hook_mask & 1))
11232b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt			continue;
11242b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		ops[i].hook     = fn;
11252b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		ops[i].owner    = table->me;
11262b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		ops[i].pf       = table->af;
11272b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		ops[i].hooknum  = hooknum;
11282b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		ops[i].priority = table->priority;
11292b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		++i;
11302b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	}
11312b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt
11322b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	ret = nf_register_hooks(ops, num_hooks);
11332b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	if (ret < 0) {
11342b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		kfree(ops);
11352b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		return ERR_PTR(ret);
11362b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	}
11372b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt
11382b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	return ops;
11392b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt}
11402b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan EngelhardtEXPORT_SYMBOL_GPL(xt_hook_link);
11412b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt
11422b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt/**
11432b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * xt_hook_unlink - remove hooks for a table
11442b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * @ops:	nf_hook_ops array as returned by nf_hook_link
11452b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * @hook_mask:	the very same mask that was passed to nf_hook_link
11462b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt */
11472b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardtvoid xt_hook_unlink(const struct xt_table *table, struct nf_hook_ops *ops)
11482b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt{
11492b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	nf_unregister_hooks(ops, hweight32(table->valid_hooks));
11502b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	kfree(ops);
11512b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt}
11522b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan EngelhardtEXPORT_SYMBOL_GPL(xt_hook_unlink);
11532b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt
115476108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtint xt_proto_init(struct net *net, u_int8_t af)
11552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
11562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
11572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	char buf[XT_FUNCTION_MAXNAMELEN];
11582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct proc_dir_entry *proc;
11592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif
11602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
11617e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	if (af >= ARRAY_SIZE(xt_prefix))
11622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return -EINVAL;
11632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
11642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
11652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
1166ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
11672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TABLES, sizeof(buf));
11688b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev	proc = proc_create_data(buf, 0440, net->proc_net, &xt_table_ops,
11698b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev				(void *)(unsigned long)af);
11702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!proc)
11712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto out;
11722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1173ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
11742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
11758b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev	proc = proc_create_data(buf, 0440, net->proc_net, &xt_match_ops,
11768b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev				(void *)(unsigned long)af);
11772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!proc)
11782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto out_remove_tables;
11792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1180ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
11812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TARGETS, sizeof(buf));
11828b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev	proc = proc_create_data(buf, 0440, net->proc_net, &xt_target_ops,
11838b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev				(void *)(unsigned long)af);
11842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!proc)
11852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto out_remove_matches;
11862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif
11872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
11882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return 0;
11892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
11902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
11912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteout_remove_matches:
1192ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
11932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
11943cb609d57c20027a8b39fc60b79b930a89da82d4Alexey Dobriyan	proc_net_remove(net, buf);
11952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
11962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteout_remove_tables:
1197ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
11982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TABLES, sizeof(buf));
11993cb609d57c20027a8b39fc60b79b930a89da82d4Alexey Dobriyan	proc_net_remove(net, buf);
12002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteout:
12012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return -1;
12022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif
12032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
12042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_proto_init);
12052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
120676108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtvoid xt_proto_fini(struct net *net, u_int8_t af)
12072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
12082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
12092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	char buf[XT_FUNCTION_MAXNAMELEN];
12102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1211ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
12122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TABLES, sizeof(buf));
12133cb609d57c20027a8b39fc60b79b930a89da82d4Alexey Dobriyan	proc_net_remove(net, buf);
12142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1215ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
12162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TARGETS, sizeof(buf));
12173cb609d57c20027a8b39fc60b79b930a89da82d4Alexey Dobriyan	proc_net_remove(net, buf);
12182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1219ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
12202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
12213cb609d57c20027a8b39fc60b79b930a89da82d4Alexey Dobriyan	proc_net_remove(net, buf);
12222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif /*CONFIG_PROC_FS*/
12232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
12242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_proto_fini);
12252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
12268d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyanstatic int __net_init xt_net_init(struct net *net)
12278d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan{
12288d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	int i;
12298d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan
12307e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	for (i = 0; i < NFPROTO_NUMPROTO; i++)
12318d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan		INIT_LIST_HEAD(&net->xt.tables[i]);
12328d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	return 0;
12338d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan}
12348d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan
12358d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyanstatic struct pernet_operations xt_net_ops = {
12368d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	.init = xt_net_init,
12378d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan};
12382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
12392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic int __init xt_init(void)
12402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
1241942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	unsigned int i;
1242942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	int rv;
1243942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger
1244942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	for_each_possible_cpu(i) {
1245942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger		struct xt_info_lock *lock = &per_cpu(xt_info_locks, i);
1246942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger		spin_lock_init(&lock->lock);
1247942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger		lock->readers = 0;
1248942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	}
12492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
12507e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	xt = kmalloc(sizeof(struct xt_af) * NFPROTO_NUMPROTO, GFP_KERNEL);
12512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!xt)
12522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return -ENOMEM;
12532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
12547e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	for (i = 0; i < NFPROTO_NUMPROTO; i++) {
12559e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar		mutex_init(&xt[i].mutex);
12562722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT
12572722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin		mutex_init(&xt[i].compat_mutex);
1258b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		xt[i].compat_offsets = NULL;
12592722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#endif
12602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		INIT_LIST_HEAD(&xt[i].target);
12612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		INIT_LIST_HEAD(&xt[i].match);
12622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
12638d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	rv = register_pernet_subsys(&xt_net_ops);
12648d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	if (rv < 0)
12658d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan		kfree(xt);
12668d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	return rv;
12672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
12682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
12692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic void __exit xt_fini(void)
12702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
12718d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	unregister_pernet_subsys(&xt_net_ops);
12722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	kfree(xt);
12732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
12742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
12752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltemodule_init(xt_init);
12762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltemodule_exit(xt_fini);
12772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1278