x_tables.c revision a45049c51ce6a3fecf2a909b591b28164c927112
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>
242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/netfilter/x_tables.h>
262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/netfilter_arp.h>
272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteMODULE_LICENSE("GPL");
292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteMODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteMODULE_DESCRIPTION("[ip,ip6,arp]_tables backend module");
312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_af {
352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct semaphore mutex;
362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct list_head match;
372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct list_head target;
382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct list_head tables;
392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte};
402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic struct xt_af *xt;
422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef DEBUG_IP_FIREWALL_USER
442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define duprintf(format, args...) printk(format , ## args)
452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#else
462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define duprintf(format, args...)
472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif
482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteenum {
502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	TABLE,
512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	TARGET,
522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	MATCH,
532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte};
542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardystatic const char *xt_prefix[NPROTO] = {
5637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	[AF_INET] 	= "ip",
5737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	[AF_INET6] 	= "ip6",
5837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	[NF_ARP]	= "arp",
5937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy};
6037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy
612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Registration hooks for targets. */
622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteint
63a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_register_target(struct xt_target *target)
642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
65a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayuso	int ret, af = target->family;
662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	ret = down_interruptible(&xt[af].mutex);
682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (ret != 0)
692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ret;
702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_add(&target->list, &xt[af].target);
712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	up(&xt[af].mutex);
722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ret;
732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_register_target);
752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid
77a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_unregister_target(struct xt_target *target)
782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
79a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayuso	int af = target->family;
80a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayuso
812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	down(&xt[af].mutex);
822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	LIST_DELETE(&xt[af].target, target);
832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	up(&xt[af].mutex);
842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_unregister_target);
862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteint
88a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_register_match(struct xt_match *match)
892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
90a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayuso	int ret, af = match->family;
912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	ret = down_interruptible(&xt[af].mutex);
932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (ret != 0)
942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ret;
952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_add(&match->list, &xt[af].match);
972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	up(&xt[af].mutex);
982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ret;
1002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
1012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_register_match);
1022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid
104a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_unregister_match(struct xt_match *match)
1052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
106a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayuso	int af =  match->family;
107a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayuso
1082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	down(&xt[af].mutex);
1092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	LIST_DELETE(&xt[af].match, match);
1102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	up(&xt[af].mutex);
1112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
1122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_unregister_match);
1132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/*
1162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * These are weird, but module loading must not be done with mutex
1172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * held (since they will register), and we have to have a single
1182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * function to use try_then_request_module().
1192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte */
1202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Find match, grabs ref.  Returns ERR_PTR() on error. */
1222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_match *xt_find_match(int af, const char *name, u8 revision)
1232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
1242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_match *m;
1252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int err = 0;
1262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (down_interruptible(&xt[af].mutex) != 0)
1282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ERR_PTR(-EINTR);
1292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(m, &xt[af].match, list) {
1312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(m->name, name) == 0) {
1322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (m->revision == revision) {
1332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				if (try_module_get(m->me)) {
1342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte					up(&xt[af].mutex);
1352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte					return m;
1362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				}
1372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			} else
1382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				err = -EPROTOTYPE; /* Found something. */
1392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
1402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
1412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	up(&xt[af].mutex);
1422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ERR_PTR(err);
1432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
1442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_find_match);
1452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Find target, grabs ref.  Returns ERR_PTR() on error. */
1472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_target *xt_find_target(int af, const char *name, u8 revision)
1482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
1492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_target *t;
1502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int err = 0;
1512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (down_interruptible(&xt[af].mutex) != 0)
1532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ERR_PTR(-EINTR);
1542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(t, &xt[af].target, list) {
1562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(t->name, name) == 0) {
1572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (t->revision == revision) {
1582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				if (try_module_get(t->me)) {
1592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte					up(&xt[af].mutex);
1602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte					return t;
1612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				}
1622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			} else
1632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				err = -EPROTOTYPE; /* Found something. */
1642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
1652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
1662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	up(&xt[af].mutex);
1672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ERR_PTR(err);
1682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
1692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_find_target);
1702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_target *xt_request_find_target(int af, const char *name, u8 revision)
1722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
1732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_target *target;
1742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	target = try_then_request_module(xt_find_target(af, name, revision),
17637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy					 "%st_%s", xt_prefix[af], name);
1772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (IS_ERR(target) || !target)
1782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
1792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return target;
1802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
1812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_request_find_target);
1822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic int match_revfn(int af, const char *name, u8 revision, int *bestp)
1842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
1852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_match *m;
1862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int have_rev = 0;
1872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(m, &xt[af].match, list) {
1892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(m->name, name) == 0) {
1902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (m->revision > *bestp)
1912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				*bestp = m->revision;
1922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (m->revision == revision)
1932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				have_rev = 1;
1942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
1952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
1962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return have_rev;
1972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
1982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic int target_revfn(int af, const char *name, u8 revision, int *bestp)
2002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
2012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_target *t;
2022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int have_rev = 0;
2032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(t, &xt[af].target, list) {
2052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(t->name, name) == 0) {
2062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (t->revision > *bestp)
2072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				*bestp = t->revision;
2082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (t->revision == revision)
2092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				have_rev = 1;
2102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
2112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
2122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return have_rev;
2132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
2142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Returns true or false (if no such extension at all) */
2162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteint xt_find_revision(int af, const char *name, u8 revision, int target,
2172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		     int *err)
2182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
2192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int have_rev, best = -1;
2202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (down_interruptible(&xt[af].mutex) != 0) {
2222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		*err = -EINTR;
2232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return 1;
2242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
2252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (target == 1)
2262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		have_rev = target_revfn(af, name, revision, &best);
2272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	else
2282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		have_rev = match_revfn(af, name, revision, &best);
2292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	up(&xt[af].mutex);
2302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Nothing at all?  Return 0 to try loading module. */
2322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (best == -1) {
2332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		*err = -ENOENT;
2342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return 0;
2352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
2362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	*err = best;
2382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!have_rev)
2392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		*err = -EPROTONOSUPPORT;
2402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return 1;
2412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
2422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_find_revision);
2432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
24437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardyint xt_check_match(const struct xt_match *match, unsigned short family,
24537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy                   unsigned int size, const char *table, unsigned int hook_mask,
24637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		   unsigned short proto, int inv_proto)
24737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy{
24837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	if (XT_ALIGN(match->matchsize) != size) {
24937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s match: invalid size %Zu != %u\n",
25037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       xt_prefix[family], match->name,
25137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       XT_ALIGN(match->matchsize), size);
25237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
25337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
25437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	if (match->table && strcmp(match->table, table)) {
25537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s match: only valid in %s table, not %s\n",
25637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       xt_prefix[family], match->name, match->table, table);
25737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
25837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
25937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	if (match->hooks && (hook_mask & ~match->hooks) != 0) {
26037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s match: bad hook_mask %u\n",
26137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       xt_prefix[family], match->name, hook_mask);
26237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
26337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
26437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	if (match->proto && (match->proto != proto || inv_proto)) {
26537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s match: only valid for protocol %u\n",
26637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       xt_prefix[family], match->name, match->proto);
26737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
26837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
26937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	return 0;
27037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy}
27137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardyEXPORT_SYMBOL_GPL(xt_check_match);
27237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy
27337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardyint xt_check_target(const struct xt_target *target, unsigned short family,
27437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		    unsigned int size, const char *table, unsigned int hook_mask,
27537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		    unsigned short proto, int inv_proto)
27637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy{
27737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	if (XT_ALIGN(target->targetsize) != size) {
27837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s target: invalid size %Zu != %u\n",
27937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       xt_prefix[family], target->name,
28037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       XT_ALIGN(target->targetsize), size);
28137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
28237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
28337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	if (target->table && strcmp(target->table, table)) {
28437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s target: only valid in %s table, not %s\n",
28537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       xt_prefix[family], target->name, target->table, table);
28637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
28737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
28837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	if (target->hooks && (hook_mask & ~target->hooks) != 0) {
28937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s target: bad hook_mask %u\n",
29037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       xt_prefix[family], target->name, hook_mask);
29137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
29237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
29337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	if (target->proto && (target->proto != proto || inv_proto)) {
29437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s target: only valid for protocol %u\n",
29537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		       xt_prefix[family], target->name, target->proto);
29637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
29737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
29837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	return 0;
29937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy}
30037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardyEXPORT_SYMBOL_GPL(xt_check_target);
30137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy
3022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_table_info *xt_alloc_table_info(unsigned int size)
3032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
3042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table_info *newinfo;
3052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int cpu;
3062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
3082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if ((SMP_ALIGN(size) >> PAGE_SHIFT) + 2 > num_physpages)
3092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
3102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	newinfo = kzalloc(sizeof(struct xt_table_info), GFP_KERNEL);
3122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!newinfo)
3132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
3142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	newinfo->size = size;
3162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	for_each_cpu(cpu) {
3182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (size <= PAGE_SIZE)
3192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			newinfo->entries[cpu] = kmalloc_node(size,
3202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte							GFP_KERNEL,
3212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte							cpu_to_node(cpu));
3222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		else
3232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			newinfo->entries[cpu] = vmalloc_node(size,
3242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte							cpu_to_node(cpu));
3252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (newinfo->entries[cpu] == NULL) {
3272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			xt_free_table_info(newinfo);
3282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			return NULL;
3292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
3302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
3312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return newinfo;
3332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
3342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_alloc_table_info);
3352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid xt_free_table_info(struct xt_table_info *info)
3372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
3382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int cpu;
3392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	for_each_cpu(cpu) {
3412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (info->size <= PAGE_SIZE)
3422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			kfree(info->entries[cpu]);
3432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		else
3442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			vfree(info->entries[cpu]);
3452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
3462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	kfree(info);
3472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
3482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_free_table_info);
3492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Find table by name, grabs mutex & ref.  Returns ERR_PTR() on error. */
3512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_table *xt_find_table_lock(int af, const char *name)
3522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
3532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table *t;
3542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (down_interruptible(&xt[af].mutex) != 0)
3562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ERR_PTR(-EINTR);
3572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(t, &xt[af].tables, list)
3592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(t->name, name) == 0 && try_module_get(t->me))
3602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			return t;
3612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	up(&xt[af].mutex);
3622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return NULL;
3632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
3642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_find_table_lock);
3652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid xt_table_unlock(struct xt_table *table)
3672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
3682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	up(&xt[table->af].mutex);
3692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
3702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_table_unlock);
3712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_table_info *
3742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltext_replace_table(struct xt_table *table,
3752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	      unsigned int num_counters,
3762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	      struct xt_table_info *newinfo,
3772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	      int *error)
3782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
3792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table_info *oldinfo, *private;
3802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Do the substitution. */
3822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	write_lock_bh(&table->lock);
3832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	private = table->private;
3842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Check inside lock: is the old number correct? */
3852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (num_counters != private->number) {
3862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		duprintf("num_counters != table->private->number (%u/%u)\n",
3872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			 num_counters, private->number);
3882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		write_unlock_bh(&table->lock);
3892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		*error = -EAGAIN;
3902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
3912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
3922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	oldinfo = private;
3932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	table->private = newinfo;
3942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	newinfo->initial_entries = oldinfo->initial_entries;
3952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	write_unlock_bh(&table->lock);
3962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return oldinfo;
3982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
3992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_replace_table);
4002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteint xt_register_table(struct xt_table *table,
4022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		      struct xt_table_info *bootstrap,
4032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		      struct xt_table_info *newinfo)
4042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
4052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int ret;
4062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table_info *private;
4072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	ret = down_interruptible(&xt[table->af].mutex);
4092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (ret != 0)
4102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ret;
4112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Don't autoload: we'd eat our tail... */
4132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (list_named_find(&xt[table->af].tables, table->name)) {
4142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		ret = -EEXIST;
4152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto unlock;
4162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
4172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Simplifies replace_table code. */
4192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	table->private = bootstrap;
4202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!xt_replace_table(table, 0, newinfo, &ret))
4212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto unlock;
4222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	private = table->private;
4242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	duprintf("table->private->number = %u\n", private->number);
4252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* save number of initial entries */
4272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	private->initial_entries = private->number;
4282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	rwlock_init(&table->lock);
4302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_prepend(&xt[table->af].tables, table);
4312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	ret = 0;
4332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte unlock:
4342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	up(&xt[table->af].mutex);
4352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ret;
4362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
4372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_register_table);
4382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid *xt_unregister_table(struct xt_table *table)
4402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
4412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table_info *private;
4422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	down(&xt[table->af].mutex);
4442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	private = table->private;
4452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	LIST_DELETE(&xt[table->af].tables, table);
4462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	up(&xt[table->af].mutex);
4472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return private;
4492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
4502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_unregister_table);
4512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
4532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic char *xt_proto_prefix[NPROTO] = {
4542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	[AF_INET]	= "ip",
4552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	[AF_INET6]	= "ip6",
4562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	[NF_ARP]	= "arp",
4572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte};
4582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic struct list_head *xt_get_idx(struct list_head *list, struct seq_file *seq, loff_t pos)
4602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
4612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct list_head *head = list->next;
4622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!head || list_empty(list))
4642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
4652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	while (pos && (head = head->next)) {
4672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (head == list)
4682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			return NULL;
4692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		pos--;
4702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
4712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return pos ? NULL : head;
4722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
4732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic struct list_head *type2list(u_int16_t af, u_int16_t type)
4752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
4762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct list_head *list;
4772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	switch (type) {
4792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	case TARGET:
4802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		list = &xt[af].target;
4812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		break;
4822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	case MATCH:
4832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		list = &xt[af].match;
4842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		break;
4852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	case TABLE:
4862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		list = &xt[af].tables;
4872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		break;
4882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	default:
4892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		list = NULL;
4902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		break;
4912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
4922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return list;
4942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
4952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
4962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic void *xt_tgt_seq_start(struct seq_file *seq, loff_t *pos)
4972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
4982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct proc_dir_entry *pde = (struct proc_dir_entry *) seq->private;
4992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	u_int16_t af = (unsigned long)pde->data & 0xffff;
5002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	u_int16_t type = (unsigned long)pde->data >> 16;
5012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct list_head *list;
5022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (af >= NPROTO)
5042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
5052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list = type2list(af, type);
5072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!list)
5082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
5092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (down_interruptible(&xt[af].mutex) != 0)
5112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
5122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return xt_get_idx(list, seq, *pos);
5142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
5152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic void *xt_tgt_seq_next(struct seq_file *seq, void *v, loff_t *pos)
5172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
5182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct proc_dir_entry *pde = seq->private;
5192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	u_int16_t af = (unsigned long)pde->data & 0xffff;
5202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	u_int16_t type = (unsigned long)pde->data >> 16;
5212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct list_head *list;
5222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (af >= NPROTO)
5242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
5252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list = type2list(af, type);
5272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!list)
5282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
5292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	(*pos)++;
5312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return xt_get_idx(list, seq, *pos);
5322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
5332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic void xt_tgt_seq_stop(struct seq_file *seq, void *v)
5352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
5362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct proc_dir_entry *pde = seq->private;
5372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	u_int16_t af = (unsigned long)pde->data & 0xffff;
5382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	up(&xt[af].mutex);
5402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
5412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic int xt_name_seq_show(struct seq_file *seq, void *v)
5432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
5442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	char *name = (char *)v + sizeof(struct list_head);
5452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (strlen(name))
5472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return seq_printf(seq, "%s\n", name);
5482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	else
5492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return 0;
5502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
5512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic struct seq_operations xt_tgt_seq_ops = {
5532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.start	= xt_tgt_seq_start,
5542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.next	= xt_tgt_seq_next,
5552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.stop	= xt_tgt_seq_stop,
5562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.show	= xt_name_seq_show,
5572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte};
5582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic int xt_tgt_open(struct inode *inode, struct file *file)
5602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
5612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int ret;
5622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	ret = seq_open(file, &xt_tgt_seq_ops);
5642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!ret) {
5652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		struct seq_file *seq = file->private_data;
5662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		struct proc_dir_entry *pde = PDE(inode);
5672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		seq->private = pde;
5692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
5702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ret;
5722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
5732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic struct file_operations xt_file_ops = {
5752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.owner	 = THIS_MODULE,
5762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.open	 = xt_tgt_open,
5772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.read	 = seq_read,
5782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.llseek	 = seq_lseek,
5792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.release = seq_release,
5802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte};
5812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define FORMAT_TABLES	"_tables_names"
5832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define	FORMAT_MATCHES	"_tables_matches"
5842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define FORMAT_TARGETS 	"_tables_targets"
5852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif /* CONFIG_PROC_FS */
5872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteint xt_proto_init(int af)
5892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
5902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
5912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	char buf[XT_FUNCTION_MAXNAMELEN];
5922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct proc_dir_entry *proc;
5932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif
5942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (af >= NPROTO)
5962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return -EINVAL;
5972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
6002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
6012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TABLES, sizeof(buf));
6022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc = proc_net_fops_create(buf, 0440, &xt_file_ops);
6032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!proc)
6042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto out;
6052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc->data = (void *) ((unsigned long) af | (TABLE << 16));
6062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
6092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
6102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc = proc_net_fops_create(buf, 0440, &xt_file_ops);
6112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!proc)
6122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto out_remove_tables;
6132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc->data = (void *) ((unsigned long) af | (MATCH << 16));
6142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
6162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TARGETS, sizeof(buf));
6172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc = proc_net_fops_create(buf, 0440, &xt_file_ops);
6182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!proc)
6192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto out_remove_matches;
6202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc->data = (void *) ((unsigned long) af | (TARGET << 16));
6212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif
6222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return 0;
6242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
6262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteout_remove_matches:
6272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
6282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
6292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc_net_remove(buf);
6302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteout_remove_tables:
6322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
6332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TABLES, sizeof(buf));
6342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc_net_remove(buf);
6352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteout:
6362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return -1;
6372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif
6382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
6392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_proto_init);
6402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid xt_proto_fini(int af)
6422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
6432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
6442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	char buf[XT_FUNCTION_MAXNAMELEN];
6452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
6472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TABLES, sizeof(buf));
6482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc_net_remove(buf);
6492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
6512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TARGETS, sizeof(buf));
6522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc_net_remove(buf);
6532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
6552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
6562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	proc_net_remove(buf);
6572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif /*CONFIG_PROC_FS*/
6582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
6592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_proto_fini);
6602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic int __init xt_init(void)
6632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
6642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int i;
6652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	xt = kmalloc(sizeof(struct xt_af) * NPROTO, GFP_KERNEL);
6672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!xt)
6682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return -ENOMEM;
6692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	for (i = 0; i < NPROTO; i++) {
6712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		init_MUTEX(&xt[i].mutex);
6722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		INIT_LIST_HEAD(&xt[i].target);
6732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		INIT_LIST_HEAD(&xt[i].match);
6742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		INIT_LIST_HEAD(&xt[i].tables);
6752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
6762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return 0;
6772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
6782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic void __exit xt_fini(void)
6802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
6812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	kfree(xt);
6822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
6832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltemodule_init(xt_init);
6852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltemodule_exit(xt_fini);
6862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
687