160c778b2SVlad Yasevich /* SCTP kernel implementation 21da177e4SLinus Torvalds * (C) Copyright IBM Corp. 2001, 2004 31da177e4SLinus Torvalds * Copyright (c) 1999-2000 Cisco, Inc. 41da177e4SLinus Torvalds * Copyright (c) 1999-2001 Motorola, Inc. 51da177e4SLinus Torvalds * Copyright (c) 2001 Intel Corp. 61da177e4SLinus Torvalds * Copyright (c) 2001 Nokia, Inc. 71da177e4SLinus Torvalds * Copyright (c) 2001 La Monte H.P. Yarroll 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * This abstraction carries sctp events to the ULP (sockets). 101da177e4SLinus Torvalds * 1160c778b2SVlad Yasevich * This SCTP implementation is free software; 121da177e4SLinus Torvalds * you can redistribute it and/or modify it under the terms of 131da177e4SLinus Torvalds * the GNU General Public License as published by 141da177e4SLinus Torvalds * the Free Software Foundation; either version 2, or (at your option) 151da177e4SLinus Torvalds * any later version. 161da177e4SLinus Torvalds * 1760c778b2SVlad Yasevich * This SCTP implementation is distributed in the hope that it 181da177e4SLinus Torvalds * will be useful, but WITHOUT ANY WARRANTY; without even the implied 191da177e4SLinus Torvalds * ************************ 201da177e4SLinus Torvalds * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 211da177e4SLinus Torvalds * See the GNU General Public License for more details. 221da177e4SLinus Torvalds * 231da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 241da177e4SLinus Torvalds * along with GNU CC; see the file COPYING. If not, write to 251da177e4SLinus Torvalds * the Free Software Foundation, 59 Temple Place - Suite 330, 261da177e4SLinus Torvalds * Boston, MA 02111-1307, USA. 271da177e4SLinus Torvalds * 281da177e4SLinus Torvalds * Please send any bug reports or fixes you make to the 291da177e4SLinus Torvalds * email address(es): 301da177e4SLinus Torvalds * lksctp developers <lksctp-developers@lists.sourceforge.net> 311da177e4SLinus Torvalds * 321da177e4SLinus Torvalds * Or submit a bug report through the following website: 331da177e4SLinus Torvalds * http://www.sf.net/projects/lksctp 341da177e4SLinus Torvalds * 351da177e4SLinus Torvalds * Written or modified by: 361da177e4SLinus Torvalds * Jon Grimm <jgrimm@us.ibm.com> 371da177e4SLinus Torvalds * La Monte H.P. Yarroll <piggy@acm.org> 381da177e4SLinus Torvalds * Sridhar Samudrala <sri@us.ibm.com> 391da177e4SLinus Torvalds * 401da177e4SLinus Torvalds * Any bugs reported given to us we will try to fix... any fixes shared will 411da177e4SLinus Torvalds * be incorporated into the next SCTP release. 421da177e4SLinus Torvalds */ 431da177e4SLinus Torvalds 445a0e3ad6STejun Heo #include <linux/slab.h> 451da177e4SLinus Torvalds #include <linux/types.h> 461da177e4SLinus Torvalds #include <linux/skbuff.h> 471da177e4SLinus Torvalds #include <net/sock.h> 481da177e4SLinus Torvalds #include <net/sctp/structs.h> 491da177e4SLinus Torvalds #include <net/sctp/sctp.h> 501da177e4SLinus Torvalds #include <net/sctp/sm.h> 511da177e4SLinus Torvalds 521da177e4SLinus Torvalds /* Forward declarations for internal helpers. */ 531da177e4SLinus Torvalds static struct sctp_ulpevent * sctp_ulpq_reasm(struct sctp_ulpq *ulpq, 541da177e4SLinus Torvalds struct sctp_ulpevent *); 551da177e4SLinus Torvalds static struct sctp_ulpevent * sctp_ulpq_order(struct sctp_ulpq *, 561da177e4SLinus Torvalds struct sctp_ulpevent *); 57ef5d4cf2SVlad Yasevich static void sctp_ulpq_reasm_drain(struct sctp_ulpq *ulpq); 581da177e4SLinus Torvalds 591da177e4SLinus Torvalds /* 1st Level Abstractions */ 601da177e4SLinus Torvalds 611da177e4SLinus Torvalds /* Initialize a ULP queue from a block of memory. */ 621da177e4SLinus Torvalds struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *ulpq, 631da177e4SLinus Torvalds struct sctp_association *asoc) 641da177e4SLinus Torvalds { 651da177e4SLinus Torvalds memset(ulpq, 0, sizeof(struct sctp_ulpq)); 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds ulpq->asoc = asoc; 681da177e4SLinus Torvalds skb_queue_head_init(&ulpq->reasm); 691da177e4SLinus Torvalds skb_queue_head_init(&ulpq->lobby); 701da177e4SLinus Torvalds ulpq->pd_mode = 0; 711da177e4SLinus Torvalds ulpq->malloced = 0; 721da177e4SLinus Torvalds 731da177e4SLinus Torvalds return ulpq; 741da177e4SLinus Torvalds } 751da177e4SLinus Torvalds 761da177e4SLinus Torvalds 771da177e4SLinus Torvalds /* Flush the reassembly and ordering queues. */ 780b58a811SVlad Yasevich void sctp_ulpq_flush(struct sctp_ulpq *ulpq) 791da177e4SLinus Torvalds { 801da177e4SLinus Torvalds struct sk_buff *skb; 811da177e4SLinus Torvalds struct sctp_ulpevent *event; 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds while ((skb = __skb_dequeue(&ulpq->lobby)) != NULL) { 841da177e4SLinus Torvalds event = sctp_skb2event(skb); 851da177e4SLinus Torvalds sctp_ulpevent_free(event); 861da177e4SLinus Torvalds } 871da177e4SLinus Torvalds 881da177e4SLinus Torvalds while ((skb = __skb_dequeue(&ulpq->reasm)) != NULL) { 891da177e4SLinus Torvalds event = sctp_skb2event(skb); 901da177e4SLinus Torvalds sctp_ulpevent_free(event); 911da177e4SLinus Torvalds } 921da177e4SLinus Torvalds 931da177e4SLinus Torvalds } 941da177e4SLinus Torvalds 951da177e4SLinus Torvalds /* Dispose of a ulpqueue. */ 961da177e4SLinus Torvalds void sctp_ulpq_free(struct sctp_ulpq *ulpq) 971da177e4SLinus Torvalds { 981da177e4SLinus Torvalds sctp_ulpq_flush(ulpq); 991da177e4SLinus Torvalds if (ulpq->malloced) 1001da177e4SLinus Torvalds kfree(ulpq); 1011da177e4SLinus Torvalds } 1021da177e4SLinus Torvalds 1031da177e4SLinus Torvalds /* Process an incoming DATA chunk. */ 1041da177e4SLinus Torvalds int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk, 105dd0fc66fSAl Viro gfp_t gfp) 1061da177e4SLinus Torvalds { 1071da177e4SLinus Torvalds struct sk_buff_head temp; 1081da177e4SLinus Torvalds struct sctp_ulpevent *event; 1091da177e4SLinus Torvalds 1101da177e4SLinus Torvalds /* Create an event from the incoming chunk. */ 1111da177e4SLinus Torvalds event = sctp_ulpevent_make_rcvmsg(chunk->asoc, chunk, gfp); 1121da177e4SLinus Torvalds if (!event) 1131da177e4SLinus Torvalds return -ENOMEM; 1141da177e4SLinus Torvalds 1151da177e4SLinus Torvalds /* Do reassembly if needed. */ 1161da177e4SLinus Torvalds event = sctp_ulpq_reasm(ulpq, event); 1171da177e4SLinus Torvalds 1181da177e4SLinus Torvalds /* Do ordering if needed. */ 1191da177e4SLinus Torvalds if ((event) && (event->msg_flags & MSG_EOR)){ 1201da177e4SLinus Torvalds /* Create a temporary list to collect chunks on. */ 1211da177e4SLinus Torvalds skb_queue_head_init(&temp); 1221da177e4SLinus Torvalds __skb_queue_tail(&temp, sctp_event2skb(event)); 1231da177e4SLinus Torvalds 1241da177e4SLinus Torvalds event = sctp_ulpq_order(ulpq, event); 1251da177e4SLinus Torvalds } 1261da177e4SLinus Torvalds 1278728b834SDavid S. Miller /* Send event to the ULP. 'event' is the sctp_ulpevent for 1288728b834SDavid S. Miller * very first SKB on the 'temp' list. 1298728b834SDavid S. Miller */ 1301da177e4SLinus Torvalds if (event) 1311da177e4SLinus Torvalds sctp_ulpq_tail_event(ulpq, event); 1321da177e4SLinus Torvalds 1331da177e4SLinus Torvalds return 0; 1341da177e4SLinus Torvalds } 1351da177e4SLinus Torvalds 1361da177e4SLinus Torvalds /* Add a new event for propagation to the ULP. */ 1371da177e4SLinus Torvalds /* Clear the partial delivery mode for this socket. Note: This 1381da177e4SLinus Torvalds * assumes that no association is currently in partial delivery mode. 1391da177e4SLinus Torvalds */ 140b6e1331fSVlad Yasevich int sctp_clear_pd(struct sock *sk, struct sctp_association *asoc) 1411da177e4SLinus Torvalds { 1421da177e4SLinus Torvalds struct sctp_sock *sp = sctp_sk(sk); 1431da177e4SLinus Torvalds 144b6e1331fSVlad Yasevich if (atomic_dec_and_test(&sp->pd_mode)) { 145b6e1331fSVlad Yasevich /* This means there are no other associations in PD, so 146b6e1331fSVlad Yasevich * we can go ahead and clear out the lobby in one shot 147b6e1331fSVlad Yasevich */ 1481da177e4SLinus Torvalds if (!skb_queue_empty(&sp->pd_lobby)) { 1491da177e4SLinus Torvalds struct list_head *list; 1501da177e4SLinus Torvalds sctp_skb_list_tail(&sp->pd_lobby, &sk->sk_receive_queue); 1511da177e4SLinus Torvalds list = (struct list_head *)&sctp_sk(sk)->pd_lobby; 1521da177e4SLinus Torvalds INIT_LIST_HEAD(list); 1531da177e4SLinus Torvalds return 1; 1541da177e4SLinus Torvalds } 155b6e1331fSVlad Yasevich } else { 156b6e1331fSVlad Yasevich /* There are other associations in PD, so we only need to 157b6e1331fSVlad Yasevich * pull stuff out of the lobby that belongs to the 158b6e1331fSVlad Yasevich * associations that is exiting PD (all of its notifications 159b6e1331fSVlad Yasevich * are posted here). 160b6e1331fSVlad Yasevich */ 161b6e1331fSVlad Yasevich if (!skb_queue_empty(&sp->pd_lobby) && asoc) { 162b6e1331fSVlad Yasevich struct sk_buff *skb, *tmp; 163b6e1331fSVlad Yasevich struct sctp_ulpevent *event; 164b6e1331fSVlad Yasevich 165b6e1331fSVlad Yasevich sctp_skb_for_each(skb, &sp->pd_lobby, tmp) { 166b6e1331fSVlad Yasevich event = sctp_skb2event(skb); 167b6e1331fSVlad Yasevich if (event->asoc == asoc) { 168b6e1331fSVlad Yasevich __skb_unlink(skb, &sp->pd_lobby); 169b6e1331fSVlad Yasevich __skb_queue_tail(&sk->sk_receive_queue, 170b6e1331fSVlad Yasevich skb); 171b6e1331fSVlad Yasevich } 172b6e1331fSVlad Yasevich } 173b6e1331fSVlad Yasevich } 174b6e1331fSVlad Yasevich } 175b6e1331fSVlad Yasevich 1761da177e4SLinus Torvalds return 0; 1771da177e4SLinus Torvalds } 1781da177e4SLinus Torvalds 179d49d91d7SVlad Yasevich /* Set the pd_mode on the socket and ulpq */ 180d49d91d7SVlad Yasevich static void sctp_ulpq_set_pd(struct sctp_ulpq *ulpq) 181d49d91d7SVlad Yasevich { 182d49d91d7SVlad Yasevich struct sctp_sock *sp = sctp_sk(ulpq->asoc->base.sk); 183d49d91d7SVlad Yasevich 184d49d91d7SVlad Yasevich atomic_inc(&sp->pd_mode); 185d49d91d7SVlad Yasevich ulpq->pd_mode = 1; 186d49d91d7SVlad Yasevich } 187d49d91d7SVlad Yasevich 1881da177e4SLinus Torvalds /* Clear the pd_mode and restart any pending messages waiting for delivery. */ 1891da177e4SLinus Torvalds static int sctp_ulpq_clear_pd(struct sctp_ulpq *ulpq) 1901da177e4SLinus Torvalds { 1911da177e4SLinus Torvalds ulpq->pd_mode = 0; 192ef5d4cf2SVlad Yasevich sctp_ulpq_reasm_drain(ulpq); 193b6e1331fSVlad Yasevich return sctp_clear_pd(ulpq->asoc->base.sk, ulpq->asoc); 1941da177e4SLinus Torvalds } 1951da177e4SLinus Torvalds 1968728b834SDavid S. Miller /* If the SKB of 'event' is on a list, it is the first such member 1978728b834SDavid S. Miller * of that list. 1988728b834SDavid S. Miller */ 1991da177e4SLinus Torvalds int sctp_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event) 2001da177e4SLinus Torvalds { 2011da177e4SLinus Torvalds struct sock *sk = ulpq->asoc->base.sk; 2028728b834SDavid S. Miller struct sk_buff_head *queue, *skb_list; 2038728b834SDavid S. Miller struct sk_buff *skb = sctp_event2skb(event); 2041da177e4SLinus Torvalds int clear_pd = 0; 2051da177e4SLinus Torvalds 2068728b834SDavid S. Miller skb_list = (struct sk_buff_head *) skb->prev; 2078728b834SDavid S. Miller 2081da177e4SLinus Torvalds /* If the socket is just going to throw this away, do not 2091da177e4SLinus Torvalds * even try to deliver it. 2101da177e4SLinus Torvalds */ 2111da177e4SLinus Torvalds if (sock_flag(sk, SOCK_DEAD) || (sk->sk_shutdown & RCV_SHUTDOWN)) 2121da177e4SLinus Torvalds goto out_free; 2131da177e4SLinus Torvalds 2141da177e4SLinus Torvalds /* Check if the user wishes to receive this event. */ 2151da177e4SLinus Torvalds if (!sctp_ulpevent_is_enabled(event, &sctp_sk(sk)->subscribe)) 2161da177e4SLinus Torvalds goto out_free; 2171da177e4SLinus Torvalds 2181da177e4SLinus Torvalds /* If we are in partial delivery mode, post to the lobby until 2191da177e4SLinus Torvalds * partial delivery is cleared, unless, of course _this_ is 2201da177e4SLinus Torvalds * the association the cause of the partial delivery. 2211da177e4SLinus Torvalds */ 2221da177e4SLinus Torvalds 223b6e1331fSVlad Yasevich if (atomic_read(&sctp_sk(sk)->pd_mode) == 0) { 2241da177e4SLinus Torvalds queue = &sk->sk_receive_queue; 225b6e1331fSVlad Yasevich } else { 226b6e1331fSVlad Yasevich if (ulpq->pd_mode) { 227d0cf0d99SVlad Yasevich /* If the association is in partial delivery, we 228d0cf0d99SVlad Yasevich * need to finish delivering the partially processed 229d0cf0d99SVlad Yasevich * packet before passing any other data. This is 230d0cf0d99SVlad Yasevich * because we don't truly support stream interleaving. 231d0cf0d99SVlad Yasevich */ 232d0cf0d99SVlad Yasevich if ((event->msg_flags & MSG_NOTIFICATION) || 233d0cf0d99SVlad Yasevich (SCTP_DATA_NOT_FRAG == 234d0cf0d99SVlad Yasevich (event->msg_flags & SCTP_DATA_FRAG_MASK))) 2351da177e4SLinus Torvalds queue = &sctp_sk(sk)->pd_lobby; 2361da177e4SLinus Torvalds else { 2371da177e4SLinus Torvalds clear_pd = event->msg_flags & MSG_EOR; 2381da177e4SLinus Torvalds queue = &sk->sk_receive_queue; 2391da177e4SLinus Torvalds } 240b6e1331fSVlad Yasevich } else { 241b6e1331fSVlad Yasevich /* 242b6e1331fSVlad Yasevich * If fragment interleave is enabled, we 24325985edcSLucas De Marchi * can queue this to the receive queue instead 244b6e1331fSVlad Yasevich * of the lobby. 245b6e1331fSVlad Yasevich */ 246b6e1331fSVlad Yasevich if (sctp_sk(sk)->frag_interleave) 247b6e1331fSVlad Yasevich queue = &sk->sk_receive_queue; 248b6e1331fSVlad Yasevich else 2491da177e4SLinus Torvalds queue = &sctp_sk(sk)->pd_lobby; 250b6e1331fSVlad Yasevich } 251b6e1331fSVlad Yasevich } 2521da177e4SLinus Torvalds 2531da177e4SLinus Torvalds /* If we are harvesting multiple skbs they will be 2541da177e4SLinus Torvalds * collected on a list. 2551da177e4SLinus Torvalds */ 2568728b834SDavid S. Miller if (skb_list) 2578728b834SDavid S. Miller sctp_skb_list_tail(skb_list, queue); 2581da177e4SLinus Torvalds else 2598728b834SDavid S. Miller __skb_queue_tail(queue, skb); 2601da177e4SLinus Torvalds 2611da177e4SLinus Torvalds /* Did we just complete partial delivery and need to get 2621da177e4SLinus Torvalds * rolling again? Move pending data to the receive 2631da177e4SLinus Torvalds * queue. 2641da177e4SLinus Torvalds */ 2651da177e4SLinus Torvalds if (clear_pd) 2661da177e4SLinus Torvalds sctp_ulpq_clear_pd(ulpq); 2671da177e4SLinus Torvalds 2681da177e4SLinus Torvalds if (queue == &sk->sk_receive_queue) 2691da177e4SLinus Torvalds sk->sk_data_ready(sk, 0); 2701da177e4SLinus Torvalds return 1; 2711da177e4SLinus Torvalds 2721da177e4SLinus Torvalds out_free: 2738728b834SDavid S. Miller if (skb_list) 2748728b834SDavid S. Miller sctp_queue_purge_ulpevents(skb_list); 2751da177e4SLinus Torvalds else 2761da177e4SLinus Torvalds sctp_ulpevent_free(event); 2778728b834SDavid S. Miller 2781da177e4SLinus Torvalds return 0; 2791da177e4SLinus Torvalds } 2801da177e4SLinus Torvalds 2811da177e4SLinus Torvalds /* 2nd Level Abstractions */ 2821da177e4SLinus Torvalds 2831da177e4SLinus Torvalds /* Helper function to store chunks that need to be reassembled. */ 28401f2d384SVlad Yasevich static void sctp_ulpq_store_reasm(struct sctp_ulpq *ulpq, 2851da177e4SLinus Torvalds struct sctp_ulpevent *event) 2861da177e4SLinus Torvalds { 2871da177e4SLinus Torvalds struct sk_buff *pos; 2881da177e4SLinus Torvalds struct sctp_ulpevent *cevent; 2891da177e4SLinus Torvalds __u32 tsn, ctsn; 2901da177e4SLinus Torvalds 2911da177e4SLinus Torvalds tsn = event->tsn; 2921da177e4SLinus Torvalds 2931da177e4SLinus Torvalds /* See if it belongs at the end. */ 2941da177e4SLinus Torvalds pos = skb_peek_tail(&ulpq->reasm); 2951da177e4SLinus Torvalds if (!pos) { 2961da177e4SLinus Torvalds __skb_queue_tail(&ulpq->reasm, sctp_event2skb(event)); 2971da177e4SLinus Torvalds return; 2981da177e4SLinus Torvalds } 2991da177e4SLinus Torvalds 3001da177e4SLinus Torvalds /* Short circuit just dropping it at the end. */ 3011da177e4SLinus Torvalds cevent = sctp_skb2event(pos); 3021da177e4SLinus Torvalds ctsn = cevent->tsn; 3031da177e4SLinus Torvalds if (TSN_lt(ctsn, tsn)) { 3041da177e4SLinus Torvalds __skb_queue_tail(&ulpq->reasm, sctp_event2skb(event)); 3051da177e4SLinus Torvalds return; 3061da177e4SLinus Torvalds } 3071da177e4SLinus Torvalds 3081da177e4SLinus Torvalds /* Find the right place in this list. We store them by TSN. */ 3091da177e4SLinus Torvalds skb_queue_walk(&ulpq->reasm, pos) { 3101da177e4SLinus Torvalds cevent = sctp_skb2event(pos); 3111da177e4SLinus Torvalds ctsn = cevent->tsn; 3121da177e4SLinus Torvalds 3131da177e4SLinus Torvalds if (TSN_lt(tsn, ctsn)) 3141da177e4SLinus Torvalds break; 3151da177e4SLinus Torvalds } 3161da177e4SLinus Torvalds 3171da177e4SLinus Torvalds /* Insert before pos. */ 31843f59c89SDavid S. Miller __skb_queue_before(&ulpq->reasm, pos, sctp_event2skb(event)); 3191da177e4SLinus Torvalds 3201da177e4SLinus Torvalds } 3211da177e4SLinus Torvalds 3221da177e4SLinus Torvalds /* Helper function to return an event corresponding to the reassembled 3231da177e4SLinus Torvalds * datagram. 3241da177e4SLinus Torvalds * This routine creates a re-assembled skb given the first and last skb's 3251da177e4SLinus Torvalds * as stored in the reassembly queue. The skb's may be non-linear if the sctp 3261da177e4SLinus Torvalds * payload was fragmented on the way and ip had to reassemble them. 3271da177e4SLinus Torvalds * We add the rest of skb's to the first skb's fraglist. 3281da177e4SLinus Torvalds */ 329b01a2407SEric W. Biederman static struct sctp_ulpevent *sctp_make_reassembled_event(struct net *net, 330b01a2407SEric W. Biederman struct sk_buff_head *queue, struct sk_buff *f_frag, 331b01a2407SEric W. Biederman struct sk_buff *l_frag) 3321da177e4SLinus Torvalds { 3331da177e4SLinus Torvalds struct sk_buff *pos; 334672e7ccaSVladislav Yasevich struct sk_buff *new = NULL; 3351da177e4SLinus Torvalds struct sctp_ulpevent *event; 3361da177e4SLinus Torvalds struct sk_buff *pnext, *last; 3371da177e4SLinus Torvalds struct sk_buff *list = skb_shinfo(f_frag)->frag_list; 3381da177e4SLinus Torvalds 3391da177e4SLinus Torvalds /* Store the pointer to the 2nd skb */ 3401da177e4SLinus Torvalds if (f_frag == l_frag) 3411da177e4SLinus Torvalds pos = NULL; 3421da177e4SLinus Torvalds else 3431da177e4SLinus Torvalds pos = f_frag->next; 3441da177e4SLinus Torvalds 3451da177e4SLinus Torvalds /* Get the last skb in the f_frag's frag_list if present. */ 3461da177e4SLinus Torvalds for (last = list; list; last = list, list = list->next); 3471da177e4SLinus Torvalds 3481da177e4SLinus Torvalds /* Add the list of remaining fragments to the first fragments 3491da177e4SLinus Torvalds * frag_list. 3501da177e4SLinus Torvalds */ 3511da177e4SLinus Torvalds if (last) 3521da177e4SLinus Torvalds last->next = pos; 353672e7ccaSVladislav Yasevich else { 354672e7ccaSVladislav Yasevich if (skb_cloned(f_frag)) { 355672e7ccaSVladislav Yasevich /* This is a cloned skb, we can't just modify 356672e7ccaSVladislav Yasevich * the frag_list. We need a new skb to do that. 357672e7ccaSVladislav Yasevich * Instead of calling skb_unshare(), we'll do it 358672e7ccaSVladislav Yasevich * ourselves since we need to delay the free. 359672e7ccaSVladislav Yasevich */ 360672e7ccaSVladislav Yasevich new = skb_copy(f_frag, GFP_ATOMIC); 361672e7ccaSVladislav Yasevich if (!new) 362672e7ccaSVladislav Yasevich return NULL; /* try again later */ 363672e7ccaSVladislav Yasevich 364331c4ee7SVlad Yasevich sctp_skb_set_owner_r(new, f_frag->sk); 365672e7ccaSVladislav Yasevich 366672e7ccaSVladislav Yasevich skb_shinfo(new)->frag_list = pos; 367672e7ccaSVladislav Yasevich } else 3681da177e4SLinus Torvalds skb_shinfo(f_frag)->frag_list = pos; 369672e7ccaSVladislav Yasevich } 3701da177e4SLinus Torvalds 3711da177e4SLinus Torvalds /* Remove the first fragment from the reassembly queue. */ 3728728b834SDavid S. Miller __skb_unlink(f_frag, queue); 373672e7ccaSVladislav Yasevich 374672e7ccaSVladislav Yasevich /* if we did unshare, then free the old skb and re-assign */ 375672e7ccaSVladislav Yasevich if (new) { 376672e7ccaSVladislav Yasevich kfree_skb(f_frag); 377672e7ccaSVladislav Yasevich f_frag = new; 378672e7ccaSVladislav Yasevich } 379672e7ccaSVladislav Yasevich 3801da177e4SLinus Torvalds while (pos) { 3811da177e4SLinus Torvalds 3821da177e4SLinus Torvalds pnext = pos->next; 3831da177e4SLinus Torvalds 3841da177e4SLinus Torvalds /* Update the len and data_len fields of the first fragment. */ 3851da177e4SLinus Torvalds f_frag->len += pos->len; 3861da177e4SLinus Torvalds f_frag->data_len += pos->len; 3871da177e4SLinus Torvalds 3881da177e4SLinus Torvalds /* Remove the fragment from the reassembly queue. */ 3898728b834SDavid S. Miller __skb_unlink(pos, queue); 3901da177e4SLinus Torvalds 3911da177e4SLinus Torvalds /* Break if we have reached the last fragment. */ 3921da177e4SLinus Torvalds if (pos == l_frag) 3931da177e4SLinus Torvalds break; 3941da177e4SLinus Torvalds pos->next = pnext; 3951da177e4SLinus Torvalds pos = pnext; 3963ff50b79SStephen Hemminger } 3971da177e4SLinus Torvalds 3981da177e4SLinus Torvalds event = sctp_skb2event(f_frag); 399b01a2407SEric W. Biederman SCTP_INC_STATS(net, SCTP_MIB_REASMUSRMSGS); 4001da177e4SLinus Torvalds 4011da177e4SLinus Torvalds return event; 4021da177e4SLinus Torvalds } 4031da177e4SLinus Torvalds 4041da177e4SLinus Torvalds 4051da177e4SLinus Torvalds /* Helper function to check if an incoming chunk has filled up the last 4061da177e4SLinus Torvalds * missing fragment in a SCTP datagram and return the corresponding event. 4071da177e4SLinus Torvalds */ 40801f2d384SVlad Yasevich static struct sctp_ulpevent *sctp_ulpq_retrieve_reassembled(struct sctp_ulpq *ulpq) 4091da177e4SLinus Torvalds { 4101da177e4SLinus Torvalds struct sk_buff *pos; 4111da177e4SLinus Torvalds struct sctp_ulpevent *cevent; 4121da177e4SLinus Torvalds struct sk_buff *first_frag = NULL; 4131da177e4SLinus Torvalds __u32 ctsn, next_tsn; 4141da177e4SLinus Torvalds struct sctp_ulpevent *retval = NULL; 415d49d91d7SVlad Yasevich struct sk_buff *pd_first = NULL; 416d49d91d7SVlad Yasevich struct sk_buff *pd_last = NULL; 417d49d91d7SVlad Yasevich size_t pd_len = 0; 418d49d91d7SVlad Yasevich struct sctp_association *asoc; 419d49d91d7SVlad Yasevich u32 pd_point; 4201da177e4SLinus Torvalds 4211da177e4SLinus Torvalds /* Initialized to 0 just to avoid compiler warning message. Will 4221da177e4SLinus Torvalds * never be used with this value. It is referenced only after it 4231da177e4SLinus Torvalds * is set when we find the first fragment of a message. 4241da177e4SLinus Torvalds */ 4251da177e4SLinus Torvalds next_tsn = 0; 4261da177e4SLinus Torvalds 4271da177e4SLinus Torvalds /* The chunks are held in the reasm queue sorted by TSN. 4281da177e4SLinus Torvalds * Walk through the queue sequentially and look for a sequence of 4291da177e4SLinus Torvalds * fragmented chunks that complete a datagram. 4301da177e4SLinus Torvalds * 'first_frag' and next_tsn are reset when we find a chunk which 4311da177e4SLinus Torvalds * is the first fragment of a datagram. Once these 2 fields are set 4321da177e4SLinus Torvalds * we expect to find the remaining middle fragments and the last 4331da177e4SLinus Torvalds * fragment in order. If not, first_frag is reset to NULL and we 4341da177e4SLinus Torvalds * start the next pass when we find another first fragment. 435d49d91d7SVlad Yasevich * 436d49d91d7SVlad Yasevich * There is a potential to do partial delivery if user sets 437d49d91d7SVlad Yasevich * SCTP_PARTIAL_DELIVERY_POINT option. Lets count some things here 438d49d91d7SVlad Yasevich * to see if can do PD. 4391da177e4SLinus Torvalds */ 4401da177e4SLinus Torvalds skb_queue_walk(&ulpq->reasm, pos) { 4411da177e4SLinus Torvalds cevent = sctp_skb2event(pos); 4421da177e4SLinus Torvalds ctsn = cevent->tsn; 4431da177e4SLinus Torvalds 4441da177e4SLinus Torvalds switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) { 4451da177e4SLinus Torvalds case SCTP_DATA_FIRST_FRAG: 446d49d91d7SVlad Yasevich /* If this "FIRST_FRAG" is the first 447d49d91d7SVlad Yasevich * element in the queue, then count it towards 448d49d91d7SVlad Yasevich * possible PD. 449d49d91d7SVlad Yasevich */ 450d49d91d7SVlad Yasevich if (pos == ulpq->reasm.next) { 451d49d91d7SVlad Yasevich pd_first = pos; 452d49d91d7SVlad Yasevich pd_last = pos; 453d49d91d7SVlad Yasevich pd_len = pos->len; 454d49d91d7SVlad Yasevich } else { 455d49d91d7SVlad Yasevich pd_first = NULL; 456d49d91d7SVlad Yasevich pd_last = NULL; 457d49d91d7SVlad Yasevich pd_len = 0; 458d49d91d7SVlad Yasevich } 459d49d91d7SVlad Yasevich 4601da177e4SLinus Torvalds first_frag = pos; 4611da177e4SLinus Torvalds next_tsn = ctsn + 1; 4621da177e4SLinus Torvalds break; 4631da177e4SLinus Torvalds 4641da177e4SLinus Torvalds case SCTP_DATA_MIDDLE_FRAG: 465d49d91d7SVlad Yasevich if ((first_frag) && (ctsn == next_tsn)) { 4661da177e4SLinus Torvalds next_tsn++; 467d49d91d7SVlad Yasevich if (pd_first) { 468d49d91d7SVlad Yasevich pd_last = pos; 469d49d91d7SVlad Yasevich pd_len += pos->len; 470d49d91d7SVlad Yasevich } 471d49d91d7SVlad Yasevich } else 4721da177e4SLinus Torvalds first_frag = NULL; 4731da177e4SLinus Torvalds break; 4741da177e4SLinus Torvalds 4751da177e4SLinus Torvalds case SCTP_DATA_LAST_FRAG: 4761da177e4SLinus Torvalds if (first_frag && (ctsn == next_tsn)) 4771da177e4SLinus Torvalds goto found; 4781da177e4SLinus Torvalds else 4791da177e4SLinus Torvalds first_frag = NULL; 4801da177e4SLinus Torvalds break; 4813ff50b79SStephen Hemminger } 482d49d91d7SVlad Yasevich } 4831da177e4SLinus Torvalds 484d49d91d7SVlad Yasevich asoc = ulpq->asoc; 485d49d91d7SVlad Yasevich if (pd_first) { 486d49d91d7SVlad Yasevich /* Make sure we can enter partial deliver. 487d49d91d7SVlad Yasevich * We can trigger partial delivery only if framgent 488d49d91d7SVlad Yasevich * interleave is set, or the socket is not already 489d49d91d7SVlad Yasevich * in partial delivery. 490d49d91d7SVlad Yasevich */ 491d49d91d7SVlad Yasevich if (!sctp_sk(asoc->base.sk)->frag_interleave && 492d49d91d7SVlad Yasevich atomic_read(&sctp_sk(asoc->base.sk)->pd_mode)) 493d49d91d7SVlad Yasevich goto done; 494d49d91d7SVlad Yasevich 495d49d91d7SVlad Yasevich cevent = sctp_skb2event(pd_first); 496d49d91d7SVlad Yasevich pd_point = sctp_sk(asoc->base.sk)->pd_point; 497d49d91d7SVlad Yasevich if (pd_point && pd_point <= pd_len) { 498b01a2407SEric W. Biederman retval = sctp_make_reassembled_event(sock_net(asoc->base.sk), 499b01a2407SEric W. Biederman &ulpq->reasm, 500d49d91d7SVlad Yasevich pd_first, 501d49d91d7SVlad Yasevich pd_last); 502d49d91d7SVlad Yasevich if (retval) 503d49d91d7SVlad Yasevich sctp_ulpq_set_pd(ulpq); 504d49d91d7SVlad Yasevich } 5051da177e4SLinus Torvalds } 5061da177e4SLinus Torvalds done: 5071da177e4SLinus Torvalds return retval; 5081da177e4SLinus Torvalds found: 509b01a2407SEric W. Biederman retval = sctp_make_reassembled_event(sock_net(ulpq->asoc->base.sk), 510b01a2407SEric W. Biederman &ulpq->reasm, first_frag, pos); 5111da177e4SLinus Torvalds if (retval) 5121da177e4SLinus Torvalds retval->msg_flags |= MSG_EOR; 5131da177e4SLinus Torvalds goto done; 5141da177e4SLinus Torvalds } 5151da177e4SLinus Torvalds 5161da177e4SLinus Torvalds /* Retrieve the next set of fragments of a partial message. */ 51701f2d384SVlad Yasevich static struct sctp_ulpevent *sctp_ulpq_retrieve_partial(struct sctp_ulpq *ulpq) 5181da177e4SLinus Torvalds { 5191da177e4SLinus Torvalds struct sk_buff *pos, *last_frag, *first_frag; 5201da177e4SLinus Torvalds struct sctp_ulpevent *cevent; 5211da177e4SLinus Torvalds __u32 ctsn, next_tsn; 5221da177e4SLinus Torvalds int is_last; 5231da177e4SLinus Torvalds struct sctp_ulpevent *retval; 5241da177e4SLinus Torvalds 5251da177e4SLinus Torvalds /* The chunks are held in the reasm queue sorted by TSN. 5261da177e4SLinus Torvalds * Walk through the queue sequentially and look for the first 5271da177e4SLinus Torvalds * sequence of fragmented chunks. 5281da177e4SLinus Torvalds */ 5291da177e4SLinus Torvalds 5301da177e4SLinus Torvalds if (skb_queue_empty(&ulpq->reasm)) 5311da177e4SLinus Torvalds return NULL; 5321da177e4SLinus Torvalds 5331da177e4SLinus Torvalds last_frag = first_frag = NULL; 5341da177e4SLinus Torvalds retval = NULL; 5351da177e4SLinus Torvalds next_tsn = 0; 5361da177e4SLinus Torvalds is_last = 0; 5371da177e4SLinus Torvalds 5381da177e4SLinus Torvalds skb_queue_walk(&ulpq->reasm, pos) { 5391da177e4SLinus Torvalds cevent = sctp_skb2event(pos); 5401da177e4SLinus Torvalds ctsn = cevent->tsn; 5411da177e4SLinus Torvalds 5421da177e4SLinus Torvalds switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) { 5431da177e4SLinus Torvalds case SCTP_DATA_MIDDLE_FRAG: 5441da177e4SLinus Torvalds if (!first_frag) { 5451da177e4SLinus Torvalds first_frag = pos; 5461da177e4SLinus Torvalds next_tsn = ctsn + 1; 5471da177e4SLinus Torvalds last_frag = pos; 5481da177e4SLinus Torvalds } else if (next_tsn == ctsn) 5491da177e4SLinus Torvalds next_tsn++; 5501da177e4SLinus Torvalds else 5511da177e4SLinus Torvalds goto done; 5521da177e4SLinus Torvalds break; 5531da177e4SLinus Torvalds case SCTP_DATA_LAST_FRAG: 5541da177e4SLinus Torvalds if (!first_frag) 5551da177e4SLinus Torvalds first_frag = pos; 5561da177e4SLinus Torvalds else if (ctsn != next_tsn) 5571da177e4SLinus Torvalds goto done; 5581da177e4SLinus Torvalds last_frag = pos; 5591da177e4SLinus Torvalds is_last = 1; 5601da177e4SLinus Torvalds goto done; 5611da177e4SLinus Torvalds default: 5621da177e4SLinus Torvalds return NULL; 5633ff50b79SStephen Hemminger } 5641da177e4SLinus Torvalds } 5651da177e4SLinus Torvalds 5661da177e4SLinus Torvalds /* We have the reassembled event. There is no need to look 5671da177e4SLinus Torvalds * further. 5681da177e4SLinus Torvalds */ 5691da177e4SLinus Torvalds done: 570b01a2407SEric W. Biederman retval = sctp_make_reassembled_event(sock_net(ulpq->asoc->base.sk), 571b01a2407SEric W. Biederman &ulpq->reasm, first_frag, last_frag); 5721da177e4SLinus Torvalds if (retval && is_last) 5731da177e4SLinus Torvalds retval->msg_flags |= MSG_EOR; 5741da177e4SLinus Torvalds 5751da177e4SLinus Torvalds return retval; 5761da177e4SLinus Torvalds } 5771da177e4SLinus Torvalds 5781da177e4SLinus Torvalds 5791da177e4SLinus Torvalds /* Helper function to reassemble chunks. Hold chunks on the reasm queue that 5801da177e4SLinus Torvalds * need reassembling. 5811da177e4SLinus Torvalds */ 5821da177e4SLinus Torvalds static struct sctp_ulpevent *sctp_ulpq_reasm(struct sctp_ulpq *ulpq, 5831da177e4SLinus Torvalds struct sctp_ulpevent *event) 5841da177e4SLinus Torvalds { 5851da177e4SLinus Torvalds struct sctp_ulpevent *retval = NULL; 5861da177e4SLinus Torvalds 5871da177e4SLinus Torvalds /* Check if this is part of a fragmented message. */ 5881da177e4SLinus Torvalds if (SCTP_DATA_NOT_FRAG == (event->msg_flags & SCTP_DATA_FRAG_MASK)) { 5891da177e4SLinus Torvalds event->msg_flags |= MSG_EOR; 5901da177e4SLinus Torvalds return event; 5911da177e4SLinus Torvalds } 5921da177e4SLinus Torvalds 5931da177e4SLinus Torvalds sctp_ulpq_store_reasm(ulpq, event); 5941da177e4SLinus Torvalds if (!ulpq->pd_mode) 5951da177e4SLinus Torvalds retval = sctp_ulpq_retrieve_reassembled(ulpq); 5961da177e4SLinus Torvalds else { 5971da177e4SLinus Torvalds __u32 ctsn, ctsnap; 5981da177e4SLinus Torvalds 5991da177e4SLinus Torvalds /* Do not even bother unless this is the next tsn to 6001da177e4SLinus Torvalds * be delivered. 6011da177e4SLinus Torvalds */ 6021da177e4SLinus Torvalds ctsn = event->tsn; 6031da177e4SLinus Torvalds ctsnap = sctp_tsnmap_get_ctsn(&ulpq->asoc->peer.tsn_map); 6041da177e4SLinus Torvalds if (TSN_lte(ctsn, ctsnap)) 6051da177e4SLinus Torvalds retval = sctp_ulpq_retrieve_partial(ulpq); 6061da177e4SLinus Torvalds } 6071da177e4SLinus Torvalds 6081da177e4SLinus Torvalds return retval; 6091da177e4SLinus Torvalds } 6101da177e4SLinus Torvalds 6111da177e4SLinus Torvalds /* Retrieve the first part (sequential fragments) for partial delivery. */ 61201f2d384SVlad Yasevich static struct sctp_ulpevent *sctp_ulpq_retrieve_first(struct sctp_ulpq *ulpq) 6131da177e4SLinus Torvalds { 6141da177e4SLinus Torvalds struct sk_buff *pos, *last_frag, *first_frag; 6151da177e4SLinus Torvalds struct sctp_ulpevent *cevent; 6161da177e4SLinus Torvalds __u32 ctsn, next_tsn; 6171da177e4SLinus Torvalds struct sctp_ulpevent *retval; 6181da177e4SLinus Torvalds 6191da177e4SLinus Torvalds /* The chunks are held in the reasm queue sorted by TSN. 6201da177e4SLinus Torvalds * Walk through the queue sequentially and look for a sequence of 6211da177e4SLinus Torvalds * fragmented chunks that start a datagram. 6221da177e4SLinus Torvalds */ 6231da177e4SLinus Torvalds 6241da177e4SLinus Torvalds if (skb_queue_empty(&ulpq->reasm)) 6251da177e4SLinus Torvalds return NULL; 6261da177e4SLinus Torvalds 6271da177e4SLinus Torvalds last_frag = first_frag = NULL; 6281da177e4SLinus Torvalds retval = NULL; 6291da177e4SLinus Torvalds next_tsn = 0; 6301da177e4SLinus Torvalds 6311da177e4SLinus Torvalds skb_queue_walk(&ulpq->reasm, pos) { 6321da177e4SLinus Torvalds cevent = sctp_skb2event(pos); 6331da177e4SLinus Torvalds ctsn = cevent->tsn; 6341da177e4SLinus Torvalds 6351da177e4SLinus Torvalds switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) { 6361da177e4SLinus Torvalds case SCTP_DATA_FIRST_FRAG: 6371da177e4SLinus Torvalds if (!first_frag) { 6381da177e4SLinus Torvalds first_frag = pos; 6391da177e4SLinus Torvalds next_tsn = ctsn + 1; 6401da177e4SLinus Torvalds last_frag = pos; 6411da177e4SLinus Torvalds } else 6421da177e4SLinus Torvalds goto done; 6431da177e4SLinus Torvalds break; 6441da177e4SLinus Torvalds 6451da177e4SLinus Torvalds case SCTP_DATA_MIDDLE_FRAG: 6461da177e4SLinus Torvalds if (!first_frag) 6471da177e4SLinus Torvalds return NULL; 6481da177e4SLinus Torvalds if (ctsn == next_tsn) { 6491da177e4SLinus Torvalds next_tsn++; 6501da177e4SLinus Torvalds last_frag = pos; 6511da177e4SLinus Torvalds } else 6521da177e4SLinus Torvalds goto done; 6531da177e4SLinus Torvalds break; 6541da177e4SLinus Torvalds default: 6551da177e4SLinus Torvalds return NULL; 6563ff50b79SStephen Hemminger } 6571da177e4SLinus Torvalds } 6581da177e4SLinus Torvalds 6591da177e4SLinus Torvalds /* We have the reassembled event. There is no need to look 6601da177e4SLinus Torvalds * further. 6611da177e4SLinus Torvalds */ 6621da177e4SLinus Torvalds done: 663b01a2407SEric W. Biederman retval = sctp_make_reassembled_event(sock_net(ulpq->asoc->base.sk), 664b01a2407SEric W. Biederman &ulpq->reasm, first_frag, last_frag); 6651da177e4SLinus Torvalds return retval; 6661da177e4SLinus Torvalds } 6671da177e4SLinus Torvalds 668ea2dfb37SVlad Yasevich /* 669ea2dfb37SVlad Yasevich * Flush out stale fragments from the reassembly queue when processing 670ea2dfb37SVlad Yasevich * a Forward TSN. 671ea2dfb37SVlad Yasevich * 672ea2dfb37SVlad Yasevich * RFC 3758, Section 3.6 673ea2dfb37SVlad Yasevich * 674ea2dfb37SVlad Yasevich * After receiving and processing a FORWARD TSN, the data receiver MUST 675ea2dfb37SVlad Yasevich * take cautions in updating its re-assembly queue. The receiver MUST 676ea2dfb37SVlad Yasevich * remove any partially reassembled message, which is still missing one 677ea2dfb37SVlad Yasevich * or more TSNs earlier than or equal to the new cumulative TSN point. 678ea2dfb37SVlad Yasevich * In the event that the receiver has invoked the partial delivery API, 679ea2dfb37SVlad Yasevich * a notification SHOULD also be generated to inform the upper layer API 680ea2dfb37SVlad Yasevich * that the message being partially delivered will NOT be completed. 681ea2dfb37SVlad Yasevich */ 682ea2dfb37SVlad Yasevich void sctp_ulpq_reasm_flushtsn(struct sctp_ulpq *ulpq, __u32 fwd_tsn) 683ea2dfb37SVlad Yasevich { 684ea2dfb37SVlad Yasevich struct sk_buff *pos, *tmp; 685ea2dfb37SVlad Yasevich struct sctp_ulpevent *event; 686ea2dfb37SVlad Yasevich __u32 tsn; 687ea2dfb37SVlad Yasevich 688ea2dfb37SVlad Yasevich if (skb_queue_empty(&ulpq->reasm)) 689ea2dfb37SVlad Yasevich return; 690ea2dfb37SVlad Yasevich 691ea2dfb37SVlad Yasevich skb_queue_walk_safe(&ulpq->reasm, pos, tmp) { 692ea2dfb37SVlad Yasevich event = sctp_skb2event(pos); 693ea2dfb37SVlad Yasevich tsn = event->tsn; 694ea2dfb37SVlad Yasevich 695ea2dfb37SVlad Yasevich /* Since the entire message must be abandoned by the 696ea2dfb37SVlad Yasevich * sender (item A3 in Section 3.5, RFC 3758), we can 697ea2dfb37SVlad Yasevich * free all fragments on the list that are less then 698ea2dfb37SVlad Yasevich * or equal to ctsn_point 699ea2dfb37SVlad Yasevich */ 700ea2dfb37SVlad Yasevich if (TSN_lte(tsn, fwd_tsn)) { 701ea2dfb37SVlad Yasevich __skb_unlink(pos, &ulpq->reasm); 702ea2dfb37SVlad Yasevich sctp_ulpevent_free(event); 703ea2dfb37SVlad Yasevich } else 704ea2dfb37SVlad Yasevich break; 705ea2dfb37SVlad Yasevich } 706ea2dfb37SVlad Yasevich } 707ea2dfb37SVlad Yasevich 708ef5d4cf2SVlad Yasevich /* 709ef5d4cf2SVlad Yasevich * Drain the reassembly queue. If we just cleared parted delivery, it 710ef5d4cf2SVlad Yasevich * is possible that the reassembly queue will contain already reassembled 711ef5d4cf2SVlad Yasevich * messages. Retrieve any such messages and give them to the user. 712ef5d4cf2SVlad Yasevich */ 713ef5d4cf2SVlad Yasevich static void sctp_ulpq_reasm_drain(struct sctp_ulpq *ulpq) 714ef5d4cf2SVlad Yasevich { 715ef5d4cf2SVlad Yasevich struct sctp_ulpevent *event = NULL; 716ef5d4cf2SVlad Yasevich struct sk_buff_head temp; 717ef5d4cf2SVlad Yasevich 718ef5d4cf2SVlad Yasevich if (skb_queue_empty(&ulpq->reasm)) 719ef5d4cf2SVlad Yasevich return; 720ef5d4cf2SVlad Yasevich 721ef5d4cf2SVlad Yasevich while ((event = sctp_ulpq_retrieve_reassembled(ulpq)) != NULL) { 722ef5d4cf2SVlad Yasevich /* Do ordering if needed. */ 723ef5d4cf2SVlad Yasevich if ((event) && (event->msg_flags & MSG_EOR)){ 724ef5d4cf2SVlad Yasevich skb_queue_head_init(&temp); 725ef5d4cf2SVlad Yasevich __skb_queue_tail(&temp, sctp_event2skb(event)); 726ef5d4cf2SVlad Yasevich 727ef5d4cf2SVlad Yasevich event = sctp_ulpq_order(ulpq, event); 728ef5d4cf2SVlad Yasevich } 729ef5d4cf2SVlad Yasevich 730ef5d4cf2SVlad Yasevich /* Send event to the ULP. 'event' is the 731ef5d4cf2SVlad Yasevich * sctp_ulpevent for very first SKB on the temp' list. 732ef5d4cf2SVlad Yasevich */ 733ef5d4cf2SVlad Yasevich if (event) 734ef5d4cf2SVlad Yasevich sctp_ulpq_tail_event(ulpq, event); 735ef5d4cf2SVlad Yasevich } 736ef5d4cf2SVlad Yasevich } 737ef5d4cf2SVlad Yasevich 738ef5d4cf2SVlad Yasevich 7391da177e4SLinus Torvalds /* Helper function to gather skbs that have possibly become 7401da177e4SLinus Torvalds * ordered by an an incoming chunk. 7411da177e4SLinus Torvalds */ 74201f2d384SVlad Yasevich static void sctp_ulpq_retrieve_ordered(struct sctp_ulpq *ulpq, 7431da177e4SLinus Torvalds struct sctp_ulpevent *event) 7441da177e4SLinus Torvalds { 7458728b834SDavid S. Miller struct sk_buff_head *event_list; 7461da177e4SLinus Torvalds struct sk_buff *pos, *tmp; 7471da177e4SLinus Torvalds struct sctp_ulpevent *cevent; 7481da177e4SLinus Torvalds struct sctp_stream *in; 749efea2c6bSHagen Paul Pfeifer __u16 sid, csid, cssn; 7501da177e4SLinus Torvalds 7511da177e4SLinus Torvalds sid = event->stream; 7521da177e4SLinus Torvalds in = &ulpq->asoc->ssnmap->in; 7531da177e4SLinus Torvalds 7548728b834SDavid S. Miller event_list = (struct sk_buff_head *) sctp_event2skb(event)->prev; 7558728b834SDavid S. Miller 7561da177e4SLinus Torvalds /* We are holding the chunks by stream, by SSN. */ 7571da177e4SLinus Torvalds sctp_skb_for_each(pos, &ulpq->lobby, tmp) { 7581da177e4SLinus Torvalds cevent = (struct sctp_ulpevent *) pos->cb; 7591da177e4SLinus Torvalds csid = cevent->stream; 7601da177e4SLinus Torvalds cssn = cevent->ssn; 7611da177e4SLinus Torvalds 7621da177e4SLinus Torvalds /* Have we gone too far? */ 7631da177e4SLinus Torvalds if (csid > sid) 7641da177e4SLinus Torvalds break; 7651da177e4SLinus Torvalds 7661da177e4SLinus Torvalds /* Have we not gone far enough? */ 7671da177e4SLinus Torvalds if (csid < sid) 7681da177e4SLinus Torvalds continue; 7691da177e4SLinus Torvalds 7701da177e4SLinus Torvalds if (cssn != sctp_ssn_peek(in, sid)) 7711da177e4SLinus Torvalds break; 7721da177e4SLinus Torvalds 7731da177e4SLinus Torvalds /* Found it, so mark in the ssnmap. */ 7741da177e4SLinus Torvalds sctp_ssn_next(in, sid); 7751da177e4SLinus Torvalds 7768728b834SDavid S. Miller __skb_unlink(pos, &ulpq->lobby); 7771da177e4SLinus Torvalds 7781da177e4SLinus Torvalds /* Attach all gathered skbs to the event. */ 7798728b834SDavid S. Miller __skb_queue_tail(event_list, pos); 7801da177e4SLinus Torvalds } 7811da177e4SLinus Torvalds } 7821da177e4SLinus Torvalds 7831da177e4SLinus Torvalds /* Helper function to store chunks needing ordering. */ 78401f2d384SVlad Yasevich static void sctp_ulpq_store_ordered(struct sctp_ulpq *ulpq, 7851da177e4SLinus Torvalds struct sctp_ulpevent *event) 7861da177e4SLinus Torvalds { 7871da177e4SLinus Torvalds struct sk_buff *pos; 7881da177e4SLinus Torvalds struct sctp_ulpevent *cevent; 7891da177e4SLinus Torvalds __u16 sid, csid; 7901da177e4SLinus Torvalds __u16 ssn, cssn; 7911da177e4SLinus Torvalds 7921da177e4SLinus Torvalds pos = skb_peek_tail(&ulpq->lobby); 7931da177e4SLinus Torvalds if (!pos) { 7941da177e4SLinus Torvalds __skb_queue_tail(&ulpq->lobby, sctp_event2skb(event)); 7951da177e4SLinus Torvalds return; 7961da177e4SLinus Torvalds } 7971da177e4SLinus Torvalds 7981da177e4SLinus Torvalds sid = event->stream; 7991da177e4SLinus Torvalds ssn = event->ssn; 8001da177e4SLinus Torvalds 8011da177e4SLinus Torvalds cevent = (struct sctp_ulpevent *) pos->cb; 8021da177e4SLinus Torvalds csid = cevent->stream; 8031da177e4SLinus Torvalds cssn = cevent->ssn; 8041da177e4SLinus Torvalds if (sid > csid) { 8051da177e4SLinus Torvalds __skb_queue_tail(&ulpq->lobby, sctp_event2skb(event)); 8061da177e4SLinus Torvalds return; 8071da177e4SLinus Torvalds } 8081da177e4SLinus Torvalds 8091da177e4SLinus Torvalds if ((sid == csid) && SSN_lt(cssn, ssn)) { 8101da177e4SLinus Torvalds __skb_queue_tail(&ulpq->lobby, sctp_event2skb(event)); 8111da177e4SLinus Torvalds return; 8121da177e4SLinus Torvalds } 8131da177e4SLinus Torvalds 8141da177e4SLinus Torvalds /* Find the right place in this list. We store them by 8151da177e4SLinus Torvalds * stream ID and then by SSN. 8161da177e4SLinus Torvalds */ 8171da177e4SLinus Torvalds skb_queue_walk(&ulpq->lobby, pos) { 8181da177e4SLinus Torvalds cevent = (struct sctp_ulpevent *) pos->cb; 8191da177e4SLinus Torvalds csid = cevent->stream; 8201da177e4SLinus Torvalds cssn = cevent->ssn; 8211da177e4SLinus Torvalds 8221da177e4SLinus Torvalds if (csid > sid) 8231da177e4SLinus Torvalds break; 8241da177e4SLinus Torvalds if (csid == sid && SSN_lt(ssn, cssn)) 8251da177e4SLinus Torvalds break; 8261da177e4SLinus Torvalds } 8271da177e4SLinus Torvalds 8281da177e4SLinus Torvalds 8291da177e4SLinus Torvalds /* Insert before pos. */ 83043f59c89SDavid S. Miller __skb_queue_before(&ulpq->lobby, pos, sctp_event2skb(event)); 8311da177e4SLinus Torvalds } 8321da177e4SLinus Torvalds 8331da177e4SLinus Torvalds static struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *ulpq, 8341da177e4SLinus Torvalds struct sctp_ulpevent *event) 8351da177e4SLinus Torvalds { 8361da177e4SLinus Torvalds __u16 sid, ssn; 8371da177e4SLinus Torvalds struct sctp_stream *in; 8381da177e4SLinus Torvalds 8391da177e4SLinus Torvalds /* Check if this message needs ordering. */ 8401da177e4SLinus Torvalds if (SCTP_DATA_UNORDERED & event->msg_flags) 8411da177e4SLinus Torvalds return event; 8421da177e4SLinus Torvalds 8431da177e4SLinus Torvalds /* Note: The stream ID must be verified before this routine. */ 8441da177e4SLinus Torvalds sid = event->stream; 8451da177e4SLinus Torvalds ssn = event->ssn; 8461da177e4SLinus Torvalds in = &ulpq->asoc->ssnmap->in; 8471da177e4SLinus Torvalds 8481da177e4SLinus Torvalds /* Is this the expected SSN for this stream ID? */ 8491da177e4SLinus Torvalds if (ssn != sctp_ssn_peek(in, sid)) { 8501da177e4SLinus Torvalds /* We've received something out of order, so find where it 8511da177e4SLinus Torvalds * needs to be placed. We order by stream and then by SSN. 8521da177e4SLinus Torvalds */ 8531da177e4SLinus Torvalds sctp_ulpq_store_ordered(ulpq, event); 8541da177e4SLinus Torvalds return NULL; 8551da177e4SLinus Torvalds } 8561da177e4SLinus Torvalds 8571da177e4SLinus Torvalds /* Mark that the next chunk has been found. */ 8581da177e4SLinus Torvalds sctp_ssn_next(in, sid); 8591da177e4SLinus Torvalds 8601da177e4SLinus Torvalds /* Go find any other chunks that were waiting for 8611da177e4SLinus Torvalds * ordering. 8621da177e4SLinus Torvalds */ 8631da177e4SLinus Torvalds sctp_ulpq_retrieve_ordered(ulpq, event); 8641da177e4SLinus Torvalds 8651da177e4SLinus Torvalds return event; 8661da177e4SLinus Torvalds } 8671da177e4SLinus Torvalds 8681da177e4SLinus Torvalds /* Helper function to gather skbs that have possibly become 8691da177e4SLinus Torvalds * ordered by forward tsn skipping their dependencies. 8701da177e4SLinus Torvalds */ 87101f2d384SVlad Yasevich static void sctp_ulpq_reap_ordered(struct sctp_ulpq *ulpq, __u16 sid) 8721da177e4SLinus Torvalds { 8731da177e4SLinus Torvalds struct sk_buff *pos, *tmp; 8741da177e4SLinus Torvalds struct sctp_ulpevent *cevent; 8758728b834SDavid S. Miller struct sctp_ulpevent *event; 8761da177e4SLinus Torvalds struct sctp_stream *in; 8771da177e4SLinus Torvalds struct sk_buff_head temp; 878c068be54SVlad Yasevich struct sk_buff_head *lobby = &ulpq->lobby; 8791da177e4SLinus Torvalds __u16 csid, cssn; 8801da177e4SLinus Torvalds 8811da177e4SLinus Torvalds in = &ulpq->asoc->ssnmap->in; 8821da177e4SLinus Torvalds 8831da177e4SLinus Torvalds /* We are holding the chunks by stream, by SSN. */ 8848728b834SDavid S. Miller skb_queue_head_init(&temp); 8858728b834SDavid S. Miller event = NULL; 886c068be54SVlad Yasevich sctp_skb_for_each(pos, lobby, tmp) { 8871da177e4SLinus Torvalds cevent = (struct sctp_ulpevent *) pos->cb; 8881da177e4SLinus Torvalds csid = cevent->stream; 8891da177e4SLinus Torvalds cssn = cevent->ssn; 8901da177e4SLinus Torvalds 891ea2dfb37SVlad Yasevich /* Have we gone too far? */ 892ea2dfb37SVlad Yasevich if (csid > sid) 8931da177e4SLinus Torvalds break; 8941da177e4SLinus Torvalds 895ea2dfb37SVlad Yasevich /* Have we not gone far enough? */ 896ea2dfb37SVlad Yasevich if (csid < sid) 897ea2dfb37SVlad Yasevich continue; 898ea2dfb37SVlad Yasevich 899ea2dfb37SVlad Yasevich /* see if this ssn has been marked by skipping */ 900c068be54SVlad Yasevich if (!SSN_lt(cssn, sctp_ssn_peek(in, csid))) 901ea2dfb37SVlad Yasevich break; 9021da177e4SLinus Torvalds 903c068be54SVlad Yasevich __skb_unlink(pos, lobby); 904ea2dfb37SVlad Yasevich if (!event) 9051da177e4SLinus Torvalds /* Create a temporary list to collect chunks on. */ 9061da177e4SLinus Torvalds event = sctp_skb2event(pos); 907ea2dfb37SVlad Yasevich 9081da177e4SLinus Torvalds /* Attach all gathered skbs to the event. */ 9098728b834SDavid S. Miller __skb_queue_tail(&temp, pos); 9101da177e4SLinus Torvalds } 9111da177e4SLinus Torvalds 912c068be54SVlad Yasevich /* If we didn't reap any data, see if the next expected SSN 913c068be54SVlad Yasevich * is next on the queue and if so, use that. 914c068be54SVlad Yasevich */ 915c068be54SVlad Yasevich if (event == NULL && pos != (struct sk_buff *)lobby) { 916c068be54SVlad Yasevich cevent = (struct sctp_ulpevent *) pos->cb; 917c068be54SVlad Yasevich csid = cevent->stream; 918c068be54SVlad Yasevich cssn = cevent->ssn; 919c068be54SVlad Yasevich 920c068be54SVlad Yasevich if (csid == sid && cssn == sctp_ssn_peek(in, csid)) { 921c068be54SVlad Yasevich sctp_ssn_next(in, csid); 922c068be54SVlad Yasevich __skb_unlink(pos, lobby); 923c068be54SVlad Yasevich __skb_queue_tail(&temp, pos); 924c068be54SVlad Yasevich event = sctp_skb2event(pos); 925c068be54SVlad Yasevich } 926c068be54SVlad Yasevich } 927c068be54SVlad Yasevich 9288728b834SDavid S. Miller /* Send event to the ULP. 'event' is the sctp_ulpevent for 9298728b834SDavid S. Miller * very first SKB on the 'temp' list. 9308728b834SDavid S. Miller */ 931ea2dfb37SVlad Yasevich if (event) { 932ea2dfb37SVlad Yasevich /* see if we have more ordered that we can deliver */ 933ea2dfb37SVlad Yasevich sctp_ulpq_retrieve_ordered(ulpq, event); 9341da177e4SLinus Torvalds sctp_ulpq_tail_event(ulpq, event); 9351da177e4SLinus Torvalds } 936ea2dfb37SVlad Yasevich } 9371da177e4SLinus Torvalds 938ea2dfb37SVlad Yasevich /* Skip over an SSN. This is used during the processing of 939ea2dfb37SVlad Yasevich * Forwared TSN chunk to skip over the abandoned ordered data 940ea2dfb37SVlad Yasevich */ 9411da177e4SLinus Torvalds void sctp_ulpq_skip(struct sctp_ulpq *ulpq, __u16 sid, __u16 ssn) 9421da177e4SLinus Torvalds { 9431da177e4SLinus Torvalds struct sctp_stream *in; 9441da177e4SLinus Torvalds 9451da177e4SLinus Torvalds /* Note: The stream ID must be verified before this routine. */ 9461da177e4SLinus Torvalds in = &ulpq->asoc->ssnmap->in; 9471da177e4SLinus Torvalds 9481da177e4SLinus Torvalds /* Is this an old SSN? If so ignore. */ 9491da177e4SLinus Torvalds if (SSN_lt(ssn, sctp_ssn_peek(in, sid))) 9501da177e4SLinus Torvalds return; 9511da177e4SLinus Torvalds 9521da177e4SLinus Torvalds /* Mark that we are no longer expecting this SSN or lower. */ 9531da177e4SLinus Torvalds sctp_ssn_skip(in, sid, ssn); 9541da177e4SLinus Torvalds 9551da177e4SLinus Torvalds /* Go find any other chunks that were waiting for 9561da177e4SLinus Torvalds * ordering and deliver them if needed. 9571da177e4SLinus Torvalds */ 958ea2dfb37SVlad Yasevich sctp_ulpq_reap_ordered(ulpq, sid); 9591da177e4SLinus Torvalds } 9601da177e4SLinus Torvalds 96116d14ef9SPavel Emelyanov static __u16 sctp_ulpq_renege_list(struct sctp_ulpq *ulpq, 96216d14ef9SPavel Emelyanov struct sk_buff_head *list, __u16 needed) 9631da177e4SLinus Torvalds { 9641da177e4SLinus Torvalds __u16 freed = 0; 9651da177e4SLinus Torvalds __u32 tsn; 9661da177e4SLinus Torvalds struct sk_buff *skb; 9671da177e4SLinus Torvalds struct sctp_ulpevent *event; 9681da177e4SLinus Torvalds struct sctp_tsnmap *tsnmap; 9691da177e4SLinus Torvalds 9701da177e4SLinus Torvalds tsnmap = &ulpq->asoc->peer.tsn_map; 9711da177e4SLinus Torvalds 97216d14ef9SPavel Emelyanov while ((skb = __skb_dequeue_tail(list)) != NULL) { 9731da177e4SLinus Torvalds freed += skb_headlen(skb); 9741da177e4SLinus Torvalds event = sctp_skb2event(skb); 9751da177e4SLinus Torvalds tsn = event->tsn; 9761da177e4SLinus Torvalds 9771da177e4SLinus Torvalds sctp_ulpevent_free(event); 9781da177e4SLinus Torvalds sctp_tsnmap_renege(tsnmap, tsn); 9791da177e4SLinus Torvalds if (freed >= needed) 9801da177e4SLinus Torvalds return freed; 9811da177e4SLinus Torvalds } 9821da177e4SLinus Torvalds 9831da177e4SLinus Torvalds return freed; 9841da177e4SLinus Torvalds } 9851da177e4SLinus Torvalds 98616d14ef9SPavel Emelyanov /* Renege 'needed' bytes from the ordering queue. */ 98716d14ef9SPavel Emelyanov static __u16 sctp_ulpq_renege_order(struct sctp_ulpq *ulpq, __u16 needed) 98816d14ef9SPavel Emelyanov { 98916d14ef9SPavel Emelyanov return sctp_ulpq_renege_list(ulpq, &ulpq->lobby, needed); 99016d14ef9SPavel Emelyanov } 99116d14ef9SPavel Emelyanov 9921da177e4SLinus Torvalds /* Renege 'needed' bytes from the reassembly queue. */ 9931da177e4SLinus Torvalds static __u16 sctp_ulpq_renege_frags(struct sctp_ulpq *ulpq, __u16 needed) 9941da177e4SLinus Torvalds { 99516d14ef9SPavel Emelyanov return sctp_ulpq_renege_list(ulpq, &ulpq->reasm, needed); 9961da177e4SLinus Torvalds } 9971da177e4SLinus Torvalds 9981da177e4SLinus Torvalds /* Partial deliver the first message as there is pressure on rwnd. */ 9991da177e4SLinus Torvalds void sctp_ulpq_partial_delivery(struct sctp_ulpq *ulpq, 1000dd0fc66fSAl Viro gfp_t gfp) 10011da177e4SLinus Torvalds { 10021da177e4SLinus Torvalds struct sctp_ulpevent *event; 10031da177e4SLinus Torvalds struct sctp_association *asoc; 1004b6e1331fSVlad Yasevich struct sctp_sock *sp; 10051da177e4SLinus Torvalds 10061da177e4SLinus Torvalds asoc = ulpq->asoc; 1007b6e1331fSVlad Yasevich sp = sctp_sk(asoc->base.sk); 10081da177e4SLinus Torvalds 1009b6e1331fSVlad Yasevich /* If the association is already in Partial Delivery mode 1010b6e1331fSVlad Yasevich * we have noting to do. 1011b6e1331fSVlad Yasevich */ 1012b6e1331fSVlad Yasevich if (ulpq->pd_mode) 1013b6e1331fSVlad Yasevich return; 10141da177e4SLinus Torvalds 1015b6e1331fSVlad Yasevich /* If the user enabled fragment interleave socket option, 1016b6e1331fSVlad Yasevich * multiple associations can enter partial delivery. 1017b6e1331fSVlad Yasevich * Otherwise, we can only enter partial delivery if the 1018b6e1331fSVlad Yasevich * socket is not in partial deliver mode. 1019b6e1331fSVlad Yasevich */ 1020b6e1331fSVlad Yasevich if (sp->frag_interleave || atomic_read(&sp->pd_mode) == 0) { 10211da177e4SLinus Torvalds /* Is partial delivery possible? */ 10221da177e4SLinus Torvalds event = sctp_ulpq_retrieve_first(ulpq); 10231da177e4SLinus Torvalds /* Send event to the ULP. */ 10241da177e4SLinus Torvalds if (event) { 10251da177e4SLinus Torvalds sctp_ulpq_tail_event(ulpq, event); 1026d49d91d7SVlad Yasevich sctp_ulpq_set_pd(ulpq); 10271da177e4SLinus Torvalds return; 10281da177e4SLinus Torvalds } 10291da177e4SLinus Torvalds } 10301da177e4SLinus Torvalds } 10311da177e4SLinus Torvalds 10321da177e4SLinus Torvalds /* Renege some packets to make room for an incoming chunk. */ 10331da177e4SLinus Torvalds void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk, 1034dd0fc66fSAl Viro gfp_t gfp) 10351da177e4SLinus Torvalds { 10361da177e4SLinus Torvalds struct sctp_association *asoc; 10371da177e4SLinus Torvalds __u16 needed, freed; 10381da177e4SLinus Torvalds 10391da177e4SLinus Torvalds asoc = ulpq->asoc; 10401da177e4SLinus Torvalds 10411da177e4SLinus Torvalds if (chunk) { 10421da177e4SLinus Torvalds needed = ntohs(chunk->chunk_hdr->length); 10431da177e4SLinus Torvalds needed -= sizeof(sctp_data_chunk_t); 10441da177e4SLinus Torvalds } else 10451da177e4SLinus Torvalds needed = SCTP_DEFAULT_MAXWINDOW; 10461da177e4SLinus Torvalds 10471da177e4SLinus Torvalds freed = 0; 10481da177e4SLinus Torvalds 10491da177e4SLinus Torvalds if (skb_queue_empty(&asoc->base.sk->sk_receive_queue)) { 10501da177e4SLinus Torvalds freed = sctp_ulpq_renege_order(ulpq, needed); 10511da177e4SLinus Torvalds if (freed < needed) { 10521da177e4SLinus Torvalds freed += sctp_ulpq_renege_frags(ulpq, needed - freed); 10531da177e4SLinus Torvalds } 10541da177e4SLinus Torvalds } 10551da177e4SLinus Torvalds /* If able to free enough room, accept this chunk. */ 10561da177e4SLinus Torvalds if (chunk && (freed >= needed)) { 10571da177e4SLinus Torvalds __u32 tsn; 10581da177e4SLinus Torvalds tsn = ntohl(chunk->subh.data_hdr->tsn); 10594244854dSNeil Horman sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn, chunk->transport); 10601da177e4SLinus Torvalds sctp_ulpq_tail_data(ulpq, chunk, gfp); 10611da177e4SLinus Torvalds 1062b26ddd81SNeil Horman sctp_ulpq_partial_delivery(ulpq, gfp); 10631da177e4SLinus Torvalds } 10641da177e4SLinus Torvalds 10653ab224beSHideo Aoki sk_mem_reclaim(asoc->base.sk); 10661da177e4SLinus Torvalds } 10671da177e4SLinus Torvalds 10681da177e4SLinus Torvalds 10691da177e4SLinus Torvalds 10701da177e4SLinus Torvalds /* Notify the application if an association is aborted and in 10711da177e4SLinus Torvalds * partial delivery mode. Send up any pending received messages. 10721da177e4SLinus Torvalds */ 1073dd0fc66fSAl Viro void sctp_ulpq_abort_pd(struct sctp_ulpq *ulpq, gfp_t gfp) 10741da177e4SLinus Torvalds { 10751da177e4SLinus Torvalds struct sctp_ulpevent *ev = NULL; 10761da177e4SLinus Torvalds struct sock *sk; 10771da177e4SLinus Torvalds 10781da177e4SLinus Torvalds if (!ulpq->pd_mode) 10791da177e4SLinus Torvalds return; 10801da177e4SLinus Torvalds 10811da177e4SLinus Torvalds sk = ulpq->asoc->base.sk; 10821da177e4SLinus Torvalds if (sctp_ulpevent_type_enabled(SCTP_PARTIAL_DELIVERY_EVENT, 10831da177e4SLinus Torvalds &sctp_sk(sk)->subscribe)) 10841da177e4SLinus Torvalds ev = sctp_ulpevent_make_pdapi(ulpq->asoc, 10851da177e4SLinus Torvalds SCTP_PARTIAL_DELIVERY_ABORTED, 10861da177e4SLinus Torvalds gfp); 10871da177e4SLinus Torvalds if (ev) 10881da177e4SLinus Torvalds __skb_queue_tail(&sk->sk_receive_queue, sctp_event2skb(ev)); 10891da177e4SLinus Torvalds 10901da177e4SLinus Torvalds /* If there is data waiting, send it up the socket now. */ 10911da177e4SLinus Torvalds if (sctp_ulpq_clear_pd(ulpq) || ev) 10921da177e4SLinus Torvalds sk->sk_data_ready(sk, 0); 10931da177e4SLinus Torvalds } 1094