x_tables.c revision 2722971cbe831117686039d5c334f2c0f560be13
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/config.h>
172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/kernel.h>
182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/socket.h>
192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/net.h>
202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/proc_fs.h>
212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/seq_file.h>
222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/string.h>
232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/vmalloc.h>
249e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar#include <linux/mutex.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);
852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	LIST_DELETE(&xt[af].target, target);
869e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_unregister_target);
892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteint
91a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_register_match(struct xt_match *match)
922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
93a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayuso	int ret, af = match->family;
942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
959e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	ret = mutex_lock_interruptible(&xt[af].mutex);
962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (ret != 0)
972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ret;
982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_add(&match->list, &xt[af].match);
1009e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
1012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ret;
1032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
1042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_register_match);
1052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid
107a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_unregister_match(struct xt_match *match)
1082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
109a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayuso	int af =  match->family;
110a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayuso
1119e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_lock(&xt[af].mutex);
1122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	LIST_DELETE(&xt[af].match, match);
1139e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
1142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
1152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_unregister_match);
1162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/*
1192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * These are weird, but module loading must not be done with mutex
1202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * held (since they will register), and we have to have a single
1212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * function to use try_then_request_module().
1222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte */
1232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Find match, grabs ref.  Returns ERR_PTR() on error. */
1252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_match *xt_find_match(int af, const char *name, u8 revision)
1262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
1272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_match *m;
1282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int err = 0;
1292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1309e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	if (mutex_lock_interruptible(&xt[af].mutex) != 0)
1312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ERR_PTR(-EINTR);
1322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(m, &xt[af].match, list) {
1342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(m->name, name) == 0) {
1352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (m->revision == revision) {
1362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				if (try_module_get(m->me)) {
1379e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar					mutex_unlock(&xt[af].mutex);
1382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte					return m;
1392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				}
1402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			} else
1412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				err = -EPROTOTYPE; /* Found something. */
1422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
1432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
1449e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
1452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ERR_PTR(err);
1462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
1472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_find_match);
1482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Find target, grabs ref.  Returns ERR_PTR() on error. */
1502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_target *xt_find_target(int af, const char *name, u8 revision)
1512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
1522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_target *t;
1532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int err = 0;
1542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1559e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	if (mutex_lock_interruptible(&xt[af].mutex) != 0)
1562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ERR_PTR(-EINTR);
1572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(t, &xt[af].target, list) {
1592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(t->name, name) == 0) {
1602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (t->revision == revision) {
1612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				if (try_module_get(t->me)) {
1629e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar					mutex_unlock(&xt[af].mutex);
1632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte					return t;
1642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				}
1652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			} else
1662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				err = -EPROTOTYPE; /* Found something. */
1672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
1682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
1699e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
1702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ERR_PTR(err);
1712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
1722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_find_target);
1732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_target *xt_request_find_target(int af, const char *name, u8 revision)
1752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
1762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_target *target;
1772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	target = try_then_request_module(xt_find_target(af, name, revision),
17937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy					 "%st_%s", xt_prefix[af], name);
1802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (IS_ERR(target) || !target)
1812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
1822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return target;
1832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
1842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_request_find_target);
1852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic int match_revfn(int af, const char *name, u8 revision, int *bestp)
1872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
1882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_match *m;
1892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int have_rev = 0;
1902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(m, &xt[af].match, list) {
1922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(m->name, name) == 0) {
1932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (m->revision > *bestp)
1942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				*bestp = m->revision;
1952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (m->revision == revision)
1962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				have_rev = 1;
1972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
1982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
1992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return have_rev;
2002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
2012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic int target_revfn(int af, const char *name, u8 revision, int *bestp)
2032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
2042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_target *t;
2052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int have_rev = 0;
2062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(t, &xt[af].target, list) {
2082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(t->name, name) == 0) {
2092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (t->revision > *bestp)
2102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				*bestp = t->revision;
2112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (t->revision == revision)
2122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				have_rev = 1;
2132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
2142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
2152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return have_rev;
2162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
2172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Returns true or false (if no such extension at all) */
2192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteint xt_find_revision(int af, const char *name, u8 revision, int target,
2202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		     int *err)
2212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
2222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int have_rev, best = -1;
2232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2249e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	if (mutex_lock_interruptible(&xt[af].mutex) != 0) {
2252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		*err = -EINTR;
2262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return 1;
2272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
2282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (target == 1)
2292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		have_rev = target_revfn(af, name, revision, &best);
2302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	else
2312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		have_rev = match_revfn(af, name, revision, &best);
2329e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
2332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Nothing at all?  Return 0 to try loading module. */
2352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (best == -1) {
2362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		*err = -ENOENT;
2372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return 0;
2382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
2392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	*err = best;
2412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!have_rev)
2422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		*err = -EPROTONOSUPPORT;
2432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return 1;
2442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
2452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_find_revision);
2462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
24737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardyint xt_check_match(const struct xt_match *match, unsigned short family,
24837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy                   unsigned int size, const char *table, unsigned int hook_mask,
24937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		   unsigned short proto, int inv_proto)
25037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy{
25137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	if (XT_ALIGN(match->matchsize) != size) {
25237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s match: invalid size %Zu != %u\n",
25337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       xt_prefix[family], match->name,
25437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       XT_ALIGN(match->matchsize), size);
25537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
25637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
25737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	if (match->table && strcmp(match->table, table)) {
25837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s match: only valid in %s table, not %s\n",
25937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       xt_prefix[family], match->name, match->table, table);
26037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
26137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
26237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	if (match->hooks && (hook_mask & ~match->hooks) != 0) {
26337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s match: bad hook_mask %u\n",
26437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       xt_prefix[family], match->name, hook_mask);
26537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
26637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
26737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	if (match->proto && (match->proto != proto || inv_proto)) {
26837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s match: only valid for protocol %u\n",
26937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       xt_prefix[family], match->name, match->proto);
27037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
27137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
27237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	return 0;
27337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy}
27437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardyEXPORT_SYMBOL_GPL(xt_check_match);
27537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy
2762722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT
2772722971cbe831117686039d5c334f2c0f560be13Dmitry Mishinint xt_compat_match(void *match, void **dstptr, int *size, int convert)
2782722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{
2792722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	struct xt_match *m;
2802722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	struct compat_xt_entry_match *pcompat_m;
2812722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	struct xt_entry_match *pm;
2822722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	u_int16_t msize;
2832722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	int off, ret;
2842722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin
2852722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	ret = 0;
2862722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	m = ((struct xt_entry_match *)match)->u.kernel.match;
2872722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	off = XT_ALIGN(m->matchsize) - COMPAT_XT_ALIGN(m->matchsize);
2882722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	switch (convert) {
2892722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin		case COMPAT_TO_USER:
2902722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			pm = (struct xt_entry_match *)match;
2912722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			msize = pm->u.user.match_size;
2922722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			if (__copy_to_user(*dstptr, pm, msize)) {
2932722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin				ret = -EFAULT;
2942722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin				break;
2952722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			}
2962722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			msize -= off;
2972722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			if (put_user(msize, (u_int16_t *)*dstptr))
2982722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin				ret = -EFAULT;
2992722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			*size -= off;
3002722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			*dstptr += msize;
3012722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			break;
3022722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin		case COMPAT_FROM_USER:
3032722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			pcompat_m = (struct compat_xt_entry_match *)match;
3042722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			pm = (struct xt_entry_match *)*dstptr;
3052722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			msize = pcompat_m->u.user.match_size;
3062722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			memcpy(pm, pcompat_m, msize);
3072722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			msize += off;
3082722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			pm->u.user.match_size = msize;
3092722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			*size += off;
3102722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			*dstptr += msize;
3112722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			break;
3122722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin		case COMPAT_CALC_SIZE:
3132722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			*size += off;
3142722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			break;
3152722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin		default:
3162722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			ret = -ENOPROTOOPT;
3172722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			break;
3182722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	}
3192722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	return ret;
3202722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin}
3212722971cbe831117686039d5c334f2c0f560be13Dmitry MishinEXPORT_SYMBOL_GPL(xt_compat_match);
3222722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#endif
3232722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin
32437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardyint xt_check_target(const struct xt_target *target, unsigned short family,
32537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		    unsigned int size, const char *table, unsigned int hook_mask,
32637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		    unsigned short proto, int inv_proto)
32737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy{
32837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	if (XT_ALIGN(target->targetsize) != size) {
32937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s target: invalid size %Zu != %u\n",
33037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       xt_prefix[family], target->name,
33137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       XT_ALIGN(target->targetsize), size);
33237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
33337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
33437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	if (target->table && strcmp(target->table, table)) {
33537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s target: only valid in %s table, not %s\n",
33637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       xt_prefix[family], target->name, target->table, table);
33737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
33837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
33937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	if (target->hooks && (hook_mask & ~target->hooks) != 0) {
34037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s target: bad hook_mask %u\n",
34137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       xt_prefix[family], target->name, hook_mask);
34237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
34337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
34437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	if (target->proto && (target->proto != proto || inv_proto)) {
34537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s target: only valid for protocol %u\n",
34637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       xt_prefix[family], target->name, target->proto);
34737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
34837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
34937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	return 0;
35037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy}
35137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardyEXPORT_SYMBOL_GPL(xt_check_target);
35237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy
3532722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT
3542722971cbe831117686039d5c334f2c0f560be13Dmitry Mishinint xt_compat_target(void *target, void **dstptr, int *size, int convert)
3552722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{
3562722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	struct xt_target *t;
3572722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	struct compat_xt_entry_target *pcompat;
3582722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	struct xt_entry_target *pt;
3592722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	u_int16_t tsize;
3602722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	int off, ret;
3612722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin
3622722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	ret = 0;
3632722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	t = ((struct xt_entry_target *)target)->u.kernel.target;
3642722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	off = XT_ALIGN(t->targetsize) - COMPAT_XT_ALIGN(t->targetsize);
3652722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	switch (convert) {
3662722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin		case COMPAT_TO_USER:
3672722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			pt = (struct xt_entry_target *)target;
3682722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			tsize = pt->u.user.target_size;
3692722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			if (__copy_to_user(*dstptr, pt, tsize)) {
3702722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin				ret = -EFAULT;
3712722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin				break;
3722722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			}
3732722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			tsize -= off;
3742722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			if (put_user(tsize, (u_int16_t *)*dstptr))
3752722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin				ret = -EFAULT;
3762722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			*size -= off;
3772722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			*dstptr += tsize;
3782722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			break;
3792722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin		case COMPAT_FROM_USER:
3802722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			pcompat = (struct compat_xt_entry_target *)target;
3812722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			pt = (struct xt_entry_target *)*dstptr;
3822722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			tsize = pcompat->u.user.target_size;
3832722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			memcpy(pt, pcompat, tsize);
3842722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			tsize += off;
3852722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			pt->u.user.target_size = tsize;
3862722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			*size += off;
3872722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			*dstptr += tsize;
3882722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			break;
3892722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin		case COMPAT_CALC_SIZE:
3902722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			*size += off;
3912722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			break;
3922722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin		default:
3932722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			ret = -ENOPROTOOPT;
3942722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			break;
3952722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	}
3962722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	return ret;
3972722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin}
3982722971cbe831117686039d5c334f2c0f560be13Dmitry MishinEXPORT_SYMBOL_GPL(xt_compat_target);
3992722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#endif
4002722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin
4012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_table_info *xt_alloc_table_info(unsigned int size)
4022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
4032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table_info *newinfo;
4042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int cpu;
4052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
4072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if ((SMP_ALIGN(size) >> PAGE_SHIFT) + 2 > num_physpages)
4082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
4092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	newinfo = kzalloc(sizeof(struct xt_table_info), GFP_KERNEL);
4112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!newinfo)
4122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
4132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	newinfo->size = size;
4152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	for_each_cpu(cpu) {
4172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (size <= PAGE_SIZE)
4182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			newinfo->entries[cpu] = kmalloc_node(size,
4192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte							GFP_KERNEL,
4202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte							cpu_to_node(cpu));
4212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		else
4222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			newinfo->entries[cpu] = vmalloc_node(size,
4232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte							cpu_to_node(cpu));
4242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (newinfo->entries[cpu] == NULL) {
4262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			xt_free_table_info(newinfo);
4272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			return NULL;
4282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
4292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
4302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return newinfo;
4322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
4332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_alloc_table_info);
4342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid xt_free_table_info(struct xt_table_info *info)
4362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
4372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int cpu;
4382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	for_each_cpu(cpu) {
4402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (info->size <= PAGE_SIZE)
4412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			kfree(info->entries[cpu]);
4422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		else
4432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			vfree(info->entries[cpu]);
4442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
4452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	kfree(info);
4462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
4472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_free_table_info);
4482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Find table by name, grabs mutex & ref.  Returns ERR_PTR() on error. */
4502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_table *xt_find_table_lock(int af, const char *name)
4512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
4522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table *t;
4532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4549e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	if (mutex_lock_interruptible(&xt[af].mutex) != 0)
4552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ERR_PTR(-EINTR);
4562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(t, &xt[af].tables, list)
4582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(t->name, name) == 0 && try_module_get(t->me))
4592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			return t;
4609e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
4612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return NULL;
4622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
4632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_find_table_lock);
4642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid xt_table_unlock(struct xt_table *table)
4662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
4679e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[table->af].mutex);
4682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
4692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_table_unlock);
4702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4712722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT
4722722971cbe831117686039d5c334f2c0f560be13Dmitry Mishinvoid xt_compat_lock(int af)
4732722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{
4742722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	mutex_lock(&xt[af].compat_mutex);
4752722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin}
4762722971cbe831117686039d5c334f2c0f560be13Dmitry MishinEXPORT_SYMBOL_GPL(xt_compat_lock);
4772722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin
4782722971cbe831117686039d5c334f2c0f560be13Dmitry Mishinvoid xt_compat_unlock(int af)
4792722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{
4802722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	mutex_unlock(&xt[af].compat_mutex);
4812722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin}
4822722971cbe831117686039d5c334f2c0f560be13Dmitry MishinEXPORT_SYMBOL_GPL(xt_compat_unlock);
4832722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#endif
4842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_table_info *
4862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltext_replace_table(struct xt_table *table,
4872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	      unsigned int num_counters,
4882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	      struct xt_table_info *newinfo,
4892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	      int *error)
4902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
4912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table_info *oldinfo, *private;
4922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Do the substitution. */
4942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	write_lock_bh(&table->lock);
4952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	private = table->private;
4962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Check inside lock: is the old number correct? */
4972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (num_counters != private->number) {
4982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		duprintf("num_counters != table->private->number (%u/%u)\n",
4992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			 num_counters, private->number);
5002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		write_unlock_bh(&table->lock);
5012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		*error = -EAGAIN;
5022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
5032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
5042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	oldinfo = private;
5052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	table->private = newinfo;
5062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	newinfo->initial_entries = oldinfo->initial_entries;
5072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	write_unlock_bh(&table->lock);
5082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return oldinfo;
5102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
5112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_replace_table);
5122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteint xt_register_table(struct xt_table *table,
5142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		      struct xt_table_info *bootstrap,
5152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		      struct xt_table_info *newinfo)
5162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
5172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int ret;
5182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table_info *private;
5192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5209e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	ret = mutex_lock_interruptible(&xt[table->af].mutex);
5212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (ret != 0)
5222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ret;
5232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Don't autoload: we'd eat our tail... */
5252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (list_named_find(&xt[table->af].tables, table->name)) {
5262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		ret = -EEXIST;
5272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto unlock;
5282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
5292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Simplifies replace_table code. */
5312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	table->private = bootstrap;
5322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!xt_replace_table(table, 0, newinfo, &ret))
5332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto unlock;
5342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	private = table->private;
5362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	duprintf("table->private->number = %u\n", private->number);
5372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* save number of initial entries */
5392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	private->initial_entries = private->number;
5402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	rwlock_init(&table->lock);
5422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_prepend(&xt[table->af].tables, table);
5432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	ret = 0;
5452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte unlock:
5469e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[table->af].mutex);
5472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ret;
5482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
5492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_register_table);
5502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid *xt_unregister_table(struct xt_table *table)
5522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
5532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table_info *private;
5542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5559e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_lock(&xt[table->af].mutex);
5562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	private = table->private;
5572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	LIST_DELETE(&xt[table->af].tables, table);
5589e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[table->af].mutex);
5592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return private;
5612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
5622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_unregister_table);
5632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
5652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic char *xt_proto_prefix[NPROTO] = {
5662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	[AF_INET]	= "ip",
5672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	[AF_INET6]	= "ip6",
5682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	[NF_ARP]	= "arp",
5692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte};
5702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic struct list_head *xt_get_idx(struct list_head *list, struct seq_file *seq, loff_t pos)
5722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
5732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct list_head *head = list->next;
5742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!head || list_empty(list))
5762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
5772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	while (pos && (head = head->next)) {
5792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (head == list)
5802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			return NULL;
5812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		pos--;
5822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
5832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return pos ? NULL : head;
5842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
5852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic struct list_head *type2list(u_int16_t af, u_int16_t type)
5872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
5882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct list_head *list;
5892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	switch (type) {
5912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	case TARGET:
5922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		list = &xt[af].target;
5932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		break;
5942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	case MATCH:
5952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		list = &xt[af].match;
5962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		break;
5972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	case TABLE:
5982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		list = &xt[af].tables;
5992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		break;
6002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	default:
6012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		list = NULL;
6022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		break;
6032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
6042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return list;
6062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
6072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic void *xt_tgt_seq_start(struct seq_file *seq, loff_t *pos)
6092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
6102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct proc_dir_entry *pde = (struct proc_dir_entry *) seq->private;
6112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	u_int16_t af = (unsigned long)pde->data & 0xffff;
6122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	u_int16_t type = (unsigned long)pde->data >> 16;
6132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct list_head *list;
6142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (af >= NPROTO)
6162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
6172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list = type2list(af, type);
6192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!list)
6202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
6212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6229e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	if (mutex_lock_interruptible(&xt[af].mutex) != 0)
6232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
6242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return xt_get_idx(list, seq, *pos);
6262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
6272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic void *xt_tgt_seq_next(struct seq_file *seq, void *v, loff_t *pos)
6292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
6302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct proc_dir_entry *pde = seq->private;
6312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	u_int16_t af = (unsigned long)pde->data & 0xffff;
6322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	u_int16_t type = (unsigned long)pde->data >> 16;
6332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct list_head *list;
6342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (af >= NPROTO)
6362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
6372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list = type2list(af, type);
6392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!list)
6402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
6412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	(*pos)++;
6432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return xt_get_idx(list, seq, *pos);
6442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
6452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic void xt_tgt_seq_stop(struct seq_file *seq, void *v)
6472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
6482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct proc_dir_entry *pde = seq->private;
6492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	u_int16_t af = (unsigned long)pde->data & 0xffff;
6502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6519e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
6522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
6532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic int xt_name_seq_show(struct seq_file *seq, void *v)
6552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
6562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	char *name = (char *)v + sizeof(struct list_head);
6572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (strlen(name))
6592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return seq_printf(seq, "%s\n", name);
6602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	else
6612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return 0;
6622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
6632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic struct seq_operations xt_tgt_seq_ops = {
6652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.start	= xt_tgt_seq_start,
6662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.next	= xt_tgt_seq_next,
6672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.stop	= xt_tgt_seq_stop,
6682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.show	= xt_name_seq_show,
6692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte};
6702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic int xt_tgt_open(struct inode *inode, struct file *file)
6722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
6732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int ret;
6742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	ret = seq_open(file, &xt_tgt_seq_ops);
6762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!ret) {
6772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		struct seq_file *seq = file->private_data;
6782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		struct proc_dir_entry *pde = PDE(inode);
6792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		seq->private = pde;
6812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
6822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ret;
6842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
6852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic struct file_operations xt_file_ops = {
6872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.owner	 = THIS_MODULE,
6882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.open	 = xt_tgt_open,
6892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.read	 = seq_read,
6902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.llseek	 = seq_lseek,
6912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.release = seq_release,
6922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte};
6932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define FORMAT_TABLES	"_tables_names"
6952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define	FORMAT_MATCHES	"_tables_matches"
6962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define FORMAT_TARGETS 	"_tables_targets"
6972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif /* CONFIG_PROC_FS */
6992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteint xt_proto_init(int af)
7012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
7022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
7032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	char buf[XT_FUNCTION_MAXNAMELEN];
7042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct proc_dir_entry *proc;
7052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif
7062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (af >= NPROTO)
7082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return -EINVAL;
7092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
7122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
7132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TABLES, sizeof(buf));
7142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc = proc_net_fops_create(buf, 0440, &xt_file_ops);
7152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!proc)
7162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto out;
7172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc->data = (void *) ((unsigned long) af | (TABLE << 16));
7182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
7212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
7222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc = proc_net_fops_create(buf, 0440, &xt_file_ops);
7232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!proc)
7242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto out_remove_tables;
7252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc->data = (void *) ((unsigned long) af | (MATCH << 16));
7262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
7282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TARGETS, sizeof(buf));
7292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc = proc_net_fops_create(buf, 0440, &xt_file_ops);
7302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!proc)
7312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto out_remove_matches;
7322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc->data = (void *) ((unsigned long) af | (TARGET << 16));
7332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif
7342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return 0;
7362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
7382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteout_remove_matches:
7392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
7402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
7412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc_net_remove(buf);
7422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteout_remove_tables:
7442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
7452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TABLES, sizeof(buf));
7462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc_net_remove(buf);
7472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteout:
7482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return -1;
7492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif
7502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
7512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_proto_init);
7522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid xt_proto_fini(int af)
7542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
7552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
7562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	char buf[XT_FUNCTION_MAXNAMELEN];
7572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
7592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TABLES, sizeof(buf));
7602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc_net_remove(buf);
7612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
7632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TARGETS, sizeof(buf));
7642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc_net_remove(buf);
7652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
7672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
7682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc_net_remove(buf);
7692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif /*CONFIG_PROC_FS*/
7702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
7712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_proto_fini);
7722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic int __init xt_init(void)
7752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
7762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int i;
7772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	xt = kmalloc(sizeof(struct xt_af) * NPROTO, GFP_KERNEL);
7792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!xt)
7802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return -ENOMEM;
7812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	for (i = 0; i < NPROTO; i++) {
7839e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar		mutex_init(&xt[i].mutex);
7842722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT
7852722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin		mutex_init(&xt[i].compat_mutex);
7862722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#endif
7872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		INIT_LIST_HEAD(&xt[i].target);
7882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		INIT_LIST_HEAD(&xt[i].match);
7892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		INIT_LIST_HEAD(&xt[i].tables);
7902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
7912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return 0;
7922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
7932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic void __exit xt_fini(void)
7952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
7962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	kfree(xt);
7972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
7982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltemodule_init(xt_init);
8002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltemodule_exit(xt_fini);
8012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
802