x_tables.c revision af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37f
12e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/*
22e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * x_tables core - Backend for {ip,ip6,arp}_tables
32e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *
42e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * Copyright (C) 2006-2006 Harald Welte <laforge@netfilter.org>
52e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *
62e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * Based on existing ip_tables code which is
72e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *   Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
82e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *   Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org>
92e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *
102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * This program is free software; you can redistribute it and/or modify
112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * it under the terms of the GNU General Public License version 2 as
122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * published by the Free Software Foundation.
132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *
142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte */
152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/kernel.h>
172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/socket.h>
182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/net.h>
192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/proc_fs.h>
202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/seq_file.h>
212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/string.h>
222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/vmalloc.h>
239e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar#include <linux/mutex.h>
24d7fe0f241dceade9c8d4af75498765c5ff7f27e6Al Viro#include <linux/mm.h>
25457c4cbc5a3dde259d2a1f15d5f9785290397267Eric W. Biederman#include <net/net_namespace.h>
262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/netfilter/x_tables.h>
282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/netfilter_arp.h>
292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
309e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar
312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteMODULE_LICENSE("GPL");
322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteMODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
33043ef46c7690bfdbd5b012e15812a14a19ca5604Jan EngelhardtMODULE_DESCRIPTION("{ip,ip6,arp,eb}_tables backend module");
342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
37b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardystruct compat_delta {
38b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	struct compat_delta *next;
39b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	unsigned int offset;
40b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	short delta;
41b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy};
42b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_af {
449e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	struct mutex mutex;
452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct list_head match;
462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct list_head target;
47b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy#ifdef CONFIG_COMPAT
482722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	struct mutex compat_mutex;
49b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	struct compat_delta *compat_offsets;
50b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy#endif
512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte};
522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic struct xt_af *xt;
542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef DEBUG_IP_FIREWALL_USER
562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define duprintf(format, args...) printk(format , ## args)
572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#else
582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define duprintf(format, args...)
592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif
602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
617e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardtstatic const char *const xt_prefix[NFPROTO_NUMPROTO] = {
627e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	[NFPROTO_UNSPEC] = "x",
637e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	[NFPROTO_IPV4]   = "ip",
647e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	[NFPROTO_ARP]    = "arp",
657e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	[NFPROTO_BRIDGE] = "eb",
667e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	[NFPROTO_IPV6]   = "ip6",
6737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy};
6837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy
692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Registration hooks for targets. */
702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteint
71a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_register_target(struct xt_target *target)
722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
7376108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	u_int8_t af = target->family;
7476108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	int ret;
752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
769e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	ret = mutex_lock_interruptible(&xt[af].mutex);
772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (ret != 0)
782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ret;
792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_add(&target->list, &xt[af].target);
809e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ret;
822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_register_target);
842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid
86a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_unregister_target(struct xt_target *target)
872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
8876108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	u_int8_t af = target->family;
89a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayuso
909e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_lock(&xt[af].mutex);
91df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy	list_del(&target->list);
929e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_unregister_target);
952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteint
9752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyxt_register_targets(struct xt_target *target, unsigned int n)
9852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy{
9952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	unsigned int i;
10052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	int err = 0;
10152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
10252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	for (i = 0; i < n; i++) {
10352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		err = xt_register_target(&target[i]);
10452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		if (err)
10552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy			goto err;
10652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	}
10752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	return err;
10852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
10952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyerr:
11052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	if (i > 0)
11152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		xt_unregister_targets(target, i);
11252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	return err;
11352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy}
11452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyEXPORT_SYMBOL(xt_register_targets);
11552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
11652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyvoid
11752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyxt_unregister_targets(struct xt_target *target, unsigned int n)
11852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy{
11952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	unsigned int i;
12052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
12152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	for (i = 0; i < n; i++)
12252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		xt_unregister_target(&target[i]);
12352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy}
12452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyEXPORT_SYMBOL(xt_unregister_targets);
12552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
12652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyint
127a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_register_match(struct xt_match *match)
1282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
12976108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	u_int8_t af = match->family;
13076108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	int ret;
1312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1329e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	ret = mutex_lock_interruptible(&xt[af].mutex);
1332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (ret != 0)
1342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ret;
1352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_add(&match->list, &xt[af].match);
1379e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
1382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ret;
1402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
1412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_register_match);
1422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid
144a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_unregister_match(struct xt_match *match)
1452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
14676108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	u_int8_t af = match->family;
147a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayuso
1489e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_lock(&xt[af].mutex);
149df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy	list_del(&match->list);
1509e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
1512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
1522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_unregister_match);
1532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
15452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyint
15552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyxt_register_matches(struct xt_match *match, unsigned int n)
15652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy{
15752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	unsigned int i;
15852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	int err = 0;
15952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
16052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	for (i = 0; i < n; i++) {
16152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		err = xt_register_match(&match[i]);
16252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		if (err)
16352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy			goto err;
16452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	}
16552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	return err;
16652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
16752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyerr:
16852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	if (i > 0)
16952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		xt_unregister_matches(match, i);
17052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	return err;
17152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy}
17252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyEXPORT_SYMBOL(xt_register_matches);
17352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
17452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyvoid
17552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyxt_unregister_matches(struct xt_match *match, unsigned int n)
17652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy{
17752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	unsigned int i;
17852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
17952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	for (i = 0; i < n; i++)
18052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		xt_unregister_match(&match[i]);
18152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy}
18252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyEXPORT_SYMBOL(xt_unregister_matches);
18352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
1842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/*
1862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * These are weird, but module loading must not be done with mutex
1872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * held (since they will register), and we have to have a single
1882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * function to use try_then_request_module().
1892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte */
1902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Find match, grabs ref.  Returns ERR_PTR() on error. */
19276108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstruct xt_match *xt_find_match(u8 af, const char *name, u8 revision)
1932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
1942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_match *m;
1952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int err = 0;
1962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1979e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	if (mutex_lock_interruptible(&xt[af].mutex) != 0)
1982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ERR_PTR(-EINTR);
1992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(m, &xt[af].match, list) {
2012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(m->name, name) == 0) {
2022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (m->revision == revision) {
2032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				if (try_module_get(m->me)) {
2049e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar					mutex_unlock(&xt[af].mutex);
2052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte					return m;
2062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				}
2072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			} else
2082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				err = -EPROTOTYPE; /* Found something. */
2092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
2102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
2119e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
21255b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt
21355b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt	if (af != NFPROTO_UNSPEC)
21455b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt		/* Try searching again in the family-independent list */
21555b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt		return xt_find_match(NFPROTO_UNSPEC, name, revision);
21655b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt
2172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ERR_PTR(err);
2182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
2192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_find_match);
2202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Find target, grabs ref.  Returns ERR_PTR() on error. */
22276108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstruct xt_target *xt_find_target(u8 af, const char *name, u8 revision)
2232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
2242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_target *t;
2252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int err = 0;
2262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2279e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	if (mutex_lock_interruptible(&xt[af].mutex) != 0)
2282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ERR_PTR(-EINTR);
2292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(t, &xt[af].target, list) {
2312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(t->name, name) == 0) {
2322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (t->revision == revision) {
2332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				if (try_module_get(t->me)) {
2349e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar					mutex_unlock(&xt[af].mutex);
2352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte					return t;
2362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				}
2372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			} else
2382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				err = -EPROTOTYPE; /* Found something. */
2392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
2402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
2419e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
24255b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt
24355b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt	if (af != NFPROTO_UNSPEC)
24455b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt		/* Try searching again in the family-independent list */
24555b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt		return xt_find_target(NFPROTO_UNSPEC, name, revision);
24655b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt
2472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ERR_PTR(err);
2482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
2492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_find_target);
2502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
25176108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstruct xt_target *xt_request_find_target(u8 af, const char *name, u8 revision)
2522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
2532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_target *target;
2542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	target = try_then_request_module(xt_find_target(af, name, revision),
25637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy					 "%st_%s", xt_prefix[af], name);
2572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (IS_ERR(target) || !target)
2582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
2592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return target;
2602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
2612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_request_find_target);
2622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
26376108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstatic int match_revfn(u8 af, const char *name, u8 revision, int *bestp)
2642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
2655452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt	const struct xt_match *m;
2662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int have_rev = 0;
2672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(m, &xt[af].match, list) {
2692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(m->name, name) == 0) {
2702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (m->revision > *bestp)
2712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				*bestp = m->revision;
2722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (m->revision == revision)
2732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				have_rev = 1;
2742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
2752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
2762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return have_rev;
2772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
2782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
27976108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstatic int target_revfn(u8 af, const char *name, u8 revision, int *bestp)
2802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
2815452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt	const struct xt_target *t;
2822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int have_rev = 0;
2832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(t, &xt[af].target, list) {
2852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(t->name, name) == 0) {
2862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (t->revision > *bestp)
2872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				*bestp = t->revision;
2882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (t->revision == revision)
2892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				have_rev = 1;
2902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
2912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
2922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return have_rev;
2932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
2942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Returns true or false (if no such extension at all) */
29676108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtint xt_find_revision(u8 af, const char *name, u8 revision, int target,
2972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		     int *err)
2982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
2992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int have_rev, best = -1;
3002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3019e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	if (mutex_lock_interruptible(&xt[af].mutex) != 0) {
3022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		*err = -EINTR;
3032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return 1;
3042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
3052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (target == 1)
3062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		have_rev = target_revfn(af, name, revision, &best);
3072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	else
3082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		have_rev = match_revfn(af, name, revision, &best);
3099e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
3102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Nothing at all?  Return 0 to try loading module. */
3122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (best == -1) {
3132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		*err = -ENOENT;
3142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return 0;
3152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
3162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	*err = best;
3182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!have_rev)
3192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		*err = -EPROTONOSUPPORT;
3202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return 1;
3212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
3222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_find_revision);
3232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3249b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardtint xt_check_match(struct xt_mtchk_param *par, u_int8_t family,
3259b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt		   unsigned int size, u_int8_t proto, bool inv_proto)
32637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy{
3279b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt	if (XT_ALIGN(par->match->matchsize) != size &&
3289b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt	    par->match->matchsize != -1) {
329043ef46c7690bfdbd5b012e15812a14a19ca5604Jan Engelhardt		/*
330043ef46c7690bfdbd5b012e15812a14a19ca5604Jan Engelhardt		 * ebt_among is exempt from centralized matchsize checking
331043ef46c7690bfdbd5b012e15812a14a19ca5604Jan Engelhardt		 * because it uses a dynamic-size data set.
332043ef46c7690bfdbd5b012e15812a14a19ca5604Jan Engelhardt		 */
33337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s match: invalid size %Zu != %u\n",
3349b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt		       xt_prefix[family], par->match->name,
3359b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt		       XT_ALIGN(par->match->matchsize), size);
33637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
33737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
3389b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt	if (par->match->table != NULL &&
3399b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt	    strcmp(par->match->table, par->table) != 0) {
34037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s match: only valid in %s table, not %s\n",
3419b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt		       xt_prefix[family], par->match->name,
3429b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt		       par->match->table, par->table);
34337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
34437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
3459b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt	if (par->match->hooks && (par->hook_mask & ~par->match->hooks) != 0) {
346102befab75c438bfa356c6976026326728771ebcJan Engelhardt		printk("%s_tables: %s match: bad hook_mask %#x/%#x\n",
3479b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt		       xt_prefix[family], par->match->name,
3489b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt		       par->hook_mask, par->match->hooks);
34937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
35037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
3519b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt	if (par->match->proto && (par->match->proto != proto || inv_proto)) {
35237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s match: only valid for protocol %u\n",
3539b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt		       xt_prefix[family], par->match->name, par->match->proto);
35437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
35537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
3569b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt	if (par->match->checkentry != NULL && !par->match->checkentry(par))
357367c679007fa4f990eb7ee381326ec59d8148b0eJan Engelhardt		return -EINVAL;
35837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	return 0;
35937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy}
36037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardyEXPORT_SYMBOL_GPL(xt_check_match);
36137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy
3622722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT
36376108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtint xt_compat_add_offset(u_int8_t af, unsigned int offset, short delta)
364b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy{
365b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	struct compat_delta *tmp;
366b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
367b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	tmp = kmalloc(sizeof(struct compat_delta), GFP_KERNEL);
368b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	if (!tmp)
369b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		return -ENOMEM;
370b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
371b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	tmp->offset = offset;
372b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	tmp->delta = delta;
373b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
374b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	if (xt[af].compat_offsets) {
375b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		tmp->next = xt[af].compat_offsets->next;
376b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		xt[af].compat_offsets->next = tmp;
377b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	} else {
378b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		xt[af].compat_offsets = tmp;
379b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		tmp->next = NULL;
380b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	}
381b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	return 0;
382b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy}
383b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_add_offset);
384b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
38576108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtvoid xt_compat_flush_offsets(u_int8_t af)
386b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy{
387b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	struct compat_delta *tmp, *next;
388b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
389b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	if (xt[af].compat_offsets) {
390b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		for (tmp = xt[af].compat_offsets; tmp; tmp = next) {
391b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy			next = tmp->next;
392b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy			kfree(tmp);
393b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		}
394b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		xt[af].compat_offsets = NULL;
395b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	}
396b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy}
397b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_flush_offsets);
398b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
39976108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtshort xt_compat_calc_jump(u_int8_t af, unsigned int offset)
400b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy{
401b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	struct compat_delta *tmp;
402b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	short delta;
403b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
404b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	for (tmp = xt[af].compat_offsets, delta = 0; tmp; tmp = tmp->next)
405b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		if (tmp->offset < offset)
406b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy			delta += tmp->delta;
407b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	return delta;
408b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy}
409b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_calc_jump);
410b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
4115452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardtint xt_compat_match_offset(const struct xt_match *match)
4122722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{
4139fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	u_int16_t csize = match->compatsize ? : match->matchsize;
4149fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	return XT_ALIGN(match->matchsize) - COMPAT_XT_ALIGN(csize);
4159fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy}
4169fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_match_offset);
4179fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
4188956695131b8a7878891667469899d667eb5892bPatrick McHardyint xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr,
419b0a6363c2418c93f25dd30b8ffcd3fdd4ce23ad6Patrick McHardy			      unsigned int *size)
4209fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy{
4215452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt	const struct xt_match *match = m->u.kernel.match;
4229fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	struct compat_xt_entry_match *cm = (struct compat_xt_entry_match *)m;
4239fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	int pad, off = xt_compat_match_offset(match);
4249fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	u_int16_t msize = cm->u.user.match_size;
4259fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
4269fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	m = *dstptr;
4279fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	memcpy(m, cm, sizeof(*cm));
4289fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (match->compat_from_user)
4299fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		match->compat_from_user(m->data, cm->data);
4309fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	else
4319fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		memcpy(m->data, cm->data, msize - sizeof(*cm));
4329fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	pad = XT_ALIGN(match->matchsize) - match->matchsize;
4339fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (pad > 0)
4349fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		memset(m->data + match->matchsize, 0, pad);
4359fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
4369fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	msize += off;
4379fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	m->u.user.match_size = msize;
4389fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
4399fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*size += off;
4409fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*dstptr += msize;
4418956695131b8a7878891667469899d667eb5892bPatrick McHardy	return 0;
4429fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy}
4439fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_match_from_user);
4449fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
4459fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyint xt_compat_match_to_user(struct xt_entry_match *m, void __user **dstptr,
446b0a6363c2418c93f25dd30b8ffcd3fdd4ce23ad6Patrick McHardy			    unsigned int *size)
4479fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy{
4485452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt	const struct xt_match *match = m->u.kernel.match;
4499fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	struct compat_xt_entry_match __user *cm = *dstptr;
4509fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	int off = xt_compat_match_offset(match);
4519fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	u_int16_t msize = m->u.user.match_size - off;
4529fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
4539fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (copy_to_user(cm, m, sizeof(*cm)) ||
454a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy	    put_user(msize, &cm->u.user.match_size) ||
455a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy	    copy_to_user(cm->u.user.name, m->u.kernel.match->name,
456a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy			 strlen(m->u.kernel.match->name) + 1))
457601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki		return -EFAULT;
4589fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
4599fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (match->compat_to_user) {
4609fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		if (match->compat_to_user((void __user *)cm->data, m->data))
4619fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy			return -EFAULT;
4629fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	} else {
4639fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		if (copy_to_user(cm->data, m->data, msize - sizeof(*cm)))
4649fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy			return -EFAULT;
4652722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	}
4669fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
4679fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*size -= off;
4689fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*dstptr += msize;
4699fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	return 0;
4702722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin}
4719fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_match_to_user);
4729fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy#endif /* CONFIG_COMPAT */
4732722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin
474af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardtint xt_check_target(struct xt_tgchk_param *par, u_int8_t family,
475af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt		    unsigned int size, u_int8_t proto, bool inv_proto)
47637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy{
477af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt	if (XT_ALIGN(par->target->targetsize) != size) {
47837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s target: invalid size %Zu != %u\n",
479af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt		       xt_prefix[family], par->target->name,
480af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt		       XT_ALIGN(par->target->targetsize), size);
48137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
48237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
483af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt	if (par->target->table != NULL &&
484af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt	    strcmp(par->target->table, par->table) != 0) {
48537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s target: only valid in %s table, not %s\n",
486af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt		       xt_prefix[family], par->target->name,
487af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt		       par->target->table, par->table);
48837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
48937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
490af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt	if (par->target->hooks && (par->hook_mask & ~par->target->hooks) != 0) {
491102befab75c438bfa356c6976026326728771ebcJan Engelhardt		printk("%s_tables: %s target: bad hook_mask %#x/%#x\n",
492af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt		       xt_prefix[family], par->target->name, par->hook_mask,
493af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt		       par->target->hooks);
49437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
49537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
496af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt	if (par->target->proto && (par->target->proto != proto || inv_proto)) {
49737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		printk("%s_tables: %s target: only valid for protocol %u\n",
498af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt		       xt_prefix[family], par->target->name,
499af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt		       par->target->proto);
50037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
50137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
502af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt	if (par->target->checkentry != NULL && !par->target->checkentry(par))
503367c679007fa4f990eb7ee381326ec59d8148b0eJan Engelhardt		return -EINVAL;
50437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	return 0;
50537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy}
50637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardyEXPORT_SYMBOL_GPL(xt_check_target);
50737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy
5082722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT
5095452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardtint xt_compat_target_offset(const struct xt_target *target)
5102722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{
5119fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	u_int16_t csize = target->compatsize ? : target->targetsize;
5129fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	return XT_ALIGN(target->targetsize) - COMPAT_XT_ALIGN(csize);
5139fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy}
5149fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_target_offset);
5159fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
5169fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyvoid xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr,
517b0a6363c2418c93f25dd30b8ffcd3fdd4ce23ad6Patrick McHardy				unsigned int *size)
5189fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy{
5195452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt	const struct xt_target *target = t->u.kernel.target;
5209fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	struct compat_xt_entry_target *ct = (struct compat_xt_entry_target *)t;
5219fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	int pad, off = xt_compat_target_offset(target);
5229fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	u_int16_t tsize = ct->u.user.target_size;
5239fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
5249fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	t = *dstptr;
5259fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	memcpy(t, ct, sizeof(*ct));
5269fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (target->compat_from_user)
5279fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		target->compat_from_user(t->data, ct->data);
5289fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	else
5299fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		memcpy(t->data, ct->data, tsize - sizeof(*ct));
5309fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	pad = XT_ALIGN(target->targetsize) - target->targetsize;
5319fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (pad > 0)
5329fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		memset(t->data + target->targetsize, 0, pad);
5339fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
5349fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	tsize += off;
5359fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	t->u.user.target_size = tsize;
5369fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
5379fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*size += off;
5389fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*dstptr += tsize;
5399fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy}
5409fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_target_from_user);
5419fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
5429fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyint xt_compat_target_to_user(struct xt_entry_target *t, void __user **dstptr,
543b0a6363c2418c93f25dd30b8ffcd3fdd4ce23ad6Patrick McHardy			     unsigned int *size)
5449fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy{
5455452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt	const struct xt_target *target = t->u.kernel.target;
5469fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	struct compat_xt_entry_target __user *ct = *dstptr;
5479fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	int off = xt_compat_target_offset(target);
5489fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	u_int16_t tsize = t->u.user.target_size - off;
5499fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
5509fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (copy_to_user(ct, t, sizeof(*ct)) ||
551a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy	    put_user(tsize, &ct->u.user.target_size) ||
552a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy	    copy_to_user(ct->u.user.name, t->u.kernel.target->name,
553a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy			 strlen(t->u.kernel.target->name) + 1))
554601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki		return -EFAULT;
5559fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
5569fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (target->compat_to_user) {
5579fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		if (target->compat_to_user((void __user *)ct->data, t->data))
5589fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy			return -EFAULT;
5599fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	} else {
5609fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		if (copy_to_user(ct->data, t->data, tsize - sizeof(*ct)))
5619fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy			return -EFAULT;
5622722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	}
5639fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
5649fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*size -= off;
5659fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*dstptr += tsize;
5669fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	return 0;
5672722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin}
5689fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_target_to_user);
5692722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#endif
5702722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin
5712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_table_info *xt_alloc_table_info(unsigned int size)
5722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
5732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table_info *newinfo;
5742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int cpu;
5752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
5772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if ((SMP_ALIGN(size) >> PAGE_SHIFT) + 2 > num_physpages)
5782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
5792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
580259d4e41f3ec25f22169daece42729f597b89f9aEric Dumazet	newinfo = kzalloc(XT_TABLE_INFO_SZ, GFP_KERNEL);
5812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!newinfo)
5822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
5832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	newinfo->size = size;
5852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5866f912042256c12b0927438122594f5379b364f5dKAMEZAWA Hiroyuki	for_each_possible_cpu(cpu) {
5872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (size <= PAGE_SIZE)
5882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			newinfo->entries[cpu] = kmalloc_node(size,
5892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte							GFP_KERNEL,
5902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte							cpu_to_node(cpu));
5912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		else
5922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			newinfo->entries[cpu] = vmalloc_node(size,
5932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte							cpu_to_node(cpu));
5942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
5952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (newinfo->entries[cpu] == NULL) {
5962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			xt_free_table_info(newinfo);
5972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			return NULL;
5982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
5992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
6002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return newinfo;
6022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
6032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_alloc_table_info);
6042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid xt_free_table_info(struct xt_table_info *info)
6062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
6072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int cpu;
6082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6096f912042256c12b0927438122594f5379b364f5dKAMEZAWA Hiroyuki	for_each_possible_cpu(cpu) {
6102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (info->size <= PAGE_SIZE)
6112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			kfree(info->entries[cpu]);
6122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		else
6132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			vfree(info->entries[cpu]);
6142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
6152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	kfree(info);
6162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
6172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_free_table_info);
6182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Find table by name, grabs mutex & ref.  Returns ERR_PTR() on error. */
62076108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstruct xt_table *xt_find_table_lock(struct net *net, u_int8_t af,
62176108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt				    const char *name)
6222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
6232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table *t;
6242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6259e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	if (mutex_lock_interruptible(&xt[af].mutex) != 0)
6262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ERR_PTR(-EINTR);
6272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6288d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	list_for_each_entry(t, &net->xt.tables[af], list)
6292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(t->name, name) == 0 && try_module_get(t->me))
6302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			return t;
6319e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
6322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return NULL;
6332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
6342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_find_table_lock);
6352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid xt_table_unlock(struct xt_table *table)
6372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
6389e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[table->af].mutex);
6392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
6402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_table_unlock);
6412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6422722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT
64376108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtvoid xt_compat_lock(u_int8_t af)
6442722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{
6452722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	mutex_lock(&xt[af].compat_mutex);
6462722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin}
6472722971cbe831117686039d5c334f2c0f560be13Dmitry MishinEXPORT_SYMBOL_GPL(xt_compat_lock);
6482722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin
64976108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtvoid xt_compat_unlock(u_int8_t af)
6502722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{
6512722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	mutex_unlock(&xt[af].compat_mutex);
6522722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin}
6532722971cbe831117686039d5c334f2c0f560be13Dmitry MishinEXPORT_SYMBOL_GPL(xt_compat_unlock);
6542722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#endif
6552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_table_info *
6572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltext_replace_table(struct xt_table *table,
6582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	      unsigned int num_counters,
6592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	      struct xt_table_info *newinfo,
6602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	      int *error)
6612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
6622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table_info *oldinfo, *private;
6632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Do the substitution. */
6652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	write_lock_bh(&table->lock);
6662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	private = table->private;
6672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Check inside lock: is the old number correct? */
6682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (num_counters != private->number) {
6692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		duprintf("num_counters != table->private->number (%u/%u)\n",
6702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			 num_counters, private->number);
6712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		write_unlock_bh(&table->lock);
6722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		*error = -EAGAIN;
6732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
6742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
6752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	oldinfo = private;
6762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	table->private = newinfo;
6772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	newinfo->initial_entries = oldinfo->initial_entries;
6782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	write_unlock_bh(&table->lock);
6792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return oldinfo;
6812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
6822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_replace_table);
6832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6848d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyanstruct xt_table *xt_register_table(struct net *net, struct xt_table *table,
685a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan				   struct xt_table_info *bootstrap,
686a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan				   struct xt_table_info *newinfo)
6872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
6882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int ret;
6892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table_info *private;
690df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy	struct xt_table *t;
6912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
69244d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan	/* Don't add one object to multiple lists. */
69344d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan	table = kmemdup(table, sizeof(struct xt_table), GFP_KERNEL);
69444d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan	if (!table) {
69544d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan		ret = -ENOMEM;
69644d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan		goto out;
69744d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan	}
69844d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan
6999e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	ret = mutex_lock_interruptible(&xt[table->af].mutex);
7002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (ret != 0)
70144d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan		goto out_free;
7022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Don't autoload: we'd eat our tail... */
7048d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	list_for_each_entry(t, &net->xt.tables[table->af], list) {
705df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy		if (strcmp(t->name, table->name) == 0) {
706df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy			ret = -EEXIST;
707df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy			goto unlock;
708df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy		}
7092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
7102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Simplifies replace_table code. */
7122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	table->private = bootstrap;
71391536b7ae67710ca888e03ea82c60f0ac073a015Dmitry Mishin	rwlock_init(&table->lock);
7142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!xt_replace_table(table, 0, newinfo, &ret))
7152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto unlock;
7162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	private = table->private;
7182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	duprintf("table->private->number = %u\n", private->number);
7192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* save number of initial entries */
7212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	private->initial_entries = private->number;
7222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7238d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	list_add(&table->list, &net->xt.tables[table->af]);
724a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan	mutex_unlock(&xt[table->af].mutex);
725a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan	return table;
7262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte unlock:
7289e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[table->af].mutex);
72944d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyanout_free:
73044d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan	kfree(table);
731a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyanout:
732a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan	return ERR_PTR(ret);
7332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
7342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_register_table);
7352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid *xt_unregister_table(struct xt_table *table)
7372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
7382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table_info *private;
7392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7409e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_lock(&xt[table->af].mutex);
7412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	private = table->private;
742df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy	list_del(&table->list);
7439e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[table->af].mutex);
74444d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan	kfree(table);
7452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return private;
7472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
7482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_unregister_table);
7492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
751715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyanstruct xt_names_priv {
752715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	struct seq_net_private p;
75376108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	u_int8_t af;
754715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan};
755025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void *xt_table_seq_start(struct seq_file *seq, loff_t *pos)
7562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
757715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	struct xt_names_priv *priv = seq->private;
7581218854afa6f659be90b748cf1bc7badee954a35YOSHIFUJI Hideaki	struct net *net = seq_file_net(seq);
75976108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	u_int8_t af = priv->af;
7602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
761025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	mutex_lock(&xt[af].mutex);
762715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	return seq_list_start(&net->xt.tables[af], *pos);
763025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
7642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
765025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void *xt_table_seq_next(struct seq_file *seq, void *v, loff_t *pos)
766025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
767715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	struct xt_names_priv *priv = seq->private;
7681218854afa6f659be90b748cf1bc7badee954a35YOSHIFUJI Hideaki	struct net *net = seq_file_net(seq);
76976108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	u_int8_t af = priv->af;
7702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
771715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	return seq_list_next(v, &net->xt.tables[af], pos);
7722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
7732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
774025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void xt_table_seq_stop(struct seq_file *seq, void *v)
7752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
776715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	struct xt_names_priv *priv = seq->private;
77776108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	u_int8_t af = priv->af;
7782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
779025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	mutex_unlock(&xt[af].mutex);
780025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
7812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
782025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_table_seq_show(struct seq_file *seq, void *v)
783025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
784025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	struct xt_table *table = list_entry(v, struct xt_table, list);
7852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
786025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	if (strlen(table->name))
787025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan		return seq_printf(seq, "%s\n", table->name);
788025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	else
789025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan		return 0;
790025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
791601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki
792025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct seq_operations xt_table_seq_ops = {
793025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.start	= xt_table_seq_start,
794025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.next	= xt_table_seq_next,
795025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.stop	= xt_table_seq_stop,
796025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.show	= xt_table_seq_show,
797025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan};
798025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
799025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_table_open(struct inode *inode, struct file *file)
800025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
801025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	int ret;
802715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	struct xt_names_priv *priv;
803025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
804715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	ret = seq_open_net(inode, file, &xt_table_seq_ops,
805715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan			   sizeof(struct xt_names_priv));
806025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	if (!ret) {
807715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan		priv = ((struct seq_file *)file->private_data)->private;
808715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan		priv->af = (unsigned long)PDE(inode)->data;
809025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	}
810025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	return ret;
8112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
8122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
813025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct file_operations xt_table_ops = {
814025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.owner	 = THIS_MODULE,
815025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.open	 = xt_table_open,
816025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.read	 = seq_read,
817025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.llseek	 = seq_lseek,
8180e93bb9459f56b50a2f71f2c230f4ad00ec40a73Pavel Emelyanov	.release = seq_release_net,
819025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan};
820025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
821025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void *xt_match_seq_start(struct seq_file *seq, loff_t *pos)
8222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
823025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	struct proc_dir_entry *pde = (struct proc_dir_entry *)seq->private;
824025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	u_int16_t af = (unsigned long)pde->data;
8252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
826025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	mutex_lock(&xt[af].mutex);
827025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	return seq_list_start(&xt[af].match, *pos);
828025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
829601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki
830025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void *xt_match_seq_next(struct seq_file *seq, void *v, loff_t *pos)
831025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
832025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	struct proc_dir_entry *pde = (struct proc_dir_entry *)seq->private;
833025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	u_int16_t af = (unsigned long)pde->data;
8342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
835025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	return seq_list_next(v, &xt[af].match, pos);
8362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
8372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
838025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void xt_match_seq_stop(struct seq_file *seq, void *v)
8392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
8402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct proc_dir_entry *pde = seq->private;
841025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	u_int16_t af = (unsigned long)pde->data;
8422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8439e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
8442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
8452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
846025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_match_seq_show(struct seq_file *seq, void *v)
8472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
848025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	struct xt_match *match = list_entry(v, struct xt_match, list);
8492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
850025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	if (strlen(match->name))
851025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan		return seq_printf(seq, "%s\n", match->name);
8522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	else
8532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return 0;
8542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
8552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
856025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct seq_operations xt_match_seq_ops = {
857025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.start	= xt_match_seq_start,
858025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.next	= xt_match_seq_next,
859025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.stop	= xt_match_seq_stop,
860025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.show	= xt_match_seq_show,
8612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte};
8622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
863025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_match_open(struct inode *inode, struct file *file)
8642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
8652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int ret;
8662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
867025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	ret = seq_open(file, &xt_match_seq_ops);
8682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!ret) {
8692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		struct seq_file *seq = file->private_data;
8702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
871025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan		seq->private = PDE(inode);
8722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
873025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	return ret;
874025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
875025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
876025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct file_operations xt_match_ops = {
877025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.owner	 = THIS_MODULE,
878025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.open	 = xt_match_open,
879025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.read	 = seq_read,
880025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.llseek	 = seq_lseek,
881025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.release = seq_release,
882025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan};
8832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
884025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void *xt_target_seq_start(struct seq_file *seq, loff_t *pos)
885025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
886025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	struct proc_dir_entry *pde = (struct proc_dir_entry *)seq->private;
887025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	u_int16_t af = (unsigned long)pde->data;
888025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
889025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	mutex_lock(&xt[af].mutex);
890025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	return seq_list_start(&xt[af].target, *pos);
891025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
892025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
893025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void *xt_target_seq_next(struct seq_file *seq, void *v, loff_t *pos)
894025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
895025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	struct proc_dir_entry *pde = (struct proc_dir_entry *)seq->private;
896025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	u_int16_t af = (unsigned long)pde->data;
897025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
898025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	return seq_list_next(v, &xt[af].target, pos);
899025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
900025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
901025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void xt_target_seq_stop(struct seq_file *seq, void *v)
902025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
903025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	struct proc_dir_entry *pde = seq->private;
904025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	u_int16_t af = (unsigned long)pde->data;
905025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
906025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	mutex_unlock(&xt[af].mutex);
907025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
908025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
909025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_target_seq_show(struct seq_file *seq, void *v)
910025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
911025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	struct xt_target *target = list_entry(v, struct xt_target, list);
912025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
913025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	if (strlen(target->name))
914025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan		return seq_printf(seq, "%s\n", target->name);
915025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	else
916025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan		return 0;
917025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
918025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
919025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct seq_operations xt_target_seq_ops = {
920025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.start	= xt_target_seq_start,
921025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.next	= xt_target_seq_next,
922025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.stop	= xt_target_seq_stop,
923025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.show	= xt_target_seq_show,
924025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan};
925025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
926025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_target_open(struct inode *inode, struct file *file)
927025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
928025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	int ret;
929025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
930025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	ret = seq_open(file, &xt_target_seq_ops);
931025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	if (!ret) {
932025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan		struct seq_file *seq = file->private_data;
933025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
934025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan		seq->private = PDE(inode);
935025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	}
9362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ret;
9372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
9382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
939025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct file_operations xt_target_ops = {
9402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.owner	 = THIS_MODULE,
941025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.open	 = xt_target_open,
9422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.read	 = seq_read,
9432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.llseek	 = seq_lseek,
9442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.release = seq_release,
9452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte};
9462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
9472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define FORMAT_TABLES	"_tables_names"
9482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define	FORMAT_MATCHES	"_tables_matches"
9492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define FORMAT_TARGETS 	"_tables_targets"
9502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
9512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif /* CONFIG_PROC_FS */
9522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
95376108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtint xt_proto_init(struct net *net, u_int8_t af)
9542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
9552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
9562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	char buf[XT_FUNCTION_MAXNAMELEN];
9572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct proc_dir_entry *proc;
9582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif
9592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
9607e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	if (af >= ARRAY_SIZE(xt_prefix))
9612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return -EINVAL;
9622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
9632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
9642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
965ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
9662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TABLES, sizeof(buf));
9678b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev	proc = proc_create_data(buf, 0440, net->proc_net, &xt_table_ops,
9688b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev				(void *)(unsigned long)af);
9692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!proc)
9702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto out;
9712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
972ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
9732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
9748b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev	proc = proc_create_data(buf, 0440, net->proc_net, &xt_match_ops,
9758b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev				(void *)(unsigned long)af);
9762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!proc)
9772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto out_remove_tables;
9782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
979ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
9802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TARGETS, sizeof(buf));
9818b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev	proc = proc_create_data(buf, 0440, net->proc_net, &xt_target_ops,
9828b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev				(void *)(unsigned long)af);
9832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!proc)
9842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto out_remove_matches;
9852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif
9862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
9872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return 0;
9882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
9892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
9902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteout_remove_matches:
991ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
9922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
9933cb609d57c20027a8b39fc60b79b930a89da82d4Alexey Dobriyan	proc_net_remove(net, buf);
9942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
9952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteout_remove_tables:
996ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
9972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TABLES, sizeof(buf));
9983cb609d57c20027a8b39fc60b79b930a89da82d4Alexey Dobriyan	proc_net_remove(net, buf);
9992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteout:
10002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return -1;
10012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif
10022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
10032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_proto_init);
10042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
100576108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtvoid xt_proto_fini(struct net *net, u_int8_t af)
10062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
10072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
10082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	char buf[XT_FUNCTION_MAXNAMELEN];
10092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1010ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
10112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TABLES, sizeof(buf));
10123cb609d57c20027a8b39fc60b79b930a89da82d4Alexey Dobriyan	proc_net_remove(net, buf);
10132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1014ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
10152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TARGETS, sizeof(buf));
10163cb609d57c20027a8b39fc60b79b930a89da82d4Alexey Dobriyan	proc_net_remove(net, buf);
10172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1018ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
10192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
10203cb609d57c20027a8b39fc60b79b930a89da82d4Alexey Dobriyan	proc_net_remove(net, buf);
10212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif /*CONFIG_PROC_FS*/
10222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
10232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_proto_fini);
10242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
10258d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyanstatic int __net_init xt_net_init(struct net *net)
10268d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan{
10278d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	int i;
10288d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan
10297e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	for (i = 0; i < NFPROTO_NUMPROTO; i++)
10308d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan		INIT_LIST_HEAD(&net->xt.tables[i]);
10318d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	return 0;
10328d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan}
10338d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan
10348d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyanstatic struct pernet_operations xt_net_ops = {
10358d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	.init = xt_net_init,
10368d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan};
10372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
10382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic int __init xt_init(void)
10392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
10408d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	int i, rv;
10412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
10427e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	xt = kmalloc(sizeof(struct xt_af) * NFPROTO_NUMPROTO, GFP_KERNEL);
10432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!xt)
10442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return -ENOMEM;
10452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
10467e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	for (i = 0; i < NFPROTO_NUMPROTO; i++) {
10479e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar		mutex_init(&xt[i].mutex);
10482722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT
10492722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin		mutex_init(&xt[i].compat_mutex);
1050b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		xt[i].compat_offsets = NULL;
10512722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#endif
10522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		INIT_LIST_HEAD(&xt[i].target);
10532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		INIT_LIST_HEAD(&xt[i].match);
10542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
10558d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	rv = register_pernet_subsys(&xt_net_ops);
10568d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	if (rv < 0)
10578d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan		kfree(xt);
10588d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	return rv;
10592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
10602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
10612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic void __exit xt_fini(void)
10622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
10638d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	unregister_pernet_subsys(&xt_net_ops);
10642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	kfree(xt);
10652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
10662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
10672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltemodule_init(xt_init);
10682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltemodule_exit(xt_fini);
10692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1070