x_tables.c revision d7fe0f241dceade9c8d4af75498765c5ff7f27e6
12e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/*
22e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * x_tables core - Backend for {ip,ip6,arp}_tables
32e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *
42e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * Copyright (C) 2006-2006 Harald Welte <laforge@netfilter.org>
52e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *
62e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * Based on existing ip_tables code which is
72e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *   Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
82e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *   Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org>
92e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *
102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * This program is free software; you can redistribute it and/or modify
112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * it under the terms of the GNU General Public License version 2 as
122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * published by the Free Software Foundation.
132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *
142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte */
152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/kernel.h>
172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/socket.h>
182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/net.h>
192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/proc_fs.h>
202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/seq_file.h>
212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/string.h>
222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/vmalloc.h>
239e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar#include <linux/mutex.h>
24d7fe0f241dceade9c8d4af75498765c5ff7f27e6Al Viro#include <linux/mm.h>
252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/netfilter/x_tables.h>
272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/netfilter_arp.h>
282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
299e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar
302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteMODULE_LICENSE("GPL");
312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteMODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteMODULE_DESCRIPTION("[ip,ip6,arp]_tables backend module");
332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_af {
379e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	struct mutex mutex;
382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct list_head match;
392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct list_head target;
402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct list_head tables;
412722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	struct mutex compat_mutex;
422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte};
432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic struct xt_af *xt;
452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef DEBUG_IP_FIREWALL_USER
472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define duprintf(format, args...) printk(format , ## args)
482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#else
492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define duprintf(format, args...)
502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif
512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteenum {
532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	TABLE,
542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	TARGET,
552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	MATCH,
562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte};
572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardystatic const char *xt_prefix[NPROTO] = {
5937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	[AF_INET] 	= "ip",
6037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	[AF_INET6] 	= "ip6",
6137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	[NF_ARP]	= "arp",
6237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy};
6337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy
642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Registration hooks for targets. */
652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteint
66a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_register_target(struct xt_target *target)
672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
68a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayuso	int ret, af = target->family;
692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
709e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	ret = mutex_lock_interruptible(&xt[af].mutex);
712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (ret != 0)
722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ret;
732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_add(&target->list, &xt[af].target);
749e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ret;
762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_register_target);
782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid
80a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_unregister_target(struct xt_target *target)
812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
82a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayuso	int af = target->family;
83a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayuso
849e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_lock(&xt[af].mutex);
85df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy	list_del(&target->list);
869e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_unregister_target);
892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteint
9152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyxt_register_targets(struct xt_target *target, unsigned int n)
9252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy{
9352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	unsigned int i;
9452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	int err = 0;
9552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
9652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	for (i = 0; i < n; i++) {
9752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		err = xt_register_target(&target[i]);
9852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		if (err)
9952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy			goto err;
10052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	}
10152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	return err;
10252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
10352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyerr:
10452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	if (i > 0)
10552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		xt_unregister_targets(target, i);
10652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	return err;
10752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy}
10852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyEXPORT_SYMBOL(xt_register_targets);
10952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
11052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyvoid
11152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyxt_unregister_targets(struct xt_target *target, unsigned int n)
11252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy{
11352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	unsigned int i;
11452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
11552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	for (i = 0; i < n; i++)
11652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		xt_unregister_target(&target[i]);
11752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy}
11852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyEXPORT_SYMBOL(xt_unregister_targets);
11952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
12052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyint
121a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_register_match(struct xt_match *match)
1222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
123a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayuso	int ret, af = match->family;
1242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1259e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	ret = mutex_lock_interruptible(&xt[af].mutex);
1262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (ret != 0)
1272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ret;
1282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_add(&match->list, &xt[af].match);
1309e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
1312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ret;
1332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
1342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_register_match);
1352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid
137a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_unregister_match(struct xt_match *match)
1382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
139a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayuso	int af =  match->family;
140a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayuso
1419e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_lock(&xt[af].mutex);
142df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy	list_del(&match->list);
1439e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
1442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
1452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_unregister_match);
1462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
14752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyint
14852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyxt_register_matches(struct xt_match *match, unsigned int n)
14952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy{
15052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	unsigned int i;
15152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	int err = 0;
15252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
15352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	for (i = 0; i < n; i++) {
15452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		err = xt_register_match(&match[i]);
15552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		if (err)
15652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy			goto err;
15752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	}
15852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	return err;
15952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
16052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyerr:
16152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	if (i > 0)
16252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		xt_unregister_matches(match, i);
16352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	return err;
16452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy}
16552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyEXPORT_SYMBOL(xt_register_matches);
16652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
16752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyvoid
16852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyxt_unregister_matches(struct xt_match *match, unsigned int n)
16952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy{
17052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	unsigned int i;
17152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
17252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	for (i = 0; i < n; i++)
17352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		xt_unregister_match(&match[i]);
17452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy}
17552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyEXPORT_SYMBOL(xt_unregister_matches);
17652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
1772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/*
1792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * These are weird, but module loading must not be done with mutex
1802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * held (since they will register), and we have to have a single
1812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * function to use try_then_request_module().
1822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte */
1832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Find match, grabs ref.  Returns ERR_PTR() on error. */
1852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_match *xt_find_match(int af, const char *name, u8 revision)
1862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
1872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_match *m;
1882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int err = 0;
1892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1909e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	if (mutex_lock_interruptible(&xt[af].mutex) != 0)
1912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ERR_PTR(-EINTR);
1922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(m, &xt[af].match, list) {
1942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(m->name, name) == 0) {
1952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (m->revision == revision) {
1962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				if (try_module_get(m->me)) {
1979e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar					mutex_unlock(&xt[af].mutex);
1982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte					return m;
1992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				}
2002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			} else
2012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				err = -EPROTOTYPE; /* Found something. */
2022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
2032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
2049e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
2052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ERR_PTR(err);
2062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
2072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_find_match);
2082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Find target, grabs ref.  Returns ERR_PTR() on error. */
2102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_target *xt_find_target(int af, const char *name, u8 revision)
2112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
2122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_target *t;
2132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int err = 0;
2142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2159e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	if (mutex_lock_interruptible(&xt[af].mutex) != 0)
2162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ERR_PTR(-EINTR);
2172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(t, &xt[af].target, list) {
2192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(t->name, name) == 0) {
2202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (t->revision == revision) {
2212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				if (try_module_get(t->me)) {
2229e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar					mutex_unlock(&xt[af].mutex);
2232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte					return t;
2242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				}
2252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			} else
2262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				err = -EPROTOTYPE; /* Found something. */
2272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
2282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
2299e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
2302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ERR_PTR(err);
2312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
2322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_find_target);
2332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_target *xt_request_find_target(int af, const char *name, u8 revision)
2352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
2362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_target *target;
2372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	target = try_then_request_module(xt_find_target(af, name, revision),
23937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy					 "%st_%s", xt_prefix[af], name);
2402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (IS_ERR(target) || !target)
2412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
2422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return target;
2432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
2442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_request_find_target);
2452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic int match_revfn(int af, const char *name, u8 revision, int *bestp)
2472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
2482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_match *m;
2492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int have_rev = 0;
2502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(m, &xt[af].match, list) {
2522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(m->name, name) == 0) {
2532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (m->revision > *bestp)
2542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				*bestp = m->revision;
2552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (m->revision == revision)
2562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				have_rev = 1;
2572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
2582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
2592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return have_rev;
2602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
2612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic int target_revfn(int af, const char *name, u8 revision, int *bestp)
2632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
2642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_target *t;
2652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int have_rev = 0;
2662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(t, &xt[af].target, list) {
2682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(t->name, name) == 0) {
2692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (t->revision > *bestp)
2702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				*bestp = t->revision;
2712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (t->revision == revision)
2722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				have_rev = 1;
2732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
2742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
2752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return have_rev;
2762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
2772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Returns true or false (if no such extension at all) */
2792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteint xt_find_revision(int af, const char *name, u8 revision, int target,
2802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		     int *err)
2812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
2822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int have_rev, best = -1;
2832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2849e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	if (mutex_lock_interruptible(&xt[af].mutex) != 0) {
2852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		*err = -EINTR;
2862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return 1;
2872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
2882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (target == 1)
2892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		have_rev = target_revfn(af, name, revision, &best);
2902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	else
2912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		have_rev = match_revfn(af, name, revision, &best);
2929e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
2932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Nothing at all?  Return 0 to try loading module. */
2952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (best == -1) {
2962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		*err = -ENOENT;
2972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return 0;
2982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
2992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	*err = best;
3012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!have_rev)
3022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		*err = -EPROTONOSUPPORT;
3032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return 1;
3042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
3052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_find_revision);
3062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
30737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardyint xt_check_match(const struct xt_match *match, unsigned short family,
30837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy                   unsigned int size, const char *table, unsigned int hook_mask,
30937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		   unsigned short proto, int inv_proto)
31037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy{
31137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	if (XT_ALIGN(match->matchsize) != size) {
31237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s match: invalid size %Zu != %u\n",
31337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       xt_prefix[family], match->name,
31437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       XT_ALIGN(match->matchsize), size);
31537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
31637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
31737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	if (match->table && strcmp(match->table, table)) {
31837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s match: only valid in %s table, not %s\n",
31937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       xt_prefix[family], match->name, match->table, table);
32037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
32137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
32237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	if (match->hooks && (hook_mask & ~match->hooks) != 0) {
32337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s match: bad hook_mask %u\n",
32437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       xt_prefix[family], match->name, hook_mask);
32537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
32637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
32737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	if (match->proto && (match->proto != proto || inv_proto)) {
32837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s match: only valid for protocol %u\n",
32937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       xt_prefix[family], match->name, match->proto);
33037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
33137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
33237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	return 0;
33337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy}
33437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardyEXPORT_SYMBOL_GPL(xt_check_match);
33537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy
3362722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT
3379fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyint xt_compat_match_offset(struct xt_match *match)
3382722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{
3399fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	u_int16_t csize = match->compatsize ? : match->matchsize;
3409fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	return XT_ALIGN(match->matchsize) - COMPAT_XT_ALIGN(csize);
3419fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy}
3429fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_match_offset);
3439fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
3449fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyvoid xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr,
3459fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy			       int *size)
3469fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy{
3479fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	struct xt_match *match = m->u.kernel.match;
3489fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	struct compat_xt_entry_match *cm = (struct compat_xt_entry_match *)m;
3499fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	int pad, off = xt_compat_match_offset(match);
3509fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	u_int16_t msize = cm->u.user.match_size;
3519fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
3529fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	m = *dstptr;
3539fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	memcpy(m, cm, sizeof(*cm));
3549fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (match->compat_from_user)
3559fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		match->compat_from_user(m->data, cm->data);
3569fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	else
3579fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		memcpy(m->data, cm->data, msize - sizeof(*cm));
3589fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	pad = XT_ALIGN(match->matchsize) - match->matchsize;
3599fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (pad > 0)
3609fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		memset(m->data + match->matchsize, 0, pad);
3619fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
3629fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	msize += off;
3639fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	m->u.user.match_size = msize;
3649fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
3659fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*size += off;
3669fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*dstptr += msize;
3679fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy}
3689fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_match_from_user);
3699fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
3709fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyint xt_compat_match_to_user(struct xt_entry_match *m, void __user **dstptr,
3719fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy			    int *size)
3729fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy{
3739fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	struct xt_match *match = m->u.kernel.match;
3749fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	struct compat_xt_entry_match __user *cm = *dstptr;
3759fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	int off = xt_compat_match_offset(match);
3769fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	u_int16_t msize = m->u.user.match_size - off;
3779fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
3789fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (copy_to_user(cm, m, sizeof(*cm)) ||
3799fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	    put_user(msize, &cm->u.user.match_size))
3809fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	    	return -EFAULT;
3819fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
3829fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (match->compat_to_user) {
3839fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		if (match->compat_to_user((void __user *)cm->data, m->data))
3849fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy			return -EFAULT;
3859fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	} else {
3869fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		if (copy_to_user(cm->data, m->data, msize - sizeof(*cm)))
3879fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy			return -EFAULT;
3882722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	}
3899fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
3909fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*size -= off;
3919fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*dstptr += msize;
3929fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	return 0;
3932722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin}
3949fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_match_to_user);
3959fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy#endif /* CONFIG_COMPAT */
3962722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin
39737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardyint xt_check_target(const struct xt_target *target, unsigned short family,
39837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		    unsigned int size, const char *table, unsigned int hook_mask,
39937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		    unsigned short proto, int inv_proto)
40037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy{
40137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	if (XT_ALIGN(target->targetsize) != size) {
40237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s target: invalid size %Zu != %u\n",
40337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       xt_prefix[family], target->name,
40437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       XT_ALIGN(target->targetsize), size);
40537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
40637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
40737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	if (target->table && strcmp(target->table, table)) {
40837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s target: only valid in %s table, not %s\n",
40937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       xt_prefix[family], target->name, target->table, table);
41037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
41137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
41237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	if (target->hooks && (hook_mask & ~target->hooks) != 0) {
41337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s target: bad hook_mask %u\n",
41437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       xt_prefix[family], target->name, hook_mask);
41537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
41637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
41737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	if (target->proto && (target->proto != proto || inv_proto)) {
41837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s target: only valid for protocol %u\n",
41937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       xt_prefix[family], target->name, target->proto);
42037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
42137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
42237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	return 0;
42337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy}
42437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardyEXPORT_SYMBOL_GPL(xt_check_target);
42537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy
4262722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT
4279fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyint xt_compat_target_offset(struct xt_target *target)
4282722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{
4299fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	u_int16_t csize = target->compatsize ? : target->targetsize;
4309fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	return XT_ALIGN(target->targetsize) - COMPAT_XT_ALIGN(csize);
4319fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy}
4329fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_target_offset);
4339fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
4349fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyvoid xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr,
4359fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy			        int *size)
4369fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy{
4379fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	struct xt_target *target = t->u.kernel.target;
4389fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	struct compat_xt_entry_target *ct = (struct compat_xt_entry_target *)t;
4399fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	int pad, off = xt_compat_target_offset(target);
4409fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	u_int16_t tsize = ct->u.user.target_size;
4419fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
4429fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	t = *dstptr;
4439fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	memcpy(t, ct, sizeof(*ct));
4449fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (target->compat_from_user)
4459fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		target->compat_from_user(t->data, ct->data);
4469fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	else
4479fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		memcpy(t->data, ct->data, tsize - sizeof(*ct));
4489fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	pad = XT_ALIGN(target->targetsize) - target->targetsize;
4499fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (pad > 0)
4509fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		memset(t->data + target->targetsize, 0, pad);
4519fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
4529fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	tsize += off;
4539fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	t->u.user.target_size = tsize;
4549fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
4559fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*size += off;
4569fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*dstptr += tsize;
4579fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy}
4589fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_target_from_user);
4599fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
4609fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyint xt_compat_target_to_user(struct xt_entry_target *t, void __user **dstptr,
4619fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy			     int *size)
4629fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy{
4639fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	struct xt_target *target = t->u.kernel.target;
4649fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	struct compat_xt_entry_target __user *ct = *dstptr;
4659fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	int off = xt_compat_target_offset(target);
4669fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	u_int16_t tsize = t->u.user.target_size - off;
4679fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
4689fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (copy_to_user(ct, t, sizeof(*ct)) ||
4699fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	    put_user(tsize, &ct->u.user.target_size))
4709fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	    	return -EFAULT;
4719fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
4729fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (target->compat_to_user) {
4739fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		if (target->compat_to_user((void __user *)ct->data, t->data))
4749fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy			return -EFAULT;
4759fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	} else {
4769fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		if (copy_to_user(ct->data, t->data, tsize - sizeof(*ct)))
4779fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy			return -EFAULT;
4782722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	}
4799fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
4809fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*size -= off;
4819fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*dstptr += tsize;
4829fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	return 0;
4832722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin}
4849fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_target_to_user);
4852722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#endif
4862722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin
4872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_table_info *xt_alloc_table_info(unsigned int size)
4882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
4892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table_info *newinfo;
4902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int cpu;
4912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
4932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if ((SMP_ALIGN(size) >> PAGE_SHIFT) + 2 > num_physpages)
4942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
4952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	newinfo = kzalloc(sizeof(struct xt_table_info), GFP_KERNEL);
4972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!newinfo)
4982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
4992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	newinfo->size = size;
5012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5026f912042256c12b0927438122594f5379b364f5dKAMEZAWA Hiroyuki	for_each_possible_cpu(cpu) {
5032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (size <= PAGE_SIZE)
5042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			newinfo->entries[cpu] = kmalloc_node(size,
5052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte							GFP_KERNEL,
5062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte							cpu_to_node(cpu));
5072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		else
5082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			newinfo->entries[cpu] = vmalloc_node(size,
5092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte							cpu_to_node(cpu));
5102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (newinfo->entries[cpu] == NULL) {
5122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			xt_free_table_info(newinfo);
5132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			return NULL;
5142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
5152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
5162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return newinfo;
5182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
5192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_alloc_table_info);
5202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid xt_free_table_info(struct xt_table_info *info)
5222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
5232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int cpu;
5242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5256f912042256c12b0927438122594f5379b364f5dKAMEZAWA Hiroyuki	for_each_possible_cpu(cpu) {
5262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (info->size <= PAGE_SIZE)
5272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			kfree(info->entries[cpu]);
5282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		else
5292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			vfree(info->entries[cpu]);
5302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
5312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	kfree(info);
5322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
5332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_free_table_info);
5342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Find table by name, grabs mutex & ref.  Returns ERR_PTR() on error. */
5362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_table *xt_find_table_lock(int af, const char *name)
5372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
5382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table *t;
5392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5409e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	if (mutex_lock_interruptible(&xt[af].mutex) != 0)
5412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ERR_PTR(-EINTR);
5422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(t, &xt[af].tables, list)
5442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(t->name, name) == 0 && try_module_get(t->me))
5452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			return t;
5469e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
5472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return NULL;
5482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
5492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_find_table_lock);
5502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid xt_table_unlock(struct xt_table *table)
5522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
5539e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[table->af].mutex);
5542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
5552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_table_unlock);
5562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5572722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT
5582722971cbe831117686039d5c334f2c0f560be13Dmitry Mishinvoid xt_compat_lock(int af)
5592722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{
5602722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	mutex_lock(&xt[af].compat_mutex);
5612722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin}
5622722971cbe831117686039d5c334f2c0f560be13Dmitry MishinEXPORT_SYMBOL_GPL(xt_compat_lock);
5632722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin
5642722971cbe831117686039d5c334f2c0f560be13Dmitry Mishinvoid xt_compat_unlock(int af)
5652722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{
5662722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	mutex_unlock(&xt[af].compat_mutex);
5672722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin}
5682722971cbe831117686039d5c334f2c0f560be13Dmitry MishinEXPORT_SYMBOL_GPL(xt_compat_unlock);
5692722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#endif
5702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_table_info *
5722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltext_replace_table(struct xt_table *table,
5732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	      unsigned int num_counters,
5742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	      struct xt_table_info *newinfo,
5752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	      int *error)
5762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
5772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table_info *oldinfo, *private;
5782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Do the substitution. */
5802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	write_lock_bh(&table->lock);
5812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	private = table->private;
5822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Check inside lock: is the old number correct? */
5832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (num_counters != private->number) {
5842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		duprintf("num_counters != table->private->number (%u/%u)\n",
5852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			 num_counters, private->number);
5862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		write_unlock_bh(&table->lock);
5872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		*error = -EAGAIN;
5882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
5892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
5902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	oldinfo = private;
5912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	table->private = newinfo;
5922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	newinfo->initial_entries = oldinfo->initial_entries;
5932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	write_unlock_bh(&table->lock);
5942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return oldinfo;
5962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
5972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_replace_table);
5982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteint xt_register_table(struct xt_table *table,
6002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		      struct xt_table_info *bootstrap,
6012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		      struct xt_table_info *newinfo)
6022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
6032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int ret;
6042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table_info *private;
605df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy	struct xt_table *t;
6062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6079e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	ret = mutex_lock_interruptible(&xt[table->af].mutex);
6082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (ret != 0)
6092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ret;
6102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Don't autoload: we'd eat our tail... */
612df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy	list_for_each_entry(t, &xt[table->af].tables, list) {
613df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy		if (strcmp(t->name, table->name) == 0) {
614df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy			ret = -EEXIST;
615df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy			goto unlock;
616df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy		}
6172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
6182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Simplifies replace_table code. */
6202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	table->private = bootstrap;
62191536b7ae67710ca888e03ea82c60f0ac073a015Dmitry Mishin	rwlock_init(&table->lock);
6222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!xt_replace_table(table, 0, newinfo, &ret))
6232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto unlock;
6242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	private = table->private;
6262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	duprintf("table->private->number = %u\n", private->number);
6272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* save number of initial entries */
6292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	private->initial_entries = private->number;
6302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
631df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy	list_add(&table->list, &xt[table->af].tables);
6322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	ret = 0;
6342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte unlock:
6359e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[table->af].mutex);
6362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ret;
6372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
6382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_register_table);
6392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid *xt_unregister_table(struct xt_table *table)
6412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
6422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table_info *private;
6432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6449e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_lock(&xt[table->af].mutex);
6452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	private = table->private;
646df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy	list_del(&table->list);
6479e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[table->af].mutex);
6482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return private;
6502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
6512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_unregister_table);
6522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
6542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic char *xt_proto_prefix[NPROTO] = {
6552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	[AF_INET]	= "ip",
6562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	[AF_INET6]	= "ip6",
6572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	[NF_ARP]	= "arp",
6582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte};
6592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic struct list_head *xt_get_idx(struct list_head *list, struct seq_file *seq, loff_t pos)
6612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
6622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct list_head *head = list->next;
6632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!head || list_empty(list))
6652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
6662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	while (pos && (head = head->next)) {
6682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (head == list)
6692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			return NULL;
6702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		pos--;
6712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
6722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return pos ? NULL : head;
6732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
6742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic struct list_head *type2list(u_int16_t af, u_int16_t type)
6762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
6772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct list_head *list;
6782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	switch (type) {
6802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	case TARGET:
6812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		list = &xt[af].target;
6822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		break;
6832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	case MATCH:
6842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		list = &xt[af].match;
6852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		break;
6862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	case TABLE:
6872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		list = &xt[af].tables;
6882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		break;
6892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	default:
6902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		list = NULL;
6912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		break;
6922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
6932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return list;
6952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
6962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic void *xt_tgt_seq_start(struct seq_file *seq, loff_t *pos)
6982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
6992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct proc_dir_entry *pde = (struct proc_dir_entry *) seq->private;
7002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	u_int16_t af = (unsigned long)pde->data & 0xffff;
7012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	u_int16_t type = (unsigned long)pde->data >> 16;
7022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct list_head *list;
7032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (af >= NPROTO)
7052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
7062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list = type2list(af, type);
7082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!list)
7092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
7102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7119e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	if (mutex_lock_interruptible(&xt[af].mutex) != 0)
7122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
7132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return xt_get_idx(list, seq, *pos);
7152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
7162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic void *xt_tgt_seq_next(struct seq_file *seq, void *v, loff_t *pos)
7182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
7192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct proc_dir_entry *pde = seq->private;
7202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	u_int16_t af = (unsigned long)pde->data & 0xffff;
7212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	u_int16_t type = (unsigned long)pde->data >> 16;
7222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct list_head *list;
7232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (af >= NPROTO)
7252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
7262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list = type2list(af, type);
7282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!list)
7292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
7302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	(*pos)++;
7322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return xt_get_idx(list, seq, *pos);
7332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
7342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic void xt_tgt_seq_stop(struct seq_file *seq, void *v)
7362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
7372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct proc_dir_entry *pde = seq->private;
7382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	u_int16_t af = (unsigned long)pde->data & 0xffff;
7392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7409e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
7412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
7422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic int xt_name_seq_show(struct seq_file *seq, void *v)
7442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
7452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	char *name = (char *)v + sizeof(struct list_head);
7462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (strlen(name))
7482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return seq_printf(seq, "%s\n", name);
7492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	else
7502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return 0;
7512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
7522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic struct seq_operations xt_tgt_seq_ops = {
7542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.start	= xt_tgt_seq_start,
7552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.next	= xt_tgt_seq_next,
7562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.stop	= xt_tgt_seq_stop,
7572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.show	= xt_name_seq_show,
7582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte};
7592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic int xt_tgt_open(struct inode *inode, struct file *file)
7612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
7622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int ret;
7632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	ret = seq_open(file, &xt_tgt_seq_ops);
7652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!ret) {
7662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		struct seq_file *seq = file->private_data;
7672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		struct proc_dir_entry *pde = PDE(inode);
7682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		seq->private = pde;
7702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
7712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ret;
7732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
7742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic struct file_operations xt_file_ops = {
7762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.owner	 = THIS_MODULE,
7772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.open	 = xt_tgt_open,
7782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.read	 = seq_read,
7792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.llseek	 = seq_lseek,
7802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.release = seq_release,
7812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte};
7822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define FORMAT_TABLES	"_tables_names"
7842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define	FORMAT_MATCHES	"_tables_matches"
7852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define FORMAT_TARGETS 	"_tables_targets"
7862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif /* CONFIG_PROC_FS */
7882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteint xt_proto_init(int af)
7902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
7912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
7922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	char buf[XT_FUNCTION_MAXNAMELEN];
7932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct proc_dir_entry *proc;
7942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif
7952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (af >= NPROTO)
7972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return -EINVAL;
7982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
8012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
8022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TABLES, sizeof(buf));
8032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc = proc_net_fops_create(buf, 0440, &xt_file_ops);
8042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!proc)
8052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto out;
8062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc->data = (void *) ((unsigned long) af | (TABLE << 16));
8072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
8102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
8112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc = proc_net_fops_create(buf, 0440, &xt_file_ops);
8122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!proc)
8132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto out_remove_tables;
8142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc->data = (void *) ((unsigned long) af | (MATCH << 16));
8152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
8172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TARGETS, sizeof(buf));
8182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc = proc_net_fops_create(buf, 0440, &xt_file_ops);
8192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!proc)
8202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto out_remove_matches;
8212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc->data = (void *) ((unsigned long) af | (TARGET << 16));
8222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif
8232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return 0;
8252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
8272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteout_remove_matches:
8282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
8292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
8302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc_net_remove(buf);
8312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteout_remove_tables:
8332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
8342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TABLES, sizeof(buf));
8352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc_net_remove(buf);
8362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteout:
8372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return -1;
8382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif
8392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
8402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_proto_init);
8412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid xt_proto_fini(int af)
8432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
8442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
8452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	char buf[XT_FUNCTION_MAXNAMELEN];
8462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
8482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TABLES, sizeof(buf));
8492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc_net_remove(buf);
8502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
8522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TARGETS, sizeof(buf));
8532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc_net_remove(buf);
8542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
8562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
8572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc_net_remove(buf);
8582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif /*CONFIG_PROC_FS*/
8592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
8602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_proto_fini);
8612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic int __init xt_init(void)
8642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
8652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int i;
8662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	xt = kmalloc(sizeof(struct xt_af) * NPROTO, GFP_KERNEL);
8682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!xt)
8692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return -ENOMEM;
8702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	for (i = 0; i < NPROTO; i++) {
8729e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar		mutex_init(&xt[i].mutex);
8732722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT
8742722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin		mutex_init(&xt[i].compat_mutex);
8752722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#endif
8762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		INIT_LIST_HEAD(&xt[i].target);
8772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		INIT_LIST_HEAD(&xt[i].match);
8782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		INIT_LIST_HEAD(&xt[i].tables);
8792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
8802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return 0;
8812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
8822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic void __exit xt_fini(void)
8842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
8852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	kfree(xt);
8862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
8872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltemodule_init(xt_init);
8892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltemodule_exit(xt_fini);
8902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
891