|
@@ -781,24 +781,40 @@ struct sk_buff *skb_copy_expand(const struct sk_buff *skb,
|
|
|
* filled. Used by network drivers which may DMA or transfer data
|
|
|
* beyond the buffer end onto the wire.
|
|
|
*
|
|
|
- * May return NULL in out of memory cases.
|
|
|
+ * May return error in out of memory cases. The skb is freed on error.
|
|
|
*/
|
|
|
|
|
|
-struct sk_buff *skb_pad(struct sk_buff *skb, int pad)
|
|
|
+int skb_pad(struct sk_buff *skb, int pad)
|
|
|
{
|
|
|
- struct sk_buff *nskb;
|
|
|
+ int err;
|
|
|
+ int ntail;
|
|
|
|
|
|
/* If the skbuff is non linear tailroom is always zero.. */
|
|
|
- if (skb_tailroom(skb) >= pad) {
|
|
|
+ if (!skb_cloned(skb) && skb_tailroom(skb) >= pad) {
|
|
|
memset(skb->data+skb->len, 0, pad);
|
|
|
- return skb;
|
|
|
+ return 0;
|
|
|
}
|
|
|
-
|
|
|
- nskb = skb_copy_expand(skb, skb_headroom(skb), skb_tailroom(skb) + pad, GFP_ATOMIC);
|
|
|
+
|
|
|
+ ntail = skb->data_len + pad - (skb->end - skb->tail);
|
|
|
+ if (likely(skb_cloned(skb) || ntail > 0)) {
|
|
|
+ err = pskb_expand_head(skb, 0, ntail, GFP_ATOMIC);
|
|
|
+ if (unlikely(err))
|
|
|
+ goto free_skb;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* FIXME: The use of this function with non-linear skb's really needs
|
|
|
+ * to be audited.
|
|
|
+ */
|
|
|
+ err = skb_linearize(skb);
|
|
|
+ if (unlikely(err))
|
|
|
+ goto free_skb;
|
|
|
+
|
|
|
+ memset(skb->data + skb->len, 0, pad);
|
|
|
+ return 0;
|
|
|
+
|
|
|
+free_skb:
|
|
|
kfree_skb(skb);
|
|
|
- if (nskb)
|
|
|
- memset(nskb->data+nskb->len, 0, pad);
|
|
|
- return nskb;
|
|
|
+ return err;
|
|
|
}
|
|
|
|
|
|
/* Trims skb to length len. It can change skb pointers.
|