aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp
diff options
context:
space:
mode:
Diffstat (limited to 'net/sctp')
-rw-r--r--net/sctp/ulpqueue.c27
1 files changed, 25 insertions, 2 deletions
diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c
index 2080b2d28c98..575e556aeb3e 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,
279static struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff_head *queue, struct sk_buff *f_frag, struct sk_buff *l_frag) 279static struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff_head *queue, struct sk_buff *f_frag, struct sk_buff *l_frag)
280{ 280{
281 struct sk_buff *pos; 281 struct sk_buff *pos;
282 struct sk_buff *new = NULL;
282 struct sctp_ulpevent *event; 283 struct sctp_ulpevent *event;
283 struct sk_buff *pnext, *last; 284 struct sk_buff *pnext, *last;
284 struct sk_buff *list = skb_shinfo(f_frag)->frag_list; 285 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
297 */ 298 */
298 if (last) 299 if (last)
299 last->next = pos; 300 last->next = pos;
300 else 301 else {
301 skb_shinfo(f_frag)->frag_list = pos; 302 if (skb_cloned(f_frag)) {
303 /* This is a cloned skb, we can't just modify
304 * the frag_list. We need a new skb to do that.
305 * Instead of calling skb_unshare(), we'll do it
306 * ourselves since we need to delay the free.
307 */
308 new = skb_copy(f_frag, GFP_ATOMIC);
309 if (!new)
310 return NULL; /* try again later */
311
312 new->sk = f_frag->sk;
313
314 skb_shinfo(new)->frag_list = pos;
315 } else
316 skb_shinfo(f_frag)->frag_list = pos;
317 }
302 318
303 /* Remove the first fragment from the reassembly queue. */ 319 /* Remove the first fragment from the reassembly queue. */
304 __skb_unlink(f_frag, queue); 320 __skb_unlink(f_frag, queue);
321
322 /* if we did unshare, then free the old skb and re-assign */
323 if (new) {
324 kfree_skb(f_frag);
325 f_frag = new;
326 }
327
305 while (pos) { 328 while (pos) {
306 329
307 pnext = pos->next; 330 pnext = pos->next;