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>
5f229f6ce481ceb33a966311722b8ef0cb6c25de7Patrick McHardy * Copyright (C) 2006-2012 Patrick McHardy <kaber@trash.net>
62e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *
72e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * Based on existing ip_tables code which is
82e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *   Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
92e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *   Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org>
102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *
112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * This program is free software; you can redistribute it and/or modify
122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * it under the terms of the GNU General Public License version 2 as
132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * published by the Free Software Foundation.
142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *
152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte */
16be91fd5e323b46450ca82f6828e933e3791fb2f2Jan Engelhardt#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/kernel.h>
183a9a231d977222eea36eae091df2c358e03ac839Paul Gortmaker#include <linux/module.h>
192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/socket.h>
202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/net.h>
212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/proc_fs.h>
222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/seq_file.h>
232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/string.h>
242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/vmalloc.h>
259e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar#include <linux/mutex.h>
26d7fe0f241dceade9c8d4af75498765c5ff7f27e6Al Viro#include <linux/mm.h>
275a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
28fbabf31e4d482149b5e2704eb0287cf9117bdcf3Thomas Graf#include <linux/audit.h>
29457c4cbc5a3dde259d2a1f15d5f9785290397267Eric W. Biederman#include <net/net_namespace.h>
302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/netfilter/x_tables.h>
322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/netfilter_arp.h>
33e3eaa9910b380530cfd2c0670fcd3f627674da8aJan Engelhardt#include <linux/netfilter_ipv4/ip_tables.h>
34e3eaa9910b380530cfd2c0670fcd3f627674da8aJan Engelhardt#include <linux/netfilter_ipv6/ip6_tables.h>
35e3eaa9910b380530cfd2c0670fcd3f627674da8aJan Engelhardt#include <linux/netfilter_arp/arp_tables.h>
369e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar
372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteMODULE_LICENSE("GPL");
382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteMODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
39043ef46c7690bfdbd5b012e15812a14a19ca5604Jan EngelhardtMODULE_DESCRIPTION("{ip,ip6,arp,eb}_tables backend module");
402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
43b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardystruct compat_delta {
44255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet	unsigned int offset; /* offset in kernel */
45255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet	int delta; /* delta in 32bit user land */
46b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy};
47b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_af {
499e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	struct mutex mutex;
502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct list_head match;
512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct list_head target;
52b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy#ifdef CONFIG_COMPAT
532722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	struct mutex compat_mutex;
54255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet	struct compat_delta *compat_tab;
55255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet	unsigned int number; /* number of slots in compat_tab[] */
56255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet	unsigned int cur; /* number of used slots in compat_tab[] */
57b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy#endif
582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte};
592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic struct xt_af *xt;
612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
627e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardtstatic const char *const xt_prefix[NFPROTO_NUMPROTO] = {
637e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	[NFPROTO_UNSPEC] = "x",
647e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	[NFPROTO_IPV4]   = "ip",
657e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	[NFPROTO_ARP]    = "arp",
667e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	[NFPROTO_BRIDGE] = "eb",
677e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	[NFPROTO_IPV6]   = "ip6",
6837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy};
6937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy
70f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt/* Allow this many total (re)entries. */
71f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardtstatic const unsigned int xt_jumpstack_multiplier = 2;
72f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt
732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Registration hooks for targets. */
747926dbfa4bc14e27f4e18a6184a031a1c1e077dcPablo Neira Ayusoint xt_register_target(struct xt_target *target)
752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
7676108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	u_int8_t af = target->family;
772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
787926dbfa4bc14e27f4e18a6184a031a1c1e077dcPablo Neira Ayuso	mutex_lock(&xt[af].mutex);
792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_add(&target->list, &xt[af].target);
809e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
817926dbfa4bc14e27f4e18a6184a031a1c1e077dcPablo Neira Ayuso	return 0;
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{
119f68c53015c5b9aa98ffd87a34009f89bdbbd7160Changli Gao	while (n-- > 0)
120f68c53015c5b9aa98ffd87a34009f89bdbbd7160Changli Gao		xt_unregister_target(&target[n]);
12152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy}
12252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyEXPORT_SYMBOL(xt_unregister_targets);
12352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
1247926dbfa4bc14e27f4e18a6184a031a1c1e077dcPablo Neira Ayusoint xt_register_match(struct xt_match *match)
1252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
12676108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	u_int8_t af = match->family;
1272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1287926dbfa4bc14e27f4e18a6184a031a1c1e077dcPablo Neira Ayuso	mutex_lock(&xt[af].mutex);
1292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_add(&match->list, &xt[af].match);
1309e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
1317926dbfa4bc14e27f4e18a6184a031a1c1e077dcPablo Neira Ayuso	return 0;
1322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
1332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_register_match);
1342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid
136a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayusoxt_unregister_match(struct xt_match *match)
1372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
13876108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	u_int8_t af = match->family;
139a45049c51ce6a3fecf2a909b591b28164c927112Pablo Neira Ayuso
1409e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_lock(&xt[af].mutex);
141df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy	list_del(&match->list);
1429e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
1432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
1442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_unregister_match);
1452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
14652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyint
14752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyxt_register_matches(struct xt_match *match, unsigned int n)
14852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy{
14952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	unsigned int i;
15052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	int err = 0;
15152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
15252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	for (i = 0; i < n; i++) {
15352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		err = xt_register_match(&match[i]);
15452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		if (err)
15552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy			goto err;
15652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	}
15752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	return err;
15852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
15952d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyerr:
16052d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	if (i > 0)
16152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy		xt_unregister_matches(match, i);
16252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy	return err;
16352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy}
16452d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyEXPORT_SYMBOL(xt_register_matches);
16552d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
16652d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyvoid
16752d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyxt_unregister_matches(struct xt_match *match, unsigned int n)
16852d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy{
169f68c53015c5b9aa98ffd87a34009f89bdbbd7160Changli Gao	while (n-- > 0)
170f68c53015c5b9aa98ffd87a34009f89bdbbd7160Changli Gao		xt_unregister_match(&match[n]);
17152d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy}
17252d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardyEXPORT_SYMBOL(xt_unregister_matches);
17352d9c42ef2563d2c420eb23b96bf5a4cae9e167bPatrick McHardy
1742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/*
1762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * These are weird, but module loading must not be done with mutex
1772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * held (since they will register), and we have to have a single
178adb00ae2ea0ec65f9d3d06079950c0f0ade3b614Stephen Hemminger * function to use.
1792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte */
1802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Find match, grabs ref.  Returns ERR_PTR() on error. */
18276108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstruct xt_match *xt_find_match(u8 af, const char *name, u8 revision)
1832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
1842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_match *m;
18542046e2e45c109ba703993c510401a11f716c8dfPatrick McHardy	int err = -ENOENT;
1862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1877926dbfa4bc14e27f4e18a6184a031a1c1e077dcPablo Neira Ayuso	mutex_lock(&xt[af].mutex);
1882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(m, &xt[af].match, list) {
1892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(m->name, name) == 0) {
1902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (m->revision == revision) {
1912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				if (try_module_get(m->me)) {
1929e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar					mutex_unlock(&xt[af].mutex);
1932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte					return m;
1942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				}
1952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			} else
1962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				err = -EPROTOTYPE; /* Found something. */
1972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
1982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
1999e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
20055b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt
20155b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt	if (af != NFPROTO_UNSPEC)
20255b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt		/* Try searching again in the family-independent list */
20355b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt		return xt_find_match(NFPROTO_UNSPEC, name, revision);
20455b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt
2052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ERR_PTR(err);
2062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
2072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_find_match);
2082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
209fd0ec0e6216baea854465bbdb177f2d1b2ccaf22Jan Engelhardtstruct xt_match *
210fd0ec0e6216baea854465bbdb177f2d1b2ccaf22Jan Engelhardtxt_request_find_match(uint8_t nfproto, const char *name, uint8_t revision)
211fd0ec0e6216baea854465bbdb177f2d1b2ccaf22Jan Engelhardt{
212fd0ec0e6216baea854465bbdb177f2d1b2ccaf22Jan Engelhardt	struct xt_match *match;
213fd0ec0e6216baea854465bbdb177f2d1b2ccaf22Jan Engelhardt
214adb00ae2ea0ec65f9d3d06079950c0f0ade3b614Stephen Hemminger	match = xt_find_match(nfproto, name, revision);
215adb00ae2ea0ec65f9d3d06079950c0f0ade3b614Stephen Hemminger	if (IS_ERR(match)) {
216adb00ae2ea0ec65f9d3d06079950c0f0ade3b614Stephen Hemminger		request_module("%st_%s", xt_prefix[nfproto], name);
217adb00ae2ea0ec65f9d3d06079950c0f0ade3b614Stephen Hemminger		match = xt_find_match(nfproto, name, revision);
218adb00ae2ea0ec65f9d3d06079950c0f0ade3b614Stephen Hemminger	}
219adb00ae2ea0ec65f9d3d06079950c0f0ade3b614Stephen Hemminger
220adb00ae2ea0ec65f9d3d06079950c0f0ade3b614Stephen Hemminger	return match;
221fd0ec0e6216baea854465bbdb177f2d1b2ccaf22Jan Engelhardt}
222fd0ec0e6216baea854465bbdb177f2d1b2ccaf22Jan EngelhardtEXPORT_SYMBOL_GPL(xt_request_find_match);
223fd0ec0e6216baea854465bbdb177f2d1b2ccaf22Jan Engelhardt
2242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Find target, grabs ref.  Returns ERR_PTR() on error. */
22576108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstruct xt_target *xt_find_target(u8 af, const char *name, u8 revision)
2262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
2272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_target *t;
22842046e2e45c109ba703993c510401a11f716c8dfPatrick McHardy	int err = -ENOENT;
2292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2307926dbfa4bc14e27f4e18a6184a031a1c1e077dcPablo Neira Ayuso	mutex_lock(&xt[af].mutex);
2312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(t, &xt[af].target, list) {
2322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(t->name, name) == 0) {
2332e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (t->revision == revision) {
2342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				if (try_module_get(t->me)) {
2359e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar					mutex_unlock(&xt[af].mutex);
2362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte					return t;
2372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				}
2382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			} else
2392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				err = -EPROTOTYPE; /* Found something. */
2402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
2412e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
2429e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
24355b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt
24455b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt	if (af != NFPROTO_UNSPEC)
24555b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt		/* Try searching again in the family-independent list */
24655b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt		return xt_find_target(NFPROTO_UNSPEC, name, revision);
24755b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt
2482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return ERR_PTR(err);
2492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
2502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_find_target);
2512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
25276108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstruct xt_target *xt_request_find_target(u8 af, const char *name, u8 revision)
2532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
2542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_target *target;
2552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
256adb00ae2ea0ec65f9d3d06079950c0f0ade3b614Stephen Hemminger	target = xt_find_target(af, name, revision);
257adb00ae2ea0ec65f9d3d06079950c0f0ade3b614Stephen Hemminger	if (IS_ERR(target)) {
258adb00ae2ea0ec65f9d3d06079950c0f0ade3b614Stephen Hemminger		request_module("%st_%s", xt_prefix[af], name);
259adb00ae2ea0ec65f9d3d06079950c0f0ade3b614Stephen Hemminger		target = xt_find_target(af, name, revision);
260adb00ae2ea0ec65f9d3d06079950c0f0ade3b614Stephen Hemminger	}
261adb00ae2ea0ec65f9d3d06079950c0f0ade3b614Stephen Hemminger
262adb00ae2ea0ec65f9d3d06079950c0f0ade3b614Stephen Hemminger	return target;
2632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
2642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_request_find_target);
2652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
26676108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstatic int match_revfn(u8 af, const char *name, u8 revision, int *bestp)
2672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
2685452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt	const struct xt_match *m;
2692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int have_rev = 0;
2702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(m, &xt[af].match, list) {
2722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(m->name, name) == 0) {
2732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (m->revision > *bestp)
2742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				*bestp = m->revision;
2752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (m->revision == revision)
2762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				have_rev = 1;
2772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
2782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
279656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy
280656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy	if (af != NFPROTO_UNSPEC && !have_rev)
281656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy		return match_revfn(NFPROTO_UNSPEC, name, revision, bestp);
282656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy
2832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return have_rev;
2842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
2852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
28676108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstatic int target_revfn(u8 af, const char *name, u8 revision, int *bestp)
2872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
2885452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt	const struct xt_target *t;
2892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int have_rev = 0;
2902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	list_for_each_entry(t, &xt[af].target, list) {
2922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(t->name, name) == 0) {
2932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (t->revision > *bestp)
2942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				*bestp = t->revision;
2952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			if (t->revision == revision)
2962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte				have_rev = 1;
2972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
2982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
299656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy
300656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy	if (af != NFPROTO_UNSPEC && !have_rev)
301656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy		return target_revfn(NFPROTO_UNSPEC, name, revision, bestp);
302656caff20e12ba6e07b4bf342641df5ab33b4e49Patrick McHardy
3032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return have_rev;
3042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
3052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3062e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Returns true or false (if no such extension at all) */
30776108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtint xt_find_revision(u8 af, const char *name, u8 revision, int target,
3082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		     int *err)
3092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
3102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int have_rev, best = -1;
3112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3127926dbfa4bc14e27f4e18a6184a031a1c1e077dcPablo Neira Ayuso	mutex_lock(&xt[af].mutex);
3132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (target == 1)
3142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		have_rev = target_revfn(af, name, revision, &best);
3152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	else
3162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		have_rev = match_revfn(af, name, revision, &best);
3179e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
3182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Nothing at all?  Return 0 to try loading module. */
3202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (best == -1) {
3212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		*err = -ENOENT;
3222e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return 0;
3232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
3242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	*err = best;
3262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!have_rev)
3272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		*err = -EPROTONOSUPPORT;
3282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return 1;
3292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
3302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_find_revision);
3312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
3325b76c4948fe6977bead2359c2054f3e6a2dcf3d0Jan Engelhardtstatic char *
3335b76c4948fe6977bead2359c2054f3e6a2dcf3d0Jan Engelhardttextify_hooks(char *buf, size_t size, unsigned int mask, uint8_t nfproto)
334451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt{
3355b76c4948fe6977bead2359c2054f3e6a2dcf3d0Jan Engelhardt	static const char *const inetbr_names[] = {
336451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		"PREROUTING", "INPUT", "FORWARD",
337451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		"OUTPUT", "POSTROUTING", "BROUTING",
338451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	};
3395b76c4948fe6977bead2359c2054f3e6a2dcf3d0Jan Engelhardt	static const char *const arp_names[] = {
3405b76c4948fe6977bead2359c2054f3e6a2dcf3d0Jan Engelhardt		"INPUT", "FORWARD", "OUTPUT",
3415b76c4948fe6977bead2359c2054f3e6a2dcf3d0Jan Engelhardt	};
3425b76c4948fe6977bead2359c2054f3e6a2dcf3d0Jan Engelhardt	const char *const *names;
3435b76c4948fe6977bead2359c2054f3e6a2dcf3d0Jan Engelhardt	unsigned int i, max;
344451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	char *p = buf;
345451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	bool np = false;
346451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	int res;
347451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt
3485b76c4948fe6977bead2359c2054f3e6a2dcf3d0Jan Engelhardt	names = (nfproto == NFPROTO_ARP) ? arp_names : inetbr_names;
3495b76c4948fe6977bead2359c2054f3e6a2dcf3d0Jan Engelhardt	max   = (nfproto == NFPROTO_ARP) ? ARRAY_SIZE(arp_names) :
3505b76c4948fe6977bead2359c2054f3e6a2dcf3d0Jan Engelhardt	                                   ARRAY_SIZE(inetbr_names);
351451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	*p = '\0';
3525b76c4948fe6977bead2359c2054f3e6a2dcf3d0Jan Engelhardt	for (i = 0; i < max; ++i) {
353451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		if (!(mask & (1 << i)))
354451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt			continue;
355451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		res = snprintf(p, size, "%s%s", np ? "/" : "", names[i]);
356451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		if (res > 0) {
357451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt			size -= res;
358451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt			p += res;
359451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		}
360451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		np = true;
361451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	}
362451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt
363451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt	return buf;
364451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt}
365451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt
366916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardtint xt_check_match(struct xt_mtchk_param *par,
3679b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt		   unsigned int size, u_int8_t proto, bool inv_proto)
36837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy{
369bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt	int ret;
370bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt
3719b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt	if (XT_ALIGN(par->match->matchsize) != size &&
3729b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt	    par->match->matchsize != -1) {
373043ef46c7690bfdbd5b012e15812a14a19ca5604Jan Engelhardt		/*
374043ef46c7690bfdbd5b012e15812a14a19ca5604Jan Engelhardt		 * ebt_among is exempt from centralized matchsize checking
375043ef46c7690bfdbd5b012e15812a14a19ca5604Jan Engelhardt		 * because it uses a dynamic-size data set.
376043ef46c7690bfdbd5b012e15812a14a19ca5604Jan Engelhardt		 */
377b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt		pr_err("%s_tables: %s.%u match: invalid size "
378b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt		       "%u (kernel) != (user) %u\n",
379916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt		       xt_prefix[par->family], par->match->name,
380b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt		       par->match->revision,
3819b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt		       XT_ALIGN(par->match->matchsize), size);
38237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
38337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
3849b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt	if (par->match->table != NULL &&
3859b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt	    strcmp(par->match->table, par->table) != 0) {
3863dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches		pr_err("%s_tables: %s match: only valid in %s table, not %s\n",
387916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt		       xt_prefix[par->family], par->match->name,
3889b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt		       par->match->table, par->table);
38937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
39037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
3919b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt	if (par->match->hooks && (par->hook_mask & ~par->match->hooks) != 0) {
392451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		char used[64], allow[64];
393451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt
3943dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches		pr_err("%s_tables: %s match: used from hooks %s, but only "
395451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		       "valid from %s\n",
396916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt		       xt_prefix[par->family], par->match->name,
3975b76c4948fe6977bead2359c2054f3e6a2dcf3d0Jan Engelhardt		       textify_hooks(used, sizeof(used), par->hook_mask,
3985b76c4948fe6977bead2359c2054f3e6a2dcf3d0Jan Engelhardt		                     par->family),
3995b76c4948fe6977bead2359c2054f3e6a2dcf3d0Jan Engelhardt		       textify_hooks(allow, sizeof(allow), par->match->hooks,
4005b76c4948fe6977bead2359c2054f3e6a2dcf3d0Jan Engelhardt		                     par->family));
40137f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
40237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
4039b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt	if (par->match->proto && (par->match->proto != proto || inv_proto)) {
4043dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches		pr_err("%s_tables: %s match: only valid for protocol %u\n",
405916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt		       xt_prefix[par->family], par->match->name,
406916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt		       par->match->proto);
40737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
40837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
409bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt	if (par->match->checkentry != NULL) {
410bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt		ret = par->match->checkentry(par);
411bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt		if (ret < 0)
412bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt			return ret;
413bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt		else if (ret > 0)
414bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt			/* Flag up potential errors. */
415bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt			return -EIO;
416bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt	}
41737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	return 0;
41837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy}
41937f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardyEXPORT_SYMBOL_GPL(xt_check_match);
42037f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy
4212722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT
422255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazetint xt_compat_add_offset(u_int8_t af, unsigned int offset, int delta)
423b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy{
424255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet	struct xt_af *xp = &xt[af];
425b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
426255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet	if (!xp->compat_tab) {
427255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet		if (!xp->number)
428255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet			return -EINVAL;
429255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet		xp->compat_tab = vmalloc(sizeof(struct compat_delta) * xp->number);
430255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet		if (!xp->compat_tab)
431255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet			return -ENOMEM;
432255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet		xp->cur = 0;
433255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet	}
434b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
435255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet	if (xp->cur >= xp->number)
436255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet		return -EINVAL;
437b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
438255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet	if (xp->cur)
439255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet		delta += xp->compat_tab[xp->cur - 1].delta;
440255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet	xp->compat_tab[xp->cur].offset = offset;
441255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet	xp->compat_tab[xp->cur].delta = delta;
442255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet	xp->cur++;
443b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	return 0;
444b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy}
445b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_add_offset);
446b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
44776108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtvoid xt_compat_flush_offsets(u_int8_t af)
448b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy{
449255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet	if (xt[af].compat_tab) {
450255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet		vfree(xt[af].compat_tab);
451255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet		xt[af].compat_tab = NULL;
452255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet		xt[af].number = 0;
4535a6351eecf8c87afed9c883bb6341d09406d74baEric Dumazet		xt[af].cur = 0;
454b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy	}
455b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy}
456b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_flush_offsets);
457b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
4583e5e524ffb5fcf2447eb5dd9f8e54ad22dd9baa7Florian Westphalint xt_compat_calc_jump(u_int8_t af, unsigned int offset)
459b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy{
460255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet	struct compat_delta *tmp = xt[af].compat_tab;
461255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet	int mid, left = 0, right = xt[af].cur - 1;
462255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet
463255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet	while (left <= right) {
464255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet		mid = (left + right) >> 1;
465255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet		if (offset > tmp[mid].offset)
466255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet			left = mid + 1;
467255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet		else if (offset < tmp[mid].offset)
468255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet			right = mid - 1;
469255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet		else
470255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet			return mid ? tmp[mid - 1].delta : 0;
471255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet	}
4725a6351eecf8c87afed9c883bb6341d09406d74baEric Dumazet	return left ? tmp[left - 1].delta : 0;
473b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy}
474b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_calc_jump);
475b386d9f5960a9afce7f077edf2095fccfbb1a8e6Patrick McHardy
476255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazetvoid xt_compat_init_offsets(u_int8_t af, unsigned int number)
477255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet{
478255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet	xt[af].number = number;
479255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet	xt[af].cur = 0;
480255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet}
481255d0dc34068a976550ce555e153c0bfcfec7cc6Eric DumazetEXPORT_SYMBOL(xt_compat_init_offsets);
482255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet
4835452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardtint xt_compat_match_offset(const struct xt_match *match)
4842722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{
4859fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	u_int16_t csize = match->compatsize ? : match->matchsize;
4869fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	return XT_ALIGN(match->matchsize) - COMPAT_XT_ALIGN(csize);
4879fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy}
4889fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_match_offset);
4899fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
4908956695131b8a7878891667469899d667eb5892bPatrick McHardyint xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr,
491b0a6363c2418c93f25dd30b8ffcd3fdd4ce23ad6Patrick McHardy			      unsigned int *size)
4929fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy{
4935452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt	const struct xt_match *match = m->u.kernel.match;
4949fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	struct compat_xt_entry_match *cm = (struct compat_xt_entry_match *)m;
4959fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	int pad, off = xt_compat_match_offset(match);
4969fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	u_int16_t msize = cm->u.user.match_size;
4979fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
4989fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	m = *dstptr;
4999fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	memcpy(m, cm, sizeof(*cm));
5009fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (match->compat_from_user)
5019fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		match->compat_from_user(m->data, cm->data);
5029fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	else
5039fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		memcpy(m->data, cm->data, msize - sizeof(*cm));
5049fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	pad = XT_ALIGN(match->matchsize) - match->matchsize;
5059fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (pad > 0)
5069fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		memset(m->data + match->matchsize, 0, pad);
5079fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
5089fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	msize += off;
5099fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	m->u.user.match_size = msize;
5109fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
5119fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*size += off;
5129fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*dstptr += msize;
5138956695131b8a7878891667469899d667eb5892bPatrick McHardy	return 0;
5149fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy}
5159fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_match_from_user);
5169fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
517739674fb7febf116e7d647031fab16989a08a965Jan Engelhardtint xt_compat_match_to_user(const struct xt_entry_match *m,
518739674fb7febf116e7d647031fab16989a08a965Jan Engelhardt			    void __user **dstptr, unsigned int *size)
5199fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy{
5205452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt	const struct xt_match *match = m->u.kernel.match;
5219fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	struct compat_xt_entry_match __user *cm = *dstptr;
5229fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	int off = xt_compat_match_offset(match);
5239fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	u_int16_t msize = m->u.user.match_size - off;
5249fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
5259fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (copy_to_user(cm, m, sizeof(*cm)) ||
526a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy	    put_user(msize, &cm->u.user.match_size) ||
527a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy	    copy_to_user(cm->u.user.name, m->u.kernel.match->name,
528a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy			 strlen(m->u.kernel.match->name) + 1))
529601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki		return -EFAULT;
5309fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
5319fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (match->compat_to_user) {
5329fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		if (match->compat_to_user((void __user *)cm->data, m->data))
5339fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy			return -EFAULT;
5349fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	} else {
5359fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		if (copy_to_user(cm->data, m->data, msize - sizeof(*cm)))
5369fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy			return -EFAULT;
5372722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	}
5389fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
5399fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*size -= off;
5409fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*dstptr += msize;
5419fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	return 0;
5422722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin}
5439fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_match_to_user);
5449fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy#endif /* CONFIG_COMPAT */
5452722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin
546916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardtint xt_check_target(struct xt_tgchk_param *par,
547af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt		    unsigned int size, u_int8_t proto, bool inv_proto)
54837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy{
549d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt	int ret;
550d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt
551af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt	if (XT_ALIGN(par->target->targetsize) != size) {
552b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt		pr_err("%s_tables: %s.%u target: invalid size "
553b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt		       "%u (kernel) != (user) %u\n",
554916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt		       xt_prefix[par->family], par->target->name,
555b402405d71beed8e4df354844353f66b4e18269fJan Engelhardt		       par->target->revision,
556af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt		       XT_ALIGN(par->target->targetsize), size);
55737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
55837f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
559af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt	if (par->target->table != NULL &&
560af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt	    strcmp(par->target->table, par->table) != 0) {
5613dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches		pr_err("%s_tables: %s target: only valid in %s table, not %s\n",
562916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt		       xt_prefix[par->family], par->target->name,
563af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt		       par->target->table, par->table);
56437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
56537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
566af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt	if (par->target->hooks && (par->hook_mask & ~par->target->hooks) != 0) {
567451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		char used[64], allow[64];
568451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt
5693dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches		pr_err("%s_tables: %s target: used from hooks %s, but only "
570451853645f3cb804b523227eca054701e4cbc589Jan Engelhardt		       "usable from %s\n",
571916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt		       xt_prefix[par->family], par->target->name,
5725b76c4948fe6977bead2359c2054f3e6a2dcf3d0Jan Engelhardt		       textify_hooks(used, sizeof(used), par->hook_mask,
5735b76c4948fe6977bead2359c2054f3e6a2dcf3d0Jan Engelhardt		                     par->family),
5745b76c4948fe6977bead2359c2054f3e6a2dcf3d0Jan Engelhardt		       textify_hooks(allow, sizeof(allow), par->target->hooks,
5755b76c4948fe6977bead2359c2054f3e6a2dcf3d0Jan Engelhardt		                     par->family));
57637f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
57737f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
578af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt	if (par->target->proto && (par->target->proto != proto || inv_proto)) {
5793dd5d7e3ba5e9b05586ff0d59ae6d700b7b7c607Joe Perches		pr_err("%s_tables: %s target: only valid for protocol %u\n",
580916a917dfec18535ff9e2afdafba82e6279eb4f4Jan Engelhardt		       xt_prefix[par->family], par->target->name,
581af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt		       par->target->proto);
58237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy		return -EINVAL;
58337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	}
584d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt	if (par->target->checkentry != NULL) {
585d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt		ret = par->target->checkentry(par);
586d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt		if (ret < 0)
587d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt			return ret;
588d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt		else if (ret > 0)
589d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt			/* Flag up potential errors. */
590d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt			return -EIO;
591d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt	}
59237f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy	return 0;
59337f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy}
59437f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardyEXPORT_SYMBOL_GPL(xt_check_target);
59537f9f7334b86ffc3b8a1921842ae33cb9aa22ee3Patrick McHardy
5962722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT
5975452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardtint xt_compat_target_offset(const struct xt_target *target)
5982722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{
5999fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	u_int16_t csize = target->compatsize ? : target->targetsize;
6009fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	return XT_ALIGN(target->targetsize) - COMPAT_XT_ALIGN(csize);
6019fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy}
6029fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_target_offset);
6039fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
6049fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyvoid xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr,
605b0a6363c2418c93f25dd30b8ffcd3fdd4ce23ad6Patrick McHardy				unsigned int *size)
6069fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy{
6075452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt	const struct xt_target *target = t->u.kernel.target;
6089fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	struct compat_xt_entry_target *ct = (struct compat_xt_entry_target *)t;
6099fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	int pad, off = xt_compat_target_offset(target);
6109fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	u_int16_t tsize = ct->u.user.target_size;
6119fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
6129fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	t = *dstptr;
6139fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	memcpy(t, ct, sizeof(*ct));
6149fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (target->compat_from_user)
6159fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		target->compat_from_user(t->data, ct->data);
6169fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	else
6179fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		memcpy(t->data, ct->data, tsize - sizeof(*ct));
6189fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	pad = XT_ALIGN(target->targetsize) - target->targetsize;
6199fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (pad > 0)
6209fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		memset(t->data + target->targetsize, 0, pad);
6219fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
6229fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	tsize += off;
6239fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	t->u.user.target_size = tsize;
6249fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
6259fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*size += off;
6269fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*dstptr += tsize;
6279fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy}
6289fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_target_from_user);
6299fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
630739674fb7febf116e7d647031fab16989a08a965Jan Engelhardtint xt_compat_target_to_user(const struct xt_entry_target *t,
631739674fb7febf116e7d647031fab16989a08a965Jan Engelhardt			     void __user **dstptr, unsigned int *size)
6329fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy{
6335452e425adfdfc4647b618e303f73d48f2405b0eJan Engelhardt	const struct xt_target *target = t->u.kernel.target;
6349fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	struct compat_xt_entry_target __user *ct = *dstptr;
6359fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	int off = xt_compat_target_offset(target);
6369fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	u_int16_t tsize = t->u.user.target_size - off;
6379fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
6389fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (copy_to_user(ct, t, sizeof(*ct)) ||
639a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy	    put_user(tsize, &ct->u.user.target_size) ||
640a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy	    copy_to_user(ct->u.user.name, t->u.kernel.target->name,
641a18aa31b7774d8b36048e256a02d9d689533fc96Patrick McHardy			 strlen(t->u.kernel.target->name) + 1))
642601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki		return -EFAULT;
6439fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
6449fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	if (target->compat_to_user) {
6459fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		if (target->compat_to_user((void __user *)ct->data, t->data))
6469fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy			return -EFAULT;
6479fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	} else {
6489fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy		if (copy_to_user(ct->data, t->data, tsize - sizeof(*ct)))
6499fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy			return -EFAULT;
6502722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	}
6519fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy
6529fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*size -= off;
6539fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	*dstptr += tsize;
6549fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardy	return 0;
6552722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin}
6569fa492cdc160cd27ce1046cb36f47d3b2b1efa21Patrick McHardyEXPORT_SYMBOL_GPL(xt_compat_target_to_user);
6572722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#endif
6582722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin
6592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_table_info *xt_alloc_table_info(unsigned int size)
6602e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
6612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table_info *newinfo;
6622e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int cpu;
6632e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
6654481374ce88ba8f460c8b89f2572027bd27057d0Jan Beulich	if ((SMP_ALIGN(size) >> PAGE_SHIFT) + 2 > totalram_pages)
6662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
6672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
668259d4e41f3ec25f22169daece42729f597b89f9aEric Dumazet	newinfo = kzalloc(XT_TABLE_INFO_SZ, GFP_KERNEL);
6692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!newinfo)
6702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
6712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	newinfo->size = size;
6732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6746f912042256c12b0927438122594f5379b364f5dKAMEZAWA Hiroyuki	for_each_possible_cpu(cpu) {
6752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (size <= PAGE_SIZE)
6762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			newinfo->entries[cpu] = kmalloc_node(size,
6772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte							GFP_KERNEL,
6782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte							cpu_to_node(cpu));
6792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		else
6802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			newinfo->entries[cpu] = vmalloc_node(size,
6812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte							cpu_to_node(cpu));
6822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (newinfo->entries[cpu] == NULL) {
6842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			xt_free_table_info(newinfo);
6852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			return NULL;
6862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		}
6872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
6882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return newinfo;
6902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
6912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_alloc_table_info);
6922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
6932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid xt_free_table_info(struct xt_table_info *info)
6942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
6952e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int cpu;
6962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
697f6b50824f7d85f72285c17fec66076a36907089fEric Dumazet	for_each_possible_cpu(cpu)
698f6b50824f7d85f72285c17fec66076a36907089fEric Dumazet		kvfree(info->entries[cpu]);
699f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt
700f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	if (info->jumpstack != NULL) {
701f6b50824f7d85f72285c17fec66076a36907089fEric Dumazet		for_each_possible_cpu(cpu)
702f6b50824f7d85f72285c17fec66076a36907089fEric Dumazet			kvfree(info->jumpstack[cpu]);
703f6b50824f7d85f72285c17fec66076a36907089fEric Dumazet		kvfree(info->jumpstack);
704f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	}
705f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt
7067489aec8eed4f2f1eb3b4d35763bd3ea30b32ef5Eric Dumazet	free_percpu(info->stackptr);
707f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt
7082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	kfree(info);
7092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
7102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL(xt_free_table_info);
7112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* Find table by name, grabs mutex & ref.  Returns ERR_PTR() on error. */
71376108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtstruct xt_table *xt_find_table_lock(struct net *net, u_int8_t af,
71476108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt				    const char *name)
7152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
7162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table *t;
7172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7187926dbfa4bc14e27f4e18a6184a031a1c1e077dcPablo Neira Ayuso	mutex_lock(&xt[af].mutex);
7198d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	list_for_each_entry(t, &net->xt.tables[af], list)
7202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		if (strcmp(t->name, name) == 0 && try_module_get(t->me))
7212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			return t;
7229e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[af].mutex);
7232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return NULL;
7242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
7252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_find_table_lock);
7262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid xt_table_unlock(struct xt_table *table)
7282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
7299e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[table->af].mutex);
7302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
7312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_table_unlock);
7322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7332722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT
73476108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtvoid xt_compat_lock(u_int8_t af)
7352722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{
7362722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	mutex_lock(&xt[af].compat_mutex);
7372722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin}
7382722971cbe831117686039d5c334f2c0f560be13Dmitry MishinEXPORT_SYMBOL_GPL(xt_compat_lock);
7392722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin
74076108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtvoid xt_compat_unlock(u_int8_t af)
7412722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin{
7422722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin	mutex_unlock(&xt[af].compat_mutex);
7432722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin}
7442722971cbe831117686039d5c334f2c0f560be13Dmitry MishinEXPORT_SYMBOL_GPL(xt_compat_unlock);
7452722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#endif
7462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
7477f5c6d4f665bb57a19a34ce1fb16cc708c04f219Eric DumazetDEFINE_PER_CPU(seqcount_t, xt_recseq);
7487f5c6d4f665bb57a19a34ce1fb16cc708c04f219Eric DumazetEXPORT_PER_CPU_SYMBOL_GPL(xt_recseq);
749942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger
750f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardtstatic int xt_jumpstack_alloc(struct xt_table_info *i)
751f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt{
752f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	unsigned int size;
753f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	int cpu;
754f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt
7557489aec8eed4f2f1eb3b4d35763bd3ea30b32ef5Eric Dumazet	i->stackptr = alloc_percpu(unsigned int);
756f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	if (i->stackptr == NULL)
757f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt		return -ENOMEM;
758f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt
759f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	size = sizeof(void **) * nr_cpu_ids;
760f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	if (size > PAGE_SIZE)
7613dbd4439837f2cfd2ff302897353f4b1b6263b2aJoe Perches		i->jumpstack = vzalloc(size);
762f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	else
7633dbd4439837f2cfd2ff302897353f4b1b6263b2aJoe Perches		i->jumpstack = kzalloc(size, GFP_KERNEL);
764f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	if (i->jumpstack == NULL)
765f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt		return -ENOMEM;
766f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt
767f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	i->stacksize *= xt_jumpstack_multiplier;
768f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	size = sizeof(void *) * i->stacksize;
769f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	for_each_possible_cpu(cpu) {
770f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt		if (size > PAGE_SIZE)
771f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt			i->jumpstack[cpu] = vmalloc_node(size,
772f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt				cpu_to_node(cpu));
773f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt		else
774f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt			i->jumpstack[cpu] = kmalloc_node(size,
775f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt				GFP_KERNEL, cpu_to_node(cpu));
776f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt		if (i->jumpstack[cpu] == NULL)
777f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt			/*
778f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt			 * Freeing will be done later on by the callers. The
779f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt			 * chain is: xt_replace_table -> __do_replace ->
780f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt			 * do_replace -> xt_free_table_info.
781f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt			 */
782f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt			return -ENOMEM;
783f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	}
784f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt
785f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	return 0;
786f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt}
787942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger
7882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestruct xt_table_info *
7892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltext_replace_table(struct xt_table *table,
7902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	      unsigned int num_counters,
7912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	      struct xt_table_info *newinfo,
7922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	      int *error)
7932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
794942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	struct xt_table_info *private;
795f3c5c1bfd430858d3a05436f82c51e53104feb6bJan Engelhardt	int ret;
7962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
797d97a9e47ba148cfc41e354c5cd241f472273207cJan Engelhardt	ret = xt_jumpstack_alloc(newinfo);
798d97a9e47ba148cfc41e354c5cd241f472273207cJan Engelhardt	if (ret < 0) {
799d97a9e47ba148cfc41e354c5cd241f472273207cJan Engelhardt		*error = ret;
800d97a9e47ba148cfc41e354c5cd241f472273207cJan Engelhardt		return NULL;
801d97a9e47ba148cfc41e354c5cd241f472273207cJan Engelhardt	}
802d97a9e47ba148cfc41e354c5cd241f472273207cJan Engelhardt
8032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Do the substitution. */
804942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	local_bh_disable();
8052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	private = table->private;
806942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger
8072e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Check inside lock: is the old number correct? */
8082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (num_counters != private->number) {
809be91fd5e323b46450ca82f6828e933e3791fb2f2Jan Engelhardt		pr_debug("num_counters != table->private->number (%u/%u)\n",
8102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte			 num_counters, private->number);
811942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger		local_bh_enable();
8122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		*error = -EAGAIN;
8132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return NULL;
8142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
8152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
816942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	newinfo->initial_entries = private->initial_entries;
817b416c144f46af1a30ddfa4e4319a8f077381ad63Will Deacon	/*
818b416c144f46af1a30ddfa4e4319a8f077381ad63Will Deacon	 * Ensure contents of newinfo are visible before assigning to
819b416c144f46af1a30ddfa4e4319a8f077381ad63Will Deacon	 * private.
820b416c144f46af1a30ddfa4e4319a8f077381ad63Will Deacon	 */
821b416c144f46af1a30ddfa4e4319a8f077381ad63Will Deacon	smp_wmb();
822b416c144f46af1a30ddfa4e4319a8f077381ad63Will Deacon	table->private = newinfo;
823942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger
824942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	/*
825942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	 * Even though table entries have now been swapped, other CPU's
826942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	 * may still be using the old entries. This is okay, because
827942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	 * resynchronization happens because of the locking done
828942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	 * during the get_counters() routine.
829942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	 */
830942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	local_bh_enable();
831942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger
832fbabf31e4d482149b5e2704eb0287cf9117bdcf3Thomas Graf#ifdef CONFIG_AUDIT
833fbabf31e4d482149b5e2704eb0287cf9117bdcf3Thomas Graf	if (audit_enabled) {
834fbabf31e4d482149b5e2704eb0287cf9117bdcf3Thomas Graf		struct audit_buffer *ab;
835fbabf31e4d482149b5e2704eb0287cf9117bdcf3Thomas Graf
836fbabf31e4d482149b5e2704eb0287cf9117bdcf3Thomas Graf		ab = audit_log_start(current->audit_context, GFP_KERNEL,
837fbabf31e4d482149b5e2704eb0287cf9117bdcf3Thomas Graf				     AUDIT_NETFILTER_CFG);
838fbabf31e4d482149b5e2704eb0287cf9117bdcf3Thomas Graf		if (ab) {
839fbabf31e4d482149b5e2704eb0287cf9117bdcf3Thomas Graf			audit_log_format(ab, "table=%s family=%u entries=%u",
840fbabf31e4d482149b5e2704eb0287cf9117bdcf3Thomas Graf					 table->name, table->af,
841fbabf31e4d482149b5e2704eb0287cf9117bdcf3Thomas Graf					 private->number);
842fbabf31e4d482149b5e2704eb0287cf9117bdcf3Thomas Graf			audit_log_end(ab);
843fbabf31e4d482149b5e2704eb0287cf9117bdcf3Thomas Graf		}
844fbabf31e4d482149b5e2704eb0287cf9117bdcf3Thomas Graf	}
845fbabf31e4d482149b5e2704eb0287cf9117bdcf3Thomas Graf#endif
846fbabf31e4d482149b5e2704eb0287cf9117bdcf3Thomas Graf
847942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	return private;
8482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
8492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_replace_table);
8502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
85135aad0ffdf548617940ca1e78be1f2e0bafc4496Jan Engelhardtstruct xt_table *xt_register_table(struct net *net,
85235aad0ffdf548617940ca1e78be1f2e0bafc4496Jan Engelhardt				   const struct xt_table *input_table,
853a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan				   struct xt_table_info *bootstrap,
854a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan				   struct xt_table_info *newinfo)
8552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
8562e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	int ret;
8572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table_info *private;
85835aad0ffdf548617940ca1e78be1f2e0bafc4496Jan Engelhardt	struct xt_table *t, *table;
8592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
86044d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan	/* Don't add one object to multiple lists. */
86135aad0ffdf548617940ca1e78be1f2e0bafc4496Jan Engelhardt	table = kmemdup(input_table, sizeof(struct xt_table), GFP_KERNEL);
86244d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan	if (!table) {
86344d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan		ret = -ENOMEM;
86444d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan		goto out;
86544d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan	}
86644d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan
8677926dbfa4bc14e27f4e18a6184a031a1c1e077dcPablo Neira Ayuso	mutex_lock(&xt[table->af].mutex);
8682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Don't autoload: we'd eat our tail... */
8698d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	list_for_each_entry(t, &net->xt.tables[table->af], list) {
870df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy		if (strcmp(t->name, table->name) == 0) {
871df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy			ret = -EEXIST;
872df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy			goto unlock;
873df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy		}
8742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
8752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* Simplifies replace_table code. */
8772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	table->private = bootstrap;
878784544739a25c30637397ace5489eeb6e15d7d49Stephen Hemminger
8792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!xt_replace_table(table, 0, newinfo, &ret))
8802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto unlock;
8812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	private = table->private;
883be91fd5e323b46450ca82f6828e933e3791fb2f2Jan Engelhardt	pr_debug("table->private->number = %u\n", private->number);
8842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	/* save number of initial entries */
8862e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	private->initial_entries = private->number;
8872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8888d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	list_add(&table->list, &net->xt.tables[table->af]);
889a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan	mutex_unlock(&xt[table->af].mutex);
890a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan	return table;
8912e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
8927926dbfa4bc14e27f4e18a6184a031a1c1e077dcPablo Neira Ayusounlock:
8939e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[table->af].mutex);
89444d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan	kfree(table);
895a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyanout:
896a98da11d88dbec1d5cebe2c6dbe9939ed8d13f69Alexey Dobriyan	return ERR_PTR(ret);
8972e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
8982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_register_table);
8992e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
9002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltevoid *xt_unregister_table(struct xt_table *table)
9012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
9022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct xt_table_info *private;
9032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
9049e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_lock(&xt[table->af].mutex);
9052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	private = table->private;
906df0933dcb027e156cb5253570ad694b81bd52b69Patrick McHardy	list_del(&table->list);
9079e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar	mutex_unlock(&xt[table->af].mutex);
90844d34e721e2c81ccdfb13cf34996309247ae2981Alexey Dobriyan	kfree(table);
9092e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
9102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return private;
9112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
9122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_unregister_table);
9132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
9142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
915715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyanstruct xt_names_priv {
916715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	struct seq_net_private p;
91776108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	u_int8_t af;
918715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan};
919025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void *xt_table_seq_start(struct seq_file *seq, loff_t *pos)
9202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
921715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	struct xt_names_priv *priv = seq->private;
9221218854afa6f659be90b748cf1bc7badee954a35YOSHIFUJI Hideaki	struct net *net = seq_file_net(seq);
92376108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	u_int8_t af = priv->af;
9242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
925025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	mutex_lock(&xt[af].mutex);
926715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	return seq_list_start(&net->xt.tables[af], *pos);
927025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
9282e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
929025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void *xt_table_seq_next(struct seq_file *seq, void *v, loff_t *pos)
930025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
931715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	struct xt_names_priv *priv = seq->private;
9321218854afa6f659be90b748cf1bc7badee954a35YOSHIFUJI Hideaki	struct net *net = seq_file_net(seq);
93376108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	u_int8_t af = priv->af;
9342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
935715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	return seq_list_next(v, &net->xt.tables[af], pos);
9362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
9372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
938025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void xt_table_seq_stop(struct seq_file *seq, void *v)
9392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
940715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	struct xt_names_priv *priv = seq->private;
94176108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	u_int8_t af = priv->af;
9422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
943025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	mutex_unlock(&xt[af].mutex);
944025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
9452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
946025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_table_seq_show(struct seq_file *seq, void *v)
947025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
948025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	struct xt_table *table = list_entry(v, struct xt_table, list);
9492e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
950025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	if (strlen(table->name))
951025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan		return seq_printf(seq, "%s\n", table->name);
952025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	else
953025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan		return 0;
954025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
955601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki
956025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct seq_operations xt_table_seq_ops = {
957025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.start	= xt_table_seq_start,
958025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.next	= xt_table_seq_next,
959025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.stop	= xt_table_seq_stop,
960025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.show	= xt_table_seq_show,
961025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan};
962025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
963025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_table_open(struct inode *inode, struct file *file)
964025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
965025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	int ret;
966715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	struct xt_names_priv *priv;
967025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
968715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan	ret = seq_open_net(inode, file, &xt_table_seq_ops,
969715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan			   sizeof(struct xt_names_priv));
970025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	if (!ret) {
971715cf35ac9291f31a4fea7d022695a64cac0af80Alexey Dobriyan		priv = ((struct seq_file *)file->private_data)->private;
972d9dda78bad879595d8c4220a067fc029d6484a16Al Viro		priv->af = (unsigned long)PDE_DATA(inode);
973025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	}
974025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	return ret;
9752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
9762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
977025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct file_operations xt_table_ops = {
978025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.owner	 = THIS_MODULE,
979025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.open	 = xt_table_open,
980025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.read	 = seq_read,
981025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.llseek	 = seq_lseek,
9820e93bb9459f56b50a2f71f2c230f4ad00ec40a73Pavel Emelyanov	.release = seq_release_net,
983025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan};
984025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
985eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt/*
986eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt * Traverse state for ip{,6}_{tables,matches} for helping crossing
987eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt * the multi-AF mutexes.
988eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt */
989eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstruct nf_mttg_trav {
990eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	struct list_head *head, *curr;
991eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	uint8_t class, nfproto;
992eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt};
993eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt
994eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtenum {
995eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	MTTG_TRAV_INIT,
996eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	MTTG_TRAV_NFP_UNSPEC,
997eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	MTTG_TRAV_NFP_SPEC,
998eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	MTTG_TRAV_DONE,
999eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt};
1000eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt
1001eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void *xt_mttg_seq_next(struct seq_file *seq, void *v, loff_t *ppos,
1002eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt    bool is_target)
10032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
1004eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	static const uint8_t next_class[] = {
1005eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		[MTTG_TRAV_NFP_UNSPEC] = MTTG_TRAV_NFP_SPEC,
1006eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		[MTTG_TRAV_NFP_SPEC]   = MTTG_TRAV_DONE,
1007eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	};
1008eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	struct nf_mttg_trav *trav = seq->private;
1009eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt
1010eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	switch (trav->class) {
1011eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	case MTTG_TRAV_INIT:
1012eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		trav->class = MTTG_TRAV_NFP_UNSPEC;
1013eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		mutex_lock(&xt[NFPROTO_UNSPEC].mutex);
1014eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		trav->head = trav->curr = is_target ?
1015eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt			&xt[NFPROTO_UNSPEC].target : &xt[NFPROTO_UNSPEC].match;
1016eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt 		break;
1017eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	case MTTG_TRAV_NFP_UNSPEC:
1018eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		trav->curr = trav->curr->next;
1019eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		if (trav->curr != trav->head)
1020eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt			break;
1021eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		mutex_unlock(&xt[NFPROTO_UNSPEC].mutex);
1022eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		mutex_lock(&xt[trav->nfproto].mutex);
1023eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		trav->head = trav->curr = is_target ?
1024eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt			&xt[trav->nfproto].target : &xt[trav->nfproto].match;
1025eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		trav->class = next_class[trav->class];
1026eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		break;
1027eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	case MTTG_TRAV_NFP_SPEC:
1028eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		trav->curr = trav->curr->next;
1029eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		if (trav->curr != trav->head)
1030eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt			break;
1031eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		/* fallthru, _stop will unlock */
1032eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	default:
1033eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		return NULL;
1034eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	}
10352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1036eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	if (ppos != NULL)
1037eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		++*ppos;
1038eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return trav;
1039025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
1040601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki
1041eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void *xt_mttg_seq_start(struct seq_file *seq, loff_t *pos,
1042eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt    bool is_target)
1043025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
1044eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	struct nf_mttg_trav *trav = seq->private;
1045eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	unsigned int j;
10462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1047eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	trav->class = MTTG_TRAV_INIT;
1048eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	for (j = 0; j < *pos; ++j)
1049eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		if (xt_mttg_seq_next(seq, NULL, NULL, is_target) == NULL)
1050eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt			return NULL;
1051eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return trav;
10522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
10532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1054eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void xt_mttg_seq_stop(struct seq_file *seq, void *v)
10552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
1056eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	struct nf_mttg_trav *trav = seq->private;
1057eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt
1058eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	switch (trav->class) {
1059eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	case MTTG_TRAV_NFP_UNSPEC:
1060eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		mutex_unlock(&xt[NFPROTO_UNSPEC].mutex);
1061eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		break;
1062eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	case MTTG_TRAV_NFP_SPEC:
1063eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		mutex_unlock(&xt[trav->nfproto].mutex);
1064eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		break;
1065eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	}
1066eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt}
10672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1068eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void *xt_match_seq_start(struct seq_file *seq, loff_t *pos)
1069eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt{
1070eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return xt_mttg_seq_start(seq, pos, false);
10712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
10722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1073eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void *xt_match_seq_next(struct seq_file *seq, void *v, loff_t *ppos)
10742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
1075eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return xt_mttg_seq_next(seq, v, ppos, false);
1076eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt}
10772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1078eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic int xt_match_seq_show(struct seq_file *seq, void *v)
1079eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt{
1080eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	const struct nf_mttg_trav *trav = seq->private;
1081eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	const struct xt_match *match;
1082eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt
1083eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	switch (trav->class) {
1084eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	case MTTG_TRAV_NFP_UNSPEC:
1085eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	case MTTG_TRAV_NFP_SPEC:
1086eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		if (trav->curr == trav->head)
1087eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt			return 0;
1088eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		match = list_entry(trav->curr, struct xt_match, list);
1089eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		return (*match->name == '\0') ? 0 :
1090eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		       seq_printf(seq, "%s\n", match->name);
1091eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	}
1092eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return 0;
10932e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
10942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1095025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct seq_operations xt_match_seq_ops = {
1096025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.start	= xt_match_seq_start,
1097025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.next	= xt_match_seq_next,
1098eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	.stop	= xt_mttg_seq_stop,
1099025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.show	= xt_match_seq_show,
11002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte};
11012e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1102025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_match_open(struct inode *inode, struct file *file)
11032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
1104eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	struct nf_mttg_trav *trav;
1105772476df7047db87ac4174d1ed396512912d23bfRob Jones	trav = __seq_open_private(file, &xt_match_seq_ops, sizeof(*trav));
1106772476df7047db87ac4174d1ed396512912d23bfRob Jones	if (!trav)
1107eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		return -ENOMEM;
11082e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1109d9dda78bad879595d8c4220a067fc029d6484a16Al Viro	trav->nfproto = (unsigned long)PDE_DATA(inode);
1110eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return 0;
1111025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
1112025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
1113025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct file_operations xt_match_ops = {
1114025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.owner	 = THIS_MODULE,
1115025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.open	 = xt_match_open,
1116025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.read	 = seq_read,
1117025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.llseek	 = seq_lseek,
1118eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	.release = seq_release_private,
1119025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan};
11202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1121025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic void *xt_target_seq_start(struct seq_file *seq, loff_t *pos)
1122025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
1123eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return xt_mttg_seq_start(seq, pos, true);
1124025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
1125025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
1126eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardtstatic void *xt_target_seq_next(struct seq_file *seq, void *v, loff_t *ppos)
1127025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
1128eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return xt_mttg_seq_next(seq, v, ppos, true);
1129025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
1130025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
1131025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_target_seq_show(struct seq_file *seq, void *v)
1132025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
1133eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	const struct nf_mttg_trav *trav = seq->private;
1134eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	const struct xt_target *target;
1135eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt
1136eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	switch (trav->class) {
1137eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	case MTTG_TRAV_NFP_UNSPEC:
1138eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	case MTTG_TRAV_NFP_SPEC:
1139eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		if (trav->curr == trav->head)
1140eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt			return 0;
1141eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		target = list_entry(trav->curr, struct xt_target, list);
1142eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		return (*target->name == '\0') ? 0 :
1143eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		       seq_printf(seq, "%s\n", target->name);
1144eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	}
1145eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return 0;
1146025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan}
1147025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
1148025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct seq_operations xt_target_seq_ops = {
1149025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.start	= xt_target_seq_start,
1150025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.next	= xt_target_seq_next,
1151eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	.stop	= xt_mttg_seq_stop,
1152025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.show	= xt_target_seq_show,
1153025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan};
1154025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
1155025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic int xt_target_open(struct inode *inode, struct file *file)
1156025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan{
1157eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	struct nf_mttg_trav *trav;
1158772476df7047db87ac4174d1ed396512912d23bfRob Jones	trav = __seq_open_private(file, &xt_target_seq_ops, sizeof(*trav));
1159772476df7047db87ac4174d1ed396512912d23bfRob Jones	if (!trav)
1160eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt		return -ENOMEM;
1161025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan
1162d9dda78bad879595d8c4220a067fc029d6484a16Al Viro	trav->nfproto = (unsigned long)PDE_DATA(inode);
1163eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	return 0;
11642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
11652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1166025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyanstatic const struct file_operations xt_target_ops = {
11672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.owner	 = THIS_MODULE,
1168025d93d148d46bedb26905975f5d9c83d280b46eAlexey Dobriyan	.open	 = xt_target_open,
11692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.read	 = seq_read,
11702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	.llseek	 = seq_lseek,
1171eb132205ca2f7ad44d8c8c482815b6911200b6a0Jan Engelhardt	.release = seq_release_private,
11722e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte};
11732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
11742e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define FORMAT_TABLES	"_tables_names"
11752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define	FORMAT_MATCHES	"_tables_matches"
11762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#define FORMAT_TARGETS 	"_tables_targets"
11772e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
11782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif /* CONFIG_PROC_FS */
11792e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
11802b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt/**
11812b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * xt_hook_link - set up hooks for a new table
11822b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * @table:	table with metadata needed to set up hooks
11832b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * @fn:		Hook function
11842b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt *
11852b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * This function will take care of creating and registering the necessary
11862b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * Netfilter hooks for XT tables.
11872b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt */
11882b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardtstruct nf_hook_ops *xt_hook_link(const struct xt_table *table, nf_hookfn *fn)
11892b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt{
11902b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	unsigned int hook_mask = table->valid_hooks;
11912b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	uint8_t i, num_hooks = hweight32(hook_mask);
11922b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	uint8_t hooknum;
11932b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	struct nf_hook_ops *ops;
11942b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	int ret;
11952b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt
11962b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	ops = kmalloc(sizeof(*ops) * num_hooks, GFP_KERNEL);
11972b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	if (ops == NULL)
11982b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		return ERR_PTR(-ENOMEM);
11992b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt
12002b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	for (i = 0, hooknum = 0; i < num_hooks && hook_mask != 0;
12012b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	     hook_mask >>= 1, ++hooknum) {
12022b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		if (!(hook_mask & 1))
12032b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt			continue;
12042b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		ops[i].hook     = fn;
12052b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		ops[i].owner    = table->me;
12062b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		ops[i].pf       = table->af;
12072b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		ops[i].hooknum  = hooknum;
12082b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		ops[i].priority = table->priority;
12092b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		++i;
12102b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	}
12112b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt
12122b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	ret = nf_register_hooks(ops, num_hooks);
12132b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	if (ret < 0) {
12142b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		kfree(ops);
12152b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt		return ERR_PTR(ret);
12162b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	}
12172b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt
12182b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	return ops;
12192b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt}
12202b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan EngelhardtEXPORT_SYMBOL_GPL(xt_hook_link);
12212b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt
12222b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt/**
12232b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * xt_hook_unlink - remove hooks for a table
12242b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * @ops:	nf_hook_ops array as returned by nf_hook_link
12252b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt * @hook_mask:	the very same mask that was passed to nf_hook_link
12262b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt */
12272b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardtvoid xt_hook_unlink(const struct xt_table *table, struct nf_hook_ops *ops)
12282b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt{
12292b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	nf_unregister_hooks(ops, hweight32(table->valid_hooks));
12302b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt	kfree(ops);
12312b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt}
12322b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan EngelhardtEXPORT_SYMBOL_GPL(xt_hook_unlink);
12332b95efe7f6bb750256a702cc32d33b0cb2cd8223Jan Engelhardt
123476108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtint xt_proto_init(struct net *net, u_int8_t af)
12352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
12362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
12372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	char buf[XT_FUNCTION_MAXNAMELEN];
12382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	struct proc_dir_entry *proc;
12392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif
12402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
12417e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	if (af >= ARRAY_SIZE(xt_prefix))
12422e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return -EINVAL;
12432e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
12442e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
12452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
1246ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
12472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TABLES, sizeof(buf));
12488b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev	proc = proc_create_data(buf, 0440, net->proc_net, &xt_table_ops,
12498b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev				(void *)(unsigned long)af);
12502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!proc)
12512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto out;
12522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1253ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
12542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
12558b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev	proc = proc_create_data(buf, 0440, net->proc_net, &xt_match_ops,
12568b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev				(void *)(unsigned long)af);
12572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!proc)
12582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto out_remove_tables;
12592e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1260ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
12612e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TARGETS, sizeof(buf));
12628b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev	proc = proc_create_data(buf, 0440, net->proc_net, &xt_target_ops,
12638b169240e266d7fc58d9b9077d18d50a548d9732Denis V. Lunev				(void *)(unsigned long)af);
12642e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!proc)
12652e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		goto out_remove_matches;
12662e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif
12672e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
12682e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return 0;
12692e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
12702e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
12712e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteout_remove_matches:
1272ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
12732e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
1274ece31ffd539e8e2b586b1ca5f50bc4f4591e3893Gao feng	remove_proc_entry(buf, net->proc_net);
12752e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
12762e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteout_remove_tables:
1277ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
12782e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TABLES, sizeof(buf));
1279ece31ffd539e8e2b586b1ca5f50bc4f4591e3893Gao feng	remove_proc_entry(buf, net->proc_net);
12802e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welteout:
12812e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return -1;
12822e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif
12832e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
12842e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_proto_init);
12852e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
128676108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtvoid xt_proto_fini(struct net *net, u_int8_t af)
12872e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
12882e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#ifdef CONFIG_PROC_FS
12892e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	char buf[XT_FUNCTION_MAXNAMELEN];
12902e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1291ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
12922e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TABLES, sizeof(buf));
1293ece31ffd539e8e2b586b1ca5f50bc4f4591e3893Gao feng	remove_proc_entry(buf, net->proc_net);
12942e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1295ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
12962e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_TARGETS, sizeof(buf));
1297ece31ffd539e8e2b586b1ca5f50bc4f4591e3893Gao feng	remove_proc_entry(buf, net->proc_net);
12982e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1299ce18afe57bf53477f133208856dd2b7e6b5db5e3Tobias Klauser	strlcpy(buf, xt_prefix[af], sizeof(buf));
13002e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
1301ece31ffd539e8e2b586b1ca5f50bc4f4591e3893Gao feng	remove_proc_entry(buf, net->proc_net);
13022e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#endif /*CONFIG_PROC_FS*/
13032e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
13042e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteEXPORT_SYMBOL_GPL(xt_proto_fini);
13052e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
13068d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyanstatic int __net_init xt_net_init(struct net *net)
13078d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan{
13088d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	int i;
13098d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan
13107e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	for (i = 0; i < NFPROTO_NUMPROTO; i++)
13118d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan		INIT_LIST_HEAD(&net->xt.tables[i]);
13128d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	return 0;
13138d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan}
13148d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan
13158d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyanstatic struct pernet_operations xt_net_ops = {
13168d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	.init = xt_net_init,
13178d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan};
13182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
13192e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic int __init xt_init(void)
13202e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
1321942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	unsigned int i;
1322942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	int rv;
1323942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger
1324942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	for_each_possible_cpu(i) {
13257f5c6d4f665bb57a19a34ce1fb16cc708c04f219Eric Dumazet		seqcount_init(&per_cpu(xt_recseq, i));
1326942e4a2bd680c606af0211e64eb216be2e19bf61Stephen Hemminger	}
13272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
13287e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	xt = kmalloc(sizeof(struct xt_af) * NFPROTO_NUMPROTO, GFP_KERNEL);
13292e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	if (!xt)
13302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		return -ENOMEM;
13312e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
13327e9c6eeb136a46dfd941852803b3a9dd78939b69Jan Engelhardt	for (i = 0; i < NFPROTO_NUMPROTO; i++) {
13339e19bb6d7a0959f5028d46e1ab99c50f0d36eda8Ingo Molnar		mutex_init(&xt[i].mutex);
13342722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#ifdef CONFIG_COMPAT
13352722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin		mutex_init(&xt[i].compat_mutex);
1336255d0dc34068a976550ce555e153c0bfcfec7cc6Eric Dumazet		xt[i].compat_tab = NULL;
13372722971cbe831117686039d5c334f2c0f560be13Dmitry Mishin#endif
13382e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		INIT_LIST_HEAD(&xt[i].target);
13392e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte		INIT_LIST_HEAD(&xt[i].match);
13402e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	}
13418d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	rv = register_pernet_subsys(&xt_net_ops);
13428d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	if (rv < 0)
13438d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan		kfree(xt);
13448d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	return rv;
13452e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
13462e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
13472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic void __exit xt_fini(void)
13482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
13498d870052079d255917ec4f8431f5ec102707b7afAlexey Dobriyan	unregister_pernet_subsys(&xt_net_ops);
13502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	kfree(xt);
13512e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
13522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
13532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltemodule_init(xt_init);
13542e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltemodule_exit(xt_fini);
13552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1356