x_tables.c revision d97a9e47ba148cfc41e354c5cd241f472273207c
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 */
15be91fd5e323b46450ca82f6828e933e3791fb2f2Jan Engelhardt#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
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>
255a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
26457c4cbc5a3dde259d2a1f15d5f9785290397267Eric W. Biederman#include <net/net_namespace.h>
272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/netfilter/x_tables.h>
292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/netfilter_arp.h>
30e3eaa9910b380530cfd2c0670fcd3f627674da8aJan Engelhardt#include <linux/netfilter_ipv4/ip_tables.h>
31e3eaa9910b380530cfd2c0670fcd3f627674da8aJan Engelhardt#include <linux/netfilter_ipv6/ip6_tables.h>
32e3eaa9910b380530cfd2c0670fcd3f627674da8aJan Engelhardt#include <linux/netfilter_arp/arp_tables.h>
339e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar
342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteMODULE_LICENSE("GPL");
352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteMODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
36043ef46c7690bfdbd5b012e15812a14a19ca5604Jan EngelhardtMODULE_DESCRIPTION("{ip,ip6,arp,eb}_tables backend module");
372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
40b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardystruct compat_delta {
41b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	struct compat_delta *next;
42b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	unsigned int offset;
433e5e524ffb5fcf2447eb5dd9f8e54ad22dd9baa7Florian Westphal	int delta;
44b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy};
45b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_af {
479e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	struct mutex mutex;
482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct list_head match;
492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct list_head target;
50b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy#ifdef CONFIG_COMPAT
512722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	struct mutex compat_mutex;
52b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	struct compat_delta *compat_offsets;
53b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy#endif
542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte};
552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic struct xt_af *xt;
572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
587e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardtstatic const char *const xt_prefix[NFPROTO_NUMPROTO] = {
597e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	[NFPROTO_UNSPEC] = "x",
607e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	[NFPROTO_IPV4]   = "ip",
617e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	[NFPROTO_ARP]    = "arp",
627e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	[NFPROTO_BRIDGE] = "eb",
637e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	[NFPROTO_IPV6]   = "ip6",
6437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy};
6537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy
66f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt/* Allow this many total (re)entries. */
67f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardtstatic const unsigned int xt_jumpstack_multiplier = 2;
68f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt
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
221fd0ec0e6216baea854465bbdb177f2d1b2ccaf22Jan Engelhardtstruct xt_match *
222fd0ec0e6216baea854465bbdb177f2d1b2ccaf22Jan Engelhardtxt_request_find_match(uint8_t nfproto, const char *name, uint8_t revision)
223fd0ec0e6216baea854465bbdb177f2d1b2ccaf22Jan Engelhardt{
224fd0ec0e6216baea854465bbdb177f2d1b2ccaf22Jan Engelhardt	struct xt_match *match;
225fd0ec0e6216baea854465bbdb177f2d1b2ccaf22Jan Engelhardt
226fd0ec0e6216baea854465bbdb177f2d1b2ccaf22Jan Engelhardt	match = try_then_request_module(xt_find_match(nfproto, name, revision),
227fd0ec0e6216baea854465bbdb177f2d1b2ccaf22Jan Engelhardt					"%st_%s", xt_prefix[nfproto], name);
228fd0ec0e6216baea854465bbdb177f2d1b2ccaf22Jan Engelhardt	return (match != NULL) ? match : ERR_PTR(-ENOENT);
229fd0ec0e6216baea854465bbdb177f2d1b2ccaf22Jan Engelhardt}
230fd0ec0e6216baea854465bbdb177f2d1b2ccaf22Jan EngelhardtEXPORT_SYMBOL_GPL(xt_request_find_match);
231fd0ec0e6216baea854465bbdb177f2d1b2ccaf22Jan Engelhardt
2322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Find target, grabs ref.  Returns ERR_PTR() on error. */
23376108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstruct xt_target *xt_find_target(u8 af, const char *name, u8 revision)
2342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
2352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_target *t;
2362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int err = 0;
2372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2389e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	if (mutex_lock_interruptible(&xt[af].mutex) != 0)
2392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ERR_PTR(-EINTR);
2402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(t, &xt[af].target, list) {
2422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(t->name, name) == 0) {
2432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (t->revision == revision) {
2442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				if (try_module_get(t->me)) {
2459e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar					mutex_unlock(&xt[af].mutex);
2462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte					return t;
2472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				}
2482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			} else
2492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				err = -EPROTOTYPE; /* Found something. */
2502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
2512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
2529e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
25355b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt
25455b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt	if (af != NFPROTO_UNSPEC)
25555b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt		/* Try searching again in the family-independent list */
25655b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt		return xt_find_target(NFPROTO_UNSPEC, name, revision);
25755b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt
2582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ERR_PTR(err);
2592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
2602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_find_target);
2612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
26276108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstruct xt_target *xt_request_find_target(u8 af, const char *name, u8 revision)
2632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
2642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_target *target;
2652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	target = try_then_request_module(xt_find_target(af, name, revision),
26737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy					 "%st_%s", xt_prefix[af], name);
268d2a7b6bad2c38e41eddb0b24d03627d9e7aa3f7bJan Engelhardt	return (target != NULL) ? target : ERR_PTR(-ENOENT);
2692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
2702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_request_find_target);
2712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
27276108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstatic int match_revfn(u8 af, const char *name, u8 revision, int *bestp)
2732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
2745452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt	const struct xt_match *m;
2752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int have_rev = 0;
2762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(m, &xt[af].match, list) {
2782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(m->name, name) == 0) {
2792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (m->revision > *bestp)
2802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				*bestp = m->revision;
2812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (m->revision == revision)
2822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				have_rev = 1;
2832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
2842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
285656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy
286656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy	if (af != NFPROTO_UNSPEC && !have_rev)
287656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy		return match_revfn(NFPROTO_UNSPEC, name, revision, bestp);
288656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy
2892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return have_rev;
2902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
2912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
29276108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstatic int target_revfn(u8 af, const char *name, u8 revision, int *bestp)
2932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
2945452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt	const struct xt_target *t;
2952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int have_rev = 0;
2962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(t, &xt[af].target, list) {
2982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(t->name, name) == 0) {
2992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (t->revision > *bestp)
3002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				*bestp = t->revision;
3012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (t->revision == revision)
3022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				have_rev = 1;
3032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
3042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
305656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy
306656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy	if (af != NFPROTO_UNSPEC && !have_rev)
307656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy		return target_revfn(NFPROTO_UNSPEC, name, revision, bestp);
308656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy
3092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return have_rev;
3102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
3112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Returns true or false (if no such extension at all) */
31376108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtint xt_find_revision(u8 af, const char *name, u8 revision, int target,
3142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		     int *err)
3152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
3162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int have_rev, best = -1;
3172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3189e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	if (mutex_lock_interruptible(&xt[af].mutex) != 0) {
3192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		*err = -EINTR;
3202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return 1;
3212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
3222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (target == 1)
3232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		have_rev = target_revfn(af, name, revision, &best);
3242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	else
3252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		have_rev = match_revfn(af, name, revision, &best);
3269e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
3272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Nothing at all?  Return 0 to try loading module. */
3292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (best == -1) {
3302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		*err = -ENOENT;
3312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return 0;
3322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
3332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	*err = best;
3352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!have_rev)
3362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		*err = -EPROTONOSUPPORT;
3372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return 1;
3382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
3392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_find_revision);
3402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
341451853645f3cb804b523227eca054701e4cbc589Jan Engelhardtstatic char *textify_hooks(char *buf, size_t size, unsigned int mask)
342451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt{
343451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	static const char *const names[] = {
344451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		"PREROUTING", "INPUT", "FORWARD",
345451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		"OUTPUT", "POSTROUTING", "BROUTING",
346451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	};
347451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	unsigned int i;
348451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	char *p = buf;
349451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	bool np = false;
350451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	int res;
351451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt
352451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	*p = '\0';
353451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	for (i = 0; i < ARRAY_SIZE(names); ++i) {
354451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		if (!(mask & (1 << i)))
355451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt			continue;
356451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		res = snprintf(p, size, "%s%s", np ? "/" : "", names[i]);
357451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		if (res > 0) {
358451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt			size -= res;
359451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt			p += res;
360451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		}
361451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		np = true;
362451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	}
363451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt
364451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	return buf;
365451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt}
366451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt
367916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardtint xt_check_match(struct xt_mtchk_param *par,
3689b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt		   unsigned int size, u_int8_t proto, bool inv_proto)
36937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy{
370bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt	int ret;
371bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt
3729b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt	if (XT_ALIGN(par->match->matchsize) != size &&
3739b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt	    par->match->matchsize != -1) {
374043ef46c7690bfdbd5b012e15812a14a19ca5604Jan Engelhardt		/*
375043ef46c7690bfdbd5b012e15812a14a19ca5604Jan Engelhardt		 * ebt_among is exempt from centralized matchsize checking
376043ef46c7690bfdbd5b012e15812a14a19ca5604Jan Engelhardt		 * because it uses a dynamic-size data set.
377043ef46c7690bfdbd5b012e15812a14a19ca5604Jan Engelhardt		 */
378b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt		pr_err("%s_tables: %s.%u match: invalid size "
379b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt		       "%u (kernel) != (user) %u\n",
380916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt		       xt_prefix[par->family], par->match->name,
381b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt		       par->match->revision,
3829b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt		       XT_ALIGN(par->match->matchsize), size);
38337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
38437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
3859b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt	if (par->match->table != NULL &&
3869b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt	    strcmp(par->match->table, par->table) != 0) {
3873dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches		pr_err("%s_tables: %s match: only valid in %s table, not %s\n",
388916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt		       xt_prefix[par->family], par->match->name,
3899b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt		       par->match->table, par->table);
39037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
39137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
3929b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt	if (par->match->hooks && (par->hook_mask & ~par->match->hooks) != 0) {
393451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		char used[64], allow[64];
394451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt
3953dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches		pr_err("%s_tables: %s match: used from hooks %s, but only "
396451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		       "valid from %s\n",
397916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt		       xt_prefix[par->family], par->match->name,
398451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		       textify_hooks(used, sizeof(used), par->hook_mask),
399451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		       textify_hooks(allow, sizeof(allow), par->match->hooks));
40037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
40137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
4029b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt	if (par->match->proto && (par->match->proto != proto || inv_proto)) {
4033dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches		pr_err("%s_tables: %s match: only valid for protocol %u\n",
404916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt		       xt_prefix[par->family], par->match->name,
405916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt		       par->match->proto);
40637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
40737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
408bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt	if (par->match->checkentry != NULL) {
409bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt		ret = par->match->checkentry(par);
410bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt		if (ret < 0)
411bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt			return ret;
412bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt		else if (ret > 0)
413bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt			/* Flag up potential errors. */
414bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt			return -EIO;
415bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt	}
41637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	return 0;
41737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy}
41837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardyEXPORT_SYMBOL_GPL(xt_check_match);
41937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy
4202722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT
42176108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtint xt_compat_add_offset(u_int8_t af, unsigned int offset, short delta)
422b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy{
423b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	struct compat_delta *tmp;
424b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
425b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	tmp = kmalloc(sizeof(struct compat_delta), GFP_KERNEL);
426b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	if (!tmp)
427b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		return -ENOMEM;
428b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
429b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	tmp->offset = offset;
430b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	tmp->delta = delta;
431b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
432b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	if (xt[af].compat_offsets) {
433b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		tmp->next = xt[af].compat_offsets->next;
434b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		xt[af].compat_offsets->next = tmp;
435b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	} else {
436b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		xt[af].compat_offsets = tmp;
437b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		tmp->next = NULL;
438b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	}
439b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	return 0;
440b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy}
441b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_add_offset);
442b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
44376108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtvoid xt_compat_flush_offsets(u_int8_t af)
444b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy{
445b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	struct compat_delta *tmp, *next;
446b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
447b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	if (xt[af].compat_offsets) {
448b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		for (tmp = xt[af].compat_offsets; tmp; tmp = next) {
449b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy			next = tmp->next;
450b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy			kfree(tmp);
451b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		}
452b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		xt[af].compat_offsets = NULL;
453b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	}
454b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy}
455b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_flush_offsets);
456b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
4573e5e524ffb5fcf2447eb5dd9f8e54ad22dd9baa7Florian Westphalint xt_compat_calc_jump(u_int8_t af, unsigned int offset)
458b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy{
459b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	struct compat_delta *tmp;
4603e5e524ffb5fcf2447eb5dd9f8e54ad22dd9baa7Florian Westphal	int delta;
461b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
462b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	for (tmp = xt[af].compat_offsets, delta = 0; tmp; tmp = tmp->next)
463b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		if (tmp->offset < offset)
464b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy			delta += tmp->delta;
465b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	return delta;
466b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy}
467b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_calc_jump);
468b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
4695452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardtint xt_compat_match_offset(const struct xt_match *match)
4702722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{
4719fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	u_int16_t csize = match->compatsize ? : match->matchsize;
4729fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	return XT_ALIGN(match->matchsize) - COMPAT_XT_ALIGN(csize);
4739fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy}
4749fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_match_offset);
4759fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
4768956695131b8a7878891667469899d667eb5892bPatrick McHardyint xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr,
477b0a6363c2418c93f25dd30b8ffcd3fdd4ce23ad6Patrick McHardy			      unsigned int *size)
4789fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy{
4795452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt	const struct xt_match *match = m->u.kernel.match;
4809fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	struct compat_xt_entry_match *cm = (struct compat_xt_entry_match *)m;
4819fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	int pad, off = xt_compat_match_offset(match);
4829fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	u_int16_t msize = cm->u.user.match_size;
4839fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
4849fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	m = *dstptr;
4859fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	memcpy(m, cm, sizeof(*cm));
4869fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (match->compat_from_user)
4879fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		match->compat_from_user(m->data, cm->data);
4889fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	else
4899fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		memcpy(m->data, cm->data, msize - sizeof(*cm));
4909fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	pad = XT_ALIGN(match->matchsize) - match->matchsize;
4919fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (pad > 0)
4929fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		memset(m->data + match->matchsize, 0, pad);
4939fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
4949fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	msize += off;
4959fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	m->u.user.match_size = msize;
4969fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
4979fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*size += off;
4989fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*dstptr += msize;
4998956695131b8a7878891667469899d667eb5892bPatrick McHardy	return 0;
5009fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy}
5019fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_match_from_user);
5029fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
503739674fb7febf116e7d647031fab16989a08a965Jan Engelhardtint xt_compat_match_to_user(const struct xt_entry_match *m,
504739674fb7febf116e7d647031fab16989a08a965Jan Engelhardt			    void __user **dstptr, unsigned int *size)
5059fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy{
5065452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt	const struct xt_match *match = m->u.kernel.match;
5079fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	struct compat_xt_entry_match __user *cm = *dstptr;
5089fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	int off = xt_compat_match_offset(match);
5099fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	u_int16_t msize = m->u.user.match_size - off;
5109fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
5119fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (copy_to_user(cm, m, sizeof(*cm)) ||
512a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy	    put_user(msize, &cm->u.user.match_size) ||
513a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy	    copy_to_user(cm->u.user.name, m->u.kernel.match->name,
514a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy			 strlen(m->u.kernel.match->name) + 1))
515601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki		return -EFAULT;
5169fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
5179fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (match->compat_to_user) {
5189fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		if (match->compat_to_user((void __user *)cm->data, m->data))
5199fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy			return -EFAULT;
5209fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	} else {
5219fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		if (copy_to_user(cm->data, m->data, msize - sizeof(*cm)))
5229fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy			return -EFAULT;
5232722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	}
5249fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
5259fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*size -= off;
5269fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*dstptr += msize;
5279fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	return 0;
5282722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin}
5299fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_match_to_user);
5309fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy#endif /* CONFIG_COMPAT */
5312722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin
532916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardtint xt_check_target(struct xt_tgchk_param *par,
533af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt		    unsigned int size, u_int8_t proto, bool inv_proto)
53437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy{
535d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt	int ret;
536d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt
537af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt	if (XT_ALIGN(par->target->targetsize) != size) {
538b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt		pr_err("%s_tables: %s.%u target: invalid size "
539b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt		       "%u (kernel) != (user) %u\n",
540916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt		       xt_prefix[par->family], par->target->name,
541b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt		       par->target->revision,
542af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt		       XT_ALIGN(par->target->targetsize), size);
54337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
54437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
545af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt	if (par->target->table != NULL &&
546af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt	    strcmp(par->target->table, par->table) != 0) {
5473dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches		pr_err("%s_tables: %s target: only valid in %s table, not %s\n",
548916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt		       xt_prefix[par->family], par->target->name,
549af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt		       par->target->table, par->table);
55037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
55137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
552af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt	if (par->target->hooks && (par->hook_mask & ~par->target->hooks) != 0) {
553451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		char used[64], allow[64];
554451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt
5553dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches		pr_err("%s_tables: %s target: used from hooks %s, but only "
556451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		       "usable from %s\n",
557916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt		       xt_prefix[par->family], par->target->name,
558451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		       textify_hooks(used, sizeof(used), par->hook_mask),
559451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		       textify_hooks(allow, sizeof(allow), par->target->hooks));
56037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
56137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
562af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt	if (par->target->proto && (par->target->proto != proto || inv_proto)) {
5633dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches		pr_err("%s_tables: %s target: only valid for protocol %u\n",
564916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt		       xt_prefix[par->family], par->target->name,
565af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt		       par->target->proto);
56637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
56737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
568d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt	if (par->target->checkentry != NULL) {
569d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt		ret = par->target->checkentry(par);
570d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt		if (ret < 0)
571d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt			return ret;
572d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt		else if (ret > 0)
573d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt			/* Flag up potential errors. */
574d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt			return -EIO;
575d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt	}
57637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	return 0;
57737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy}
57837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardyEXPORT_SYMBOL_GPL(xt_check_target);
57937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy
5802722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT
5815452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardtint xt_compat_target_offset(const struct xt_target *target)
5822722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{
5839fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	u_int16_t csize = target->compatsize ? : target->targetsize;
5849fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	return XT_ALIGN(target->targetsize) - COMPAT_XT_ALIGN(csize);
5859fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy}
5869fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_target_offset);
5879fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
5889fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyvoid xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr,
589b0a6363c2418c93f25dd30b8ffcd3fdd4ce23ad6Patrick McHardy				unsigned int *size)
5909fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy{
5915452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt	const struct xt_target *target = t->u.kernel.target;
5929fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	struct compat_xt_entry_target *ct = (struct compat_xt_entry_target *)t;
5939fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	int pad, off = xt_compat_target_offset(target);
5949fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	u_int16_t tsize = ct->u.user.target_size;
5959fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
5969fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	t = *dstptr;
5979fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	memcpy(t, ct, sizeof(*ct));
5989fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (target->compat_from_user)
5999fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		target->compat_from_user(t->data, ct->data);
6009fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	else
6019fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		memcpy(t->data, ct->data, tsize - sizeof(*ct));
6029fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	pad = XT_ALIGN(target->targetsize) - target->targetsize;
6039fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (pad > 0)
6049fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		memset(t->data + target->targetsize, 0, pad);
6059fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
6069fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	tsize += off;
6079fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	t->u.user.target_size = tsize;
6089fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
6099fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*size += off;
6109fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*dstptr += tsize;
6119fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy}
6129fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_target_from_user);
6139fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
614739674fb7febf116e7d647031fab16989a08a965Jan Engelhardtint xt_compat_target_to_user(const struct xt_entry_target *t,
615739674fb7febf116e7d647031fab16989a08a965Jan Engelhardt			     void __user **dstptr, unsigned int *size)
6169fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy{
6175452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt	const struct xt_target *target = t->u.kernel.target;
6189fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	struct compat_xt_entry_target __user *ct = *dstptr;
6199fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	int off = xt_compat_target_offset(target);
6209fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	u_int16_t tsize = t->u.user.target_size - off;
6219fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
6229fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (copy_to_user(ct, t, sizeof(*ct)) ||
623a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy	    put_user(tsize, &ct->u.user.target_size) ||
624a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy	    copy_to_user(ct->u.user.name, t->u.kernel.target->name,
625a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy			 strlen(t->u.kernel.target->name) + 1))
626601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki		return -EFAULT;
6279fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
6289fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (target->compat_to_user) {
6299fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		if (target->compat_to_user((void __user *)ct->data, t->data))
6309fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy			return -EFAULT;
6319fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	} else {
6329fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		if (copy_to_user(ct->data, t->data, tsize - sizeof(*ct)))
6339fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy			return -EFAULT;
6342722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	}
6359fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
6369fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*size -= off;
6379fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*dstptr += tsize;
6389fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	return 0;
6392722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin}
6409fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_target_to_user);
6412722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#endif
6422722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin
6432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_table_info *xt_alloc_table_info(unsigned int size)
6442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
6452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table_info *newinfo;
6462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int cpu;
6472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
6494481374ce88ba8f460c8b89f2572027bd27057d0Jan Beulich	if ((SMP_ALIGN(size) >> PAGE_SHIFT) + 2 > totalram_pages)
6502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
6512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
652259d4e41f3ec25f22169daece42729f597b89f9aEric Dumazet	newinfo = kzalloc(XT_TABLE_INFO_SZ, GFP_KERNEL);
6532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!newinfo)
6542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
6552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	newinfo->size = size;
6572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6586f912042256c12b0927438122594f5379b364f5dKAMEZAWA Hiroyuki	for_each_possible_cpu(cpu) {
6592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (size <= PAGE_SIZE)
6602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			newinfo->entries[cpu] = kmalloc_node(size,
6612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte							GFP_KERNEL,
6622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte							cpu_to_node(cpu));
6632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		else
6642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			newinfo->entries[cpu] = vmalloc_node(size,
6652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte							cpu_to_node(cpu));
6662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (newinfo->entries[cpu] == NULL) {
6682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			xt_free_table_info(newinfo);
6692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			return NULL;
6702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
6712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
6722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return newinfo;
6742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
6752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_alloc_table_info);
6762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid xt_free_table_info(struct xt_table_info *info)
6782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
6792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int cpu;
6802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6816f912042256c12b0927438122594f5379b364f5dKAMEZAWA Hiroyuki	for_each_possible_cpu(cpu) {
6822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (info->size <= PAGE_SIZE)
6832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			kfree(info->entries[cpu]);
6842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		else
6852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			vfree(info->entries[cpu]);
6862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
687f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt
688f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	if (info->jumpstack != NULL) {
689f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt		if (sizeof(void *) * info->stacksize > PAGE_SIZE) {
690f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt			for_each_possible_cpu(cpu)
691f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt				vfree(info->jumpstack[cpu]);
692f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt		} else {
693f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt			for_each_possible_cpu(cpu)
694f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt				kfree(info->jumpstack[cpu]);
695f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt		}
696f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	}
697f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt
698f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	if (sizeof(void **) * nr_cpu_ids > PAGE_SIZE)
699f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt		vfree(info->jumpstack);
700f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	else
701f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt		kfree(info->jumpstack);
702f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	if (sizeof(unsigned int) * nr_cpu_ids > PAGE_SIZE)
703f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt		vfree(info->stackptr);
704f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	else
705f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt		kfree(info->stackptr);
706f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt
7072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	kfree(info);
7082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
7092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_free_table_info);
7102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Find table by name, grabs mutex & ref.  Returns ERR_PTR() on error. */
71276108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstruct xt_table *xt_find_table_lock(struct net *net, u_int8_t af,
71376108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt				    const char *name)
7142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
7152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table *t;
7162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7179e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	if (mutex_lock_interruptible(&xt[af].mutex) != 0)
7182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return ERR_PTR(-EINTR);
7192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7208d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	list_for_each_entry(t, &net->xt.tables[af], list)
7212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(t->name, name) == 0 && try_module_get(t->me))
7222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			return t;
7239e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
7242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return NULL;
7252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
7262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_find_table_lock);
7272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid xt_table_unlock(struct xt_table *table)
7292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
7309e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[table->af].mutex);
7312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
7322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_table_unlock);
7332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7342722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT
73576108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtvoid xt_compat_lock(u_int8_t af)
7362722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{
7372722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	mutex_lock(&xt[af].compat_mutex);
7382722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin}
7392722971cbe831117686039d5c334f2c0f560be13Dmitry MishinEXPORT_SYMBOL_GPL(xt_compat_lock);
7402722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin
74176108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtvoid xt_compat_unlock(u_int8_t af)
7422722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{
7432722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	mutex_unlock(&xt[af].compat_mutex);
7442722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin}
7452722971cbe831117686039d5c334f2c0f560be13Dmitry MishinEXPORT_SYMBOL_GPL(xt_compat_unlock);
7462722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#endif
7472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
748942e4a2bd680c606af0211e64eb216be2e19bf61Stephen HemmingerDEFINE_PER_CPU(struct xt_info_lock, xt_info_locks);
749942e4a2bd680c606af0211e64eb216be2e19bf61Stephen HemmingerEXPORT_PER_CPU_SYMBOL_GPL(xt_info_locks);
750942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger
751f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardtstatic int xt_jumpstack_alloc(struct xt_table_info *i)
752f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt{
753f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	unsigned int size;
754f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	int cpu;
755f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt
756f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	size = sizeof(unsigned int) * nr_cpu_ids;
757f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	if (size > PAGE_SIZE)
758f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt		i->stackptr = vmalloc(size);
759f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	else
760f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt		i->stackptr = kmalloc(size, GFP_KERNEL);
761f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	if (i->stackptr == NULL)
762f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt		return -ENOMEM;
763f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	memset(i->stackptr, 0, size);
764f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt
765f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	size = sizeof(void **) * nr_cpu_ids;
766f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	if (size > PAGE_SIZE)
767f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt		i->jumpstack = vmalloc(size);
768f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	else
769f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt		i->jumpstack = kmalloc(size, GFP_KERNEL);
770f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	if (i->jumpstack == NULL)
771f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt		return -ENOMEM;
772f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	memset(i->jumpstack, 0, size);
773f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt
774f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	i->stacksize *= xt_jumpstack_multiplier;
775f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	size = sizeof(void *) * i->stacksize;
776f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	for_each_possible_cpu(cpu) {
777f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt		if (size > PAGE_SIZE)
778f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt			i->jumpstack[cpu] = vmalloc_node(size,
779f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt				cpu_to_node(cpu));
780f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt		else
781f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt			i->jumpstack[cpu] = kmalloc_node(size,
782f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt				GFP_KERNEL, cpu_to_node(cpu));
783f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt		if (i->jumpstack[cpu] == NULL)
784f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt			/*
785f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt			 * Freeing will be done later on by the callers. The
786f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt			 * chain is: xt_replace_table -> __do_replace ->
787f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt			 * do_replace -> xt_free_table_info.
788f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt			 */
789f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt			return -ENOMEM;
790f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	}
791f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt
792f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	return 0;
793f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt}
794942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger
7952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_table_info *
7962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltext_replace_table(struct xt_table *table,
7972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	      unsigned int num_counters,
7982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	      struct xt_table_info *newinfo,
7992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	      int *error)
8002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
801942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	struct xt_table_info *private;
802f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	int ret;
8032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
804d97a9e47ba148cfc41e354c5cd241f472273207cJan Engelhardt	ret = xt_jumpstack_alloc(newinfo);
805d97a9e47ba148cfc41e354c5cd241f472273207cJan Engelhardt	if (ret < 0) {
806d97a9e47ba148cfc41e354c5cd241f472273207cJan Engelhardt		*error = ret;
807d97a9e47ba148cfc41e354c5cd241f472273207cJan Engelhardt		return NULL;
808d97a9e47ba148cfc41e354c5cd241f472273207cJan Engelhardt	}
809d97a9e47ba148cfc41e354c5cd241f472273207cJan Engelhardt
8102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Do the substitution. */
811942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	local_bh_disable();
8122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	private = table->private;
813942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger
8142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Check inside lock: is the old number correct? */
8152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (num_counters != private->number) {
816be91fd5e323b46450ca82f6828e933e3791fb2f2Jan Engelhardt		pr_debug("num_counters != table->private->number (%u/%u)\n",
8172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			 num_counters, private->number);
818942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger		local_bh_enable();
8192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		*error = -EAGAIN;
8202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
8212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
8222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
823942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	table->private = newinfo;
824942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	newinfo->initial_entries = private->initial_entries;
825942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger
826942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	/*
827942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	 * Even though table entries have now been swapped, other CPU's
828942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	 * may still be using the old entries. This is okay, because
829942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	 * resynchronization happens because of the locking done
830942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	 * during the get_counters() routine.
831942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	 */
832942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	local_bh_enable();
833942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger
834942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	return private;
8352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
8362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_replace_table);
8372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
83835aad0ffdf548617940ca1e78be1f2e0bafc4496Jan Engelhardtstruct xt_table *xt_register_table(struct net *net,
83935aad0ffdf548617940ca1e78be1f2e0bafc4496Jan Engelhardt				   const struct xt_table *input_table,
840a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan				   struct xt_table_info *bootstrap,
841a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan				   struct xt_table_info *newinfo)
8422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
8432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int ret;
8442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table_info *private;
84535aad0ffdf548617940ca1e78be1f2e0bafc4496Jan Engelhardt	struct xt_table *t, *table;
8462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
847f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	ret = xt_jumpstack_alloc(newinfo);
848f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	if (ret < 0)
849f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt		return ERR_PTR(ret);
850f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt
85144d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan	/* Don't add one object to multiple lists. */
85235aad0ffdf548617940ca1e78be1f2e0bafc4496Jan Engelhardt	table = kmemdup(input_table, sizeof(struct xt_table), GFP_KERNEL);
85344d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan	if (!table) {
85444d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan		ret = -ENOMEM;
85544d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan		goto out;
85644d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan	}
85744d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan
8589e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	ret = mutex_lock_interruptible(&xt[table->af].mutex);
8592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (ret != 0)
86044d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan		goto out_free;
8612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Don't autoload: we'd eat our tail... */
8638d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	list_for_each_entry(t, &net->xt.tables[table->af], list) {
864df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy		if (strcmp(t->name, table->name) == 0) {
865df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy			ret = -EEXIST;
866df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy			goto unlock;
867df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy		}
8682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
8692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Simplifies replace_table code. */
8712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	table->private = bootstrap;
872784544739a25c30637397ace5489eeb6e15d7d49Stephen Hemminger
8732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!xt_replace_table(table, 0, newinfo, &ret))
8742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto unlock;
8752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	private = table->private;
877be91fd5e323b46450ca82f6828e933e3791fb2f2Jan Engelhardt	pr_debug("table->private->number = %u\n", private->number);
8782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* save number of initial entries */
8802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	private->initial_entries = private->number;
8812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8828d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	list_add(&table->list, &net->xt.tables[table->af]);
883a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan	mutex_unlock(&xt[table->af].mutex);
884a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan	return table;
8852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte unlock:
8879e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[table->af].mutex);
88844d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyanout_free:
88944d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan	kfree(table);
890a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyanout:
891a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan	return ERR_PTR(ret);
8922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
8932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_register_table);
8942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid *xt_unregister_table(struct xt_table *table)
8962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
8972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table_info *private;
8982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8999e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_lock(&xt[table->af].mutex);
9002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	private = table->private;
901df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy	list_del(&table->list);
9029e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[table->af].mutex);
90344d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan	kfree(table);
9042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
9052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return private;
9062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
9072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_unregister_table);
9082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
9092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
910715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyanstruct xt_names_priv {
911715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	struct seq_net_private p;
91276108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	u_int8_t af;
913715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan};
914025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void *xt_table_seq_start(struct seq_file *seq, loff_t *pos)
9152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
916715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	struct xt_names_priv *priv = seq->private;
9171218854afa6f659be90b748cf1bc7badee954a35YOSHIFUJI Hideaki	struct net *net = seq_file_net(seq);
91876108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	u_int8_t af = priv->af;
9192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
920025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	mutex_lock(&xt[af].mutex);
921715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	return seq_list_start(&net->xt.tables[af], *pos);
922025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
9232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
924025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void *xt_table_seq_next(struct seq_file *seq, void *v, loff_t *pos)
925025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
926715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	struct xt_names_priv *priv = seq->private;
9271218854afa6f659be90b748cf1bc7badee954a35YOSHIFUJI Hideaki	struct net *net = seq_file_net(seq);
92876108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	u_int8_t af = priv->af;
9292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
930715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	return seq_list_next(v, &net->xt.tables[af], pos);
9312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
9322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
933025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void xt_table_seq_stop(struct seq_file *seq, void *v)
9342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
935715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	struct xt_names_priv *priv = seq->private;
93676108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	u_int8_t af = priv->af;
9372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
938025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	mutex_unlock(&xt[af].mutex);
939025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
9402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
941025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_table_seq_show(struct seq_file *seq, void *v)
942025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
943025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	struct xt_table *table = list_entry(v, struct xt_table, list);
9442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
945025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	if (strlen(table->name))
946025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan		return seq_printf(seq, "%s\n", table->name);
947025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	else
948025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan		return 0;
949025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
950601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki
951025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct seq_operations xt_table_seq_ops = {
952025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.start	= xt_table_seq_start,
953025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.next	= xt_table_seq_next,
954025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.stop	= xt_table_seq_stop,
955025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.show	= xt_table_seq_show,
956025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan};
957025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
958025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_table_open(struct inode *inode, struct file *file)
959025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
960025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	int ret;
961715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	struct xt_names_priv *priv;
962025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
963715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	ret = seq_open_net(inode, file, &xt_table_seq_ops,
964715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan			   sizeof(struct xt_names_priv));
965025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	if (!ret) {
966715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan		priv = ((struct seq_file *)file->private_data)->private;
967715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan		priv->af = (unsigned long)PDE(inode)->data;
968025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	}
969025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	return ret;
9702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
9712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
972025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct file_operations xt_table_ops = {
973025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.owner	 = THIS_MODULE,
974025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.open	 = xt_table_open,
975025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.read	 = seq_read,
976025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.llseek	 = seq_lseek,
9770e93bb9459f56b50a2f71f2c230f4ad00ec40a73Pavel Emelyanov	.release = seq_release_net,
978025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan};
979025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
980eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt/*
981eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt * Traverse state for ip{,6}_{tables,matches} for helping crossing
982eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt * the multi-AF mutexes.
983eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt */
984eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstruct nf_mttg_trav {
985eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	struct list_head *head, *curr;
986eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	uint8_t class, nfproto;
987eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt};
988eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt
989eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtenum {
990eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	MTTG_TRAV_INIT,
991eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	MTTG_TRAV_NFP_UNSPEC,
992eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	MTTG_TRAV_NFP_SPEC,
993eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	MTTG_TRAV_DONE,
994eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt};
995eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt
996eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void *xt_mttg_seq_next(struct seq_file *seq, void *v, loff_t *ppos,
997eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt    bool is_target)
9982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
999eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	static const uint8_t next_class[] = {
1000eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		[MTTG_TRAV_NFP_UNSPEC] = MTTG_TRAV_NFP_SPEC,
1001eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		[MTTG_TRAV_NFP_SPEC]   = MTTG_TRAV_DONE,
1002eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	};
1003eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	struct nf_mttg_trav *trav = seq->private;
1004eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt
1005eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	switch (trav->class) {
1006eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	case MTTG_TRAV_INIT:
1007eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		trav->class = MTTG_TRAV_NFP_UNSPEC;
1008eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		mutex_lock(&xt[NFPROTO_UNSPEC].mutex);
1009eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		trav->head = trav->curr = is_target ?
1010eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt			&xt[NFPROTO_UNSPEC].target : &xt[NFPROTO_UNSPEC].match;
1011eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt 		break;
1012eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	case MTTG_TRAV_NFP_UNSPEC:
1013eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		trav->curr = trav->curr->next;
1014eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		if (trav->curr != trav->head)
1015eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt			break;
1016eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		mutex_unlock(&xt[NFPROTO_UNSPEC].mutex);
1017eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		mutex_lock(&xt[trav->nfproto].mutex);
1018eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		trav->head = trav->curr = is_target ?
1019eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt			&xt[trav->nfproto].target : &xt[trav->nfproto].match;
1020eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		trav->class = next_class[trav->class];
1021eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		break;
1022eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	case MTTG_TRAV_NFP_SPEC:
1023eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		trav->curr = trav->curr->next;
1024eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		if (trav->curr != trav->head)
1025eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt			break;
1026eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		/* fallthru, _stop will unlock */
1027eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	default:
1028eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		return NULL;
1029eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	}
10302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1031eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	if (ppos != NULL)
1032eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		++*ppos;
1033eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return trav;
1034025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
1035601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki
1036eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void *xt_mttg_seq_start(struct seq_file *seq, loff_t *pos,
1037eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt    bool is_target)
1038025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
1039eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	struct nf_mttg_trav *trav = seq->private;
1040eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	unsigned int j;
10412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1042eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	trav->class = MTTG_TRAV_INIT;
1043eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	for (j = 0; j < *pos; ++j)
1044eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		if (xt_mttg_seq_next(seq, NULL, NULL, is_target) == NULL)
1045eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt			return NULL;
1046eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return trav;
10472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
10482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1049eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void xt_mttg_seq_stop(struct seq_file *seq, void *v)
10502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
1051eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	struct nf_mttg_trav *trav = seq->private;
1052eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt
1053eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	switch (trav->class) {
1054eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	case MTTG_TRAV_NFP_UNSPEC:
1055eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		mutex_unlock(&xt[NFPROTO_UNSPEC].mutex);
1056eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		break;
1057eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	case MTTG_TRAV_NFP_SPEC:
1058eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		mutex_unlock(&xt[trav->nfproto].mutex);
1059eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		break;
1060eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	}
1061eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt}
10622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1063eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void *xt_match_seq_start(struct seq_file *seq, loff_t *pos)
1064eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt{
1065eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return xt_mttg_seq_start(seq, pos, false);
10662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
10672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1068eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void *xt_match_seq_next(struct seq_file *seq, void *v, loff_t *ppos)
10692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
1070eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return xt_mttg_seq_next(seq, v, ppos, false);
1071eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt}
10722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1073eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic int xt_match_seq_show(struct seq_file *seq, void *v)
1074eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt{
1075eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	const struct nf_mttg_trav *trav = seq->private;
1076eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	const struct xt_match *match;
1077eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt
1078eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	switch (trav->class) {
1079eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	case MTTG_TRAV_NFP_UNSPEC:
1080eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	case MTTG_TRAV_NFP_SPEC:
1081eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		if (trav->curr == trav->head)
1082eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt			return 0;
1083eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		match = list_entry(trav->curr, struct xt_match, list);
1084eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		return (*match->name == '\0') ? 0 :
1085eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		       seq_printf(seq, "%s\n", match->name);
1086eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	}
1087eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return 0;
10882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
10892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1090025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct seq_operations xt_match_seq_ops = {
1091025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.start	= xt_match_seq_start,
1092025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.next	= xt_match_seq_next,
1093eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	.stop	= xt_mttg_seq_stop,
1094025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.show	= xt_match_seq_show,
10952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte};
10962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1097025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_match_open(struct inode *inode, struct file *file)
10982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
1099eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	struct seq_file *seq;
1100eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	struct nf_mttg_trav *trav;
11012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int ret;
11022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1103eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	trav = kmalloc(sizeof(*trav), GFP_KERNEL);
1104eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	if (trav == NULL)
1105eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		return -ENOMEM;
11062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1107eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	ret = seq_open(file, &xt_match_seq_ops);
1108eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	if (ret < 0) {
1109eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		kfree(trav);
1110eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		return ret;
11112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
1112eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt
1113eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	seq = file->private_data;
1114eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	seq->private = trav;
1115eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	trav->nfproto = (unsigned long)PDE(inode)->data;
1116eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return 0;
1117025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
1118025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
1119025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct file_operations xt_match_ops = {
1120025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.owner	 = THIS_MODULE,
1121025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.open	 = xt_match_open,
1122025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.read	 = seq_read,
1123025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.llseek	 = seq_lseek,
1124eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	.release = seq_release_private,
1125025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan};
11262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1127025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void *xt_target_seq_start(struct seq_file *seq, loff_t *pos)
1128025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
1129eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return xt_mttg_seq_start(seq, pos, true);
1130025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
1131025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
1132eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void *xt_target_seq_next(struct seq_file *seq, void *v, loff_t *ppos)
1133025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
1134eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return xt_mttg_seq_next(seq, v, ppos, true);
1135025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
1136025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
1137025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_target_seq_show(struct seq_file *seq, void *v)
1138025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
1139eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	const struct nf_mttg_trav *trav = seq->private;
1140eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	const struct xt_target *target;
1141eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt
1142eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	switch (trav->class) {
1143eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	case MTTG_TRAV_NFP_UNSPEC:
1144eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	case MTTG_TRAV_NFP_SPEC:
1145eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		if (trav->curr == trav->head)
1146eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt			return 0;
1147eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		target = list_entry(trav->curr, struct xt_target, list);
1148eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		return (*target->name == '\0') ? 0 :
1149eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		       seq_printf(seq, "%s\n", target->name);
1150eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	}
1151eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return 0;
1152025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
1153025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
1154025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct seq_operations xt_target_seq_ops = {
1155025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.start	= xt_target_seq_start,
1156025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.next	= xt_target_seq_next,
1157eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	.stop	= xt_mttg_seq_stop,
1158025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.show	= xt_target_seq_show,
1159025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan};
1160025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
1161025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_target_open(struct inode *inode, struct file *file)
1162025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
1163eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	struct seq_file *seq;
1164eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	struct nf_mttg_trav *trav;
1165025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	int ret;
1166025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
1167eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	trav = kmalloc(sizeof(*trav), GFP_KERNEL);
1168eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	if (trav == NULL)
1169eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		return -ENOMEM;
1170025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
1171eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	ret = seq_open(file, &xt_target_seq_ops);
1172eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	if (ret < 0) {
1173eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		kfree(trav);
1174eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		return ret;
1175025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	}
1176eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt
1177eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	seq = file->private_data;
1178eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	seq->private = trav;
1179eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	trav->nfproto = (unsigned long)PDE(inode)->data;
1180eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return 0;
11812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
11822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1183025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct file_operations xt_target_ops = {
11842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.owner	 = THIS_MODULE,
1185025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.open	 = xt_target_open,
11862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.read	 = seq_read,
11872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.llseek	 = seq_lseek,
1188eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	.release = seq_release_private,
11892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte};
11902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
11912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define FORMAT_TABLES	"_tables_names"
11922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define	FORMAT_MATCHES	"_tables_matches"
11932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define FORMAT_TARGETS 	"_tables_targets"
11942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
11952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif /* CONFIG_PROC_FS */
11962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
11972b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt/**
11982b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * xt_hook_link - set up hooks for a new table
11992b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * @table:	table with metadata needed to set up hooks
12002b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * @fn:		Hook function
12012b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt *
12022b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * This function will take care of creating and registering the necessary
12032b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * Netfilter hooks for XT tables.
12042b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt */
12052b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardtstruct nf_hook_ops *xt_hook_link(const struct xt_table *table, nf_hookfn *fn)
12062b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt{
12072b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	unsigned int hook_mask = table->valid_hooks;
12082b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	uint8_t i, num_hooks = hweight32(hook_mask);
12092b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	uint8_t hooknum;
12102b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	struct nf_hook_ops *ops;
12112b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	int ret;
12122b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt
12132b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	ops = kmalloc(sizeof(*ops) * num_hooks, GFP_KERNEL);
12142b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	if (ops == NULL)
12152b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		return ERR_PTR(-ENOMEM);
12162b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt
12172b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	for (i = 0, hooknum = 0; i < num_hooks && hook_mask != 0;
12182b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	     hook_mask >>= 1, ++hooknum) {
12192b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		if (!(hook_mask & 1))
12202b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt			continue;
12212b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		ops[i].hook     = fn;
12222b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		ops[i].owner    = table->me;
12232b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		ops[i].pf       = table->af;
12242b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		ops[i].hooknum  = hooknum;
12252b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		ops[i].priority = table->priority;
12262b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		++i;
12272b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	}
12282b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt
12292b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	ret = nf_register_hooks(ops, num_hooks);
12302b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	if (ret < 0) {
12312b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		kfree(ops);
12322b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		return ERR_PTR(ret);
12332b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	}
12342b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt
12352b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	return ops;
12362b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt}
12372b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan EngelhardtEXPORT_SYMBOL_GPL(xt_hook_link);
12382b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt
12392b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt/**
12402b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * xt_hook_unlink - remove hooks for a table
12412b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * @ops:	nf_hook_ops array as returned by nf_hook_link
12422b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * @hook_mask:	the very same mask that was passed to nf_hook_link
12432b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt */
12442b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardtvoid xt_hook_unlink(const struct xt_table *table, struct nf_hook_ops *ops)
12452b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt{
12462b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	nf_unregister_hooks(ops, hweight32(table->valid_hooks));
12472b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	kfree(ops);
12482b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt}
12492b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan EngelhardtEXPORT_SYMBOL_GPL(xt_hook_unlink);
12502b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt
125176108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtint xt_proto_init(struct net *net, u_int8_t af)
12522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
12532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
12542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	char buf[XT_FUNCTION_MAXNAMELEN];
12552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct proc_dir_entry *proc;
12562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif
12572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
12587e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	if (af >= ARRAY_SIZE(xt_prefix))
12592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return -EINVAL;
12602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
12612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
12622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
1263ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
12642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TABLES, sizeof(buf));
12658b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev	proc = proc_create_data(buf, 0440, net->proc_net, &xt_table_ops,
12668b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev				(void *)(unsigned long)af);
12672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!proc)
12682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto out;
12692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1270ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
12712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
12728b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev	proc = proc_create_data(buf, 0440, net->proc_net, &xt_match_ops,
12738b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev				(void *)(unsigned long)af);
12742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!proc)
12752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto out_remove_tables;
12762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1277ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
12782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TARGETS, sizeof(buf));
12798b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev	proc = proc_create_data(buf, 0440, net->proc_net, &xt_target_ops,
12808b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev				(void *)(unsigned long)af);
12812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!proc)
12822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto out_remove_matches;
12832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif
12842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
12852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return 0;
12862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
12872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
12882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteout_remove_matches:
1289ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
12902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
12913cb609d57c20027a8b39fc60b79b930a89da82d4Alexey Dobriyan	proc_net_remove(net, buf);
12922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
12932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteout_remove_tables:
1294ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
12952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TABLES, sizeof(buf));
12963cb609d57c20027a8b39fc60b79b930a89da82d4Alexey Dobriyan	proc_net_remove(net, buf);
12972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteout:
12982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return -1;
12992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif
13002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
13012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_proto_init);
13022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
130376108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtvoid xt_proto_fini(struct net *net, u_int8_t af)
13042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
13052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
13062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	char buf[XT_FUNCTION_MAXNAMELEN];
13072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1308ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
13092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TABLES, sizeof(buf));
13103cb609d57c20027a8b39fc60b79b930a89da82d4Alexey Dobriyan	proc_net_remove(net, buf);
13112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1312ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
13132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TARGETS, sizeof(buf));
13143cb609d57c20027a8b39fc60b79b930a89da82d4Alexey Dobriyan	proc_net_remove(net, buf);
13152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1316ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
13172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
13183cb609d57c20027a8b39fc60b79b930a89da82d4Alexey Dobriyan	proc_net_remove(net, buf);
13192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif /*CONFIG_PROC_FS*/
13202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
13212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_proto_fini);
13222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
13238d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyanstatic int __net_init xt_net_init(struct net *net)
13248d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan{
13258d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	int i;
13268d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan
13277e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	for (i = 0; i < NFPROTO_NUMPROTO; i++)
13288d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan		INIT_LIST_HEAD(&net->xt.tables[i]);
13298d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	return 0;
13308d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan}
13318d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan
13328d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyanstatic struct pernet_operations xt_net_ops = {
13338d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	.init = xt_net_init,
13348d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan};
13352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
13362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic int __init xt_init(void)
13372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
1338942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	unsigned int i;
1339942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	int rv;
1340942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger
1341942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	for_each_possible_cpu(i) {
1342942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger		struct xt_info_lock *lock = &per_cpu(xt_info_locks, i);
1343942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger		spin_lock_init(&lock->lock);
1344942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger		lock->readers = 0;
1345942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	}
13462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
13477e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	xt = kmalloc(sizeof(struct xt_af) * NFPROTO_NUMPROTO, GFP_KERNEL);
13482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!xt)
13492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return -ENOMEM;
13502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
13517e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	for (i = 0; i < NFPROTO_NUMPROTO; i++) {
13529e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar		mutex_init(&xt[i].mutex);
13532722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT
13542722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin		mutex_init(&xt[i].compat_mutex);
1355b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy		xt[i].compat_offsets = NULL;
13562722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#endif
13572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		INIT_LIST_HEAD(&xt[i].target);
13582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		INIT_LIST_HEAD(&xt[i].match);
13592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
13608d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	rv = register_pernet_subsys(&xt_net_ops);
13618d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	if (rv < 0)
13628d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan		kfree(xt);
13638d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	return rv;
13642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
13652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
13662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic void __exit xt_fini(void)
13672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
13688d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	unregister_pernet_subsys(&xt_net_ops);
13692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	kfree(xt);
13702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
13712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
13722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltemodule_init(xt_init);
13732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltemodule_exit(xt_fini);
13742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1375