Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 394f545d authored by Patrick McHardy's avatar Patrick McHardy Committed by David S. Miller
Browse files

[NETFILTER]: nf_queue: handle GSO packets



Handle GSO packets in nf_queue by segmenting them before queueing to
avoid breaking GSO in case they get mangled.

Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4cf411de
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -182,7 +182,7 @@ int nf_hook_slow(int pf, unsigned int hook, struct sk_buff **pskb,
		ret = -EPERM;
	} else if ((verdict & NF_VERDICT_MASK)  == NF_QUEUE) {
		NFDEBUG("nf_hook: Verdict = QUEUE.\n");
		if (!nf_queue(pskb, elem, pf, hook, indev, outdev, okfn,
		if (!nf_queue(*pskb, elem, pf, hook, indev, outdev, okfn,
			      verdict >> NF_VERDICT_BITS))
			goto next_hook;
	}
+1 −1
Original line number Diff line number Diff line
@@ -23,7 +23,7 @@ extern unsigned int nf_iterate(struct list_head *head,
				int hook_thresh);

/* nf_queue.c */
extern int nf_queue(struct sk_buff **skb, 
extern int nf_queue(struct sk_buff *skb,
		    struct list_head *elem, 
		    int pf, unsigned int hook,
		    struct net_device *indev,
+60 −20
Original line number Diff line number Diff line
@@ -74,7 +74,7 @@ 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, 
static int __nf_queue(struct sk_buff *skb,
		      struct list_head *elem,
		      int pf, unsigned int hook,
		      struct net_device *indev,
@@ -94,14 +94,14 @@ int nf_queue(struct sk_buff **skb,
	read_lock(&queue_handler_lock);
	if (!queue_handler[pf]) {
		read_unlock(&queue_handler_lock);
		kfree_skb(*skb);
		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;
	}

@@ -109,9 +109,9 @@ int nf_queue(struct sk_buff **skb,
	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;
	}

@@ -130,15 +130,15 @@ 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
	afinfo->saveroute(*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);

	read_unlock(&queue_handler_lock);
@@ -153,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;
	}
@@ -161,6 +161,46 @@ 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)
{
@@ -224,7 +264,7 @@ void nf_reinject(struct sk_buff *skb, struct nf_info *info,
	case NF_STOLEN:
		break;
	case NF_QUEUE:
		if (!nf_queue(&skb, elem, info->pf, info->hook, 
		if (!__nf_queue(skb, elem, info->pf, info->hook,
				info->indev, info->outdev, info->okfn,
				verdict >> NF_VERDICT_BITS))
			goto next_hook;