x_tables.c revision be91fd5e323b46450ca82f6828e933e3791fb2f2
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 */
15be91fd5e323b46450ca82f6828e933e3791fb2f2Jan Engelhardt#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
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;
423e5e524ffb5fcf2447eb5dd9f8e54ad22dd9baa7Florian Westphal	int 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
577e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardtstatic const char *const xt_prefix[NFPROTO_NUMPROTO] = {
587e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	[NFPROTO_UNSPEC] = "x",
597e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	[NFPROTO_IPV4]   = "ip",
607e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	[NFPROTO_ARP]    = "arp",
617e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	[NFPROTO_BRIDGE] = "eb",
627e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	[NFPROTO_IPV6]   = "ip6",
6337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy};
6437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy
652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Registration hooks for targets. */
662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteint
67a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_register_target(struct xt_target *target)
682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
6976108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	u_int8_t af = target->family;
7076108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	int ret;
712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
729e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	ret = mutex_lock_interruptible(&xt[af].mutex);
732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (ret != 0)
742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ret;
752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_add(&target->list, &xt[af].target);
769e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ret;
782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_register_target);
802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid
82a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_unregister_target(struct xt_target *target)
832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
8476108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	u_int8_t af = target->family;
85a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayuso
869e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_lock(&xt[af].mutex);
87df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy	list_del(&target->list);
889e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_unregister_target);
912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteint
9352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyxt_register_targets(struct xt_target *target, unsigned int n)
9452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy{
9552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	unsigned int i;
9652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	int err = 0;
9752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
9852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	for (i = 0; i < n; i++) {
9952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		err = xt_register_target(&target[i]);
10052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		if (err)
10152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy			goto err;
10252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	}
10352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	return err;
10452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
10552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyerr:
10652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	if (i > 0)
10752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		xt_unregister_targets(target, i);
10852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	return err;
10952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy}
11052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyEXPORT_SYMBOL(xt_register_targets);
11152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
11252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyvoid
11352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyxt_unregister_targets(struct xt_target *target, unsigned int n)
11452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy{
11552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	unsigned int i;
11652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
11752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	for (i = 0; i < n; i++)
11852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		xt_unregister_target(&target[i]);
11952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy}
12052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyEXPORT_SYMBOL(xt_unregister_targets);
12152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
12252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyint
123a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_register_match(struct xt_match *match)
1242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
12576108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	u_int8_t af = match->family;
12676108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	int ret;
1272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1289e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	ret = mutex_lock_interruptible(&xt[af].mutex);
1292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (ret != 0)
1302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ret;
1312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_add(&match->list, &xt[af].match);
1339e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
1342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ret;
1362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
1372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_register_match);
1382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid
140a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_unregister_match(struct xt_match *match)
1412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
14276108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	u_int8_t af = match->family;
143a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayuso
1449e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_lock(&xt[af].mutex);
145df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy	list_del(&match->list);
1469e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
1472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
1482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_unregister_match);
1492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
15052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyint
15152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyxt_register_matches(struct xt_match *match, unsigned int n)
15252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy{
15352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	unsigned int i;
15452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	int err = 0;
15552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
15652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	for (i = 0; i < n; i++) {
15752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		err = xt_register_match(&match[i]);
15852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		if (err)
15952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy			goto err;
16052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	}
16152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	return err;
16252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
16352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyerr:
16452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	if (i > 0)
16552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		xt_unregister_matches(match, i);
16652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	return err;
16752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy}
16852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyEXPORT_SYMBOL(xt_register_matches);
16952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
17052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyvoid
17152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyxt_unregister_matches(struct xt_match *match, unsigned int n)
17252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy{
17352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	unsigned int i;
17452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
17552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	for (i = 0; i < n; i++)
17652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		xt_unregister_match(&match[i]);
17752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy}
17852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyEXPORT_SYMBOL(xt_unregister_matches);
17952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
1802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/*
1822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * These are weird, but module loading must not be done with mutex
1832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * held (since they will register), and we have to have a single
1842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * function to use try_then_request_module().
1852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte */
1862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Find match, grabs ref.  Returns ERR_PTR() on error. */
18876108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstruct xt_match *xt_find_match(u8 af, const char *name, u8 revision)
1892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
1902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_match *m;
1912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int err = 0;
1922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1939e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	if (mutex_lock_interruptible(&xt[af].mutex) != 0)
1942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ERR_PTR(-EINTR);
1952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(m, &xt[af].match, list) {
1972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(m->name, name) == 0) {
1982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (m->revision == revision) {
1992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				if (try_module_get(m->me)) {
2009e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar					mutex_unlock(&xt[af].mutex);
2012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte					return m;
2022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				}
2032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			} else
2042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				err = -EPROTOTYPE; /* Found something. */
2052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
2062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
2079e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
20855b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt
20955b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt	if (af != NFPROTO_UNSPEC)
21055b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt		/* Try searching again in the family-independent list */
21155b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt		return xt_find_match(NFPROTO_UNSPEC, name, revision);
21255b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt
2132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ERR_PTR(err);
2142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
2152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_find_match);
2162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Find target, grabs ref.  Returns ERR_PTR() on error. */
21876108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstruct xt_target *xt_find_target(u8 af, const char *name, u8 revision)
2192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
2202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_target *t;
2212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int err = 0;
2222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2239e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	if (mutex_lock_interruptible(&xt[af].mutex) != 0)
2242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ERR_PTR(-EINTR);
2252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(t, &xt[af].target, list) {
2272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(t->name, name) == 0) {
2282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (t->revision == revision) {
2292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				if (try_module_get(t->me)) {
2309e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar					mutex_unlock(&xt[af].mutex);
2312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte					return t;
2322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				}
2332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			} else
2342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				err = -EPROTOTYPE; /* Found something. */
2352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
2362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
2379e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
23855b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt
23955b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt	if (af != NFPROTO_UNSPEC)
24055b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt		/* Try searching again in the family-independent list */
24155b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt		return xt_find_target(NFPROTO_UNSPEC, name, revision);
24255b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt
2432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ERR_PTR(err);
2442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
2452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_find_target);
2462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
24776108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstruct xt_target *xt_request_find_target(u8 af, const char *name, u8 revision)
2482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
2492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_target *target;
2502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	target = try_then_request_module(xt_find_target(af, name, revision),
25237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy					 "%st_%s", xt_prefix[af], name);
2532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (IS_ERR(target) || !target)
2542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
2552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return target;
2562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
2572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_request_find_target);
2582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
25976108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstatic int match_revfn(u8 af, const char *name, u8 revision, int *bestp)
2602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
2615452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt	const struct xt_match *m;
2622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int have_rev = 0;
2632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(m, &xt[af].match, list) {
2652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(m->name, name) == 0) {
2662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (m->revision > *bestp)
2672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				*bestp = m->revision;
2682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (m->revision == revision)
2692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				have_rev = 1;
2702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
2712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
272656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy
273656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy	if (af != NFPROTO_UNSPEC && !have_rev)
274656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy		return match_revfn(NFPROTO_UNSPEC, name, revision, bestp);
275656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy
2762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return have_rev;
2772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
2782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
27976108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstatic int target_revfn(u8 af, const char *name, u8 revision, int *bestp)
2802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
2815452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt	const struct xt_target *t;
2822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int have_rev = 0;
2832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(t, &xt[af].target, list) {
2852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(t->name, name) == 0) {
2862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (t->revision > *bestp)
2872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				*bestp = t->revision;
2882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (t->revision == revision)
2892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				have_rev = 1;
2902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
2912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
292656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy
293656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy	if (af != NFPROTO_UNSPEC && !have_rev)
294656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy		return target_revfn(NFPROTO_UNSPEC, name, revision, bestp);
295656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy
2962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return have_rev;
2972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
2982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Returns true or false (if no such extension at all) */
30076108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtint xt_find_revision(u8 af, const char *name, u8 revision, int target,
3012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		     int *err)
3022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
3032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int have_rev, best = -1;
3042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3059e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	if (mutex_lock_interruptible(&xt[af].mutex) != 0) {
3062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		*err = -EINTR;
3072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return 1;
3082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
3092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (target == 1)
3102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		have_rev = target_revfn(af, name, revision, &best);
3112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	else
3122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		have_rev = match_revfn(af, name, revision, &best);
3139e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
3142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Nothing at all?  Return 0 to try loading module. */
3162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (best == -1) {
3172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		*err = -ENOENT;
3182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return 0;
3192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
3202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	*err = best;
3222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!have_rev)
3232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		*err = -EPROTONOSUPPORT;
3242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return 1;
3252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
3262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_find_revision);
3272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
328451853645f3cb804b523227eca054701e4cbc589Jan Engelhardtstatic char *textify_hooks(char *buf, size_t size, unsigned int mask)
329451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt{
330451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	static const char *const names[] = {
331451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		"PREROUTING", "INPUT", "FORWARD",
332451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		"OUTPUT", "POSTROUTING", "BROUTING",
333451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	};
334451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	unsigned int i;
335451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	char *p = buf;
336451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	bool np = false;
337451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	int res;
338451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt
339451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	*p = '\0';
340451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	for (i = 0; i < ARRAY_SIZE(names); ++i) {
341451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		if (!(mask & (1 << i)))
342451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt			continue;
343451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		res = snprintf(p, size, "%s%s", np ? "/" : "", names[i]);
344451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		if (res > 0) {
345451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt			size -= res;
346451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt			p += res;
347451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		}
348451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		np = true;
349451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	}
350451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt
351451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	return buf;
352451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt}
353451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt
354916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardtint xt_check_match(struct xt_mtchk_param *par,
3559b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt		   unsigned int size, u_int8_t proto, bool inv_proto)
35637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy{
3579b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt	if (XT_ALIGN(par->match->matchsize) != size &&
3589b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt	    par->match->matchsize != -1) {
359043ef46c7690bfdbd5b012e15812a14a19ca5604Jan Engelhardt		/*
360043ef46c7690bfdbd5b012e15812a14a19ca5604Jan Engelhardt		 * ebt_among is exempt from centralized matchsize checking
361043ef46c7690bfdbd5b012e15812a14a19ca5604Jan Engelhardt		 * because it uses a dynamic-size data set.
362043ef46c7690bfdbd5b012e15812a14a19ca5604Jan Engelhardt		 */
363b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt		pr_err("%s_tables: %s.%u match: invalid size "
364b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt		       "%u (kernel) != (user) %u\n",
365916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt		       xt_prefix[par->family], par->match->name,
366b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt		       par->match->revision,
3679b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt		       XT_ALIGN(par->match->matchsize), size);
36837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
36937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
3709b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt	if (par->match->table != NULL &&
3719b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt	    strcmp(par->match->table, par->table) != 0) {
3723dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches		pr_err("%s_tables: %s match: only valid in %s table, not %s\n",
373916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt		       xt_prefix[par->family], par->match->name,
3749b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt		       par->match->table, par->table);
37537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
37637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
3779b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt	if (par->match->hooks && (par->hook_mask & ~par->match->hooks) != 0) {
378451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		char used[64], allow[64];
379451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt
3803dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches		pr_err("%s_tables: %s match: used from hooks %s, but only "
381451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		       "valid from %s\n",
382916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt		       xt_prefix[par->family], par->match->name,
383451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		       textify_hooks(used, sizeof(used), par->hook_mask),
384451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		       textify_hooks(allow, sizeof(allow), par->match->hooks));
38537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
38637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
3879b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt	if (par->match->proto && (par->match->proto != proto || inv_proto)) {
3883dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches		pr_err("%s_tables: %s match: only valid for protocol %u\n",
389916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt		       xt_prefix[par->family], par->match->name,
390916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt		       par->match->proto);
39137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
39237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
3939b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt	if (par->match->checkentry != NULL && !par->match->checkentry(par))
394367c679007fa4f990eb7ee381326ec59d8148b0eJan Engelhardt		return -EINVAL;
39537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	return 0;
39637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy}
39737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardyEXPORT_SYMBOL_GPL(xt_check_match);
39837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy
3992722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT
40076108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtint xt_compat_add_offset(u_int8_t af, unsigned int offset, short delta)
401b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy{
402b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	struct compat_delta *tmp;
403b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
404b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	tmp = kmalloc(sizeof(struct compat_delta), GFP_KERNEL);
405b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	if (!tmp)
406b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		return -ENOMEM;
407b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
408b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	tmp->offset = offset;
409b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	tmp->delta = delta;
410b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
411b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	if (xt[af].compat_offsets) {
412b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		tmp->next = xt[af].compat_offsets->next;
413b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		xt[af].compat_offsets->next = tmp;
414b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	} else {
415b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		xt[af].compat_offsets = tmp;
416b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		tmp->next = NULL;
417b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	}
418b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	return 0;
419b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy}
420b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_add_offset);
421b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
42276108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtvoid xt_compat_flush_offsets(u_int8_t af)
423b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy{
424b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	struct compat_delta *tmp, *next;
425b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
426b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	if (xt[af].compat_offsets) {
427b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		for (tmp = xt[af].compat_offsets; tmp; tmp = next) {
428b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy			next = tmp->next;
429b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy			kfree(tmp);
430b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		}
431b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		xt[af].compat_offsets = NULL;
432b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	}
433b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy}
434b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_flush_offsets);
435b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
4363e5e524ffb5fcf2447eb5dd9f8e54ad22dd9baa7Florian Westphalint xt_compat_calc_jump(u_int8_t af, unsigned int offset)
437b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy{
438b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	struct compat_delta *tmp;
4393e5e524ffb5fcf2447eb5dd9f8e54ad22dd9baa7Florian Westphal	int delta;
440b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
441b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	for (tmp = xt[af].compat_offsets, delta = 0; tmp; tmp = tmp->next)
442b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		if (tmp->offset < offset)
443b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy			delta += tmp->delta;
444b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	return delta;
445b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy}
446b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_calc_jump);
447b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
4485452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardtint xt_compat_match_offset(const struct xt_match *match)
4492722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{
4509fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	u_int16_t csize = match->compatsize ? : match->matchsize;
4519fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	return XT_ALIGN(match->matchsize) - COMPAT_XT_ALIGN(csize);
4529fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy}
4539fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_match_offset);
4549fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
4558956695131b8a7878891667469899d667eb5892bPatrick McHardyint xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr,
456b0a6363c2418c93f25dd30b8ffcd3fdd4ce23ad6Patrick McHardy			      unsigned int *size)
4579fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy{
4585452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt	const struct xt_match *match = m->u.kernel.match;
4599fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	struct compat_xt_entry_match *cm = (struct compat_xt_entry_match *)m;
4609fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	int pad, off = xt_compat_match_offset(match);
4619fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	u_int16_t msize = cm->u.user.match_size;
4629fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
4639fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	m = *dstptr;
4649fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	memcpy(m, cm, sizeof(*cm));
4659fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (match->compat_from_user)
4669fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		match->compat_from_user(m->data, cm->data);
4679fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	else
4689fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		memcpy(m->data, cm->data, msize - sizeof(*cm));
4699fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	pad = XT_ALIGN(match->matchsize) - match->matchsize;
4709fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (pad > 0)
4719fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		memset(m->data + match->matchsize, 0, pad);
4729fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
4739fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	msize += off;
4749fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	m->u.user.match_size = msize;
4759fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
4769fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*size += off;
4779fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*dstptr += msize;
4788956695131b8a7878891667469899d667eb5892bPatrick McHardy	return 0;
4799fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy}
4809fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_match_from_user);
4819fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
482739674fb7febf116e7d647031fab16989a08a965Jan Engelhardtint xt_compat_match_to_user(const struct xt_entry_match *m,
483739674fb7febf116e7d647031fab16989a08a965Jan Engelhardt			    void __user **dstptr, unsigned int *size)
4849fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy{
4855452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt	const struct xt_match *match = m->u.kernel.match;
4869fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	struct compat_xt_entry_match __user *cm = *dstptr;
4879fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	int off = xt_compat_match_offset(match);
4889fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	u_int16_t msize = m->u.user.match_size - off;
4899fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
4909fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (copy_to_user(cm, m, sizeof(*cm)) ||
491a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy	    put_user(msize, &cm->u.user.match_size) ||
492a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy	    copy_to_user(cm->u.user.name, m->u.kernel.match->name,
493a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy			 strlen(m->u.kernel.match->name) + 1))
494601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki		return -EFAULT;
4959fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
4969fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (match->compat_to_user) {
4979fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		if (match->compat_to_user((void __user *)cm->data, m->data))
4989fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy			return -EFAULT;
4999fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	} else {
5009fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		if (copy_to_user(cm->data, m->data, msize - sizeof(*cm)))
5019fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy			return -EFAULT;
5022722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	}
5039fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
5049fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*size -= off;
5059fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*dstptr += msize;
5069fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	return 0;
5072722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin}
5089fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_match_to_user);
5099fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy#endif /* CONFIG_COMPAT */
5102722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin
511916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardtint xt_check_target(struct xt_tgchk_param *par,
512af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt		    unsigned int size, u_int8_t proto, bool inv_proto)
51337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy{
514af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt	if (XT_ALIGN(par->target->targetsize) != size) {
515b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt		pr_err("%s_tables: %s.%u target: invalid size "
516b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt		       "%u (kernel) != (user) %u\n",
517916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt		       xt_prefix[par->family], par->target->name,
518b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt		       par->target->revision,
519af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt		       XT_ALIGN(par->target->targetsize), size);
52037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
52137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
522af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt	if (par->target->table != NULL &&
523af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt	    strcmp(par->target->table, par->table) != 0) {
5243dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches		pr_err("%s_tables: %s target: only valid in %s table, not %s\n",
525916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt		       xt_prefix[par->family], par->target->name,
526af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt		       par->target->table, par->table);
52737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
52837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
529af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt	if (par->target->hooks && (par->hook_mask & ~par->target->hooks) != 0) {
530451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		char used[64], allow[64];
531451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt
5323dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches		pr_err("%s_tables: %s target: used from hooks %s, but only "
533451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		       "usable from %s\n",
534916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt		       xt_prefix[par->family], par->target->name,
535451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		       textify_hooks(used, sizeof(used), par->hook_mask),
536451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		       textify_hooks(allow, sizeof(allow), par->target->hooks));
53737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
53837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
539af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt	if (par->target->proto && (par->target->proto != proto || inv_proto)) {
5403dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches		pr_err("%s_tables: %s target: only valid for protocol %u\n",
541916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt		       xt_prefix[par->family], par->target->name,
542af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt		       par->target->proto);
54337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
54437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
545af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt	if (par->target->checkentry != NULL && !par->target->checkentry(par))
546367c679007fa4f990eb7ee381326ec59d8148b0eJan Engelhardt		return -EINVAL;
54737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	return 0;
54837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy}
54937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardyEXPORT_SYMBOL_GPL(xt_check_target);
55037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy
5512722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT
5525452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardtint xt_compat_target_offset(const struct xt_target *target)
5532722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{
5549fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	u_int16_t csize = target->compatsize ? : target->targetsize;
5559fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	return XT_ALIGN(target->targetsize) - COMPAT_XT_ALIGN(csize);
5569fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy}
5579fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_target_offset);
5589fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
5599fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyvoid xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr,
560b0a6363c2418c93f25dd30b8ffcd3fdd4ce23ad6Patrick McHardy				unsigned int *size)
5619fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy{
5625452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt	const struct xt_target *target = t->u.kernel.target;
5639fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	struct compat_xt_entry_target *ct = (struct compat_xt_entry_target *)t;
5649fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	int pad, off = xt_compat_target_offset(target);
5659fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	u_int16_t tsize = ct->u.user.target_size;
5669fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
5679fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	t = *dstptr;
5689fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	memcpy(t, ct, sizeof(*ct));
5699fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (target->compat_from_user)
5709fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		target->compat_from_user(t->data, ct->data);
5719fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	else
5729fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		memcpy(t->data, ct->data, tsize - sizeof(*ct));
5739fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	pad = XT_ALIGN(target->targetsize) - target->targetsize;
5749fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (pad > 0)
5759fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		memset(t->data + target->targetsize, 0, pad);
5769fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
5779fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	tsize += off;
5789fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	t->u.user.target_size = tsize;
5799fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
5809fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*size += off;
5819fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*dstptr += tsize;
5829fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy}
5839fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_target_from_user);
5849fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
585739674fb7febf116e7d647031fab16989a08a965Jan Engelhardtint xt_compat_target_to_user(const struct xt_entry_target *t,
586739674fb7febf116e7d647031fab16989a08a965Jan Engelhardt			     void __user **dstptr, unsigned int *size)
5879fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy{
5885452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt	const struct xt_target *target = t->u.kernel.target;
5899fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	struct compat_xt_entry_target __user *ct = *dstptr;
5909fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	int off = xt_compat_target_offset(target);
5919fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	u_int16_t tsize = t->u.user.target_size - off;
5929fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
5939fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (copy_to_user(ct, t, sizeof(*ct)) ||
594a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy	    put_user(tsize, &ct->u.user.target_size) ||
595a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy	    copy_to_user(ct->u.user.name, t->u.kernel.target->name,
596a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy			 strlen(t->u.kernel.target->name) + 1))
597601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki		return -EFAULT;
5989fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
5999fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (target->compat_to_user) {
6009fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		if (target->compat_to_user((void __user *)ct->data, t->data))
6019fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy			return -EFAULT;
6029fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	} else {
6039fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		if (copy_to_user(ct->data, t->data, tsize - sizeof(*ct)))
6049fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy			return -EFAULT;
6052722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	}
6069fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
6079fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*size -= off;
6089fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*dstptr += tsize;
6099fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	return 0;
6102722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin}
6119fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_target_to_user);
6122722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#endif
6132722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin
6142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_table_info *xt_alloc_table_info(unsigned int size)
6152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
6162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table_info *newinfo;
6172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int cpu;
6182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
6204481374ce88ba8f460c8b89f2572027bd27057d0Jan Beulich	if ((SMP_ALIGN(size) >> PAGE_SHIFT) + 2 > totalram_pages)
6212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
6222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
623259d4e41f3ec25f22169daece42729f597b89f9aEric Dumazet	newinfo = kzalloc(XT_TABLE_INFO_SZ, GFP_KERNEL);
6242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!newinfo)
6252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
6262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	newinfo->size = size;
6282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6296f912042256c12b0927438122594f5379b364f5dKAMEZAWA Hiroyuki	for_each_possible_cpu(cpu) {
6302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (size <= PAGE_SIZE)
6312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			newinfo->entries[cpu] = kmalloc_node(size,
6322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte							GFP_KERNEL,
6332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte							cpu_to_node(cpu));
6342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		else
6352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			newinfo->entries[cpu] = vmalloc_node(size,
6362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte							cpu_to_node(cpu));
6372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (newinfo->entries[cpu] == NULL) {
6392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			xt_free_table_info(newinfo);
6402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			return NULL;
6412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
6422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
6432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return newinfo;
6452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
6462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_alloc_table_info);
6472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid xt_free_table_info(struct xt_table_info *info)
6492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
6502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int cpu;
6512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6526f912042256c12b0927438122594f5379b364f5dKAMEZAWA Hiroyuki	for_each_possible_cpu(cpu) {
6532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (info->size <= PAGE_SIZE)
6542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			kfree(info->entries[cpu]);
6552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		else
6562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			vfree(info->entries[cpu]);
6572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
6582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	kfree(info);
6592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
6602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_free_table_info);
6612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Find table by name, grabs mutex & ref.  Returns ERR_PTR() on error. */
66376108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstruct xt_table *xt_find_table_lock(struct net *net, u_int8_t af,
66476108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt				    const char *name)
6652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
6662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table *t;
6672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6689e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	if (mutex_lock_interruptible(&xt[af].mutex) != 0)
6692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ERR_PTR(-EINTR);
6702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6718d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	list_for_each_entry(t, &net->xt.tables[af], list)
6722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(t->name, name) == 0 && try_module_get(t->me))
6732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			return t;
6749e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
6752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return NULL;
6762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
6772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_find_table_lock);
6782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid xt_table_unlock(struct xt_table *table)
6802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
6819e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[table->af].mutex);
6822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
6832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_table_unlock);
6842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6852722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT
68676108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtvoid xt_compat_lock(u_int8_t af)
6872722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{
6882722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	mutex_lock(&xt[af].compat_mutex);
6892722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin}
6902722971cbe831117686039d5c334f2c0f560be13Dmitry MishinEXPORT_SYMBOL_GPL(xt_compat_lock);
6912722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin
69276108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtvoid xt_compat_unlock(u_int8_t af)
6932722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{
6942722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	mutex_unlock(&xt[af].compat_mutex);
6952722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin}
6962722971cbe831117686039d5c334f2c0f560be13Dmitry MishinEXPORT_SYMBOL_GPL(xt_compat_unlock);
6972722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#endif
6982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
699942e4a2bd680c606af0211e64eb216be2e19bf61Stephen HemmingerDEFINE_PER_CPU(struct xt_info_lock, xt_info_locks);
700942e4a2bd680c606af0211e64eb216be2e19bf61Stephen HemmingerEXPORT_PER_CPU_SYMBOL_GPL(xt_info_locks);
701942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger
702942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger
7032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_table_info *
7042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltext_replace_table(struct xt_table *table,
7052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	      unsigned int num_counters,
7062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	      struct xt_table_info *newinfo,
7072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	      int *error)
7082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
709942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	struct xt_table_info *private;
7102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Do the substitution. */
712942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	local_bh_disable();
7132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	private = table->private;
714942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger
7152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Check inside lock: is the old number correct? */
7162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (num_counters != private->number) {
717be91fd5e323b46450ca82f6828e933e3791fb2f2Jan Engelhardt		pr_debug("num_counters != table->private->number (%u/%u)\n",
7182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			 num_counters, private->number);
719942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger		local_bh_enable();
7202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		*error = -EAGAIN;
7212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
7222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
7232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
724942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	table->private = newinfo;
725942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	newinfo->initial_entries = private->initial_entries;
726942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger
727942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	/*
728942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	 * Even though table entries have now been swapped, other CPU's
729942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	 * may still be using the old entries. This is okay, because
730942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	 * resynchronization happens because of the locking done
731942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	 * during the get_counters() routine.
732942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	 */
733942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	local_bh_enable();
734942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger
735942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	return private;
7362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
7372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_replace_table);
7382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
73935aad0ffdf548617940ca1e78be1f2e0bafc4496Jan Engelhardtstruct xt_table *xt_register_table(struct net *net,
74035aad0ffdf548617940ca1e78be1f2e0bafc4496Jan Engelhardt				   const struct xt_table *input_table,
741a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan				   struct xt_table_info *bootstrap,
742a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan				   struct xt_table_info *newinfo)
7432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
7442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int ret;
7452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table_info *private;
74635aad0ffdf548617940ca1e78be1f2e0bafc4496Jan Engelhardt	struct xt_table *t, *table;
7472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
74844d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan	/* Don't add one object to multiple lists. */
74935aad0ffdf548617940ca1e78be1f2e0bafc4496Jan Engelhardt	table = kmemdup(input_table, sizeof(struct xt_table), GFP_KERNEL);
75044d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan	if (!table) {
75144d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan		ret = -ENOMEM;
75244d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan		goto out;
75344d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan	}
75444d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan
7559e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	ret = mutex_lock_interruptible(&xt[table->af].mutex);
7562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (ret != 0)
75744d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan		goto out_free;
7582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Don't autoload: we'd eat our tail... */
7608d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	list_for_each_entry(t, &net->xt.tables[table->af], list) {
761df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy		if (strcmp(t->name, table->name) == 0) {
762df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy			ret = -EEXIST;
763df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy			goto unlock;
764df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy		}
7652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
7662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Simplifies replace_table code. */
7682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	table->private = bootstrap;
769784544739a25c30637397ace5489eeb6e15d7d49Stephen Hemminger
7702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!xt_replace_table(table, 0, newinfo, &ret))
7712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto unlock;
7722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	private = table->private;
774be91fd5e323b46450ca82f6828e933e3791fb2f2Jan Engelhardt	pr_debug("table->private->number = %u\n", private->number);
7752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* save number of initial entries */
7772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	private->initial_entries = private->number;
7782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7798d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	list_add(&table->list, &net->xt.tables[table->af]);
780a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan	mutex_unlock(&xt[table->af].mutex);
781a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan	return table;
7822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte unlock:
7849e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[table->af].mutex);
78544d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyanout_free:
78644d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan	kfree(table);
787a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyanout:
788a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan	return ERR_PTR(ret);
7892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
7902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_register_table);
7912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid *xt_unregister_table(struct xt_table *table)
7932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
7942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table_info *private;
7952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7969e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_lock(&xt[table->af].mutex);
7972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	private = table->private;
798df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy	list_del(&table->list);
7999e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[table->af].mutex);
80044d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan	kfree(table);
8012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return private;
8032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
8042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_unregister_table);
8052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
807715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyanstruct xt_names_priv {
808715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	struct seq_net_private p;
80976108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	u_int8_t af;
810715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan};
811025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void *xt_table_seq_start(struct seq_file *seq, loff_t *pos)
8122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
813715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	struct xt_names_priv *priv = seq->private;
8141218854afa6f659be90b748cf1bc7badee954a35YOSHIFUJI Hideaki	struct net *net = seq_file_net(seq);
81576108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	u_int8_t af = priv->af;
8162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
817025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	mutex_lock(&xt[af].mutex);
818715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	return seq_list_start(&net->xt.tables[af], *pos);
819025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
8202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
821025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void *xt_table_seq_next(struct seq_file *seq, void *v, loff_t *pos)
822025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
823715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	struct xt_names_priv *priv = seq->private;
8241218854afa6f659be90b748cf1bc7badee954a35YOSHIFUJI Hideaki	struct net *net = seq_file_net(seq);
82576108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	u_int8_t af = priv->af;
8262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
827715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	return seq_list_next(v, &net->xt.tables[af], pos);
8282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
8292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
830025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void xt_table_seq_stop(struct seq_file *seq, void *v)
8312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
832715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	struct xt_names_priv *priv = seq->private;
83376108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	u_int8_t af = priv->af;
8342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
835025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	mutex_unlock(&xt[af].mutex);
836025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
8372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
838025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_table_seq_show(struct seq_file *seq, void *v)
839025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
840025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	struct xt_table *table = list_entry(v, struct xt_table, list);
8412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
842025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	if (strlen(table->name))
843025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan		return seq_printf(seq, "%s\n", table->name);
844025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	else
845025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan		return 0;
846025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
847601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki
848025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct seq_operations xt_table_seq_ops = {
849025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.start	= xt_table_seq_start,
850025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.next	= xt_table_seq_next,
851025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.stop	= xt_table_seq_stop,
852025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.show	= xt_table_seq_show,
853025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan};
854025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
855025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_table_open(struct inode *inode, struct file *file)
856025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
857025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	int ret;
858715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	struct xt_names_priv *priv;
859025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
860715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	ret = seq_open_net(inode, file, &xt_table_seq_ops,
861715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan			   sizeof(struct xt_names_priv));
862025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	if (!ret) {
863715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan		priv = ((struct seq_file *)file->private_data)->private;
864715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan		priv->af = (unsigned long)PDE(inode)->data;
865025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	}
866025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	return ret;
8672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
8682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
869025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct file_operations xt_table_ops = {
870025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.owner	 = THIS_MODULE,
871025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.open	 = xt_table_open,
872025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.read	 = seq_read,
873025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.llseek	 = seq_lseek,
8740e93bb9459f56b50a2f71f2c230f4ad00ec40a73Pavel Emelyanov	.release = seq_release_net,
875025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan};
876025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
877eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt/*
878eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt * Traverse state for ip{,6}_{tables,matches} for helping crossing
879eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt * the multi-AF mutexes.
880eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt */
881eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstruct nf_mttg_trav {
882eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	struct list_head *head, *curr;
883eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	uint8_t class, nfproto;
884eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt};
885eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt
886eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtenum {
887eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	MTTG_TRAV_INIT,
888eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	MTTG_TRAV_NFP_UNSPEC,
889eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	MTTG_TRAV_NFP_SPEC,
890eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	MTTG_TRAV_DONE,
891eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt};
892eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt
893eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void *xt_mttg_seq_next(struct seq_file *seq, void *v, loff_t *ppos,
894eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt    bool is_target)
8952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
896eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	static const uint8_t next_class[] = {
897eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		[MTTG_TRAV_NFP_UNSPEC] = MTTG_TRAV_NFP_SPEC,
898eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		[MTTG_TRAV_NFP_SPEC]   = MTTG_TRAV_DONE,
899eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	};
900eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	struct nf_mttg_trav *trav = seq->private;
901eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt
902eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	switch (trav->class) {
903eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	case MTTG_TRAV_INIT:
904eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		trav->class = MTTG_TRAV_NFP_UNSPEC;
905eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		mutex_lock(&xt[NFPROTO_UNSPEC].mutex);
906eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		trav->head = trav->curr = is_target ?
907eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt			&xt[NFPROTO_UNSPEC].target : &xt[NFPROTO_UNSPEC].match;
908eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt 		break;
909eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	case MTTG_TRAV_NFP_UNSPEC:
910eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		trav->curr = trav->curr->next;
911eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		if (trav->curr != trav->head)
912eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt			break;
913eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		mutex_unlock(&xt[NFPROTO_UNSPEC].mutex);
914eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		mutex_lock(&xt[trav->nfproto].mutex);
915eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		trav->head = trav->curr = is_target ?
916eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt			&xt[trav->nfproto].target : &xt[trav->nfproto].match;
917eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		trav->class = next_class[trav->class];
918eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		break;
919eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	case MTTG_TRAV_NFP_SPEC:
920eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		trav->curr = trav->curr->next;
921eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		if (trav->curr != trav->head)
922eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt			break;
923eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		/* fallthru, _stop will unlock */
924eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	default:
925eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		return NULL;
926eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	}
9272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
928eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	if (ppos != NULL)
929eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		++*ppos;
930eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return trav;
931025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
932601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki
933eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void *xt_mttg_seq_start(struct seq_file *seq, loff_t *pos,
934eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt    bool is_target)
935025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
936eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	struct nf_mttg_trav *trav = seq->private;
937eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	unsigned int j;
9382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
939eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	trav->class = MTTG_TRAV_INIT;
940eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	for (j = 0; j < *pos; ++j)
941eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		if (xt_mttg_seq_next(seq, NULL, NULL, is_target) == NULL)
942eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt			return NULL;
943eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return trav;
9442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
9452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
946eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void xt_mttg_seq_stop(struct seq_file *seq, void *v)
9472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
948eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	struct nf_mttg_trav *trav = seq->private;
949eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt
950eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	switch (trav->class) {
951eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	case MTTG_TRAV_NFP_UNSPEC:
952eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		mutex_unlock(&xt[NFPROTO_UNSPEC].mutex);
953eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		break;
954eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	case MTTG_TRAV_NFP_SPEC:
955eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		mutex_unlock(&xt[trav->nfproto].mutex);
956eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		break;
957eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	}
958eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt}
9592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
960eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void *xt_match_seq_start(struct seq_file *seq, loff_t *pos)
961eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt{
962eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return xt_mttg_seq_start(seq, pos, false);
9632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
9642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
965eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void *xt_match_seq_next(struct seq_file *seq, void *v, loff_t *ppos)
9662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
967eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return xt_mttg_seq_next(seq, v, ppos, false);
968eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt}
9692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
970eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic int xt_match_seq_show(struct seq_file *seq, void *v)
971eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt{
972eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	const struct nf_mttg_trav *trav = seq->private;
973eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	const struct xt_match *match;
974eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt
975eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	switch (trav->class) {
976eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	case MTTG_TRAV_NFP_UNSPEC:
977eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	case MTTG_TRAV_NFP_SPEC:
978eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		if (trav->curr == trav->head)
979eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt			return 0;
980eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		match = list_entry(trav->curr, struct xt_match, list);
981eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		return (*match->name == '\0') ? 0 :
982eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		       seq_printf(seq, "%s\n", match->name);
983eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	}
984eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return 0;
9852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
9862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
987025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct seq_operations xt_match_seq_ops = {
988025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.start	= xt_match_seq_start,
989025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.next	= xt_match_seq_next,
990eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	.stop	= xt_mttg_seq_stop,
991025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.show	= xt_match_seq_show,
9922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte};
9932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
994025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_match_open(struct inode *inode, struct file *file)
9952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
996eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	struct seq_file *seq;
997eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	struct nf_mttg_trav *trav;
9982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int ret;
9992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1000eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	trav = kmalloc(sizeof(*trav), GFP_KERNEL);
1001eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	if (trav == NULL)
1002eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		return -ENOMEM;
10032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1004eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	ret = seq_open(file, &xt_match_seq_ops);
1005eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	if (ret < 0) {
1006eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		kfree(trav);
1007eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		return ret;
10082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
1009eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt
1010eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	seq = file->private_data;
1011eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	seq->private = trav;
1012eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	trav->nfproto = (unsigned long)PDE(inode)->data;
1013eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return 0;
1014025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
1015025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
1016025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct file_operations xt_match_ops = {
1017025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.owner	 = THIS_MODULE,
1018025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.open	 = xt_match_open,
1019025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.read	 = seq_read,
1020025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.llseek	 = seq_lseek,
1021eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	.release = seq_release_private,
1022025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan};
10232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1024025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void *xt_target_seq_start(struct seq_file *seq, loff_t *pos)
1025025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
1026eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return xt_mttg_seq_start(seq, pos, true);
1027025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
1028025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
1029eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void *xt_target_seq_next(struct seq_file *seq, void *v, loff_t *ppos)
1030025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
1031eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return xt_mttg_seq_next(seq, v, ppos, true);
1032025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
1033025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
1034025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_target_seq_show(struct seq_file *seq, void *v)
1035025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
1036eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	const struct nf_mttg_trav *trav = seq->private;
1037eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	const struct xt_target *target;
1038eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt
1039eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	switch (trav->class) {
1040eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	case MTTG_TRAV_NFP_UNSPEC:
1041eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	case MTTG_TRAV_NFP_SPEC:
1042eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		if (trav->curr == trav->head)
1043eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt			return 0;
1044eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		target = list_entry(trav->curr, struct xt_target, list);
1045eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		return (*target->name == '\0') ? 0 :
1046eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		       seq_printf(seq, "%s\n", target->name);
1047eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	}
1048eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return 0;
1049025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
1050025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
1051025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct seq_operations xt_target_seq_ops = {
1052025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.start	= xt_target_seq_start,
1053025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.next	= xt_target_seq_next,
1054eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	.stop	= xt_mttg_seq_stop,
1055025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.show	= xt_target_seq_show,
1056025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan};
1057025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
1058025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_target_open(struct inode *inode, struct file *file)
1059025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
1060eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	struct seq_file *seq;
1061eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	struct nf_mttg_trav *trav;
1062025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	int ret;
1063025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
1064eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	trav = kmalloc(sizeof(*trav), GFP_KERNEL);
1065eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	if (trav == NULL)
1066eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		return -ENOMEM;
1067025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
1068eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	ret = seq_open(file, &xt_target_seq_ops);
1069eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	if (ret < 0) {
1070eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		kfree(trav);
1071eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		return ret;
1072025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	}
1073eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt
1074eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	seq = file->private_data;
1075eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	seq->private = trav;
1076eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	trav->nfproto = (unsigned long)PDE(inode)->data;
1077eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return 0;
10782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
10792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1080025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct file_operations xt_target_ops = {
10812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.owner	 = THIS_MODULE,
1082025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.open	 = xt_target_open,
10832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.read	 = seq_read,
10842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.llseek	 = seq_lseek,
1085eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	.release = seq_release_private,
10862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte};
10872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
10882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define FORMAT_TABLES	"_tables_names"
10892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define	FORMAT_MATCHES	"_tables_matches"
10902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define FORMAT_TARGETS 	"_tables_targets"
10912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
10922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif /* CONFIG_PROC_FS */
10932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
10942b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt/**
10952b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * xt_hook_link - set up hooks for a new table
10962b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * @table:	table with metadata needed to set up hooks
10972b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * @fn:		Hook function
10982b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt *
10992b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * This function will take care of creating and registering the necessary
11002b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * Netfilter hooks for XT tables.
11012b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt */
11022b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardtstruct nf_hook_ops *xt_hook_link(const struct xt_table *table, nf_hookfn *fn)
11032b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt{
11042b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	unsigned int hook_mask = table->valid_hooks;
11052b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	uint8_t i, num_hooks = hweight32(hook_mask);
11062b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	uint8_t hooknum;
11072b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	struct nf_hook_ops *ops;
11082b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	int ret;
11092b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt
11102b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	ops = kmalloc(sizeof(*ops) * num_hooks, GFP_KERNEL);
11112b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	if (ops == NULL)
11122b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		return ERR_PTR(-ENOMEM);
11132b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt
11142b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	for (i = 0, hooknum = 0; i < num_hooks && hook_mask != 0;
11152b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	     hook_mask >>= 1, ++hooknum) {
11162b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		if (!(hook_mask & 1))
11172b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt			continue;
11182b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		ops[i].hook     = fn;
11192b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		ops[i].owner    = table->me;
11202b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		ops[i].pf       = table->af;
11212b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		ops[i].hooknum  = hooknum;
11222b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		ops[i].priority = table->priority;
11232b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		++i;
11242b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	}
11252b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt
11262b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	ret = nf_register_hooks(ops, num_hooks);
11272b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	if (ret < 0) {
11282b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		kfree(ops);
11292b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		return ERR_PTR(ret);
11302b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	}
11312b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt
11322b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	return ops;
11332b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt}
11342b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan EngelhardtEXPORT_SYMBOL_GPL(xt_hook_link);
11352b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt
11362b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt/**
11372b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * xt_hook_unlink - remove hooks for a table
11382b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * @ops:	nf_hook_ops array as returned by nf_hook_link
11392b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * @hook_mask:	the very same mask that was passed to nf_hook_link
11402b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt */
11412b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardtvoid xt_hook_unlink(const struct xt_table *table, struct nf_hook_ops *ops)
11422b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt{
11432b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	nf_unregister_hooks(ops, hweight32(table->valid_hooks));
11442b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	kfree(ops);
11452b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt}
11462b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan EngelhardtEXPORT_SYMBOL_GPL(xt_hook_unlink);
11472b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt
114876108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtint xt_proto_init(struct net *net, u_int8_t af)
11492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
11502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
11512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	char buf[XT_FUNCTION_MAXNAMELEN];
11522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct proc_dir_entry *proc;
11532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif
11542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
11557e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	if (af >= ARRAY_SIZE(xt_prefix))
11562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return -EINVAL;
11572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
11582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
11592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
1160ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
11612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TABLES, sizeof(buf));
11628b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev	proc = proc_create_data(buf, 0440, net->proc_net, &xt_table_ops,
11638b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev				(void *)(unsigned long)af);
11642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!proc)
11652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto out;
11662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1167ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
11682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
11698b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev	proc = proc_create_data(buf, 0440, net->proc_net, &xt_match_ops,
11708b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev				(void *)(unsigned long)af);
11712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!proc)
11722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto out_remove_tables;
11732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1174ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
11752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TARGETS, sizeof(buf));
11768b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev	proc = proc_create_data(buf, 0440, net->proc_net, &xt_target_ops,
11778b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev				(void *)(unsigned long)af);
11782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!proc)
11792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto out_remove_matches;
11802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif
11812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
11822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return 0;
11832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
11842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
11852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteout_remove_matches:
1186ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
11872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
11883cb609d57c20027a8b39fc60b79b930a89da82d4Alexey Dobriyan	proc_net_remove(net, buf);
11892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
11902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteout_remove_tables:
1191ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
11922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TABLES, sizeof(buf));
11933cb609d57c20027a8b39fc60b79b930a89da82d4Alexey Dobriyan	proc_net_remove(net, buf);
11942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteout:
11952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return -1;
11962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif
11972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
11982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_proto_init);
11992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
120076108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtvoid xt_proto_fini(struct net *net, u_int8_t af)
12012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
12022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
12032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	char buf[XT_FUNCTION_MAXNAMELEN];
12042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1205ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
12062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TABLES, sizeof(buf));
12073cb609d57c20027a8b39fc60b79b930a89da82d4Alexey Dobriyan	proc_net_remove(net, buf);
12082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1209ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
12102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TARGETS, sizeof(buf));
12113cb609d57c20027a8b39fc60b79b930a89da82d4Alexey Dobriyan	proc_net_remove(net, buf);
12122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1213ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
12142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
12153cb609d57c20027a8b39fc60b79b930a89da82d4Alexey Dobriyan	proc_net_remove(net, buf);
12162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif /*CONFIG_PROC_FS*/
12172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
12182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_proto_fini);
12192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
12208d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyanstatic int __net_init xt_net_init(struct net *net)
12218d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan{
12228d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	int i;
12238d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan
12247e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	for (i = 0; i < NFPROTO_NUMPROTO; i++)
12258d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan		INIT_LIST_HEAD(&net->xt.tables[i]);
12268d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	return 0;
12278d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan}
12288d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan
12298d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyanstatic struct pernet_operations xt_net_ops = {
12308d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	.init = xt_net_init,
12318d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan};
12322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
12332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic int __init xt_init(void)
12342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
1235942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	unsigned int i;
1236942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	int rv;
1237942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger
1238942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	for_each_possible_cpu(i) {
1239942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger		struct xt_info_lock *lock = &per_cpu(xt_info_locks, i);
1240942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger		spin_lock_init(&lock->lock);
1241942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger		lock->readers = 0;
1242942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	}
12432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
12447e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	xt = kmalloc(sizeof(struct xt_af) * NFPROTO_NUMPROTO, GFP_KERNEL);
12452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!xt)
12462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return -ENOMEM;
12472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
12487e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	for (i = 0; i < NFPROTO_NUMPROTO; i++) {
12499e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar		mutex_init(&xt[i].mutex);
12502722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT
12512722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin		mutex_init(&xt[i].compat_mutex);
1252b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		xt[i].compat_offsets = NULL;
12532722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#endif
12542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		INIT_LIST_HEAD(&xt[i].target);
12552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		INIT_LIST_HEAD(&xt[i].match);
12562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
12578d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	rv = register_pernet_subsys(&xt_net_ops);
12588d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	if (rv < 0)
12598d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan		kfree(xt);
12608d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	return rv;
12612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
12622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
12632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic void __exit xt_fini(void)
12642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
12658d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	unregister_pernet_subsys(&xt_net_ops);
12662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	kfree(xt);
12672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
12682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
12692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltemodule_init(xt_init);
12702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltemodule_exit(xt_fini);
12712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1272