diff options
author | David Woodhouse <dwmw2@infradead.org> | 2006-05-06 19:59:18 +0100 |
---|---|---|
committer | David Woodhouse <dwmw2@infradead.org> | 2006-05-06 19:59:18 +0100 |
commit | 5047f09b56d0bc3c21aec9cb16de60283da645c6 (patch) | |
tree | 09a07554b933c3bb912ce3bfc0ea7c7e1f16041c /net/sctp/ulpqueue.c | |
parent | c0f1fe00c3923135b2c2f443448585482da8a53e (diff) | |
parent | 5528e568a760442e0ec8fd2dea1f0791875a066b (diff) | |
download | kernel_samsung_smdk4412-5047f09b56d0bc3c21aec9cb16de60283da645c6.tar.gz kernel_samsung_smdk4412-5047f09b56d0bc3c21aec9cb16de60283da645c6.tar.bz2 kernel_samsung_smdk4412-5047f09b56d0bc3c21aec9cb16de60283da645c6.zip |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Diffstat (limited to 'net/sctp/ulpqueue.c')
-rw-r--r-- | net/sctp/ulpqueue.c | 27 |
1 files changed, 25 insertions, 2 deletions
diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c index 2080b2d28c9..575e556aeb3 100644 --- a/net/sctp/ulpqueue.c +++ b/net/sctp/ulpqueue.c @@ -279,6 +279,7 @@ static inline void sctp_ulpq_store_reasm(struct sctp_ulpq *ulpq, static struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff_head *queue, struct sk_buff *f_frag, struct sk_buff *l_frag) { struct sk_buff *pos; + struct sk_buff *new = NULL; struct sctp_ulpevent *event; struct sk_buff *pnext, *last; struct sk_buff *list = skb_shinfo(f_frag)->frag_list; @@ -297,11 +298,33 @@ static struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff_head *qu */ if (last) last->next = pos; - else - skb_shinfo(f_frag)->frag_list = pos; + else { + if (skb_cloned(f_frag)) { + /* This is a cloned skb, we can't just modify + * the frag_list. We need a new skb to do that. + * Instead of calling skb_unshare(), we'll do it + * ourselves since we need to delay the free. + */ + new = skb_copy(f_frag, GFP_ATOMIC); + if (!new) + return NULL; /* try again later */ + + new->sk = f_frag->sk; + + skb_shinfo(new)->frag_list = pos; + } else + skb_shinfo(f_frag)->frag_list = pos; + } /* Remove the first fragment from the reassembly queue. */ __skb_unlink(f_frag, queue); + + /* if we did unshare, then free the old skb and re-assign */ + if (new) { + kfree_skb(f_frag); + f_frag = new; + } + while (pos) { pnext = pos->next; |