From 4a5396937e998ae8b9a281871e213545b2953f6c Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Tue, 11 Nov 2008 15:40:28 -0800 Subject: [PATCH] Fix datapath make_writable() function. - We weren't necessarily pulling enough into the headers in the non-shared case, since the IP header by itself can be longer than 40 bytes. - The skb is guaranteed not to have a destructor at this point. --- datapath/dp_act.c | 35 +++++++++++++---------------------- 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/datapath/dp_act.c b/datapath/dp_act.c index daa319a2..14eaac33 100644 --- a/datapath/dp_act.c +++ b/datapath/dp_act.c @@ -502,26 +502,17 @@ void execute_actions(struct datapath *dp, struct sk_buff *skb, int make_writable(struct sk_buff **pskb) { - /* Based on skb_make_writable() in net/netfilter/core.c. */ - struct sk_buff *nskb; - - /* Not exclusive use of packet? Must copy. */ - if (skb_shared(*pskb) || skb_cloned(*pskb)) - goto copy_skb; - - return pskb_may_pull(*pskb, 40); /* FIXME? */ - -copy_skb: - nskb = skb_copy(*pskb, GFP_ATOMIC); - if (!nskb) - return 0; - BUG_ON(skb_is_nonlinear(nskb)); - - /* Rest of kernel will get very unhappy if we pass it a - suddenly-orphaned skbuff */ - if ((*pskb)->sk) - skb_set_owner_w(nskb, (*pskb)->sk); - kfree_skb(*pskb); - *pskb = nskb; - return 1; + struct sk_buff *skb = *pskb; + if (skb_shared(skb) || skb_cloned(skb)) { + struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC); + if (!nskb) + return 0; + kfree_skb(skb); + *pskb = nskb; + return 1; + } else { + unsigned int hdr_len = (skb_transport_offset(skb) + + sizeof(struct tcphdr)); + return pskb_may_pull(skb, min(hdr_len, skb->len)); + } } -- 2.30.2