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));
+ }
}