diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/core/skbuff.c | 36 |
1 files changed, 26 insertions, 10 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index bb7210f4005e..fe63d4efbd4d 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
@@ -781,24 +781,40 @@ struct sk_buff *skb_copy_expand(const struct sk_buff *skb, | |||
781 | * filled. Used by network drivers which may DMA or transfer data | 781 | * filled. Used by network drivers which may DMA or transfer data |
782 | * beyond the buffer end onto the wire. | 782 | * beyond the buffer end onto the wire. |
783 | * | 783 | * |
784 | * May return NULL in out of memory cases. | 784 | * May return error in out of memory cases. The skb is freed on error. |
785 | */ | 785 | */ |
786 | 786 | ||
787 | struct sk_buff *skb_pad(struct sk_buff *skb, int pad) | 787 | int skb_pad(struct sk_buff *skb, int pad) |
788 | { | 788 | { |
789 | struct sk_buff *nskb; | 789 | int err; |
790 | int ntail; | ||
790 | 791 | ||
791 | /* If the skbuff is non linear tailroom is always zero.. */ | 792 | /* If the skbuff is non linear tailroom is always zero.. */ |
792 | if (skb_tailroom(skb) >= pad) { | 793 | if (!skb_cloned(skb) && skb_tailroom(skb) >= pad) { |
793 | memset(skb->data+skb->len, 0, pad); | 794 | memset(skb->data+skb->len, 0, pad); |
794 | return skb; | 795 | return 0; |
795 | } | 796 | } |
796 | 797 | ||
797 | nskb = skb_copy_expand(skb, skb_headroom(skb), skb_tailroom(skb) + pad, GFP_ATOMIC); | 798 | ntail = skb->data_len + pad - (skb->end - skb->tail); |
799 | if (likely(skb_cloned(skb) || ntail > 0)) { | ||
800 | err = pskb_expand_head(skb, 0, ntail, GFP_ATOMIC); | ||
801 | if (unlikely(err)) | ||
802 | goto free_skb; | ||
803 | } | ||
804 | |||
805 | /* FIXME: The use of this function with non-linear skb's really needs | ||
806 | * to be audited. | ||
807 | */ | ||
808 | err = skb_linearize(skb); | ||
809 | if (unlikely(err)) | ||
810 | goto free_skb; | ||
811 | |||
812 | memset(skb->data + skb->len, 0, pad); | ||
813 | return 0; | ||
814 | |||
815 | free_skb: | ||
798 | kfree_skb(skb); | 816 | kfree_skb(skb); |
799 | if (nskb) | 817 | return err; |
800 | memset(nskb->data+nskb->len, 0, pad); | ||
801 | return nskb; | ||
802 | } | 818 | } |
803 | 819 | ||
804 | /* Trims skb to length len. It can change skb pointers. | 820 | /* Trims skb to length len. It can change skb pointers. |