+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
* for queueing and must reinject all packets it receives, no matter what.
*/
static struct nf_queue_handler *queue_handler[NPROTO];
+static struct nf_queue_rerouter *queue_rerouter[NPROTO];
static DEFINE_RWLOCK(queue_handler_lock);
}
EXPORT_SYMBOL(nf_unregister_queue_handler);
+int nf_register_queue_rerouter(int pf, struct nf_queue_rerouter *rer)
+{
+ if (pf >= NPROTO)
+ return -EINVAL;
+
+ write_lock_bh(&queue_handler_lock);
+ rcu_assign_pointer(queue_rerouter[pf], rer);
+ write_unlock_bh(&queue_handler_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(nf_register_queue_rerouter);
+
+int nf_unregister_queue_rerouter(int pf)
+{
+ if (pf >= NPROTO)
+ return -EINVAL;
+
+ write_lock_bh(&queue_handler_lock);
+ rcu_assign_pointer(queue_rerouter[pf], NULL);
+ write_unlock_bh(&queue_handler_lock);
+ synchronize_rcu();
+ return 0;
+}
+EXPORT_SYMBOL_GPL(nf_unregister_queue_rerouter);
+
void nf_unregister_queue_handlers(struct nf_queue_handler *qh)
{
int pf;
struct net_device *physindev = NULL;
struct net_device *physoutdev = NULL;
#endif
- struct nf_afinfo *afinfo;
+ struct nf_queue_rerouter *rerouter;
/* QUEUE == DROP if noone is waiting, to be safe. */
read_lock(&queue_handler_lock);
return 1;
}
- afinfo = nf_get_afinfo(pf);
- if (!afinfo) {
- read_unlock(&queue_handler_lock);
- kfree_skb(*skb);
- return 1;
- }
-
- info = kmalloc(sizeof(*info) + afinfo->route_key_size, GFP_ATOMIC);
+ info = kmalloc(sizeof(*info)+queue_rerouter[pf]->rer_size, GFP_ATOMIC);
if (!info) {
if (net_ratelimit())
printk(KERN_ERR "OOM queueing packet %p\n",
if (physoutdev) dev_hold(physoutdev);
}
#endif
- afinfo->saveroute(*skb, info);
+ rerouter = rcu_dereference(queue_rerouter[pf]);
+ if (rerouter)
+ rerouter->save(*skb, info);
+
status = queue_handler[pf]->outfn(*skb, info, queuenum,
queue_handler[pf]->data);
{
struct list_head *elem = &info->elem->list;
struct list_head *i;
- struct nf_afinfo *afinfo;
+ struct nf_queue_rerouter *rerouter;
rcu_read_lock();
}
if (verdict == NF_ACCEPT) {
- afinfo = nf_get_afinfo(info->pf);
- if (!afinfo || afinfo->reroute(&skb, info) < 0)
+ rerouter = rcu_dereference(queue_rerouter[info->pf]);
+ if (rerouter && rerouter->reroute(&skb, info) < 0)
verdict = NF_DROP;
}
switch (verdict & NF_VERDICT_MASK) {
case NF_ACCEPT:
- case NF_STOP:
info->okfn(skb);
- case NF_STOLEN:
break;
+
case NF_QUEUE:
if (!nf_queue(&skb, elem, info->pf, info->hook,
info->indev, info->outdev, info->okfn,
verdict >> NF_VERDICT_BITS))
goto next_hook;
break;
- default:
- kfree_skb(skb);
}
rcu_read_unlock();
+
+ if (verdict == NF_DROP)
+ kfree_skb(skb);
+
kfree(info);
return;
}