18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* SCTP kernel implementation 38c2ecf20Sopenharmony_ci * (C) Copyright IBM Corp. 2001, 2004 48c2ecf20Sopenharmony_ci * Copyright (c) 1999-2000 Cisco, Inc. 58c2ecf20Sopenharmony_ci * Copyright (c) 1999-2001 Motorola, Inc. 68c2ecf20Sopenharmony_ci * Copyright (c) 2001 Intel Corp. 78c2ecf20Sopenharmony_ci * Copyright (c) 2001 Nokia, Inc. 88c2ecf20Sopenharmony_ci * Copyright (c) 2001 La Monte H.P. Yarroll 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * This abstraction carries sctp events to the ULP (sockets). 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Please send any bug reports or fixes you make to the 138c2ecf20Sopenharmony_ci * email address(es): 148c2ecf20Sopenharmony_ci * lksctp developers <linux-sctp@vger.kernel.org> 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * Written or modified by: 178c2ecf20Sopenharmony_ci * Jon Grimm <jgrimm@us.ibm.com> 188c2ecf20Sopenharmony_ci * La Monte H.P. Yarroll <piggy@acm.org> 198c2ecf20Sopenharmony_ci * Sridhar Samudrala <sri@us.ibm.com> 208c2ecf20Sopenharmony_ci */ 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <linux/slab.h> 238c2ecf20Sopenharmony_ci#include <linux/types.h> 248c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 258c2ecf20Sopenharmony_ci#include <net/sock.h> 268c2ecf20Sopenharmony_ci#include <net/busy_poll.h> 278c2ecf20Sopenharmony_ci#include <net/sctp/structs.h> 288c2ecf20Sopenharmony_ci#include <net/sctp/sctp.h> 298c2ecf20Sopenharmony_ci#include <net/sctp/sm.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* Forward declarations for internal helpers. */ 328c2ecf20Sopenharmony_cistatic struct sctp_ulpevent *sctp_ulpq_reasm(struct sctp_ulpq *ulpq, 338c2ecf20Sopenharmony_ci struct sctp_ulpevent *); 348c2ecf20Sopenharmony_cistatic struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *, 358c2ecf20Sopenharmony_ci struct sctp_ulpevent *); 368c2ecf20Sopenharmony_cistatic void sctp_ulpq_reasm_drain(struct sctp_ulpq *ulpq); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* 1st Level Abstractions */ 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/* Initialize a ULP queue from a block of memory. */ 418c2ecf20Sopenharmony_cistruct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *ulpq, 428c2ecf20Sopenharmony_ci struct sctp_association *asoc) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci memset(ulpq, 0, sizeof(struct sctp_ulpq)); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci ulpq->asoc = asoc; 478c2ecf20Sopenharmony_ci skb_queue_head_init(&ulpq->reasm); 488c2ecf20Sopenharmony_ci skb_queue_head_init(&ulpq->reasm_uo); 498c2ecf20Sopenharmony_ci skb_queue_head_init(&ulpq->lobby); 508c2ecf20Sopenharmony_ci ulpq->pd_mode = 0; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci return ulpq; 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci/* Flush the reassembly and ordering queues. */ 578c2ecf20Sopenharmony_civoid sctp_ulpq_flush(struct sctp_ulpq *ulpq) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci struct sk_buff *skb; 608c2ecf20Sopenharmony_ci struct sctp_ulpevent *event; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci while ((skb = __skb_dequeue(&ulpq->lobby)) != NULL) { 638c2ecf20Sopenharmony_ci event = sctp_skb2event(skb); 648c2ecf20Sopenharmony_ci sctp_ulpevent_free(event); 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci while ((skb = __skb_dequeue(&ulpq->reasm)) != NULL) { 688c2ecf20Sopenharmony_ci event = sctp_skb2event(skb); 698c2ecf20Sopenharmony_ci sctp_ulpevent_free(event); 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci while ((skb = __skb_dequeue(&ulpq->reasm_uo)) != NULL) { 738c2ecf20Sopenharmony_ci event = sctp_skb2event(skb); 748c2ecf20Sopenharmony_ci sctp_ulpevent_free(event); 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/* Dispose of a ulpqueue. */ 798c2ecf20Sopenharmony_civoid sctp_ulpq_free(struct sctp_ulpq *ulpq) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci sctp_ulpq_flush(ulpq); 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci/* Process an incoming DATA chunk. */ 858c2ecf20Sopenharmony_ciint sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk, 868c2ecf20Sopenharmony_ci gfp_t gfp) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci struct sk_buff_head temp; 898c2ecf20Sopenharmony_ci struct sctp_ulpevent *event; 908c2ecf20Sopenharmony_ci int event_eor = 0; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci /* Create an event from the incoming chunk. */ 938c2ecf20Sopenharmony_ci event = sctp_ulpevent_make_rcvmsg(chunk->asoc, chunk, gfp); 948c2ecf20Sopenharmony_ci if (!event) 958c2ecf20Sopenharmony_ci return -ENOMEM; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci event->ssn = ntohs(chunk->subh.data_hdr->ssn); 988c2ecf20Sopenharmony_ci event->ppid = chunk->subh.data_hdr->ppid; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci /* Do reassembly if needed. */ 1018c2ecf20Sopenharmony_ci event = sctp_ulpq_reasm(ulpq, event); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci /* Do ordering if needed. */ 1048c2ecf20Sopenharmony_ci if (event) { 1058c2ecf20Sopenharmony_ci /* Create a temporary list to collect chunks on. */ 1068c2ecf20Sopenharmony_ci skb_queue_head_init(&temp); 1078c2ecf20Sopenharmony_ci __skb_queue_tail(&temp, sctp_event2skb(event)); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci if (event->msg_flags & MSG_EOR) 1108c2ecf20Sopenharmony_ci event = sctp_ulpq_order(ulpq, event); 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci /* Send event to the ULP. 'event' is the sctp_ulpevent for 1148c2ecf20Sopenharmony_ci * very first SKB on the 'temp' list. 1158c2ecf20Sopenharmony_ci */ 1168c2ecf20Sopenharmony_ci if (event) { 1178c2ecf20Sopenharmony_ci event_eor = (event->msg_flags & MSG_EOR) ? 1 : 0; 1188c2ecf20Sopenharmony_ci sctp_ulpq_tail_event(ulpq, &temp); 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci return event_eor; 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci/* Add a new event for propagation to the ULP. */ 1258c2ecf20Sopenharmony_ci/* Clear the partial delivery mode for this socket. Note: This 1268c2ecf20Sopenharmony_ci * assumes that no association is currently in partial delivery mode. 1278c2ecf20Sopenharmony_ci */ 1288c2ecf20Sopenharmony_ciint sctp_clear_pd(struct sock *sk, struct sctp_association *asoc) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci if (atomic_dec_and_test(&sp->pd_mode)) { 1338c2ecf20Sopenharmony_ci /* This means there are no other associations in PD, so 1348c2ecf20Sopenharmony_ci * we can go ahead and clear out the lobby in one shot 1358c2ecf20Sopenharmony_ci */ 1368c2ecf20Sopenharmony_ci if (!skb_queue_empty(&sp->pd_lobby)) { 1378c2ecf20Sopenharmony_ci skb_queue_splice_tail_init(&sp->pd_lobby, 1388c2ecf20Sopenharmony_ci &sk->sk_receive_queue); 1398c2ecf20Sopenharmony_ci return 1; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci } else { 1428c2ecf20Sopenharmony_ci /* There are other associations in PD, so we only need to 1438c2ecf20Sopenharmony_ci * pull stuff out of the lobby that belongs to the 1448c2ecf20Sopenharmony_ci * associations that is exiting PD (all of its notifications 1458c2ecf20Sopenharmony_ci * are posted here). 1468c2ecf20Sopenharmony_ci */ 1478c2ecf20Sopenharmony_ci if (!skb_queue_empty(&sp->pd_lobby) && asoc) { 1488c2ecf20Sopenharmony_ci struct sk_buff *skb, *tmp; 1498c2ecf20Sopenharmony_ci struct sctp_ulpevent *event; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci sctp_skb_for_each(skb, &sp->pd_lobby, tmp) { 1528c2ecf20Sopenharmony_ci event = sctp_skb2event(skb); 1538c2ecf20Sopenharmony_ci if (event->asoc == asoc) { 1548c2ecf20Sopenharmony_ci __skb_unlink(skb, &sp->pd_lobby); 1558c2ecf20Sopenharmony_ci __skb_queue_tail(&sk->sk_receive_queue, 1568c2ecf20Sopenharmony_ci skb); 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci return 0; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci/* Set the pd_mode on the socket and ulpq */ 1668c2ecf20Sopenharmony_cistatic void sctp_ulpq_set_pd(struct sctp_ulpq *ulpq) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(ulpq->asoc->base.sk); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci atomic_inc(&sp->pd_mode); 1718c2ecf20Sopenharmony_ci ulpq->pd_mode = 1; 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci/* Clear the pd_mode and restart any pending messages waiting for delivery. */ 1758c2ecf20Sopenharmony_cistatic int sctp_ulpq_clear_pd(struct sctp_ulpq *ulpq) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci ulpq->pd_mode = 0; 1788c2ecf20Sopenharmony_ci sctp_ulpq_reasm_drain(ulpq); 1798c2ecf20Sopenharmony_ci return sctp_clear_pd(ulpq->asoc->base.sk, ulpq->asoc); 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ciint sctp_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sk_buff_head *skb_list) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci struct sock *sk = ulpq->asoc->base.sk; 1858c2ecf20Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 1868c2ecf20Sopenharmony_ci struct sctp_ulpevent *event; 1878c2ecf20Sopenharmony_ci struct sk_buff_head *queue; 1888c2ecf20Sopenharmony_ci struct sk_buff *skb; 1898c2ecf20Sopenharmony_ci int clear_pd = 0; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci skb = __skb_peek(skb_list); 1928c2ecf20Sopenharmony_ci event = sctp_skb2event(skb); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci /* If the socket is just going to throw this away, do not 1958c2ecf20Sopenharmony_ci * even try to deliver it. 1968c2ecf20Sopenharmony_ci */ 1978c2ecf20Sopenharmony_ci if (sk->sk_shutdown & RCV_SHUTDOWN && 1988c2ecf20Sopenharmony_ci (sk->sk_shutdown & SEND_SHUTDOWN || 1998c2ecf20Sopenharmony_ci !sctp_ulpevent_is_notification(event))) 2008c2ecf20Sopenharmony_ci goto out_free; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci if (!sctp_ulpevent_is_notification(event)) { 2038c2ecf20Sopenharmony_ci sk_mark_napi_id(sk, skb); 2048c2ecf20Sopenharmony_ci sk_incoming_cpu_update(sk); 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci /* Check if the user wishes to receive this event. */ 2078c2ecf20Sopenharmony_ci if (!sctp_ulpevent_is_enabled(event, ulpq->asoc->subscribe)) 2088c2ecf20Sopenharmony_ci goto out_free; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci /* If we are in partial delivery mode, post to the lobby until 2118c2ecf20Sopenharmony_ci * partial delivery is cleared, unless, of course _this_ is 2128c2ecf20Sopenharmony_ci * the association the cause of the partial delivery. 2138c2ecf20Sopenharmony_ci */ 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (atomic_read(&sp->pd_mode) == 0) { 2168c2ecf20Sopenharmony_ci queue = &sk->sk_receive_queue; 2178c2ecf20Sopenharmony_ci } else { 2188c2ecf20Sopenharmony_ci if (ulpq->pd_mode) { 2198c2ecf20Sopenharmony_ci /* If the association is in partial delivery, we 2208c2ecf20Sopenharmony_ci * need to finish delivering the partially processed 2218c2ecf20Sopenharmony_ci * packet before passing any other data. This is 2228c2ecf20Sopenharmony_ci * because we don't truly support stream interleaving. 2238c2ecf20Sopenharmony_ci */ 2248c2ecf20Sopenharmony_ci if ((event->msg_flags & MSG_NOTIFICATION) || 2258c2ecf20Sopenharmony_ci (SCTP_DATA_NOT_FRAG == 2268c2ecf20Sopenharmony_ci (event->msg_flags & SCTP_DATA_FRAG_MASK))) 2278c2ecf20Sopenharmony_ci queue = &sp->pd_lobby; 2288c2ecf20Sopenharmony_ci else { 2298c2ecf20Sopenharmony_ci clear_pd = event->msg_flags & MSG_EOR; 2308c2ecf20Sopenharmony_ci queue = &sk->sk_receive_queue; 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci } else { 2338c2ecf20Sopenharmony_ci /* 2348c2ecf20Sopenharmony_ci * If fragment interleave is enabled, we 2358c2ecf20Sopenharmony_ci * can queue this to the receive queue instead 2368c2ecf20Sopenharmony_ci * of the lobby. 2378c2ecf20Sopenharmony_ci */ 2388c2ecf20Sopenharmony_ci if (sp->frag_interleave) 2398c2ecf20Sopenharmony_ci queue = &sk->sk_receive_queue; 2408c2ecf20Sopenharmony_ci else 2418c2ecf20Sopenharmony_ci queue = &sp->pd_lobby; 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci skb_queue_splice_tail_init(skb_list, queue); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci /* Did we just complete partial delivery and need to get 2488c2ecf20Sopenharmony_ci * rolling again? Move pending data to the receive 2498c2ecf20Sopenharmony_ci * queue. 2508c2ecf20Sopenharmony_ci */ 2518c2ecf20Sopenharmony_ci if (clear_pd) 2528c2ecf20Sopenharmony_ci sctp_ulpq_clear_pd(ulpq); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci if (queue == &sk->sk_receive_queue && !sp->data_ready_signalled) { 2558c2ecf20Sopenharmony_ci if (!sock_owned_by_user(sk)) 2568c2ecf20Sopenharmony_ci sp->data_ready_signalled = 1; 2578c2ecf20Sopenharmony_ci sk->sk_data_ready(sk); 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci return 1; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ciout_free: 2628c2ecf20Sopenharmony_ci if (skb_list) 2638c2ecf20Sopenharmony_ci sctp_queue_purge_ulpevents(skb_list); 2648c2ecf20Sopenharmony_ci else 2658c2ecf20Sopenharmony_ci sctp_ulpevent_free(event); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci return 0; 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci/* 2nd Level Abstractions */ 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci/* Helper function to store chunks that need to be reassembled. */ 2738c2ecf20Sopenharmony_cistatic void sctp_ulpq_store_reasm(struct sctp_ulpq *ulpq, 2748c2ecf20Sopenharmony_ci struct sctp_ulpevent *event) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci struct sk_buff *pos; 2778c2ecf20Sopenharmony_ci struct sctp_ulpevent *cevent; 2788c2ecf20Sopenharmony_ci __u32 tsn, ctsn; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci tsn = event->tsn; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci /* See if it belongs at the end. */ 2838c2ecf20Sopenharmony_ci pos = skb_peek_tail(&ulpq->reasm); 2848c2ecf20Sopenharmony_ci if (!pos) { 2858c2ecf20Sopenharmony_ci __skb_queue_tail(&ulpq->reasm, sctp_event2skb(event)); 2868c2ecf20Sopenharmony_ci return; 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci /* Short circuit just dropping it at the end. */ 2908c2ecf20Sopenharmony_ci cevent = sctp_skb2event(pos); 2918c2ecf20Sopenharmony_ci ctsn = cevent->tsn; 2928c2ecf20Sopenharmony_ci if (TSN_lt(ctsn, tsn)) { 2938c2ecf20Sopenharmony_ci __skb_queue_tail(&ulpq->reasm, sctp_event2skb(event)); 2948c2ecf20Sopenharmony_ci return; 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci /* Find the right place in this list. We store them by TSN. */ 2988c2ecf20Sopenharmony_ci skb_queue_walk(&ulpq->reasm, pos) { 2998c2ecf20Sopenharmony_ci cevent = sctp_skb2event(pos); 3008c2ecf20Sopenharmony_ci ctsn = cevent->tsn; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci if (TSN_lt(tsn, ctsn)) 3038c2ecf20Sopenharmony_ci break; 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci /* Insert before pos. */ 3078c2ecf20Sopenharmony_ci __skb_queue_before(&ulpq->reasm, pos, sctp_event2skb(event)); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci} 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci/* Helper function to return an event corresponding to the reassembled 3128c2ecf20Sopenharmony_ci * datagram. 3138c2ecf20Sopenharmony_ci * This routine creates a re-assembled skb given the first and last skb's 3148c2ecf20Sopenharmony_ci * as stored in the reassembly queue. The skb's may be non-linear if the sctp 3158c2ecf20Sopenharmony_ci * payload was fragmented on the way and ip had to reassemble them. 3168c2ecf20Sopenharmony_ci * We add the rest of skb's to the first skb's fraglist. 3178c2ecf20Sopenharmony_ci */ 3188c2ecf20Sopenharmony_cistruct sctp_ulpevent *sctp_make_reassembled_event(struct net *net, 3198c2ecf20Sopenharmony_ci struct sk_buff_head *queue, 3208c2ecf20Sopenharmony_ci struct sk_buff *f_frag, 3218c2ecf20Sopenharmony_ci struct sk_buff *l_frag) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci struct sk_buff *pos; 3248c2ecf20Sopenharmony_ci struct sk_buff *new = NULL; 3258c2ecf20Sopenharmony_ci struct sctp_ulpevent *event; 3268c2ecf20Sopenharmony_ci struct sk_buff *pnext, *last; 3278c2ecf20Sopenharmony_ci struct sk_buff *list = skb_shinfo(f_frag)->frag_list; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci /* Store the pointer to the 2nd skb */ 3308c2ecf20Sopenharmony_ci if (f_frag == l_frag) 3318c2ecf20Sopenharmony_ci pos = NULL; 3328c2ecf20Sopenharmony_ci else 3338c2ecf20Sopenharmony_ci pos = f_frag->next; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci /* Get the last skb in the f_frag's frag_list if present. */ 3368c2ecf20Sopenharmony_ci for (last = list; list; last = list, list = list->next) 3378c2ecf20Sopenharmony_ci ; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci /* Add the list of remaining fragments to the first fragments 3408c2ecf20Sopenharmony_ci * frag_list. 3418c2ecf20Sopenharmony_ci */ 3428c2ecf20Sopenharmony_ci if (last) 3438c2ecf20Sopenharmony_ci last->next = pos; 3448c2ecf20Sopenharmony_ci else { 3458c2ecf20Sopenharmony_ci if (skb_cloned(f_frag)) { 3468c2ecf20Sopenharmony_ci /* This is a cloned skb, we can't just modify 3478c2ecf20Sopenharmony_ci * the frag_list. We need a new skb to do that. 3488c2ecf20Sopenharmony_ci * Instead of calling skb_unshare(), we'll do it 3498c2ecf20Sopenharmony_ci * ourselves since we need to delay the free. 3508c2ecf20Sopenharmony_ci */ 3518c2ecf20Sopenharmony_ci new = skb_copy(f_frag, GFP_ATOMIC); 3528c2ecf20Sopenharmony_ci if (!new) 3538c2ecf20Sopenharmony_ci return NULL; /* try again later */ 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci sctp_skb_set_owner_r(new, f_frag->sk); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci skb_shinfo(new)->frag_list = pos; 3588c2ecf20Sopenharmony_ci } else 3598c2ecf20Sopenharmony_ci skb_shinfo(f_frag)->frag_list = pos; 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci /* Remove the first fragment from the reassembly queue. */ 3638c2ecf20Sopenharmony_ci __skb_unlink(f_frag, queue); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci /* if we did unshare, then free the old skb and re-assign */ 3668c2ecf20Sopenharmony_ci if (new) { 3678c2ecf20Sopenharmony_ci kfree_skb(f_frag); 3688c2ecf20Sopenharmony_ci f_frag = new; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci while (pos) { 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci pnext = pos->next; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci /* Update the len and data_len fields of the first fragment. */ 3768c2ecf20Sopenharmony_ci f_frag->len += pos->len; 3778c2ecf20Sopenharmony_ci f_frag->data_len += pos->len; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci /* Remove the fragment from the reassembly queue. */ 3808c2ecf20Sopenharmony_ci __skb_unlink(pos, queue); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci /* Break if we have reached the last fragment. */ 3838c2ecf20Sopenharmony_ci if (pos == l_frag) 3848c2ecf20Sopenharmony_ci break; 3858c2ecf20Sopenharmony_ci pos->next = pnext; 3868c2ecf20Sopenharmony_ci pos = pnext; 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci event = sctp_skb2event(f_frag); 3908c2ecf20Sopenharmony_ci SCTP_INC_STATS(net, SCTP_MIB_REASMUSRMSGS); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci return event; 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci/* Helper function to check if an incoming chunk has filled up the last 3978c2ecf20Sopenharmony_ci * missing fragment in a SCTP datagram and return the corresponding event. 3988c2ecf20Sopenharmony_ci */ 3998c2ecf20Sopenharmony_cistatic struct sctp_ulpevent *sctp_ulpq_retrieve_reassembled(struct sctp_ulpq *ulpq) 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci struct sk_buff *pos; 4028c2ecf20Sopenharmony_ci struct sctp_ulpevent *cevent; 4038c2ecf20Sopenharmony_ci struct sk_buff *first_frag = NULL; 4048c2ecf20Sopenharmony_ci __u32 ctsn, next_tsn; 4058c2ecf20Sopenharmony_ci struct sctp_ulpevent *retval = NULL; 4068c2ecf20Sopenharmony_ci struct sk_buff *pd_first = NULL; 4078c2ecf20Sopenharmony_ci struct sk_buff *pd_last = NULL; 4088c2ecf20Sopenharmony_ci size_t pd_len = 0; 4098c2ecf20Sopenharmony_ci struct sctp_association *asoc; 4108c2ecf20Sopenharmony_ci u32 pd_point; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci /* Initialized to 0 just to avoid compiler warning message. Will 4138c2ecf20Sopenharmony_ci * never be used with this value. It is referenced only after it 4148c2ecf20Sopenharmony_ci * is set when we find the first fragment of a message. 4158c2ecf20Sopenharmony_ci */ 4168c2ecf20Sopenharmony_ci next_tsn = 0; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci /* The chunks are held in the reasm queue sorted by TSN. 4198c2ecf20Sopenharmony_ci * Walk through the queue sequentially and look for a sequence of 4208c2ecf20Sopenharmony_ci * fragmented chunks that complete a datagram. 4218c2ecf20Sopenharmony_ci * 'first_frag' and next_tsn are reset when we find a chunk which 4228c2ecf20Sopenharmony_ci * is the first fragment of a datagram. Once these 2 fields are set 4238c2ecf20Sopenharmony_ci * we expect to find the remaining middle fragments and the last 4248c2ecf20Sopenharmony_ci * fragment in order. If not, first_frag is reset to NULL and we 4258c2ecf20Sopenharmony_ci * start the next pass when we find another first fragment. 4268c2ecf20Sopenharmony_ci * 4278c2ecf20Sopenharmony_ci * There is a potential to do partial delivery if user sets 4288c2ecf20Sopenharmony_ci * SCTP_PARTIAL_DELIVERY_POINT option. Lets count some things here 4298c2ecf20Sopenharmony_ci * to see if can do PD. 4308c2ecf20Sopenharmony_ci */ 4318c2ecf20Sopenharmony_ci skb_queue_walk(&ulpq->reasm, pos) { 4328c2ecf20Sopenharmony_ci cevent = sctp_skb2event(pos); 4338c2ecf20Sopenharmony_ci ctsn = cevent->tsn; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) { 4368c2ecf20Sopenharmony_ci case SCTP_DATA_FIRST_FRAG: 4378c2ecf20Sopenharmony_ci /* If this "FIRST_FRAG" is the first 4388c2ecf20Sopenharmony_ci * element in the queue, then count it towards 4398c2ecf20Sopenharmony_ci * possible PD. 4408c2ecf20Sopenharmony_ci */ 4418c2ecf20Sopenharmony_ci if (skb_queue_is_first(&ulpq->reasm, pos)) { 4428c2ecf20Sopenharmony_ci pd_first = pos; 4438c2ecf20Sopenharmony_ci pd_last = pos; 4448c2ecf20Sopenharmony_ci pd_len = pos->len; 4458c2ecf20Sopenharmony_ci } else { 4468c2ecf20Sopenharmony_ci pd_first = NULL; 4478c2ecf20Sopenharmony_ci pd_last = NULL; 4488c2ecf20Sopenharmony_ci pd_len = 0; 4498c2ecf20Sopenharmony_ci } 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci first_frag = pos; 4528c2ecf20Sopenharmony_ci next_tsn = ctsn + 1; 4538c2ecf20Sopenharmony_ci break; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci case SCTP_DATA_MIDDLE_FRAG: 4568c2ecf20Sopenharmony_ci if ((first_frag) && (ctsn == next_tsn)) { 4578c2ecf20Sopenharmony_ci next_tsn++; 4588c2ecf20Sopenharmony_ci if (pd_first) { 4598c2ecf20Sopenharmony_ci pd_last = pos; 4608c2ecf20Sopenharmony_ci pd_len += pos->len; 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci } else 4638c2ecf20Sopenharmony_ci first_frag = NULL; 4648c2ecf20Sopenharmony_ci break; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci case SCTP_DATA_LAST_FRAG: 4678c2ecf20Sopenharmony_ci if (first_frag && (ctsn == next_tsn)) 4688c2ecf20Sopenharmony_ci goto found; 4698c2ecf20Sopenharmony_ci else 4708c2ecf20Sopenharmony_ci first_frag = NULL; 4718c2ecf20Sopenharmony_ci break; 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci asoc = ulpq->asoc; 4768c2ecf20Sopenharmony_ci if (pd_first) { 4778c2ecf20Sopenharmony_ci /* Make sure we can enter partial deliver. 4788c2ecf20Sopenharmony_ci * We can trigger partial delivery only if framgent 4798c2ecf20Sopenharmony_ci * interleave is set, or the socket is not already 4808c2ecf20Sopenharmony_ci * in partial delivery. 4818c2ecf20Sopenharmony_ci */ 4828c2ecf20Sopenharmony_ci if (!sctp_sk(asoc->base.sk)->frag_interleave && 4838c2ecf20Sopenharmony_ci atomic_read(&sctp_sk(asoc->base.sk)->pd_mode)) 4848c2ecf20Sopenharmony_ci goto done; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci cevent = sctp_skb2event(pd_first); 4878c2ecf20Sopenharmony_ci pd_point = sctp_sk(asoc->base.sk)->pd_point; 4888c2ecf20Sopenharmony_ci if (pd_point && pd_point <= pd_len) { 4898c2ecf20Sopenharmony_ci retval = sctp_make_reassembled_event(asoc->base.net, 4908c2ecf20Sopenharmony_ci &ulpq->reasm, 4918c2ecf20Sopenharmony_ci pd_first, pd_last); 4928c2ecf20Sopenharmony_ci if (retval) 4938c2ecf20Sopenharmony_ci sctp_ulpq_set_pd(ulpq); 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci } 4968c2ecf20Sopenharmony_cidone: 4978c2ecf20Sopenharmony_ci return retval; 4988c2ecf20Sopenharmony_cifound: 4998c2ecf20Sopenharmony_ci retval = sctp_make_reassembled_event(ulpq->asoc->base.net, 5008c2ecf20Sopenharmony_ci &ulpq->reasm, first_frag, pos); 5018c2ecf20Sopenharmony_ci if (retval) 5028c2ecf20Sopenharmony_ci retval->msg_flags |= MSG_EOR; 5038c2ecf20Sopenharmony_ci goto done; 5048c2ecf20Sopenharmony_ci} 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci/* Retrieve the next set of fragments of a partial message. */ 5078c2ecf20Sopenharmony_cistatic struct sctp_ulpevent *sctp_ulpq_retrieve_partial(struct sctp_ulpq *ulpq) 5088c2ecf20Sopenharmony_ci{ 5098c2ecf20Sopenharmony_ci struct sk_buff *pos, *last_frag, *first_frag; 5108c2ecf20Sopenharmony_ci struct sctp_ulpevent *cevent; 5118c2ecf20Sopenharmony_ci __u32 ctsn, next_tsn; 5128c2ecf20Sopenharmony_ci int is_last; 5138c2ecf20Sopenharmony_ci struct sctp_ulpevent *retval; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci /* The chunks are held in the reasm queue sorted by TSN. 5168c2ecf20Sopenharmony_ci * Walk through the queue sequentially and look for the first 5178c2ecf20Sopenharmony_ci * sequence of fragmented chunks. 5188c2ecf20Sopenharmony_ci */ 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci if (skb_queue_empty(&ulpq->reasm)) 5218c2ecf20Sopenharmony_ci return NULL; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci last_frag = first_frag = NULL; 5248c2ecf20Sopenharmony_ci retval = NULL; 5258c2ecf20Sopenharmony_ci next_tsn = 0; 5268c2ecf20Sopenharmony_ci is_last = 0; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci skb_queue_walk(&ulpq->reasm, pos) { 5298c2ecf20Sopenharmony_ci cevent = sctp_skb2event(pos); 5308c2ecf20Sopenharmony_ci ctsn = cevent->tsn; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) { 5338c2ecf20Sopenharmony_ci case SCTP_DATA_FIRST_FRAG: 5348c2ecf20Sopenharmony_ci if (!first_frag) 5358c2ecf20Sopenharmony_ci return NULL; 5368c2ecf20Sopenharmony_ci goto done; 5378c2ecf20Sopenharmony_ci case SCTP_DATA_MIDDLE_FRAG: 5388c2ecf20Sopenharmony_ci if (!first_frag) { 5398c2ecf20Sopenharmony_ci first_frag = pos; 5408c2ecf20Sopenharmony_ci next_tsn = ctsn + 1; 5418c2ecf20Sopenharmony_ci last_frag = pos; 5428c2ecf20Sopenharmony_ci } else if (next_tsn == ctsn) { 5438c2ecf20Sopenharmony_ci next_tsn++; 5448c2ecf20Sopenharmony_ci last_frag = pos; 5458c2ecf20Sopenharmony_ci } else 5468c2ecf20Sopenharmony_ci goto done; 5478c2ecf20Sopenharmony_ci break; 5488c2ecf20Sopenharmony_ci case SCTP_DATA_LAST_FRAG: 5498c2ecf20Sopenharmony_ci if (!first_frag) 5508c2ecf20Sopenharmony_ci first_frag = pos; 5518c2ecf20Sopenharmony_ci else if (ctsn != next_tsn) 5528c2ecf20Sopenharmony_ci goto done; 5538c2ecf20Sopenharmony_ci last_frag = pos; 5548c2ecf20Sopenharmony_ci is_last = 1; 5558c2ecf20Sopenharmony_ci goto done; 5568c2ecf20Sopenharmony_ci default: 5578c2ecf20Sopenharmony_ci return NULL; 5588c2ecf20Sopenharmony_ci } 5598c2ecf20Sopenharmony_ci } 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci /* We have the reassembled event. There is no need to look 5628c2ecf20Sopenharmony_ci * further. 5638c2ecf20Sopenharmony_ci */ 5648c2ecf20Sopenharmony_cidone: 5658c2ecf20Sopenharmony_ci retval = sctp_make_reassembled_event(ulpq->asoc->base.net, &ulpq->reasm, 5668c2ecf20Sopenharmony_ci first_frag, last_frag); 5678c2ecf20Sopenharmony_ci if (retval && is_last) 5688c2ecf20Sopenharmony_ci retval->msg_flags |= MSG_EOR; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci return retval; 5718c2ecf20Sopenharmony_ci} 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci/* Helper function to reassemble chunks. Hold chunks on the reasm queue that 5758c2ecf20Sopenharmony_ci * need reassembling. 5768c2ecf20Sopenharmony_ci */ 5778c2ecf20Sopenharmony_cistatic struct sctp_ulpevent *sctp_ulpq_reasm(struct sctp_ulpq *ulpq, 5788c2ecf20Sopenharmony_ci struct sctp_ulpevent *event) 5798c2ecf20Sopenharmony_ci{ 5808c2ecf20Sopenharmony_ci struct sctp_ulpevent *retval = NULL; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci /* Check if this is part of a fragmented message. */ 5838c2ecf20Sopenharmony_ci if (SCTP_DATA_NOT_FRAG == (event->msg_flags & SCTP_DATA_FRAG_MASK)) { 5848c2ecf20Sopenharmony_ci event->msg_flags |= MSG_EOR; 5858c2ecf20Sopenharmony_ci return event; 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci sctp_ulpq_store_reasm(ulpq, event); 5898c2ecf20Sopenharmony_ci if (!ulpq->pd_mode) 5908c2ecf20Sopenharmony_ci retval = sctp_ulpq_retrieve_reassembled(ulpq); 5918c2ecf20Sopenharmony_ci else { 5928c2ecf20Sopenharmony_ci __u32 ctsn, ctsnap; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci /* Do not even bother unless this is the next tsn to 5958c2ecf20Sopenharmony_ci * be delivered. 5968c2ecf20Sopenharmony_ci */ 5978c2ecf20Sopenharmony_ci ctsn = event->tsn; 5988c2ecf20Sopenharmony_ci ctsnap = sctp_tsnmap_get_ctsn(&ulpq->asoc->peer.tsn_map); 5998c2ecf20Sopenharmony_ci if (TSN_lte(ctsn, ctsnap)) 6008c2ecf20Sopenharmony_ci retval = sctp_ulpq_retrieve_partial(ulpq); 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci return retval; 6048c2ecf20Sopenharmony_ci} 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci/* Retrieve the first part (sequential fragments) for partial delivery. */ 6078c2ecf20Sopenharmony_cistatic struct sctp_ulpevent *sctp_ulpq_retrieve_first(struct sctp_ulpq *ulpq) 6088c2ecf20Sopenharmony_ci{ 6098c2ecf20Sopenharmony_ci struct sk_buff *pos, *last_frag, *first_frag; 6108c2ecf20Sopenharmony_ci struct sctp_ulpevent *cevent; 6118c2ecf20Sopenharmony_ci __u32 ctsn, next_tsn; 6128c2ecf20Sopenharmony_ci struct sctp_ulpevent *retval; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci /* The chunks are held in the reasm queue sorted by TSN. 6158c2ecf20Sopenharmony_ci * Walk through the queue sequentially and look for a sequence of 6168c2ecf20Sopenharmony_ci * fragmented chunks that start a datagram. 6178c2ecf20Sopenharmony_ci */ 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci if (skb_queue_empty(&ulpq->reasm)) 6208c2ecf20Sopenharmony_ci return NULL; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci last_frag = first_frag = NULL; 6238c2ecf20Sopenharmony_ci retval = NULL; 6248c2ecf20Sopenharmony_ci next_tsn = 0; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci skb_queue_walk(&ulpq->reasm, pos) { 6278c2ecf20Sopenharmony_ci cevent = sctp_skb2event(pos); 6288c2ecf20Sopenharmony_ci ctsn = cevent->tsn; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) { 6318c2ecf20Sopenharmony_ci case SCTP_DATA_FIRST_FRAG: 6328c2ecf20Sopenharmony_ci if (!first_frag) { 6338c2ecf20Sopenharmony_ci first_frag = pos; 6348c2ecf20Sopenharmony_ci next_tsn = ctsn + 1; 6358c2ecf20Sopenharmony_ci last_frag = pos; 6368c2ecf20Sopenharmony_ci } else 6378c2ecf20Sopenharmony_ci goto done; 6388c2ecf20Sopenharmony_ci break; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci case SCTP_DATA_MIDDLE_FRAG: 6418c2ecf20Sopenharmony_ci if (!first_frag) 6428c2ecf20Sopenharmony_ci return NULL; 6438c2ecf20Sopenharmony_ci if (ctsn == next_tsn) { 6448c2ecf20Sopenharmony_ci next_tsn++; 6458c2ecf20Sopenharmony_ci last_frag = pos; 6468c2ecf20Sopenharmony_ci } else 6478c2ecf20Sopenharmony_ci goto done; 6488c2ecf20Sopenharmony_ci break; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci case SCTP_DATA_LAST_FRAG: 6518c2ecf20Sopenharmony_ci if (!first_frag) 6528c2ecf20Sopenharmony_ci return NULL; 6538c2ecf20Sopenharmony_ci else 6548c2ecf20Sopenharmony_ci goto done; 6558c2ecf20Sopenharmony_ci break; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci default: 6588c2ecf20Sopenharmony_ci return NULL; 6598c2ecf20Sopenharmony_ci } 6608c2ecf20Sopenharmony_ci } 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci /* We have the reassembled event. There is no need to look 6638c2ecf20Sopenharmony_ci * further. 6648c2ecf20Sopenharmony_ci */ 6658c2ecf20Sopenharmony_cidone: 6668c2ecf20Sopenharmony_ci retval = sctp_make_reassembled_event(ulpq->asoc->base.net, &ulpq->reasm, 6678c2ecf20Sopenharmony_ci first_frag, last_frag); 6688c2ecf20Sopenharmony_ci return retval; 6698c2ecf20Sopenharmony_ci} 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci/* 6728c2ecf20Sopenharmony_ci * Flush out stale fragments from the reassembly queue when processing 6738c2ecf20Sopenharmony_ci * a Forward TSN. 6748c2ecf20Sopenharmony_ci * 6758c2ecf20Sopenharmony_ci * RFC 3758, Section 3.6 6768c2ecf20Sopenharmony_ci * 6778c2ecf20Sopenharmony_ci * After receiving and processing a FORWARD TSN, the data receiver MUST 6788c2ecf20Sopenharmony_ci * take cautions in updating its re-assembly queue. The receiver MUST 6798c2ecf20Sopenharmony_ci * remove any partially reassembled message, which is still missing one 6808c2ecf20Sopenharmony_ci * or more TSNs earlier than or equal to the new cumulative TSN point. 6818c2ecf20Sopenharmony_ci * In the event that the receiver has invoked the partial delivery API, 6828c2ecf20Sopenharmony_ci * a notification SHOULD also be generated to inform the upper layer API 6838c2ecf20Sopenharmony_ci * that the message being partially delivered will NOT be completed. 6848c2ecf20Sopenharmony_ci */ 6858c2ecf20Sopenharmony_civoid sctp_ulpq_reasm_flushtsn(struct sctp_ulpq *ulpq, __u32 fwd_tsn) 6868c2ecf20Sopenharmony_ci{ 6878c2ecf20Sopenharmony_ci struct sk_buff *pos, *tmp; 6888c2ecf20Sopenharmony_ci struct sctp_ulpevent *event; 6898c2ecf20Sopenharmony_ci __u32 tsn; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci if (skb_queue_empty(&ulpq->reasm)) 6928c2ecf20Sopenharmony_ci return; 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci skb_queue_walk_safe(&ulpq->reasm, pos, tmp) { 6958c2ecf20Sopenharmony_ci event = sctp_skb2event(pos); 6968c2ecf20Sopenharmony_ci tsn = event->tsn; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci /* Since the entire message must be abandoned by the 6998c2ecf20Sopenharmony_ci * sender (item A3 in Section 3.5, RFC 3758), we can 7008c2ecf20Sopenharmony_ci * free all fragments on the list that are less then 7018c2ecf20Sopenharmony_ci * or equal to ctsn_point 7028c2ecf20Sopenharmony_ci */ 7038c2ecf20Sopenharmony_ci if (TSN_lte(tsn, fwd_tsn)) { 7048c2ecf20Sopenharmony_ci __skb_unlink(pos, &ulpq->reasm); 7058c2ecf20Sopenharmony_ci sctp_ulpevent_free(event); 7068c2ecf20Sopenharmony_ci } else 7078c2ecf20Sopenharmony_ci break; 7088c2ecf20Sopenharmony_ci } 7098c2ecf20Sopenharmony_ci} 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci/* 7128c2ecf20Sopenharmony_ci * Drain the reassembly queue. If we just cleared parted delivery, it 7138c2ecf20Sopenharmony_ci * is possible that the reassembly queue will contain already reassembled 7148c2ecf20Sopenharmony_ci * messages. Retrieve any such messages and give them to the user. 7158c2ecf20Sopenharmony_ci */ 7168c2ecf20Sopenharmony_cistatic void sctp_ulpq_reasm_drain(struct sctp_ulpq *ulpq) 7178c2ecf20Sopenharmony_ci{ 7188c2ecf20Sopenharmony_ci struct sctp_ulpevent *event = NULL; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci if (skb_queue_empty(&ulpq->reasm)) 7218c2ecf20Sopenharmony_ci return; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci while ((event = sctp_ulpq_retrieve_reassembled(ulpq)) != NULL) { 7248c2ecf20Sopenharmony_ci struct sk_buff_head temp; 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci skb_queue_head_init(&temp); 7278c2ecf20Sopenharmony_ci __skb_queue_tail(&temp, sctp_event2skb(event)); 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci /* Do ordering if needed. */ 7308c2ecf20Sopenharmony_ci if (event->msg_flags & MSG_EOR) 7318c2ecf20Sopenharmony_ci event = sctp_ulpq_order(ulpq, event); 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci /* Send event to the ULP. 'event' is the 7348c2ecf20Sopenharmony_ci * sctp_ulpevent for very first SKB on the temp' list. 7358c2ecf20Sopenharmony_ci */ 7368c2ecf20Sopenharmony_ci if (event) 7378c2ecf20Sopenharmony_ci sctp_ulpq_tail_event(ulpq, &temp); 7388c2ecf20Sopenharmony_ci } 7398c2ecf20Sopenharmony_ci} 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci/* Helper function to gather skbs that have possibly become 7438c2ecf20Sopenharmony_ci * ordered by an incoming chunk. 7448c2ecf20Sopenharmony_ci */ 7458c2ecf20Sopenharmony_cistatic void sctp_ulpq_retrieve_ordered(struct sctp_ulpq *ulpq, 7468c2ecf20Sopenharmony_ci struct sctp_ulpevent *event) 7478c2ecf20Sopenharmony_ci{ 7488c2ecf20Sopenharmony_ci struct sk_buff_head *event_list; 7498c2ecf20Sopenharmony_ci struct sk_buff *pos, *tmp; 7508c2ecf20Sopenharmony_ci struct sctp_ulpevent *cevent; 7518c2ecf20Sopenharmony_ci struct sctp_stream *stream; 7528c2ecf20Sopenharmony_ci __u16 sid, csid, cssn; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci sid = event->stream; 7558c2ecf20Sopenharmony_ci stream = &ulpq->asoc->stream; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci event_list = (struct sk_buff_head *) sctp_event2skb(event)->prev; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci /* We are holding the chunks by stream, by SSN. */ 7608c2ecf20Sopenharmony_ci sctp_skb_for_each(pos, &ulpq->lobby, tmp) { 7618c2ecf20Sopenharmony_ci cevent = (struct sctp_ulpevent *) pos->cb; 7628c2ecf20Sopenharmony_ci csid = cevent->stream; 7638c2ecf20Sopenharmony_ci cssn = cevent->ssn; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci /* Have we gone too far? */ 7668c2ecf20Sopenharmony_ci if (csid > sid) 7678c2ecf20Sopenharmony_ci break; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci /* Have we not gone far enough? */ 7708c2ecf20Sopenharmony_ci if (csid < sid) 7718c2ecf20Sopenharmony_ci continue; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci if (cssn != sctp_ssn_peek(stream, in, sid)) 7748c2ecf20Sopenharmony_ci break; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci /* Found it, so mark in the stream. */ 7778c2ecf20Sopenharmony_ci sctp_ssn_next(stream, in, sid); 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci __skb_unlink(pos, &ulpq->lobby); 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci /* Attach all gathered skbs to the event. */ 7828c2ecf20Sopenharmony_ci __skb_queue_tail(event_list, pos); 7838c2ecf20Sopenharmony_ci } 7848c2ecf20Sopenharmony_ci} 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci/* Helper function to store chunks needing ordering. */ 7878c2ecf20Sopenharmony_cistatic void sctp_ulpq_store_ordered(struct sctp_ulpq *ulpq, 7888c2ecf20Sopenharmony_ci struct sctp_ulpevent *event) 7898c2ecf20Sopenharmony_ci{ 7908c2ecf20Sopenharmony_ci struct sk_buff *pos; 7918c2ecf20Sopenharmony_ci struct sctp_ulpevent *cevent; 7928c2ecf20Sopenharmony_ci __u16 sid, csid; 7938c2ecf20Sopenharmony_ci __u16 ssn, cssn; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci pos = skb_peek_tail(&ulpq->lobby); 7968c2ecf20Sopenharmony_ci if (!pos) { 7978c2ecf20Sopenharmony_ci __skb_queue_tail(&ulpq->lobby, sctp_event2skb(event)); 7988c2ecf20Sopenharmony_ci return; 7998c2ecf20Sopenharmony_ci } 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci sid = event->stream; 8028c2ecf20Sopenharmony_ci ssn = event->ssn; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci cevent = (struct sctp_ulpevent *) pos->cb; 8058c2ecf20Sopenharmony_ci csid = cevent->stream; 8068c2ecf20Sopenharmony_ci cssn = cevent->ssn; 8078c2ecf20Sopenharmony_ci if (sid > csid) { 8088c2ecf20Sopenharmony_ci __skb_queue_tail(&ulpq->lobby, sctp_event2skb(event)); 8098c2ecf20Sopenharmony_ci return; 8108c2ecf20Sopenharmony_ci } 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci if ((sid == csid) && SSN_lt(cssn, ssn)) { 8138c2ecf20Sopenharmony_ci __skb_queue_tail(&ulpq->lobby, sctp_event2skb(event)); 8148c2ecf20Sopenharmony_ci return; 8158c2ecf20Sopenharmony_ci } 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci /* Find the right place in this list. We store them by 8188c2ecf20Sopenharmony_ci * stream ID and then by SSN. 8198c2ecf20Sopenharmony_ci */ 8208c2ecf20Sopenharmony_ci skb_queue_walk(&ulpq->lobby, pos) { 8218c2ecf20Sopenharmony_ci cevent = (struct sctp_ulpevent *) pos->cb; 8228c2ecf20Sopenharmony_ci csid = cevent->stream; 8238c2ecf20Sopenharmony_ci cssn = cevent->ssn; 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci if (csid > sid) 8268c2ecf20Sopenharmony_ci break; 8278c2ecf20Sopenharmony_ci if (csid == sid && SSN_lt(ssn, cssn)) 8288c2ecf20Sopenharmony_ci break; 8298c2ecf20Sopenharmony_ci } 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci /* Insert before pos. */ 8338c2ecf20Sopenharmony_ci __skb_queue_before(&ulpq->lobby, pos, sctp_event2skb(event)); 8348c2ecf20Sopenharmony_ci} 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_cistatic struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *ulpq, 8378c2ecf20Sopenharmony_ci struct sctp_ulpevent *event) 8388c2ecf20Sopenharmony_ci{ 8398c2ecf20Sopenharmony_ci __u16 sid, ssn; 8408c2ecf20Sopenharmony_ci struct sctp_stream *stream; 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci /* Check if this message needs ordering. */ 8438c2ecf20Sopenharmony_ci if (event->msg_flags & SCTP_DATA_UNORDERED) 8448c2ecf20Sopenharmony_ci return event; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci /* Note: The stream ID must be verified before this routine. */ 8478c2ecf20Sopenharmony_ci sid = event->stream; 8488c2ecf20Sopenharmony_ci ssn = event->ssn; 8498c2ecf20Sopenharmony_ci stream = &ulpq->asoc->stream; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci /* Is this the expected SSN for this stream ID? */ 8528c2ecf20Sopenharmony_ci if (ssn != sctp_ssn_peek(stream, in, sid)) { 8538c2ecf20Sopenharmony_ci /* We've received something out of order, so find where it 8548c2ecf20Sopenharmony_ci * needs to be placed. We order by stream and then by SSN. 8558c2ecf20Sopenharmony_ci */ 8568c2ecf20Sopenharmony_ci sctp_ulpq_store_ordered(ulpq, event); 8578c2ecf20Sopenharmony_ci return NULL; 8588c2ecf20Sopenharmony_ci } 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci /* Mark that the next chunk has been found. */ 8618c2ecf20Sopenharmony_ci sctp_ssn_next(stream, in, sid); 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci /* Go find any other chunks that were waiting for 8648c2ecf20Sopenharmony_ci * ordering. 8658c2ecf20Sopenharmony_ci */ 8668c2ecf20Sopenharmony_ci sctp_ulpq_retrieve_ordered(ulpq, event); 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci return event; 8698c2ecf20Sopenharmony_ci} 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci/* Helper function to gather skbs that have possibly become 8728c2ecf20Sopenharmony_ci * ordered by forward tsn skipping their dependencies. 8738c2ecf20Sopenharmony_ci */ 8748c2ecf20Sopenharmony_cistatic void sctp_ulpq_reap_ordered(struct sctp_ulpq *ulpq, __u16 sid) 8758c2ecf20Sopenharmony_ci{ 8768c2ecf20Sopenharmony_ci struct sk_buff *pos, *tmp; 8778c2ecf20Sopenharmony_ci struct sctp_ulpevent *cevent; 8788c2ecf20Sopenharmony_ci struct sctp_ulpevent *event; 8798c2ecf20Sopenharmony_ci struct sctp_stream *stream; 8808c2ecf20Sopenharmony_ci struct sk_buff_head temp; 8818c2ecf20Sopenharmony_ci struct sk_buff_head *lobby = &ulpq->lobby; 8828c2ecf20Sopenharmony_ci __u16 csid, cssn; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci stream = &ulpq->asoc->stream; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci /* We are holding the chunks by stream, by SSN. */ 8878c2ecf20Sopenharmony_ci skb_queue_head_init(&temp); 8888c2ecf20Sopenharmony_ci event = NULL; 8898c2ecf20Sopenharmony_ci sctp_skb_for_each(pos, lobby, tmp) { 8908c2ecf20Sopenharmony_ci cevent = (struct sctp_ulpevent *) pos->cb; 8918c2ecf20Sopenharmony_ci csid = cevent->stream; 8928c2ecf20Sopenharmony_ci cssn = cevent->ssn; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci /* Have we gone too far? */ 8958c2ecf20Sopenharmony_ci if (csid > sid) 8968c2ecf20Sopenharmony_ci break; 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci /* Have we not gone far enough? */ 8998c2ecf20Sopenharmony_ci if (csid < sid) 9008c2ecf20Sopenharmony_ci continue; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci /* see if this ssn has been marked by skipping */ 9038c2ecf20Sopenharmony_ci if (!SSN_lt(cssn, sctp_ssn_peek(stream, in, csid))) 9048c2ecf20Sopenharmony_ci break; 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci __skb_unlink(pos, lobby); 9078c2ecf20Sopenharmony_ci if (!event) 9088c2ecf20Sopenharmony_ci /* Create a temporary list to collect chunks on. */ 9098c2ecf20Sopenharmony_ci event = sctp_skb2event(pos); 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci /* Attach all gathered skbs to the event. */ 9128c2ecf20Sopenharmony_ci __skb_queue_tail(&temp, pos); 9138c2ecf20Sopenharmony_ci } 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci /* If we didn't reap any data, see if the next expected SSN 9168c2ecf20Sopenharmony_ci * is next on the queue and if so, use that. 9178c2ecf20Sopenharmony_ci */ 9188c2ecf20Sopenharmony_ci if (event == NULL && pos != (struct sk_buff *)lobby) { 9198c2ecf20Sopenharmony_ci cevent = (struct sctp_ulpevent *) pos->cb; 9208c2ecf20Sopenharmony_ci csid = cevent->stream; 9218c2ecf20Sopenharmony_ci cssn = cevent->ssn; 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci if (csid == sid && cssn == sctp_ssn_peek(stream, in, csid)) { 9248c2ecf20Sopenharmony_ci sctp_ssn_next(stream, in, csid); 9258c2ecf20Sopenharmony_ci __skb_unlink(pos, lobby); 9268c2ecf20Sopenharmony_ci __skb_queue_tail(&temp, pos); 9278c2ecf20Sopenharmony_ci event = sctp_skb2event(pos); 9288c2ecf20Sopenharmony_ci } 9298c2ecf20Sopenharmony_ci } 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci /* Send event to the ULP. 'event' is the sctp_ulpevent for 9328c2ecf20Sopenharmony_ci * very first SKB on the 'temp' list. 9338c2ecf20Sopenharmony_ci */ 9348c2ecf20Sopenharmony_ci if (event) { 9358c2ecf20Sopenharmony_ci /* see if we have more ordered that we can deliver */ 9368c2ecf20Sopenharmony_ci sctp_ulpq_retrieve_ordered(ulpq, event); 9378c2ecf20Sopenharmony_ci sctp_ulpq_tail_event(ulpq, &temp); 9388c2ecf20Sopenharmony_ci } 9398c2ecf20Sopenharmony_ci} 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci/* Skip over an SSN. This is used during the processing of 9428c2ecf20Sopenharmony_ci * Forwared TSN chunk to skip over the abandoned ordered data 9438c2ecf20Sopenharmony_ci */ 9448c2ecf20Sopenharmony_civoid sctp_ulpq_skip(struct sctp_ulpq *ulpq, __u16 sid, __u16 ssn) 9458c2ecf20Sopenharmony_ci{ 9468c2ecf20Sopenharmony_ci struct sctp_stream *stream; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci /* Note: The stream ID must be verified before this routine. */ 9498c2ecf20Sopenharmony_ci stream = &ulpq->asoc->stream; 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci /* Is this an old SSN? If so ignore. */ 9528c2ecf20Sopenharmony_ci if (SSN_lt(ssn, sctp_ssn_peek(stream, in, sid))) 9538c2ecf20Sopenharmony_ci return; 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci /* Mark that we are no longer expecting this SSN or lower. */ 9568c2ecf20Sopenharmony_ci sctp_ssn_skip(stream, in, sid, ssn); 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci /* Go find any other chunks that were waiting for 9598c2ecf20Sopenharmony_ci * ordering and deliver them if needed. 9608c2ecf20Sopenharmony_ci */ 9618c2ecf20Sopenharmony_ci sctp_ulpq_reap_ordered(ulpq, sid); 9628c2ecf20Sopenharmony_ci} 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci__u16 sctp_ulpq_renege_list(struct sctp_ulpq *ulpq, struct sk_buff_head *list, 9658c2ecf20Sopenharmony_ci __u16 needed) 9668c2ecf20Sopenharmony_ci{ 9678c2ecf20Sopenharmony_ci __u16 freed = 0; 9688c2ecf20Sopenharmony_ci __u32 tsn, last_tsn; 9698c2ecf20Sopenharmony_ci struct sk_buff *skb, *flist, *last; 9708c2ecf20Sopenharmony_ci struct sctp_ulpevent *event; 9718c2ecf20Sopenharmony_ci struct sctp_tsnmap *tsnmap; 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci tsnmap = &ulpq->asoc->peer.tsn_map; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci while ((skb = skb_peek_tail(list)) != NULL) { 9768c2ecf20Sopenharmony_ci event = sctp_skb2event(skb); 9778c2ecf20Sopenharmony_ci tsn = event->tsn; 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci /* Don't renege below the Cumulative TSN ACK Point. */ 9808c2ecf20Sopenharmony_ci if (TSN_lte(tsn, sctp_tsnmap_get_ctsn(tsnmap))) 9818c2ecf20Sopenharmony_ci break; 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci /* Events in ordering queue may have multiple fragments 9848c2ecf20Sopenharmony_ci * corresponding to additional TSNs. Sum the total 9858c2ecf20Sopenharmony_ci * freed space; find the last TSN. 9868c2ecf20Sopenharmony_ci */ 9878c2ecf20Sopenharmony_ci freed += skb_headlen(skb); 9888c2ecf20Sopenharmony_ci flist = skb_shinfo(skb)->frag_list; 9898c2ecf20Sopenharmony_ci for (last = flist; flist; flist = flist->next) { 9908c2ecf20Sopenharmony_ci last = flist; 9918c2ecf20Sopenharmony_ci freed += skb_headlen(last); 9928c2ecf20Sopenharmony_ci } 9938c2ecf20Sopenharmony_ci if (last) 9948c2ecf20Sopenharmony_ci last_tsn = sctp_skb2event(last)->tsn; 9958c2ecf20Sopenharmony_ci else 9968c2ecf20Sopenharmony_ci last_tsn = tsn; 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci /* Unlink the event, then renege all applicable TSNs. */ 9998c2ecf20Sopenharmony_ci __skb_unlink(skb, list); 10008c2ecf20Sopenharmony_ci sctp_ulpevent_free(event); 10018c2ecf20Sopenharmony_ci while (TSN_lte(tsn, last_tsn)) { 10028c2ecf20Sopenharmony_ci sctp_tsnmap_renege(tsnmap, tsn); 10038c2ecf20Sopenharmony_ci tsn++; 10048c2ecf20Sopenharmony_ci } 10058c2ecf20Sopenharmony_ci if (freed >= needed) 10068c2ecf20Sopenharmony_ci return freed; 10078c2ecf20Sopenharmony_ci } 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci return freed; 10108c2ecf20Sopenharmony_ci} 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci/* Renege 'needed' bytes from the ordering queue. */ 10138c2ecf20Sopenharmony_cistatic __u16 sctp_ulpq_renege_order(struct sctp_ulpq *ulpq, __u16 needed) 10148c2ecf20Sopenharmony_ci{ 10158c2ecf20Sopenharmony_ci return sctp_ulpq_renege_list(ulpq, &ulpq->lobby, needed); 10168c2ecf20Sopenharmony_ci} 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci/* Renege 'needed' bytes from the reassembly queue. */ 10198c2ecf20Sopenharmony_cistatic __u16 sctp_ulpq_renege_frags(struct sctp_ulpq *ulpq, __u16 needed) 10208c2ecf20Sopenharmony_ci{ 10218c2ecf20Sopenharmony_ci return sctp_ulpq_renege_list(ulpq, &ulpq->reasm, needed); 10228c2ecf20Sopenharmony_ci} 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci/* Partial deliver the first message as there is pressure on rwnd. */ 10258c2ecf20Sopenharmony_civoid sctp_ulpq_partial_delivery(struct sctp_ulpq *ulpq, 10268c2ecf20Sopenharmony_ci gfp_t gfp) 10278c2ecf20Sopenharmony_ci{ 10288c2ecf20Sopenharmony_ci struct sctp_ulpevent *event; 10298c2ecf20Sopenharmony_ci struct sctp_association *asoc; 10308c2ecf20Sopenharmony_ci struct sctp_sock *sp; 10318c2ecf20Sopenharmony_ci __u32 ctsn; 10328c2ecf20Sopenharmony_ci struct sk_buff *skb; 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci asoc = ulpq->asoc; 10358c2ecf20Sopenharmony_ci sp = sctp_sk(asoc->base.sk); 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci /* If the association is already in Partial Delivery mode 10388c2ecf20Sopenharmony_ci * we have nothing to do. 10398c2ecf20Sopenharmony_ci */ 10408c2ecf20Sopenharmony_ci if (ulpq->pd_mode) 10418c2ecf20Sopenharmony_ci return; 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci /* Data must be at or below the Cumulative TSN ACK Point to 10448c2ecf20Sopenharmony_ci * start partial delivery. 10458c2ecf20Sopenharmony_ci */ 10468c2ecf20Sopenharmony_ci skb = skb_peek(&asoc->ulpq.reasm); 10478c2ecf20Sopenharmony_ci if (skb != NULL) { 10488c2ecf20Sopenharmony_ci ctsn = sctp_skb2event(skb)->tsn; 10498c2ecf20Sopenharmony_ci if (!TSN_lte(ctsn, sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map))) 10508c2ecf20Sopenharmony_ci return; 10518c2ecf20Sopenharmony_ci } 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci /* If the user enabled fragment interleave socket option, 10548c2ecf20Sopenharmony_ci * multiple associations can enter partial delivery. 10558c2ecf20Sopenharmony_ci * Otherwise, we can only enter partial delivery if the 10568c2ecf20Sopenharmony_ci * socket is not in partial deliver mode. 10578c2ecf20Sopenharmony_ci */ 10588c2ecf20Sopenharmony_ci if (sp->frag_interleave || atomic_read(&sp->pd_mode) == 0) { 10598c2ecf20Sopenharmony_ci /* Is partial delivery possible? */ 10608c2ecf20Sopenharmony_ci event = sctp_ulpq_retrieve_first(ulpq); 10618c2ecf20Sopenharmony_ci /* Send event to the ULP. */ 10628c2ecf20Sopenharmony_ci if (event) { 10638c2ecf20Sopenharmony_ci struct sk_buff_head temp; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci skb_queue_head_init(&temp); 10668c2ecf20Sopenharmony_ci __skb_queue_tail(&temp, sctp_event2skb(event)); 10678c2ecf20Sopenharmony_ci sctp_ulpq_tail_event(ulpq, &temp); 10688c2ecf20Sopenharmony_ci sctp_ulpq_set_pd(ulpq); 10698c2ecf20Sopenharmony_ci return; 10708c2ecf20Sopenharmony_ci } 10718c2ecf20Sopenharmony_ci } 10728c2ecf20Sopenharmony_ci} 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci/* Renege some packets to make room for an incoming chunk. */ 10758c2ecf20Sopenharmony_civoid sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk, 10768c2ecf20Sopenharmony_ci gfp_t gfp) 10778c2ecf20Sopenharmony_ci{ 10788c2ecf20Sopenharmony_ci struct sctp_association *asoc = ulpq->asoc; 10798c2ecf20Sopenharmony_ci __u32 freed = 0; 10808c2ecf20Sopenharmony_ci __u16 needed; 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci needed = ntohs(chunk->chunk_hdr->length) - 10838c2ecf20Sopenharmony_ci sizeof(struct sctp_data_chunk); 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci if (skb_queue_empty(&asoc->base.sk->sk_receive_queue)) { 10868c2ecf20Sopenharmony_ci freed = sctp_ulpq_renege_order(ulpq, needed); 10878c2ecf20Sopenharmony_ci if (freed < needed) 10888c2ecf20Sopenharmony_ci freed += sctp_ulpq_renege_frags(ulpq, needed - freed); 10898c2ecf20Sopenharmony_ci } 10908c2ecf20Sopenharmony_ci /* If able to free enough room, accept this chunk. */ 10918c2ecf20Sopenharmony_ci if (sk_rmem_schedule(asoc->base.sk, chunk->skb, needed) && 10928c2ecf20Sopenharmony_ci freed >= needed) { 10938c2ecf20Sopenharmony_ci int retval = sctp_ulpq_tail_data(ulpq, chunk, gfp); 10948c2ecf20Sopenharmony_ci /* 10958c2ecf20Sopenharmony_ci * Enter partial delivery if chunk has not been 10968c2ecf20Sopenharmony_ci * delivered; otherwise, drain the reassembly queue. 10978c2ecf20Sopenharmony_ci */ 10988c2ecf20Sopenharmony_ci if (retval <= 0) 10998c2ecf20Sopenharmony_ci sctp_ulpq_partial_delivery(ulpq, gfp); 11008c2ecf20Sopenharmony_ci else if (retval == 1) 11018c2ecf20Sopenharmony_ci sctp_ulpq_reasm_drain(ulpq); 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci sk_mem_reclaim(asoc->base.sk); 11058c2ecf20Sopenharmony_ci} 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci/* Notify the application if an association is aborted and in 11108c2ecf20Sopenharmony_ci * partial delivery mode. Send up any pending received messages. 11118c2ecf20Sopenharmony_ci */ 11128c2ecf20Sopenharmony_civoid sctp_ulpq_abort_pd(struct sctp_ulpq *ulpq, gfp_t gfp) 11138c2ecf20Sopenharmony_ci{ 11148c2ecf20Sopenharmony_ci struct sctp_ulpevent *ev = NULL; 11158c2ecf20Sopenharmony_ci struct sctp_sock *sp; 11168c2ecf20Sopenharmony_ci struct sock *sk; 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci if (!ulpq->pd_mode) 11198c2ecf20Sopenharmony_ci return; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci sk = ulpq->asoc->base.sk; 11228c2ecf20Sopenharmony_ci sp = sctp_sk(sk); 11238c2ecf20Sopenharmony_ci if (sctp_ulpevent_type_enabled(ulpq->asoc->subscribe, 11248c2ecf20Sopenharmony_ci SCTP_PARTIAL_DELIVERY_EVENT)) 11258c2ecf20Sopenharmony_ci ev = sctp_ulpevent_make_pdapi(ulpq->asoc, 11268c2ecf20Sopenharmony_ci SCTP_PARTIAL_DELIVERY_ABORTED, 11278c2ecf20Sopenharmony_ci 0, 0, 0, gfp); 11288c2ecf20Sopenharmony_ci if (ev) 11298c2ecf20Sopenharmony_ci __skb_queue_tail(&sk->sk_receive_queue, sctp_event2skb(ev)); 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci /* If there is data waiting, send it up the socket now. */ 11328c2ecf20Sopenharmony_ci if ((sctp_ulpq_clear_pd(ulpq) || ev) && !sp->data_ready_signalled) { 11338c2ecf20Sopenharmony_ci sp->data_ready_signalled = 1; 11348c2ecf20Sopenharmony_ci sk->sk_data_ready(sk); 11358c2ecf20Sopenharmony_ci } 11368c2ecf20Sopenharmony_ci} 1137