nf_queue.c revision 76108cea065cda58366d16a7eb6ca90d717a1396
1f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte#include <linux/kernel.h>
2f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte#include <linux/init.h>
3f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte#include <linux/module.h>
4f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte#include <linux/proc_fs.h>
5f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte#include <linux/skbuff.h>
6f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte#include <linux/netfilter.h>
7bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte#include <linux/seq_file.h>
87a11b9848ae27e571f219fab5541bd84700f0d68Patrick McHardy#include <linux/rcupdate.h>
9f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte#include <net/protocol.h>
10c01cd429fc118c5db92475c5f08b307718aa4efcPatrick McHardy#include <net/netfilter/nf_queue.h>
11f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
12f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte#include "nf_internals.h"
13f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
14601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki/*
15f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte * A queue handler may be registered for each protocol.  Each is protected by
16f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte * long term mutex.  The handler must provide an an outfn() to accept packets
17f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte * for queueing and must reinject all packets it receives, no matter what.
18f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte */
19e3ac5298159c5286cef86f0865d4fa6a606bd391Patrick McHardystatic const struct nf_queue_handler *queue_handler[NPROTO];
20f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
21585426fdc5b4cccaacf0afc8cf821ff763750ae8Yasuyuki Kozakaistatic DEFINE_MUTEX(queue_handler_mutex);
22f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
23d72367b6f36e557f122beefaa8c6b80eb1c7f245Harald Welte/* return EBUSY when somebody else is registered, return EEXIST if the
24d72367b6f36e557f122beefaa8c6b80eb1c7f245Harald Welte * same handler is registered, return 0 in case of success. */
2576108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtint nf_register_queue_handler(u_int8_t pf, const struct nf_queue_handler *qh)
26601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki{
27f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	int ret;
28f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
29f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	if (pf >= NPROTO)
30f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		return -EINVAL;
31f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
32585426fdc5b4cccaacf0afc8cf821ff763750ae8Yasuyuki Kozakai	mutex_lock(&queue_handler_mutex);
33d72367b6f36e557f122beefaa8c6b80eb1c7f245Harald Welte	if (queue_handler[pf] == qh)
34d72367b6f36e557f122beefaa8c6b80eb1c7f245Harald Welte		ret = -EEXIST;
35d72367b6f36e557f122beefaa8c6b80eb1c7f245Harald Welte	else if (queue_handler[pf])
36f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		ret = -EBUSY;
37f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	else {
38585426fdc5b4cccaacf0afc8cf821ff763750ae8Yasuyuki Kozakai		rcu_assign_pointer(queue_handler[pf], qh);
39f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		ret = 0;
40f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	}
41585426fdc5b4cccaacf0afc8cf821ff763750ae8Yasuyuki Kozakai	mutex_unlock(&queue_handler_mutex);
42f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
43f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	return ret;
44f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte}
45f6ebe77f955d77a988ce726f0818ec0103b11323Harald WelteEXPORT_SYMBOL(nf_register_queue_handler);
46f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
47f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte/* The caller must flush their queue before this */
4876108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardtint nf_unregister_queue_handler(u_int8_t pf, const struct nf_queue_handler *qh)
49f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte{
50f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	if (pf >= NPROTO)
51f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		return -EINVAL;
52f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
53585426fdc5b4cccaacf0afc8cf821ff763750ae8Yasuyuki Kozakai	mutex_lock(&queue_handler_mutex);
5494be1a3f365e2b9f2615575d7fef16a0bad106a3Patrick McHardy	if (queue_handler[pf] && queue_handler[pf] != qh) {
55585426fdc5b4cccaacf0afc8cf821ff763750ae8Yasuyuki Kozakai		mutex_unlock(&queue_handler_mutex);
56ce7663d84a87bb4e1743f62950bf7dceed723a13Yasuyuki Kozakai		return -EINVAL;
57ce7663d84a87bb4e1743f62950bf7dceed723a13Yasuyuki Kozakai	}
58ce7663d84a87bb4e1743f62950bf7dceed723a13Yasuyuki Kozakai
59585426fdc5b4cccaacf0afc8cf821ff763750ae8Yasuyuki Kozakai	rcu_assign_pointer(queue_handler[pf], NULL);
60585426fdc5b4cccaacf0afc8cf821ff763750ae8Yasuyuki Kozakai	mutex_unlock(&queue_handler_mutex);
61585426fdc5b4cccaacf0afc8cf821ff763750ae8Yasuyuki Kozakai
62585426fdc5b4cccaacf0afc8cf821ff763750ae8Yasuyuki Kozakai	synchronize_rcu();
63601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki
64f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	return 0;
65f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte}
66f6ebe77f955d77a988ce726f0818ec0103b11323Harald WelteEXPORT_SYMBOL(nf_unregister_queue_handler);
67f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
68e3ac5298159c5286cef86f0865d4fa6a606bd391Patrick McHardyvoid nf_unregister_queue_handlers(const struct nf_queue_handler *qh)
69f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte{
7076108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	u_int8_t pf;
71f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
72585426fdc5b4cccaacf0afc8cf821ff763750ae8Yasuyuki Kozakai	mutex_lock(&queue_handler_mutex);
73f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	for (pf = 0; pf < NPROTO; pf++)  {
74bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte		if (queue_handler[pf] == qh)
75585426fdc5b4cccaacf0afc8cf821ff763750ae8Yasuyuki Kozakai			rcu_assign_pointer(queue_handler[pf], NULL);
76f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	}
77585426fdc5b4cccaacf0afc8cf821ff763750ae8Yasuyuki Kozakai	mutex_unlock(&queue_handler_mutex);
78585426fdc5b4cccaacf0afc8cf821ff763750ae8Yasuyuki Kozakai
79585426fdc5b4cccaacf0afc8cf821ff763750ae8Yasuyuki Kozakai	synchronize_rcu();
80f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte}
81f6ebe77f955d77a988ce726f0818ec0103b11323Harald WelteEXPORT_SYMBOL_GPL(nf_unregister_queue_handlers);
82f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
83daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardystatic void nf_queue_entry_release_refs(struct nf_queue_entry *entry)
84daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy{
85daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy	/* Release those devices we held, or Alexey will kill me. */
86daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy	if (entry->indev)
87daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy		dev_put(entry->indev);
88daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy	if (entry->outdev)
89daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy		dev_put(entry->outdev);
90daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy#ifdef CONFIG_BRIDGE_NETFILTER
91daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy	if (entry->skb->nf_bridge) {
92daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy		struct nf_bridge_info *nf_bridge = entry->skb->nf_bridge;
93daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy
94daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy		if (nf_bridge->physindev)
95daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy			dev_put(nf_bridge->physindev);
96daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy		if (nf_bridge->physoutdev)
97daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy			dev_put(nf_bridge->physoutdev);
98daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy	}
99daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy#endif
100daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy	/* Drop reference to owner of hook which queued us. */
101daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy	module_put(entry->elem->owner);
102daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy}
103daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy
104601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki/*
105601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki * Any packet that leaves via this function must come back
106f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte * through nf_reinject().
107f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte */
108394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardystatic int __nf_queue(struct sk_buff *skb,
109394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy		      struct list_head *elem,
11076108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt		      u_int8_t pf, unsigned int hook,
111394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy		      struct net_device *indev,
112394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy		      struct net_device *outdev,
113394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy		      int (*okfn)(struct sk_buff *),
114394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy		      unsigned int queuenum)
115f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte{
116f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	int status;
117daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy	struct nf_queue_entry *entry = NULL;
118f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte#ifdef CONFIG_BRIDGE_NETFILTER
119daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy	struct net_device *physindev;
120daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy	struct net_device *physoutdev;
121f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte#endif
1221e796fda00f06bac584f0e4ad8750ab9430d79d3Patrick McHardy	const struct nf_afinfo *afinfo;
123e3ac5298159c5286cef86f0865d4fa6a606bd391Patrick McHardy	const struct nf_queue_handler *qh;
124f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
125f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	/* QUEUE == DROP if noone is waiting, to be safe. */
126585426fdc5b4cccaacf0afc8cf821ff763750ae8Yasuyuki Kozakai	rcu_read_lock();
127585426fdc5b4cccaacf0afc8cf821ff763750ae8Yasuyuki Kozakai
128585426fdc5b4cccaacf0afc8cf821ff763750ae8Yasuyuki Kozakai	qh = rcu_dereference(queue_handler[pf]);
129daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy	if (!qh)
130daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy		goto err_unlock;
131f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
132bce8032ef3cc58170ab3550e9e271dba7b4c4764Patrick McHardy	afinfo = nf_get_afinfo(pf);
133daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy	if (!afinfo)
134daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy		goto err_unlock;
135bce8032ef3cc58170ab3550e9e271dba7b4c4764Patrick McHardy
13602f014d88831f73b895c1fe09badb66c88e932d3Patrick McHardy	entry = kmalloc(sizeof(*entry) + afinfo->route_key_size, GFP_ATOMIC);
137daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy	if (!entry)
138daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy		goto err_unlock;
139f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
14002f014d88831f73b895c1fe09badb66c88e932d3Patrick McHardy	*entry = (struct nf_queue_entry) {
14102f014d88831f73b895c1fe09badb66c88e932d3Patrick McHardy		.skb	= skb,
14202f014d88831f73b895c1fe09badb66c88e932d3Patrick McHardy		.elem	= list_entry(elem, struct nf_hook_ops, list),
14302f014d88831f73b895c1fe09badb66c88e932d3Patrick McHardy		.pf	= pf,
14402f014d88831f73b895c1fe09badb66c88e932d3Patrick McHardy		.hook	= hook,
14502f014d88831f73b895c1fe09badb66c88e932d3Patrick McHardy		.indev	= indev,
14602f014d88831f73b895c1fe09badb66c88e932d3Patrick McHardy		.outdev	= outdev,
14702f014d88831f73b895c1fe09badb66c88e932d3Patrick McHardy		.okfn	= okfn,
14802f014d88831f73b895c1fe09badb66c88e932d3Patrick McHardy	};
149f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
150f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	/* If it's going away, ignore hook. */
15102f014d88831f73b895c1fe09badb66c88e932d3Patrick McHardy	if (!try_module_get(entry->elem->owner)) {
152585426fdc5b4cccaacf0afc8cf821ff763750ae8Yasuyuki Kozakai		rcu_read_unlock();
15302f014d88831f73b895c1fe09badb66c88e932d3Patrick McHardy		kfree(entry);
154f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		return 0;
155f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	}
156f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
157f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	/* Bump dev refs so they don't vanish while packet is out */
1588b1cf0db2aced837fcd50072e81e32c5836a1ee1Patrick McHardy	if (indev)
1598b1cf0db2aced837fcd50072e81e32c5836a1ee1Patrick McHardy		dev_hold(indev);
1608b1cf0db2aced837fcd50072e81e32c5836a1ee1Patrick McHardy	if (outdev)
1618b1cf0db2aced837fcd50072e81e32c5836a1ee1Patrick McHardy		dev_hold(outdev);
162f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte#ifdef CONFIG_BRIDGE_NETFILTER
163394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy	if (skb->nf_bridge) {
164394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy		physindev = skb->nf_bridge->physindev;
1658b1cf0db2aced837fcd50072e81e32c5836a1ee1Patrick McHardy		if (physindev)
1668b1cf0db2aced837fcd50072e81e32c5836a1ee1Patrick McHardy			dev_hold(physindev);
167394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy		physoutdev = skb->nf_bridge->physoutdev;
1688b1cf0db2aced837fcd50072e81e32c5836a1ee1Patrick McHardy		if (physoutdev)
1698b1cf0db2aced837fcd50072e81e32c5836a1ee1Patrick McHardy			dev_hold(physoutdev);
170f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	}
171f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte#endif
17202f014d88831f73b895c1fe09badb66c88e932d3Patrick McHardy	afinfo->saveroute(skb, entry);
17302f014d88831f73b895c1fe09badb66c88e932d3Patrick McHardy	status = qh->outfn(entry, queuenum);
174f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
175585426fdc5b4cccaacf0afc8cf821ff763750ae8Yasuyuki Kozakai	rcu_read_unlock();
176f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
177f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	if (status < 0) {
178daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy		nf_queue_entry_release_refs(entry);
179daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy		goto err;
180f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	}
181f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
182f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	return 1;
183daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy
184daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardyerr_unlock:
185daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy	rcu_read_unlock();
186daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardyerr:
187daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy	kfree_skb(skb);
188daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy	kfree(entry);
189daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy	return 1;
190f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte}
191f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
192394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardyint nf_queue(struct sk_buff *skb,
193394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy	     struct list_head *elem,
19476108cea065cda58366d16a7eb6ca90d717a1396Jan Engelhardt	     u_int8_t pf, unsigned int hook,
195394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy	     struct net_device *indev,
196394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy	     struct net_device *outdev,
197394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy	     int (*okfn)(struct sk_buff *),
198394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy	     unsigned int queuenum)
199394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy{
200394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy	struct sk_buff *segs;
201394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy
202394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy	if (!skb_is_gso(skb))
203394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy		return __nf_queue(skb, elem, pf, hook, indev, outdev, okfn,
204394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy				  queuenum);
205394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy
206394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy	switch (pf) {
207394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy	case AF_INET:
208394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy		skb->protocol = htons(ETH_P_IP);
209394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy		break;
210394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy	case AF_INET6:
211394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy		skb->protocol = htons(ETH_P_IPV6);
212394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy		break;
213394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy	}
214394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy
215394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy	segs = skb_gso_segment(skb, 0);
216394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy	kfree_skb(skb);
217801678c5a3b4c79236970bcca27c733f5559e0d1Hirofumi Nakagawa	if (IS_ERR(segs))
218394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy		return 1;
219394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy
220394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy	do {
221394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy		struct sk_buff *nskb = segs->next;
222394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy
223394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy		segs->next = NULL;
224394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy		if (!__nf_queue(segs, elem, pf, hook, indev, outdev, okfn,
225394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy				queuenum))
226394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy			kfree_skb(segs);
227394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy		segs = nskb;
228394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy	} while (segs);
229394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy	return 1;
230394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy}
231394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy
23202f014d88831f73b895c1fe09badb66c88e932d3Patrick McHardyvoid nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
233f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte{
23402f014d88831f73b895c1fe09badb66c88e932d3Patrick McHardy	struct sk_buff *skb = entry->skb;
23502f014d88831f73b895c1fe09badb66c88e932d3Patrick McHardy	struct list_head *elem = &entry->elem->list;
2361e796fda00f06bac584f0e4ad8750ab9430d79d3Patrick McHardy	const struct nf_afinfo *afinfo;
237f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
238f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	rcu_read_lock();
239f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
240daaa8be2e0ec1c27d11e6724c8ebd8ed53914ae2Patrick McHardy	nf_queue_entry_release_refs(entry);
241f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
242f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	/* Continue traversal iff userspace said ok... */
243f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	if (verdict == NF_REPEAT) {
244f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		elem = elem->prev;
245f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		verdict = NF_ACCEPT;
246f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	}
247f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
248f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	if (verdict == NF_ACCEPT) {
24902f014d88831f73b895c1fe09badb66c88e932d3Patrick McHardy		afinfo = nf_get_afinfo(entry->pf);
25002f014d88831f73b895c1fe09badb66c88e932d3Patrick McHardy		if (!afinfo || afinfo->reroute(skb, entry) < 0)
2517a11b9848ae27e571f219fab5541bd84700f0d68Patrick McHardy			verdict = NF_DROP;
2527a11b9848ae27e571f219fab5541bd84700f0d68Patrick McHardy	}
2537a11b9848ae27e571f219fab5541bd84700f0d68Patrick McHardy
2547a11b9848ae27e571f219fab5541bd84700f0d68Patrick McHardy	if (verdict == NF_ACCEPT) {
255f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	next_hook:
25602f014d88831f73b895c1fe09badb66c88e932d3Patrick McHardy		verdict = nf_iterate(&nf_hooks[entry->pf][entry->hook],
25702f014d88831f73b895c1fe09badb66c88e932d3Patrick McHardy				     skb, entry->hook,
25802f014d88831f73b895c1fe09badb66c88e932d3Patrick McHardy				     entry->indev, entry->outdev, &elem,
25902f014d88831f73b895c1fe09badb66c88e932d3Patrick McHardy				     entry->okfn, INT_MIN);
260f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	}
261f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
262f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	switch (verdict & NF_VERDICT_MASK) {
263f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	case NF_ACCEPT:
2643bc38712e3a6e0596ccb6f8299043a826f983701Patrick McHardy	case NF_STOP:
2654b3d15ef4a88683d93d1b76351297d2298a02a99Patrick McHardy		local_bh_disable();
26602f014d88831f73b895c1fe09badb66c88e932d3Patrick McHardy		entry->okfn(skb);
2674b3d15ef4a88683d93d1b76351297d2298a02a99Patrick McHardy		local_bh_enable();
2683bc38712e3a6e0596ccb6f8299043a826f983701Patrick McHardy	case NF_STOLEN:
269f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		break;
270f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	case NF_QUEUE:
27102f014d88831f73b895c1fe09badb66c88e932d3Patrick McHardy		if (!__nf_queue(skb, elem, entry->pf, entry->hook,
27202f014d88831f73b895c1fe09badb66c88e932d3Patrick McHardy				entry->indev, entry->outdev, entry->okfn,
273394f545db6e7e4d7a6a2fa3f543b755ca39d58acPatrick McHardy				verdict >> NF_VERDICT_BITS))
274f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte			goto next_hook;
275f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		break;
2763bc38712e3a6e0596ccb6f8299043a826f983701Patrick McHardy	default:
2773bc38712e3a6e0596ccb6f8299043a826f983701Patrick McHardy		kfree_skb(skb);
278f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	}
279f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	rcu_read_unlock();
28002f014d88831f73b895c1fe09badb66c88e932d3Patrick McHardy	kfree(entry);
281f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	return;
282f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte}
283f6ebe77f955d77a988ce726f0818ec0103b11323Harald WelteEXPORT_SYMBOL(nf_reinject);
284f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
285bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte#ifdef CONFIG_PROC_FS
286bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Weltestatic void *seq_start(struct seq_file *seq, loff_t *pos)
287bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte{
288bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	if (*pos >= NPROTO)
289bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte		return NULL;
290bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte
291bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	return pos;
292bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte}
293bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte
294bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Weltestatic void *seq_next(struct seq_file *s, void *v, loff_t *pos)
295bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte{
296bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	(*pos)++;
297bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte
298bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	if (*pos >= NPROTO)
299bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte		return NULL;
300bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte
301bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	return pos;
302bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte}
303bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte
304bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Weltestatic void seq_stop(struct seq_file *s, void *v)
305bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte{
306bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte
307bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte}
308bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte
309bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Weltestatic int seq_show(struct seq_file *s, void *v)
310bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte{
311bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	int ret;
312bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	loff_t *pos = v;
313e3ac5298159c5286cef86f0865d4fa6a606bd391Patrick McHardy	const struct nf_queue_handler *qh;
314bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte
315585426fdc5b4cccaacf0afc8cf821ff763750ae8Yasuyuki Kozakai	rcu_read_lock();
316585426fdc5b4cccaacf0afc8cf821ff763750ae8Yasuyuki Kozakai	qh = rcu_dereference(queue_handler[*pos]);
317bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	if (!qh)
318bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte		ret = seq_printf(s, "%2lld NONE\n", *pos);
319bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	else
320bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte		ret = seq_printf(s, "%2lld %s\n", *pos, qh->name);
321585426fdc5b4cccaacf0afc8cf821ff763750ae8Yasuyuki Kozakai	rcu_read_unlock();
322bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte
323bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	return ret;
324bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte}
325bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte
32656b3d975bbce65f655c5612b4822da671f9fd9b2Philippe De Muyterstatic const struct seq_operations nfqueue_seq_ops = {
327bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	.start	= seq_start,
328bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	.next	= seq_next,
329bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	.stop	= seq_stop,
330bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	.show	= seq_show,
331bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte};
332bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte
333bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Weltestatic int nfqueue_open(struct inode *inode, struct file *file)
334bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte{
335bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	return seq_open(file, &nfqueue_seq_ops);
336bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte}
337bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte
338da7071d7e32d15149cc513f096a3638097b66387Arjan van de Venstatic const struct file_operations nfqueue_file_ops = {
339bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	.owner	 = THIS_MODULE,
340bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	.open	 = nfqueue_open,
341bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	.read	 = seq_read,
342bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	.llseek	 = seq_lseek,
343bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	.release = seq_release,
344bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte};
345bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte#endif /* PROC_FS */
346bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte
347bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte
348f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welteint __init netfilter_queue_init(void)
349f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte{
350bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte#ifdef CONFIG_PROC_FS
3518eeee8b152ae6bbe181518efaf62ba8e9c613693Denis V. Lunev	if (!proc_create("nf_queue", S_IRUGO,
3528eeee8b152ae6bbe181518efaf62ba8e9c613693Denis V. Lunev			 proc_net_netfilter, &nfqueue_file_ops))
353bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte		return -1;
354bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte#endif
355f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	return 0;
356f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte}
357f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
358