X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=net%2Fnetfilter%2Fnf_queue.c;h=4d8936ed581d2f9e524e6b1a59a844db1546676b;hb=f034b5d4efdfe0fb9e2a1ce1d95fa7914f24de49;hp=d3a4f30a7f2247f0bac16cdc9466c31b12409e39;hpb=24bfb00123e82a2e70bd115277d922438813515b;p=powerpc.git diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c index d3a4f30a7f..4d8936ed58 100644 --- a/net/netfilter/nf_queue.c +++ b/net/netfilter/nf_queue.c @@ -1,4 +1,3 @@ -#include #include #include #include @@ -6,6 +5,7 @@ #include #include #include +#include #include #include "nf_internals.h" @@ -16,7 +16,6 @@ * 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; static DEFINE_RWLOCK(queue_handler_lock); @@ -58,31 +57,6 @@ int nf_unregister_queue_handler(int pf) } 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); - memcpy(&queue_rerouter[pf], rer, sizeof(queue_rerouter[pf])); - 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); - memset(&queue_rerouter[pf], 0, sizeof(queue_rerouter[pf])); - write_unlock_bh(&queue_handler_lock); - return 0; -} -EXPORT_SYMBOL_GPL(nf_unregister_queue_rerouter); - void nf_unregister_queue_handlers(struct nf_queue_handler *qh) { int pf; @@ -100,13 +74,13 @@ EXPORT_SYMBOL_GPL(nf_unregister_queue_handlers); * Any packet that leaves via this function must come back * through nf_reinject(). */ -int nf_queue(struct sk_buff **skb, - struct list_head *elem, - int pf, unsigned int hook, - struct net_device *indev, - struct net_device *outdev, - int (*okfn)(struct sk_buff *), - unsigned int queuenum) +static int __nf_queue(struct sk_buff *skb, + struct list_head *elem, + int pf, unsigned int hook, + struct net_device *indev, + struct net_device *outdev, + int (*okfn)(struct sk_buff *), + unsigned int queuenum) { int status; struct nf_info *info; @@ -114,22 +88,30 @@ int nf_queue(struct sk_buff **skb, struct net_device *physindev = NULL; struct net_device *physoutdev = NULL; #endif + struct nf_afinfo *afinfo; /* QUEUE == DROP if noone is waiting, to be safe. */ read_lock(&queue_handler_lock); - if (!queue_handler[pf] || !queue_handler[pf]->outfn) { + if (!queue_handler[pf]) { + read_unlock(&queue_handler_lock); + kfree_skb(skb); + return 1; + } + + afinfo = nf_get_afinfo(pf); + if (!afinfo) { read_unlock(&queue_handler_lock); - kfree_skb(*skb); + kfree_skb(skb); return 1; } - info = kmalloc(sizeof(*info)+queue_rerouter[pf].rer_size, GFP_ATOMIC); + info = kmalloc(sizeof(*info) + afinfo->route_key_size, GFP_ATOMIC); if (!info) { if (net_ratelimit()) printk(KERN_ERR "OOM queueing packet %p\n", - *skb); + skb); read_unlock(&queue_handler_lock); - kfree_skb(*skb); + kfree_skb(skb); return 1; } @@ -148,22 +130,17 @@ int nf_queue(struct sk_buff **skb, if (outdev) dev_hold(outdev); #ifdef CONFIG_BRIDGE_NETFILTER - if ((*skb)->nf_bridge) { - physindev = (*skb)->nf_bridge->physindev; + if (skb->nf_bridge) { + physindev = skb->nf_bridge->physindev; if (physindev) dev_hold(physindev); - physoutdev = (*skb)->nf_bridge->physoutdev; + physoutdev = skb->nf_bridge->physoutdev; if (physoutdev) dev_hold(physoutdev); } #endif - if (queue_rerouter[pf].save) - queue_rerouter[pf].save(*skb, info); - - status = queue_handler[pf]->outfn(*skb, info, queuenum, + afinfo->saveroute(skb, info); + status = queue_handler[pf]->outfn(skb, info, queuenum, queue_handler[pf]->data); - if (status >= 0 && queue_rerouter[pf].reroute) - status = queue_rerouter[pf].reroute(skb, info); - read_unlock(&queue_handler_lock); if (status < 0) { @@ -176,7 +153,7 @@ int nf_queue(struct sk_buff **skb, #endif module_put(info->elem->owner); kfree(info); - kfree_skb(*skb); + kfree_skb(skb); return 1; } @@ -184,11 +161,52 @@ int nf_queue(struct sk_buff **skb, return 1; } +int nf_queue(struct sk_buff *skb, + struct list_head *elem, + int pf, unsigned int hook, + struct net_device *indev, + struct net_device *outdev, + int (*okfn)(struct sk_buff *), + unsigned int queuenum) +{ + struct sk_buff *segs; + + if (!skb_is_gso(skb)) + return __nf_queue(skb, elem, pf, hook, indev, outdev, okfn, + queuenum); + + switch (pf) { + case AF_INET: + skb->protocol = htons(ETH_P_IP); + break; + case AF_INET6: + skb->protocol = htons(ETH_P_IPV6); + break; + } + + segs = skb_gso_segment(skb, 0); + kfree_skb(skb); + if (unlikely(IS_ERR(segs))) + return 1; + + do { + struct sk_buff *nskb = segs->next; + + segs->next = NULL; + if (!__nf_queue(segs, elem, pf, hook, indev, outdev, okfn, + queuenum)) + kfree_skb(segs); + segs = nskb; + } while (segs); + return 1; +} + void nf_reinject(struct sk_buff *skb, struct nf_info *info, unsigned int verdict) { struct list_head *elem = &info->elem->list; struct list_head *i; + struct nf_afinfo *afinfo; rcu_read_lock(); @@ -212,7 +230,7 @@ void nf_reinject(struct sk_buff *skb, struct nf_info *info, break; } - if (elem == &nf_hooks[info->pf][info->hook]) { + if (i == &nf_hooks[info->pf][info->hook]) { /* The module which sent it to userspace is gone. */ NFDEBUG("%s: module disappeared, dropping packet.\n", __FUNCTION__); @@ -225,6 +243,12 @@ void nf_reinject(struct sk_buff *skb, struct nf_info *info, verdict = NF_ACCEPT; } + if (verdict == NF_ACCEPT) { + afinfo = nf_get_afinfo(info->pf); + if (!afinfo || afinfo->reroute(&skb, info) < 0) + verdict = NF_DROP; + } + if (verdict == NF_ACCEPT) { next_hook: verdict = nf_iterate(&nf_hooks[info->pf][info->hook], @@ -235,21 +259,20 @@ void nf_reinject(struct sk_buff *skb, struct nf_info *info, 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)) + 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; } @@ -322,22 +345,12 @@ int __init netfilter_queue_init(void) { #ifdef CONFIG_PROC_FS struct proc_dir_entry *pde; -#endif - queue_rerouter = kmalloc(NPROTO * sizeof(struct nf_queue_rerouter), - GFP_KERNEL); - if (!queue_rerouter) - return -ENOMEM; -#ifdef CONFIG_PROC_FS pde = create_proc_entry("nf_queue", S_IRUGO, proc_net_netfilter); - if (!pde) { - kfree(queue_rerouter); + if (!pde) return -1; - } pde->proc_fops = &nfqueue_file_ops; #endif - memset(queue_rerouter, 0, NPROTO * sizeof(struct nf_queue_rerouter)); - return 0; }