x_tables.c revision df0933dcb027e156cb5253570ad694b81bd52b69
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>
242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/netfilter/x_tables.h>
262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/netfilter_arp.h>
272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
289e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar
292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteMODULE_LICENSE("GPL");
302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteMODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteMODULE_DESCRIPTION("[ip,ip6,arp]_tables backend module");
322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_af {
369e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	struct mutex mutex;
372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct list_head match;
382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct list_head target;
392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct list_head tables;
402722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	struct mutex compat_mutex;
412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte};
422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic struct xt_af *xt;
442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef DEBUG_IP_FIREWALL_USER
462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define duprintf(format, args...) printk(format , ## args)
472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#else
482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define duprintf(format, args...)
492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif
502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteenum {
522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	TABLE,
532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	TARGET,
542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	MATCH,
552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte};
562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardystatic const char *xt_prefix[NPROTO] = {
5837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	[AF_INET] 	= "ip",
5937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	[AF_INET6] 	= "ip6",
6037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	[NF_ARP]	= "arp",
6137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy};
6237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy
632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Registration hooks for targets. */
642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteint
65a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_register_target(struct xt_target *target)
662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
67a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayuso	int ret, af = target->family;
682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
699e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	ret = mutex_lock_interruptible(&xt[af].mutex);
702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (ret != 0)
712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ret;
722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_add(&target->list, &xt[af].target);
739e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ret;
752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_register_target);
772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid
79a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_unregister_target(struct xt_target *target)
802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
81a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayuso	int af = target->family;
82a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayuso
839e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_lock(&xt[af].mutex);
84df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy	list_del(&target->list);
859e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_unregister_target);
882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteint
9052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyxt_register_targets(struct xt_target *target, unsigned int n)
9152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy{
9252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	unsigned int i;
9352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	int err = 0;
9452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
9552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	for (i = 0; i < n; i++) {
9652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		err = xt_register_target(&target[i]);
9752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		if (err)
9852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy			goto err;
9952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	}
10052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	return err;
10152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
10252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyerr:
10352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	if (i > 0)
10452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		xt_unregister_targets(target, i);
10552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	return err;
10652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy}
10752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyEXPORT_SYMBOL(xt_register_targets);
10852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
10952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyvoid
11052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyxt_unregister_targets(struct xt_target *target, unsigned int n)
11152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy{
11252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	unsigned int i;
11352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
11452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	for (i = 0; i < n; i++)
11552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		xt_unregister_target(&target[i]);
11652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy}
11752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyEXPORT_SYMBOL(xt_unregister_targets);
11852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
11952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyint
120a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_register_match(struct xt_match *match)
1212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
122a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayuso	int ret, af = match->family;
1232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1249e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	ret = mutex_lock_interruptible(&xt[af].mutex);
1252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (ret != 0)
1262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ret;
1272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_add(&match->list, &xt[af].match);
1299e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
1302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ret;
1322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
1332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_register_match);
1342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid
136a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_unregister_match(struct xt_match *match)
1372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
138a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayuso	int af =  match->family;
139a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayuso
1409e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_lock(&xt[af].mutex);
141df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy	list_del(&match->list);
1429e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
1432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
1442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_unregister_match);
1452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
14652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyint
14752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyxt_register_matches(struct xt_match *match, unsigned int n)
14852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy{
14952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	unsigned int i;
15052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	int err = 0;
15152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
15252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	for (i = 0; i < n; i++) {
15352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		err = xt_register_match(&match[i]);
15452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		if (err)
15552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy			goto err;
15652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	}
15752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	return err;
15852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
15952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyerr:
16052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	if (i > 0)
16152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		xt_unregister_matches(match, i);
16252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	return err;
16352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy}
16452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyEXPORT_SYMBOL(xt_register_matches);
16552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
16652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyvoid
16752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyxt_unregister_matches(struct xt_match *match, unsigned int n)
16852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy{
16952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	unsigned int i;
17052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
17152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	for (i = 0; i < n; i++)
17252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		xt_unregister_match(&match[i]);
17352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy}
17452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyEXPORT_SYMBOL(xt_unregister_matches);
17552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
1762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/*
1782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * These are weird, but module loading must not be done with mutex
1792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * held (since they will register), and we have to have a single
1802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * function to use try_then_request_module().
1812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte */
1822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Find match, grabs ref.  Returns ERR_PTR() on error. */
1842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_match *xt_find_match(int af, const char *name, u8 revision)
1852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
1862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_match *m;
1872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int err = 0;
1882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1899e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	if (mutex_lock_interruptible(&xt[af].mutex) != 0)
1902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ERR_PTR(-EINTR);
1912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(m, &xt[af].match, list) {
1932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(m->name, name) == 0) {
1942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (m->revision == revision) {
1952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				if (try_module_get(m->me)) {
1969e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar					mutex_unlock(&xt[af].mutex);
1972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte					return m;
1982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				}
1992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			} else
2002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				err = -EPROTOTYPE; /* Found something. */
2012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
2022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
2039e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
2042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ERR_PTR(err);
2052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
2062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_find_match);
2072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Find target, grabs ref.  Returns ERR_PTR() on error. */
2092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_target *xt_find_target(int af, const char *name, u8 revision)
2102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
2112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_target *t;
2122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int err = 0;
2132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2149e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	if (mutex_lock_interruptible(&xt[af].mutex) != 0)
2152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ERR_PTR(-EINTR);
2162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(t, &xt[af].target, list) {
2182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(t->name, name) == 0) {
2192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (t->revision == revision) {
2202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				if (try_module_get(t->me)) {
2219e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar					mutex_unlock(&xt[af].mutex);
2222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte					return t;
2232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				}
2242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			} else
2252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				err = -EPROTOTYPE; /* Found something. */
2262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
2272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
2289e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
2292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ERR_PTR(err);
2302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
2312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_find_target);
2322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_target *xt_request_find_target(int af, const char *name, u8 revision)
2342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
2352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_target *target;
2362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	target = try_then_request_module(xt_find_target(af, name, revision),
23837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy					 "%st_%s", xt_prefix[af], name);
2392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (IS_ERR(target) || !target)
2402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
2412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return target;
2422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
2432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_request_find_target);
2442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic int match_revfn(int af, const char *name, u8 revision, int *bestp)
2462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
2472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_match *m;
2482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int have_rev = 0;
2492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(m, &xt[af].match, list) {
2512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(m->name, name) == 0) {
2522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (m->revision > *bestp)
2532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				*bestp = m->revision;
2542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (m->revision == revision)
2552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				have_rev = 1;
2562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
2572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
2582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return have_rev;
2592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
2602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic int target_revfn(int af, const char *name, u8 revision, int *bestp)
2622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
2632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_target *t;
2642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int have_rev = 0;
2652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(t, &xt[af].target, list) {
2672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(t->name, name) == 0) {
2682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (t->revision > *bestp)
2692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				*bestp = t->revision;
2702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (t->revision == revision)
2712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				have_rev = 1;
2722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
2732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
2742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return have_rev;
2752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
2762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Returns true or false (if no such extension at all) */
2782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteint xt_find_revision(int af, const char *name, u8 revision, int target,
2792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		     int *err)
2802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
2812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int have_rev, best = -1;
2822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2839e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	if (mutex_lock_interruptible(&xt[af].mutex) != 0) {
2842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		*err = -EINTR;
2852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return 1;
2862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
2872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (target == 1)
2882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		have_rev = target_revfn(af, name, revision, &best);
2892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	else
2902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		have_rev = match_revfn(af, name, revision, &best);
2919e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
2922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Nothing at all?  Return 0 to try loading module. */
2942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (best == -1) {
2952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		*err = -ENOENT;
2962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return 0;
2972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
2982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	*err = best;
3002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!have_rev)
3012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		*err = -EPROTONOSUPPORT;
3022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return 1;
3032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
3042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_find_revision);
3052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
30637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardyint xt_check_match(const struct xt_match *match, unsigned short family,
30737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy                   unsigned int size, const char *table, unsigned int hook_mask,
30837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		   unsigned short proto, int inv_proto)
30937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy{
31037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	if (XT_ALIGN(match->matchsize) != size) {
31137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s match: invalid size %Zu != %u\n",
31237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       xt_prefix[family], match->name,
31337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       XT_ALIGN(match->matchsize), size);
31437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
31537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
31637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	if (match->table && strcmp(match->table, table)) {
31737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s match: only valid in %s table, not %s\n",
31837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       xt_prefix[family], match->name, match->table, table);
31937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
32037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
32137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	if (match->hooks && (hook_mask & ~match->hooks) != 0) {
32237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s match: bad hook_mask %u\n",
32337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       xt_prefix[family], match->name, hook_mask);
32437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
32537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
32637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	if (match->proto && (match->proto != proto || inv_proto)) {
32737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s match: only valid for protocol %u\n",
32837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       xt_prefix[family], match->name, match->proto);
32937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
33037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
33137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	return 0;
33237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy}
33337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardyEXPORT_SYMBOL_GPL(xt_check_match);
33437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy
3352722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT
3362722971cbe831117686039d5c334f2c0f560be13Dmitry Mishinint xt_compat_match(void *match, void **dstptr, int *size, int convert)
3372722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{
3382722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	struct xt_match *m;
3392722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	struct compat_xt_entry_match *pcompat_m;
3402722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	struct xt_entry_match *pm;
3412722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	u_int16_t msize;
3422722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	int off, ret;
3432722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin
3442722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	ret = 0;
3452722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	m = ((struct xt_entry_match *)match)->u.kernel.match;
3462722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	off = XT_ALIGN(m->matchsize) - COMPAT_XT_ALIGN(m->matchsize);
3472722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	switch (convert) {
3482722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin		case COMPAT_TO_USER:
3492722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			pm = (struct xt_entry_match *)match;
3502722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			msize = pm->u.user.match_size;
3517800007c1e2d42cd4120b87b0ba3f3480f17f30aPatrick McHardy			if (copy_to_user(*dstptr, pm, msize)) {
3522722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin				ret = -EFAULT;
3532722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin				break;
3542722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			}
3552722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			msize -= off;
3562722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			if (put_user(msize, (u_int16_t *)*dstptr))
3572722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin				ret = -EFAULT;
3582722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			*size -= off;
3592722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			*dstptr += msize;
3602722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			break;
3612722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin		case COMPAT_FROM_USER:
3622722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			pcompat_m = (struct compat_xt_entry_match *)match;
3632722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			pm = (struct xt_entry_match *)*dstptr;
3642722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			msize = pcompat_m->u.user.match_size;
3652722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			memcpy(pm, pcompat_m, msize);
3662722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			msize += off;
3672722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			pm->u.user.match_size = msize;
3682722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			*size += off;
3692722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			*dstptr += msize;
3702722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			break;
3712722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin		case COMPAT_CALC_SIZE:
3722722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			*size += off;
3732722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			break;
3742722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin		default:
3752722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			ret = -ENOPROTOOPT;
3762722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			break;
3772722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	}
3782722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	return ret;
3792722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin}
3802722971cbe831117686039d5c334f2c0f560be13Dmitry MishinEXPORT_SYMBOL_GPL(xt_compat_match);
3812722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#endif
3822722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin
38337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardyint xt_check_target(const struct xt_target *target, unsigned short family,
38437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		    unsigned int size, const char *table, unsigned int hook_mask,
38537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		    unsigned short proto, int inv_proto)
38637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy{
38737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	if (XT_ALIGN(target->targetsize) != size) {
38837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s target: invalid size %Zu != %u\n",
38937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       xt_prefix[family], target->name,
39037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       XT_ALIGN(target->targetsize), size);
39137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
39237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
39337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	if (target->table && strcmp(target->table, table)) {
39437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s target: only valid in %s table, not %s\n",
39537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       xt_prefix[family], target->name, target->table, table);
39637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
39737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
39837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	if (target->hooks && (hook_mask & ~target->hooks) != 0) {
39937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s target: bad hook_mask %u\n",
40037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       xt_prefix[family], target->name, hook_mask);
40137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
40237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
40337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	if (target->proto && (target->proto != proto || inv_proto)) {
40437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s target: only valid for protocol %u\n",
40537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       xt_prefix[family], target->name, target->proto);
40637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
40737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
40837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	return 0;
40937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy}
41037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardyEXPORT_SYMBOL_GPL(xt_check_target);
41137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy
4122722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT
4132722971cbe831117686039d5c334f2c0f560be13Dmitry Mishinint xt_compat_target(void *target, void **dstptr, int *size, int convert)
4142722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{
4152722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	struct xt_target *t;
4162722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	struct compat_xt_entry_target *pcompat;
4172722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	struct xt_entry_target *pt;
4182722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	u_int16_t tsize;
4192722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	int off, ret;
4202722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin
4212722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	ret = 0;
4222722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	t = ((struct xt_entry_target *)target)->u.kernel.target;
4232722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	off = XT_ALIGN(t->targetsize) - COMPAT_XT_ALIGN(t->targetsize);
4242722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	switch (convert) {
4252722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin		case COMPAT_TO_USER:
4262722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			pt = (struct xt_entry_target *)target;
4272722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			tsize = pt->u.user.target_size;
4287800007c1e2d42cd4120b87b0ba3f3480f17f30aPatrick McHardy			if (copy_to_user(*dstptr, pt, tsize)) {
4292722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin				ret = -EFAULT;
4302722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin				break;
4312722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			}
4322722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			tsize -= off;
4332722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			if (put_user(tsize, (u_int16_t *)*dstptr))
4342722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin				ret = -EFAULT;
4352722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			*size -= off;
4362722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			*dstptr += tsize;
4372722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			break;
4382722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin		case COMPAT_FROM_USER:
4392722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			pcompat = (struct compat_xt_entry_target *)target;
4402722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			pt = (struct xt_entry_target *)*dstptr;
4412722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			tsize = pcompat->u.user.target_size;
4422722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			memcpy(pt, pcompat, tsize);
4432722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			tsize += off;
4442722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			pt->u.user.target_size = tsize;
4452722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			*size += off;
4462722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			*dstptr += tsize;
4472722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			break;
4482722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin		case COMPAT_CALC_SIZE:
4492722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			*size += off;
4502722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			break;
4512722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin		default:
4522722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			ret = -ENOPROTOOPT;
4532722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin			break;
4542722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	}
4552722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	return ret;
4562722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin}
4572722971cbe831117686039d5c334f2c0f560be13Dmitry MishinEXPORT_SYMBOL_GPL(xt_compat_target);
4582722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#endif
4592722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin
4602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_table_info *xt_alloc_table_info(unsigned int size)
4612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
4622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table_info *newinfo;
4632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int cpu;
4642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
4662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if ((SMP_ALIGN(size) >> PAGE_SHIFT) + 2 > num_physpages)
4672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
4682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	newinfo = kzalloc(sizeof(struct xt_table_info), GFP_KERNEL);
4702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!newinfo)
4712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
4722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	newinfo->size = size;
4742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4756f912042256c12b0927438122594f5379b364f5dKAMEZAWA Hiroyuki	for_each_possible_cpu(cpu) {
4762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (size <= PAGE_SIZE)
4772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			newinfo->entries[cpu] = kmalloc_node(size,
4782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte							GFP_KERNEL,
4792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte							cpu_to_node(cpu));
4802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		else
4812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			newinfo->entries[cpu] = vmalloc_node(size,
4822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte							cpu_to_node(cpu));
4832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (newinfo->entries[cpu] == NULL) {
4852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			xt_free_table_info(newinfo);
4862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			return NULL;
4872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
4882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
4892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return newinfo;
4912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
4922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_alloc_table_info);
4932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid xt_free_table_info(struct xt_table_info *info)
4952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
4962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int cpu;
4972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4986f912042256c12b0927438122594f5379b364f5dKAMEZAWA Hiroyuki	for_each_possible_cpu(cpu) {
4992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (info->size <= PAGE_SIZE)
5002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			kfree(info->entries[cpu]);
5012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		else
5022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			vfree(info->entries[cpu]);
5032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
5042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	kfree(info);
5052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
5062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_free_table_info);
5072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Find table by name, grabs mutex & ref.  Returns ERR_PTR() on error. */
5092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_table *xt_find_table_lock(int af, const char *name)
5102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
5112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table *t;
5122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5139e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	if (mutex_lock_interruptible(&xt[af].mutex) != 0)
5142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ERR_PTR(-EINTR);
5152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(t, &xt[af].tables, list)
5172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(t->name, name) == 0 && try_module_get(t->me))
5182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			return t;
5199e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
5202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return NULL;
5212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
5222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_find_table_lock);
5232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid xt_table_unlock(struct xt_table *table)
5252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
5269e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[table->af].mutex);
5272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
5282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_table_unlock);
5292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5302722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT
5312722971cbe831117686039d5c334f2c0f560be13Dmitry Mishinvoid xt_compat_lock(int af)
5322722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{
5332722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	mutex_lock(&xt[af].compat_mutex);
5342722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin}
5352722971cbe831117686039d5c334f2c0f560be13Dmitry MishinEXPORT_SYMBOL_GPL(xt_compat_lock);
5362722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin
5372722971cbe831117686039d5c334f2c0f560be13Dmitry Mishinvoid xt_compat_unlock(int af)
5382722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{
5392722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	mutex_unlock(&xt[af].compat_mutex);
5402722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin}
5412722971cbe831117686039d5c334f2c0f560be13Dmitry MishinEXPORT_SYMBOL_GPL(xt_compat_unlock);
5422722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#endif
5432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_table_info *
5452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltext_replace_table(struct xt_table *table,
5462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	      unsigned int num_counters,
5472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	      struct xt_table_info *newinfo,
5482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	      int *error)
5492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
5502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table_info *oldinfo, *private;
5512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Do the substitution. */
5532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	write_lock_bh(&table->lock);
5542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	private = table->private;
5552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Check inside lock: is the old number correct? */
5562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (num_counters != private->number) {
5572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		duprintf("num_counters != table->private->number (%u/%u)\n",
5582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			 num_counters, private->number);
5592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		write_unlock_bh(&table->lock);
5602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		*error = -EAGAIN;
5612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
5622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
5632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	oldinfo = private;
5642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	table->private = newinfo;
5652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	newinfo->initial_entries = oldinfo->initial_entries;
5662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	write_unlock_bh(&table->lock);
5672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return oldinfo;
5692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
5702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_replace_table);
5712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteint xt_register_table(struct xt_table *table,
5732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		      struct xt_table_info *bootstrap,
5742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		      struct xt_table_info *newinfo)
5752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
5762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int ret;
5772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table_info *private;
578df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy	struct xt_table *t;
5792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5809e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	ret = mutex_lock_interruptible(&xt[table->af].mutex);
5812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (ret != 0)
5822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ret;
5832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Don't autoload: we'd eat our tail... */
585df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy	list_for_each_entry(t, &xt[table->af].tables, list) {
586df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy		if (strcmp(t->name, table->name) == 0) {
587df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy			ret = -EEXIST;
588df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy			goto unlock;
589df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy		}
5902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
5912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Simplifies replace_table code. */
5932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	table->private = bootstrap;
59491536b7ae67710ca888e03ea82c60f0ac073a015Dmitry Mishin	rwlock_init(&table->lock);
5952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!xt_replace_table(table, 0, newinfo, &ret))
5962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto unlock;
5972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	private = table->private;
5992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	duprintf("table->private->number = %u\n", private->number);
6002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* save number of initial entries */
6022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	private->initial_entries = private->number;
6032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
604df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy	list_add(&table->list, &xt[table->af].tables);
6052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	ret = 0;
6072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte unlock:
6089e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[table->af].mutex);
6092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ret;
6102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
6112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_register_table);
6122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid *xt_unregister_table(struct xt_table *table)
6142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
6152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table_info *private;
6162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6179e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_lock(&xt[table->af].mutex);
6182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	private = table->private;
619df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy	list_del(&table->list);
6209e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[table->af].mutex);
6212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return private;
6232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
6242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_unregister_table);
6252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
6272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic char *xt_proto_prefix[NPROTO] = {
6282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	[AF_INET]	= "ip",
6292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	[AF_INET6]	= "ip6",
6302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	[NF_ARP]	= "arp",
6312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte};
6322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic struct list_head *xt_get_idx(struct list_head *list, struct seq_file *seq, loff_t pos)
6342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
6352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct list_head *head = list->next;
6362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!head || list_empty(list))
6382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
6392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	while (pos && (head = head->next)) {
6412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (head == list)
6422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			return NULL;
6432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		pos--;
6442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
6452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return pos ? NULL : head;
6462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
6472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic struct list_head *type2list(u_int16_t af, u_int16_t type)
6492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
6502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct list_head *list;
6512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	switch (type) {
6532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	case TARGET:
6542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		list = &xt[af].target;
6552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		break;
6562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	case MATCH:
6572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		list = &xt[af].match;
6582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		break;
6592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	case TABLE:
6602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		list = &xt[af].tables;
6612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		break;
6622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	default:
6632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		list = NULL;
6642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		break;
6652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
6662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return list;
6682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
6692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic void *xt_tgt_seq_start(struct seq_file *seq, loff_t *pos)
6712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
6722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct proc_dir_entry *pde = (struct proc_dir_entry *) seq->private;
6732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	u_int16_t af = (unsigned long)pde->data & 0xffff;
6742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	u_int16_t type = (unsigned long)pde->data >> 16;
6752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct list_head *list;
6762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (af >= NPROTO)
6782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
6792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list = type2list(af, type);
6812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!list)
6822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
6832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6849e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	if (mutex_lock_interruptible(&xt[af].mutex) != 0)
6852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
6862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return xt_get_idx(list, seq, *pos);
6882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
6892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic void *xt_tgt_seq_next(struct seq_file *seq, void *v, loff_t *pos)
6912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
6922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct proc_dir_entry *pde = seq->private;
6932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	u_int16_t af = (unsigned long)pde->data & 0xffff;
6942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	u_int16_t type = (unsigned long)pde->data >> 16;
6952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct list_head *list;
6962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (af >= NPROTO)
6982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
6992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list = type2list(af, type);
7012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!list)
7022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
7032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	(*pos)++;
7052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return xt_get_idx(list, seq, *pos);
7062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
7072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic void xt_tgt_seq_stop(struct seq_file *seq, void *v)
7092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
7102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct proc_dir_entry *pde = seq->private;
7112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	u_int16_t af = (unsigned long)pde->data & 0xffff;
7122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7139e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
7142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
7152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic int xt_name_seq_show(struct seq_file *seq, void *v)
7172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
7182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	char *name = (char *)v + sizeof(struct list_head);
7192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (strlen(name))
7212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return seq_printf(seq, "%s\n", name);
7222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	else
7232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return 0;
7242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
7252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic struct seq_operations xt_tgt_seq_ops = {
7272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.start	= xt_tgt_seq_start,
7282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.next	= xt_tgt_seq_next,
7292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.stop	= xt_tgt_seq_stop,
7302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.show	= xt_name_seq_show,
7312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte};
7322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic int xt_tgt_open(struct inode *inode, struct file *file)
7342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
7352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int ret;
7362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	ret = seq_open(file, &xt_tgt_seq_ops);
7382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!ret) {
7392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		struct seq_file *seq = file->private_data;
7402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		struct proc_dir_entry *pde = PDE(inode);
7412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		seq->private = pde;
7432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
7442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ret;
7462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
7472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic struct file_operations xt_file_ops = {
7492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.owner	 = THIS_MODULE,
7502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.open	 = xt_tgt_open,
7512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.read	 = seq_read,
7522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.llseek	 = seq_lseek,
7532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.release = seq_release,
7542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte};
7552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define FORMAT_TABLES	"_tables_names"
7572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define	FORMAT_MATCHES	"_tables_matches"
7582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define FORMAT_TARGETS 	"_tables_targets"
7592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif /* CONFIG_PROC_FS */
7612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteint xt_proto_init(int af)
7632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
7642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
7652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	char buf[XT_FUNCTION_MAXNAMELEN];
7662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct proc_dir_entry *proc;
7672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif
7682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (af >= NPROTO)
7702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return -EINVAL;
7712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
7742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
7752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TABLES, sizeof(buf));
7762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc = proc_net_fops_create(buf, 0440, &xt_file_ops);
7772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!proc)
7782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto out;
7792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc->data = (void *) ((unsigned long) af | (TABLE << 16));
7802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
7832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
7842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc = proc_net_fops_create(buf, 0440, &xt_file_ops);
7852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!proc)
7862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto out_remove_tables;
7872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc->data = (void *) ((unsigned long) af | (MATCH << 16));
7882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
7902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TARGETS, sizeof(buf));
7912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc = proc_net_fops_create(buf, 0440, &xt_file_ops);
7922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!proc)
7932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto out_remove_matches;
7942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc->data = (void *) ((unsigned long) af | (TARGET << 16));
7952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif
7962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return 0;
7982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
8002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteout_remove_matches:
8012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
8022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
8032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc_net_remove(buf);
8042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteout_remove_tables:
8062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
8072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TABLES, sizeof(buf));
8082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc_net_remove(buf);
8092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteout:
8102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return -1;
8112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif
8122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
8132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_proto_init);
8142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid xt_proto_fini(int af)
8162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
8172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
8182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	char buf[XT_FUNCTION_MAXNAMELEN];
8192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
8212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TABLES, sizeof(buf));
8222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc_net_remove(buf);
8232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
8252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TARGETS, sizeof(buf));
8262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc_net_remove(buf);
8272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
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#endif /*CONFIG_PROC_FS*/
8322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
8332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_proto_fini);
8342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic int __init xt_init(void)
8372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
8382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int i;
8392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	xt = kmalloc(sizeof(struct xt_af) * NPROTO, GFP_KERNEL);
8412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!xt)
8422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return -ENOMEM;
8432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	for (i = 0; i < NPROTO; i++) {
8459e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar		mutex_init(&xt[i].mutex);
8462722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT
8472722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin		mutex_init(&xt[i].compat_mutex);
8482722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#endif
8492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		INIT_LIST_HEAD(&xt[i].target);
8502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		INIT_LIST_HEAD(&xt[i].match);
8512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		INIT_LIST_HEAD(&xt[i].tables);
8522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
8532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return 0;
8542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
8552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic void __exit xt_fini(void)
8572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
8582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	kfree(xt);
8592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
8602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltemodule_init(xt_init);
8622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltemodule_exit(xt_fini);
8632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
864