162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* SCTP kernel implementation 362306a36Sopenharmony_ci * (C) Copyright IBM Corp. 2001, 2004 462306a36Sopenharmony_ci * Copyright (c) 1999-2000 Cisco, Inc. 562306a36Sopenharmony_ci * Copyright (c) 1999-2001 Motorola, Inc. 662306a36Sopenharmony_ci * Copyright (c) 2001 Intel Corp. 762306a36Sopenharmony_ci * Copyright (c) 2001 Nokia, Inc. 862306a36Sopenharmony_ci * Copyright (c) 2001 La Monte H.P. Yarroll 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * This abstraction carries sctp events to the ULP (sockets). 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Please send any bug reports or fixes you make to the 1362306a36Sopenharmony_ci * email address(es): 1462306a36Sopenharmony_ci * lksctp developers <linux-sctp@vger.kernel.org> 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * Written or modified by: 1762306a36Sopenharmony_ci * Jon Grimm <jgrimm@us.ibm.com> 1862306a36Sopenharmony_ci * La Monte H.P. Yarroll <piggy@acm.org> 1962306a36Sopenharmony_ci * Sridhar Samudrala <sri@us.ibm.com> 2062306a36Sopenharmony_ci */ 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include <linux/slab.h> 2362306a36Sopenharmony_ci#include <linux/types.h> 2462306a36Sopenharmony_ci#include <linux/skbuff.h> 2562306a36Sopenharmony_ci#include <net/sock.h> 2662306a36Sopenharmony_ci#include <net/busy_poll.h> 2762306a36Sopenharmony_ci#include <net/sctp/structs.h> 2862306a36Sopenharmony_ci#include <net/sctp/sctp.h> 2962306a36Sopenharmony_ci#include <net/sctp/sm.h> 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* Forward declarations for internal helpers. */ 3262306a36Sopenharmony_cistatic struct sctp_ulpevent *sctp_ulpq_reasm(struct sctp_ulpq *ulpq, 3362306a36Sopenharmony_ci struct sctp_ulpevent *); 3462306a36Sopenharmony_cistatic struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *, 3562306a36Sopenharmony_ci struct sctp_ulpevent *); 3662306a36Sopenharmony_cistatic void sctp_ulpq_reasm_drain(struct sctp_ulpq *ulpq); 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* 1st Level Abstractions */ 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/* Initialize a ULP queue from a block of memory. */ 4162306a36Sopenharmony_civoid sctp_ulpq_init(struct sctp_ulpq *ulpq, struct sctp_association *asoc) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci memset(ulpq, 0, sizeof(struct sctp_ulpq)); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci ulpq->asoc = asoc; 4662306a36Sopenharmony_ci skb_queue_head_init(&ulpq->reasm); 4762306a36Sopenharmony_ci skb_queue_head_init(&ulpq->reasm_uo); 4862306a36Sopenharmony_ci skb_queue_head_init(&ulpq->lobby); 4962306a36Sopenharmony_ci ulpq->pd_mode = 0; 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/* Flush the reassembly and ordering queues. */ 5462306a36Sopenharmony_civoid sctp_ulpq_flush(struct sctp_ulpq *ulpq) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci struct sk_buff *skb; 5762306a36Sopenharmony_ci struct sctp_ulpevent *event; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci while ((skb = __skb_dequeue(&ulpq->lobby)) != NULL) { 6062306a36Sopenharmony_ci event = sctp_skb2event(skb); 6162306a36Sopenharmony_ci sctp_ulpevent_free(event); 6262306a36Sopenharmony_ci } 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci while ((skb = __skb_dequeue(&ulpq->reasm)) != NULL) { 6562306a36Sopenharmony_ci event = sctp_skb2event(skb); 6662306a36Sopenharmony_ci sctp_ulpevent_free(event); 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci while ((skb = __skb_dequeue(&ulpq->reasm_uo)) != NULL) { 7062306a36Sopenharmony_ci event = sctp_skb2event(skb); 7162306a36Sopenharmony_ci sctp_ulpevent_free(event); 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/* Dispose of a ulpqueue. */ 7662306a36Sopenharmony_civoid sctp_ulpq_free(struct sctp_ulpq *ulpq) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci sctp_ulpq_flush(ulpq); 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/* Process an incoming DATA chunk. */ 8262306a36Sopenharmony_ciint sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk, 8362306a36Sopenharmony_ci gfp_t gfp) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci struct sk_buff_head temp; 8662306a36Sopenharmony_ci struct sctp_ulpevent *event; 8762306a36Sopenharmony_ci int event_eor = 0; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci /* Create an event from the incoming chunk. */ 9062306a36Sopenharmony_ci event = sctp_ulpevent_make_rcvmsg(chunk->asoc, chunk, gfp); 9162306a36Sopenharmony_ci if (!event) 9262306a36Sopenharmony_ci return -ENOMEM; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci event->ssn = ntohs(chunk->subh.data_hdr->ssn); 9562306a36Sopenharmony_ci event->ppid = chunk->subh.data_hdr->ppid; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci /* Do reassembly if needed. */ 9862306a36Sopenharmony_ci event = sctp_ulpq_reasm(ulpq, event); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci /* Do ordering if needed. */ 10162306a36Sopenharmony_ci if (event) { 10262306a36Sopenharmony_ci /* Create a temporary list to collect chunks on. */ 10362306a36Sopenharmony_ci skb_queue_head_init(&temp); 10462306a36Sopenharmony_ci __skb_queue_tail(&temp, sctp_event2skb(event)); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci if (event->msg_flags & MSG_EOR) 10762306a36Sopenharmony_ci event = sctp_ulpq_order(ulpq, event); 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci /* Send event to the ULP. 'event' is the sctp_ulpevent for 11162306a36Sopenharmony_ci * very first SKB on the 'temp' list. 11262306a36Sopenharmony_ci */ 11362306a36Sopenharmony_ci if (event) { 11462306a36Sopenharmony_ci event_eor = (event->msg_flags & MSG_EOR) ? 1 : 0; 11562306a36Sopenharmony_ci sctp_ulpq_tail_event(ulpq, &temp); 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci return event_eor; 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci/* Add a new event for propagation to the ULP. */ 12262306a36Sopenharmony_ci/* Clear the partial delivery mode for this socket. Note: This 12362306a36Sopenharmony_ci * assumes that no association is currently in partial delivery mode. 12462306a36Sopenharmony_ci */ 12562306a36Sopenharmony_ciint sctp_clear_pd(struct sock *sk, struct sctp_association *asoc) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci if (atomic_dec_and_test(&sp->pd_mode)) { 13062306a36Sopenharmony_ci /* This means there are no other associations in PD, so 13162306a36Sopenharmony_ci * we can go ahead and clear out the lobby in one shot 13262306a36Sopenharmony_ci */ 13362306a36Sopenharmony_ci if (!skb_queue_empty(&sp->pd_lobby)) { 13462306a36Sopenharmony_ci skb_queue_splice_tail_init(&sp->pd_lobby, 13562306a36Sopenharmony_ci &sk->sk_receive_queue); 13662306a36Sopenharmony_ci return 1; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci } else { 13962306a36Sopenharmony_ci /* There are other associations in PD, so we only need to 14062306a36Sopenharmony_ci * pull stuff out of the lobby that belongs to the 14162306a36Sopenharmony_ci * associations that is exiting PD (all of its notifications 14262306a36Sopenharmony_ci * are posted here). 14362306a36Sopenharmony_ci */ 14462306a36Sopenharmony_ci if (!skb_queue_empty(&sp->pd_lobby) && asoc) { 14562306a36Sopenharmony_ci struct sk_buff *skb, *tmp; 14662306a36Sopenharmony_ci struct sctp_ulpevent *event; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci sctp_skb_for_each(skb, &sp->pd_lobby, tmp) { 14962306a36Sopenharmony_ci event = sctp_skb2event(skb); 15062306a36Sopenharmony_ci if (event->asoc == asoc) { 15162306a36Sopenharmony_ci __skb_unlink(skb, &sp->pd_lobby); 15262306a36Sopenharmony_ci __skb_queue_tail(&sk->sk_receive_queue, 15362306a36Sopenharmony_ci skb); 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci return 0; 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci/* Set the pd_mode on the socket and ulpq */ 16362306a36Sopenharmony_cistatic void sctp_ulpq_set_pd(struct sctp_ulpq *ulpq) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci struct sctp_sock *sp = sctp_sk(ulpq->asoc->base.sk); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci atomic_inc(&sp->pd_mode); 16862306a36Sopenharmony_ci ulpq->pd_mode = 1; 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci/* Clear the pd_mode and restart any pending messages waiting for delivery. */ 17262306a36Sopenharmony_cistatic int sctp_ulpq_clear_pd(struct sctp_ulpq *ulpq) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci ulpq->pd_mode = 0; 17562306a36Sopenharmony_ci sctp_ulpq_reasm_drain(ulpq); 17662306a36Sopenharmony_ci return sctp_clear_pd(ulpq->asoc->base.sk, ulpq->asoc); 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ciint sctp_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sk_buff_head *skb_list) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci struct sock *sk = ulpq->asoc->base.sk; 18262306a36Sopenharmony_ci struct sctp_sock *sp = sctp_sk(sk); 18362306a36Sopenharmony_ci struct sctp_ulpevent *event; 18462306a36Sopenharmony_ci struct sk_buff_head *queue; 18562306a36Sopenharmony_ci struct sk_buff *skb; 18662306a36Sopenharmony_ci int clear_pd = 0; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci skb = __skb_peek(skb_list); 18962306a36Sopenharmony_ci event = sctp_skb2event(skb); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci /* If the socket is just going to throw this away, do not 19262306a36Sopenharmony_ci * even try to deliver it. 19362306a36Sopenharmony_ci */ 19462306a36Sopenharmony_ci if (sk->sk_shutdown & RCV_SHUTDOWN && 19562306a36Sopenharmony_ci (sk->sk_shutdown & SEND_SHUTDOWN || 19662306a36Sopenharmony_ci !sctp_ulpevent_is_notification(event))) 19762306a36Sopenharmony_ci goto out_free; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci if (!sctp_ulpevent_is_notification(event)) { 20062306a36Sopenharmony_ci sk_mark_napi_id(sk, skb); 20162306a36Sopenharmony_ci sk_incoming_cpu_update(sk); 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci /* Check if the user wishes to receive this event. */ 20462306a36Sopenharmony_ci if (!sctp_ulpevent_is_enabled(event, ulpq->asoc->subscribe)) 20562306a36Sopenharmony_ci goto out_free; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci /* If we are in partial delivery mode, post to the lobby until 20862306a36Sopenharmony_ci * partial delivery is cleared, unless, of course _this_ is 20962306a36Sopenharmony_ci * the association the cause of the partial delivery. 21062306a36Sopenharmony_ci */ 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci if (atomic_read(&sp->pd_mode) == 0) { 21362306a36Sopenharmony_ci queue = &sk->sk_receive_queue; 21462306a36Sopenharmony_ci } else { 21562306a36Sopenharmony_ci if (ulpq->pd_mode) { 21662306a36Sopenharmony_ci /* If the association is in partial delivery, we 21762306a36Sopenharmony_ci * need to finish delivering the partially processed 21862306a36Sopenharmony_ci * packet before passing any other data. This is 21962306a36Sopenharmony_ci * because we don't truly support stream interleaving. 22062306a36Sopenharmony_ci */ 22162306a36Sopenharmony_ci if ((event->msg_flags & MSG_NOTIFICATION) || 22262306a36Sopenharmony_ci (SCTP_DATA_NOT_FRAG == 22362306a36Sopenharmony_ci (event->msg_flags & SCTP_DATA_FRAG_MASK))) 22462306a36Sopenharmony_ci queue = &sp->pd_lobby; 22562306a36Sopenharmony_ci else { 22662306a36Sopenharmony_ci clear_pd = event->msg_flags & MSG_EOR; 22762306a36Sopenharmony_ci queue = &sk->sk_receive_queue; 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci } else { 23062306a36Sopenharmony_ci /* 23162306a36Sopenharmony_ci * If fragment interleave is enabled, we 23262306a36Sopenharmony_ci * can queue this to the receive queue instead 23362306a36Sopenharmony_ci * of the lobby. 23462306a36Sopenharmony_ci */ 23562306a36Sopenharmony_ci if (sp->frag_interleave) 23662306a36Sopenharmony_ci queue = &sk->sk_receive_queue; 23762306a36Sopenharmony_ci else 23862306a36Sopenharmony_ci queue = &sp->pd_lobby; 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci } 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci skb_queue_splice_tail_init(skb_list, queue); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci /* Did we just complete partial delivery and need to get 24562306a36Sopenharmony_ci * rolling again? Move pending data to the receive 24662306a36Sopenharmony_ci * queue. 24762306a36Sopenharmony_ci */ 24862306a36Sopenharmony_ci if (clear_pd) 24962306a36Sopenharmony_ci sctp_ulpq_clear_pd(ulpq); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci if (queue == &sk->sk_receive_queue && !sp->data_ready_signalled) { 25262306a36Sopenharmony_ci if (!sock_owned_by_user(sk)) 25362306a36Sopenharmony_ci sp->data_ready_signalled = 1; 25462306a36Sopenharmony_ci sk->sk_data_ready(sk); 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci return 1; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ciout_free: 25962306a36Sopenharmony_ci sctp_queue_purge_ulpevents(skb_list); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci return 0; 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci/* 2nd Level Abstractions */ 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci/* Helper function to store chunks that need to be reassembled. */ 26762306a36Sopenharmony_cistatic void sctp_ulpq_store_reasm(struct sctp_ulpq *ulpq, 26862306a36Sopenharmony_ci struct sctp_ulpevent *event) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci struct sk_buff *pos; 27162306a36Sopenharmony_ci struct sctp_ulpevent *cevent; 27262306a36Sopenharmony_ci __u32 tsn, ctsn; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci tsn = event->tsn; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci /* See if it belongs at the end. */ 27762306a36Sopenharmony_ci pos = skb_peek_tail(&ulpq->reasm); 27862306a36Sopenharmony_ci if (!pos) { 27962306a36Sopenharmony_ci __skb_queue_tail(&ulpq->reasm, sctp_event2skb(event)); 28062306a36Sopenharmony_ci return; 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci /* Short circuit just dropping it at the end. */ 28462306a36Sopenharmony_ci cevent = sctp_skb2event(pos); 28562306a36Sopenharmony_ci ctsn = cevent->tsn; 28662306a36Sopenharmony_ci if (TSN_lt(ctsn, tsn)) { 28762306a36Sopenharmony_ci __skb_queue_tail(&ulpq->reasm, sctp_event2skb(event)); 28862306a36Sopenharmony_ci return; 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci /* Find the right place in this list. We store them by TSN. */ 29262306a36Sopenharmony_ci skb_queue_walk(&ulpq->reasm, pos) { 29362306a36Sopenharmony_ci cevent = sctp_skb2event(pos); 29462306a36Sopenharmony_ci ctsn = cevent->tsn; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci if (TSN_lt(tsn, ctsn)) 29762306a36Sopenharmony_ci break; 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci /* Insert before pos. */ 30162306a36Sopenharmony_ci __skb_queue_before(&ulpq->reasm, pos, sctp_event2skb(event)); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci/* Helper function to return an event corresponding to the reassembled 30662306a36Sopenharmony_ci * datagram. 30762306a36Sopenharmony_ci * This routine creates a re-assembled skb given the first and last skb's 30862306a36Sopenharmony_ci * as stored in the reassembly queue. The skb's may be non-linear if the sctp 30962306a36Sopenharmony_ci * payload was fragmented on the way and ip had to reassemble them. 31062306a36Sopenharmony_ci * We add the rest of skb's to the first skb's fraglist. 31162306a36Sopenharmony_ci */ 31262306a36Sopenharmony_cistruct sctp_ulpevent *sctp_make_reassembled_event(struct net *net, 31362306a36Sopenharmony_ci struct sk_buff_head *queue, 31462306a36Sopenharmony_ci struct sk_buff *f_frag, 31562306a36Sopenharmony_ci struct sk_buff *l_frag) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci struct sk_buff *pos; 31862306a36Sopenharmony_ci struct sk_buff *new = NULL; 31962306a36Sopenharmony_ci struct sctp_ulpevent *event; 32062306a36Sopenharmony_ci struct sk_buff *pnext, *last; 32162306a36Sopenharmony_ci struct sk_buff *list = skb_shinfo(f_frag)->frag_list; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci /* Store the pointer to the 2nd skb */ 32462306a36Sopenharmony_ci if (f_frag == l_frag) 32562306a36Sopenharmony_ci pos = NULL; 32662306a36Sopenharmony_ci else 32762306a36Sopenharmony_ci pos = f_frag->next; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci /* Get the last skb in the f_frag's frag_list if present. */ 33062306a36Sopenharmony_ci for (last = list; list; last = list, list = list->next) 33162306a36Sopenharmony_ci ; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci /* Add the list of remaining fragments to the first fragments 33462306a36Sopenharmony_ci * frag_list. 33562306a36Sopenharmony_ci */ 33662306a36Sopenharmony_ci if (last) 33762306a36Sopenharmony_ci last->next = pos; 33862306a36Sopenharmony_ci else { 33962306a36Sopenharmony_ci if (skb_cloned(f_frag)) { 34062306a36Sopenharmony_ci /* This is a cloned skb, we can't just modify 34162306a36Sopenharmony_ci * the frag_list. We need a new skb to do that. 34262306a36Sopenharmony_ci * Instead of calling skb_unshare(), we'll do it 34362306a36Sopenharmony_ci * ourselves since we need to delay the free. 34462306a36Sopenharmony_ci */ 34562306a36Sopenharmony_ci new = skb_copy(f_frag, GFP_ATOMIC); 34662306a36Sopenharmony_ci if (!new) 34762306a36Sopenharmony_ci return NULL; /* try again later */ 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci sctp_skb_set_owner_r(new, f_frag->sk); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci skb_shinfo(new)->frag_list = pos; 35262306a36Sopenharmony_ci } else 35362306a36Sopenharmony_ci skb_shinfo(f_frag)->frag_list = pos; 35462306a36Sopenharmony_ci } 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci /* Remove the first fragment from the reassembly queue. */ 35762306a36Sopenharmony_ci __skb_unlink(f_frag, queue); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci /* if we did unshare, then free the old skb and re-assign */ 36062306a36Sopenharmony_ci if (new) { 36162306a36Sopenharmony_ci kfree_skb(f_frag); 36262306a36Sopenharmony_ci f_frag = new; 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci while (pos) { 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci pnext = pos->next; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci /* Update the len and data_len fields of the first fragment. */ 37062306a36Sopenharmony_ci f_frag->len += pos->len; 37162306a36Sopenharmony_ci f_frag->data_len += pos->len; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci /* Remove the fragment from the reassembly queue. */ 37462306a36Sopenharmony_ci __skb_unlink(pos, queue); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci /* Break if we have reached the last fragment. */ 37762306a36Sopenharmony_ci if (pos == l_frag) 37862306a36Sopenharmony_ci break; 37962306a36Sopenharmony_ci pos->next = pnext; 38062306a36Sopenharmony_ci pos = pnext; 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci event = sctp_skb2event(f_frag); 38462306a36Sopenharmony_ci SCTP_INC_STATS(net, SCTP_MIB_REASMUSRMSGS); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci return event; 38762306a36Sopenharmony_ci} 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci/* Helper function to check if an incoming chunk has filled up the last 39162306a36Sopenharmony_ci * missing fragment in a SCTP datagram and return the corresponding event. 39262306a36Sopenharmony_ci */ 39362306a36Sopenharmony_cistatic struct sctp_ulpevent *sctp_ulpq_retrieve_reassembled(struct sctp_ulpq *ulpq) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci struct sk_buff *pos; 39662306a36Sopenharmony_ci struct sctp_ulpevent *cevent; 39762306a36Sopenharmony_ci struct sk_buff *first_frag = NULL; 39862306a36Sopenharmony_ci __u32 ctsn, next_tsn; 39962306a36Sopenharmony_ci struct sctp_ulpevent *retval = NULL; 40062306a36Sopenharmony_ci struct sk_buff *pd_first = NULL; 40162306a36Sopenharmony_ci struct sk_buff *pd_last = NULL; 40262306a36Sopenharmony_ci size_t pd_len = 0; 40362306a36Sopenharmony_ci struct sctp_association *asoc; 40462306a36Sopenharmony_ci u32 pd_point; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci /* Initialized to 0 just to avoid compiler warning message. Will 40762306a36Sopenharmony_ci * never be used with this value. It is referenced only after it 40862306a36Sopenharmony_ci * is set when we find the first fragment of a message. 40962306a36Sopenharmony_ci */ 41062306a36Sopenharmony_ci next_tsn = 0; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci /* The chunks are held in the reasm queue sorted by TSN. 41362306a36Sopenharmony_ci * Walk through the queue sequentially and look for a sequence of 41462306a36Sopenharmony_ci * fragmented chunks that complete a datagram. 41562306a36Sopenharmony_ci * 'first_frag' and next_tsn are reset when we find a chunk which 41662306a36Sopenharmony_ci * is the first fragment of a datagram. Once these 2 fields are set 41762306a36Sopenharmony_ci * we expect to find the remaining middle fragments and the last 41862306a36Sopenharmony_ci * fragment in order. If not, first_frag is reset to NULL and we 41962306a36Sopenharmony_ci * start the next pass when we find another first fragment. 42062306a36Sopenharmony_ci * 42162306a36Sopenharmony_ci * There is a potential to do partial delivery if user sets 42262306a36Sopenharmony_ci * SCTP_PARTIAL_DELIVERY_POINT option. Lets count some things here 42362306a36Sopenharmony_ci * to see if can do PD. 42462306a36Sopenharmony_ci */ 42562306a36Sopenharmony_ci skb_queue_walk(&ulpq->reasm, pos) { 42662306a36Sopenharmony_ci cevent = sctp_skb2event(pos); 42762306a36Sopenharmony_ci ctsn = cevent->tsn; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) { 43062306a36Sopenharmony_ci case SCTP_DATA_FIRST_FRAG: 43162306a36Sopenharmony_ci /* If this "FIRST_FRAG" is the first 43262306a36Sopenharmony_ci * element in the queue, then count it towards 43362306a36Sopenharmony_ci * possible PD. 43462306a36Sopenharmony_ci */ 43562306a36Sopenharmony_ci if (skb_queue_is_first(&ulpq->reasm, pos)) { 43662306a36Sopenharmony_ci pd_first = pos; 43762306a36Sopenharmony_ci pd_last = pos; 43862306a36Sopenharmony_ci pd_len = pos->len; 43962306a36Sopenharmony_ci } else { 44062306a36Sopenharmony_ci pd_first = NULL; 44162306a36Sopenharmony_ci pd_last = NULL; 44262306a36Sopenharmony_ci pd_len = 0; 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci first_frag = pos; 44662306a36Sopenharmony_ci next_tsn = ctsn + 1; 44762306a36Sopenharmony_ci break; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci case SCTP_DATA_MIDDLE_FRAG: 45062306a36Sopenharmony_ci if ((first_frag) && (ctsn == next_tsn)) { 45162306a36Sopenharmony_ci next_tsn++; 45262306a36Sopenharmony_ci if (pd_first) { 45362306a36Sopenharmony_ci pd_last = pos; 45462306a36Sopenharmony_ci pd_len += pos->len; 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci } else 45762306a36Sopenharmony_ci first_frag = NULL; 45862306a36Sopenharmony_ci break; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci case SCTP_DATA_LAST_FRAG: 46162306a36Sopenharmony_ci if (first_frag && (ctsn == next_tsn)) 46262306a36Sopenharmony_ci goto found; 46362306a36Sopenharmony_ci else 46462306a36Sopenharmony_ci first_frag = NULL; 46562306a36Sopenharmony_ci break; 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci } 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci asoc = ulpq->asoc; 47062306a36Sopenharmony_ci if (pd_first) { 47162306a36Sopenharmony_ci /* Make sure we can enter partial deliver. 47262306a36Sopenharmony_ci * We can trigger partial delivery only if framgent 47362306a36Sopenharmony_ci * interleave is set, or the socket is not already 47462306a36Sopenharmony_ci * in partial delivery. 47562306a36Sopenharmony_ci */ 47662306a36Sopenharmony_ci if (!sctp_sk(asoc->base.sk)->frag_interleave && 47762306a36Sopenharmony_ci atomic_read(&sctp_sk(asoc->base.sk)->pd_mode)) 47862306a36Sopenharmony_ci goto done; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci cevent = sctp_skb2event(pd_first); 48162306a36Sopenharmony_ci pd_point = sctp_sk(asoc->base.sk)->pd_point; 48262306a36Sopenharmony_ci if (pd_point && pd_point <= pd_len) { 48362306a36Sopenharmony_ci retval = sctp_make_reassembled_event(asoc->base.net, 48462306a36Sopenharmony_ci &ulpq->reasm, 48562306a36Sopenharmony_ci pd_first, pd_last); 48662306a36Sopenharmony_ci if (retval) 48762306a36Sopenharmony_ci sctp_ulpq_set_pd(ulpq); 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_cidone: 49162306a36Sopenharmony_ci return retval; 49262306a36Sopenharmony_cifound: 49362306a36Sopenharmony_ci retval = sctp_make_reassembled_event(ulpq->asoc->base.net, 49462306a36Sopenharmony_ci &ulpq->reasm, first_frag, pos); 49562306a36Sopenharmony_ci if (retval) 49662306a36Sopenharmony_ci retval->msg_flags |= MSG_EOR; 49762306a36Sopenharmony_ci goto done; 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci/* Retrieve the next set of fragments of a partial message. */ 50162306a36Sopenharmony_cistatic struct sctp_ulpevent *sctp_ulpq_retrieve_partial(struct sctp_ulpq *ulpq) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci struct sk_buff *pos, *last_frag, *first_frag; 50462306a36Sopenharmony_ci struct sctp_ulpevent *cevent; 50562306a36Sopenharmony_ci __u32 ctsn, next_tsn; 50662306a36Sopenharmony_ci int is_last; 50762306a36Sopenharmony_ci struct sctp_ulpevent *retval; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci /* The chunks are held in the reasm queue sorted by TSN. 51062306a36Sopenharmony_ci * Walk through the queue sequentially and look for the first 51162306a36Sopenharmony_ci * sequence of fragmented chunks. 51262306a36Sopenharmony_ci */ 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci if (skb_queue_empty(&ulpq->reasm)) 51562306a36Sopenharmony_ci return NULL; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci last_frag = first_frag = NULL; 51862306a36Sopenharmony_ci retval = NULL; 51962306a36Sopenharmony_ci next_tsn = 0; 52062306a36Sopenharmony_ci is_last = 0; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci skb_queue_walk(&ulpq->reasm, pos) { 52362306a36Sopenharmony_ci cevent = sctp_skb2event(pos); 52462306a36Sopenharmony_ci ctsn = cevent->tsn; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) { 52762306a36Sopenharmony_ci case SCTP_DATA_FIRST_FRAG: 52862306a36Sopenharmony_ci if (!first_frag) 52962306a36Sopenharmony_ci return NULL; 53062306a36Sopenharmony_ci goto done; 53162306a36Sopenharmony_ci case SCTP_DATA_MIDDLE_FRAG: 53262306a36Sopenharmony_ci if (!first_frag) { 53362306a36Sopenharmony_ci first_frag = pos; 53462306a36Sopenharmony_ci next_tsn = ctsn + 1; 53562306a36Sopenharmony_ci last_frag = pos; 53662306a36Sopenharmony_ci } else if (next_tsn == ctsn) { 53762306a36Sopenharmony_ci next_tsn++; 53862306a36Sopenharmony_ci last_frag = pos; 53962306a36Sopenharmony_ci } else 54062306a36Sopenharmony_ci goto done; 54162306a36Sopenharmony_ci break; 54262306a36Sopenharmony_ci case SCTP_DATA_LAST_FRAG: 54362306a36Sopenharmony_ci if (!first_frag) 54462306a36Sopenharmony_ci first_frag = pos; 54562306a36Sopenharmony_ci else if (ctsn != next_tsn) 54662306a36Sopenharmony_ci goto done; 54762306a36Sopenharmony_ci last_frag = pos; 54862306a36Sopenharmony_ci is_last = 1; 54962306a36Sopenharmony_ci goto done; 55062306a36Sopenharmony_ci default: 55162306a36Sopenharmony_ci return NULL; 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci /* We have the reassembled event. There is no need to look 55662306a36Sopenharmony_ci * further. 55762306a36Sopenharmony_ci */ 55862306a36Sopenharmony_cidone: 55962306a36Sopenharmony_ci retval = sctp_make_reassembled_event(ulpq->asoc->base.net, &ulpq->reasm, 56062306a36Sopenharmony_ci first_frag, last_frag); 56162306a36Sopenharmony_ci if (retval && is_last) 56262306a36Sopenharmony_ci retval->msg_flags |= MSG_EOR; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci return retval; 56562306a36Sopenharmony_ci} 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci/* Helper function to reassemble chunks. Hold chunks on the reasm queue that 56962306a36Sopenharmony_ci * need reassembling. 57062306a36Sopenharmony_ci */ 57162306a36Sopenharmony_cistatic struct sctp_ulpevent *sctp_ulpq_reasm(struct sctp_ulpq *ulpq, 57262306a36Sopenharmony_ci struct sctp_ulpevent *event) 57362306a36Sopenharmony_ci{ 57462306a36Sopenharmony_ci struct sctp_ulpevent *retval = NULL; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci /* Check if this is part of a fragmented message. */ 57762306a36Sopenharmony_ci if (SCTP_DATA_NOT_FRAG == (event->msg_flags & SCTP_DATA_FRAG_MASK)) { 57862306a36Sopenharmony_ci event->msg_flags |= MSG_EOR; 57962306a36Sopenharmony_ci return event; 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci sctp_ulpq_store_reasm(ulpq, event); 58362306a36Sopenharmony_ci if (!ulpq->pd_mode) 58462306a36Sopenharmony_ci retval = sctp_ulpq_retrieve_reassembled(ulpq); 58562306a36Sopenharmony_ci else { 58662306a36Sopenharmony_ci __u32 ctsn, ctsnap; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci /* Do not even bother unless this is the next tsn to 58962306a36Sopenharmony_ci * be delivered. 59062306a36Sopenharmony_ci */ 59162306a36Sopenharmony_ci ctsn = event->tsn; 59262306a36Sopenharmony_ci ctsnap = sctp_tsnmap_get_ctsn(&ulpq->asoc->peer.tsn_map); 59362306a36Sopenharmony_ci if (TSN_lte(ctsn, ctsnap)) 59462306a36Sopenharmony_ci retval = sctp_ulpq_retrieve_partial(ulpq); 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci return retval; 59862306a36Sopenharmony_ci} 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci/* Retrieve the first part (sequential fragments) for partial delivery. */ 60162306a36Sopenharmony_cistatic struct sctp_ulpevent *sctp_ulpq_retrieve_first(struct sctp_ulpq *ulpq) 60262306a36Sopenharmony_ci{ 60362306a36Sopenharmony_ci struct sk_buff *pos, *last_frag, *first_frag; 60462306a36Sopenharmony_ci struct sctp_ulpevent *cevent; 60562306a36Sopenharmony_ci __u32 ctsn, next_tsn; 60662306a36Sopenharmony_ci struct sctp_ulpevent *retval; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci /* The chunks are held in the reasm queue sorted by TSN. 60962306a36Sopenharmony_ci * Walk through the queue sequentially and look for a sequence of 61062306a36Sopenharmony_ci * fragmented chunks that start a datagram. 61162306a36Sopenharmony_ci */ 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci if (skb_queue_empty(&ulpq->reasm)) 61462306a36Sopenharmony_ci return NULL; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci last_frag = first_frag = NULL; 61762306a36Sopenharmony_ci retval = NULL; 61862306a36Sopenharmony_ci next_tsn = 0; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci skb_queue_walk(&ulpq->reasm, pos) { 62162306a36Sopenharmony_ci cevent = sctp_skb2event(pos); 62262306a36Sopenharmony_ci ctsn = cevent->tsn; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) { 62562306a36Sopenharmony_ci case SCTP_DATA_FIRST_FRAG: 62662306a36Sopenharmony_ci if (!first_frag) { 62762306a36Sopenharmony_ci first_frag = pos; 62862306a36Sopenharmony_ci next_tsn = ctsn + 1; 62962306a36Sopenharmony_ci last_frag = pos; 63062306a36Sopenharmony_ci } else 63162306a36Sopenharmony_ci goto done; 63262306a36Sopenharmony_ci break; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci case SCTP_DATA_MIDDLE_FRAG: 63562306a36Sopenharmony_ci if (!first_frag) 63662306a36Sopenharmony_ci return NULL; 63762306a36Sopenharmony_ci if (ctsn == next_tsn) { 63862306a36Sopenharmony_ci next_tsn++; 63962306a36Sopenharmony_ci last_frag = pos; 64062306a36Sopenharmony_ci } else 64162306a36Sopenharmony_ci goto done; 64262306a36Sopenharmony_ci break; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci case SCTP_DATA_LAST_FRAG: 64562306a36Sopenharmony_ci if (!first_frag) 64662306a36Sopenharmony_ci return NULL; 64762306a36Sopenharmony_ci else 64862306a36Sopenharmony_ci goto done; 64962306a36Sopenharmony_ci break; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci default: 65262306a36Sopenharmony_ci return NULL; 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci } 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci /* We have the reassembled event. There is no need to look 65762306a36Sopenharmony_ci * further. 65862306a36Sopenharmony_ci */ 65962306a36Sopenharmony_cidone: 66062306a36Sopenharmony_ci retval = sctp_make_reassembled_event(ulpq->asoc->base.net, &ulpq->reasm, 66162306a36Sopenharmony_ci first_frag, last_frag); 66262306a36Sopenharmony_ci return retval; 66362306a36Sopenharmony_ci} 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci/* 66662306a36Sopenharmony_ci * Flush out stale fragments from the reassembly queue when processing 66762306a36Sopenharmony_ci * a Forward TSN. 66862306a36Sopenharmony_ci * 66962306a36Sopenharmony_ci * RFC 3758, Section 3.6 67062306a36Sopenharmony_ci * 67162306a36Sopenharmony_ci * After receiving and processing a FORWARD TSN, the data receiver MUST 67262306a36Sopenharmony_ci * take cautions in updating its re-assembly queue. The receiver MUST 67362306a36Sopenharmony_ci * remove any partially reassembled message, which is still missing one 67462306a36Sopenharmony_ci * or more TSNs earlier than or equal to the new cumulative TSN point. 67562306a36Sopenharmony_ci * In the event that the receiver has invoked the partial delivery API, 67662306a36Sopenharmony_ci * a notification SHOULD also be generated to inform the upper layer API 67762306a36Sopenharmony_ci * that the message being partially delivered will NOT be completed. 67862306a36Sopenharmony_ci */ 67962306a36Sopenharmony_civoid sctp_ulpq_reasm_flushtsn(struct sctp_ulpq *ulpq, __u32 fwd_tsn) 68062306a36Sopenharmony_ci{ 68162306a36Sopenharmony_ci struct sk_buff *pos, *tmp; 68262306a36Sopenharmony_ci struct sctp_ulpevent *event; 68362306a36Sopenharmony_ci __u32 tsn; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci if (skb_queue_empty(&ulpq->reasm)) 68662306a36Sopenharmony_ci return; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci skb_queue_walk_safe(&ulpq->reasm, pos, tmp) { 68962306a36Sopenharmony_ci event = sctp_skb2event(pos); 69062306a36Sopenharmony_ci tsn = event->tsn; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci /* Since the entire message must be abandoned by the 69362306a36Sopenharmony_ci * sender (item A3 in Section 3.5, RFC 3758), we can 69462306a36Sopenharmony_ci * free all fragments on the list that are less then 69562306a36Sopenharmony_ci * or equal to ctsn_point 69662306a36Sopenharmony_ci */ 69762306a36Sopenharmony_ci if (TSN_lte(tsn, fwd_tsn)) { 69862306a36Sopenharmony_ci __skb_unlink(pos, &ulpq->reasm); 69962306a36Sopenharmony_ci sctp_ulpevent_free(event); 70062306a36Sopenharmony_ci } else 70162306a36Sopenharmony_ci break; 70262306a36Sopenharmony_ci } 70362306a36Sopenharmony_ci} 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci/* 70662306a36Sopenharmony_ci * Drain the reassembly queue. If we just cleared parted delivery, it 70762306a36Sopenharmony_ci * is possible that the reassembly queue will contain already reassembled 70862306a36Sopenharmony_ci * messages. Retrieve any such messages and give them to the user. 70962306a36Sopenharmony_ci */ 71062306a36Sopenharmony_cistatic void sctp_ulpq_reasm_drain(struct sctp_ulpq *ulpq) 71162306a36Sopenharmony_ci{ 71262306a36Sopenharmony_ci struct sctp_ulpevent *event = NULL; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci if (skb_queue_empty(&ulpq->reasm)) 71562306a36Sopenharmony_ci return; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci while ((event = sctp_ulpq_retrieve_reassembled(ulpq)) != NULL) { 71862306a36Sopenharmony_ci struct sk_buff_head temp; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci skb_queue_head_init(&temp); 72162306a36Sopenharmony_ci __skb_queue_tail(&temp, sctp_event2skb(event)); 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci /* Do ordering if needed. */ 72462306a36Sopenharmony_ci if (event->msg_flags & MSG_EOR) 72562306a36Sopenharmony_ci event = sctp_ulpq_order(ulpq, event); 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci /* Send event to the ULP. 'event' is the 72862306a36Sopenharmony_ci * sctp_ulpevent for very first SKB on the temp' list. 72962306a36Sopenharmony_ci */ 73062306a36Sopenharmony_ci if (event) 73162306a36Sopenharmony_ci sctp_ulpq_tail_event(ulpq, &temp); 73262306a36Sopenharmony_ci } 73362306a36Sopenharmony_ci} 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci/* Helper function to gather skbs that have possibly become 73762306a36Sopenharmony_ci * ordered by an incoming chunk. 73862306a36Sopenharmony_ci */ 73962306a36Sopenharmony_cistatic void sctp_ulpq_retrieve_ordered(struct sctp_ulpq *ulpq, 74062306a36Sopenharmony_ci struct sctp_ulpevent *event) 74162306a36Sopenharmony_ci{ 74262306a36Sopenharmony_ci struct sk_buff_head *event_list; 74362306a36Sopenharmony_ci struct sk_buff *pos, *tmp; 74462306a36Sopenharmony_ci struct sctp_ulpevent *cevent; 74562306a36Sopenharmony_ci struct sctp_stream *stream; 74662306a36Sopenharmony_ci __u16 sid, csid, cssn; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci sid = event->stream; 74962306a36Sopenharmony_ci stream = &ulpq->asoc->stream; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci event_list = (struct sk_buff_head *) sctp_event2skb(event)->prev; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci /* We are holding the chunks by stream, by SSN. */ 75462306a36Sopenharmony_ci sctp_skb_for_each(pos, &ulpq->lobby, tmp) { 75562306a36Sopenharmony_ci cevent = (struct sctp_ulpevent *) pos->cb; 75662306a36Sopenharmony_ci csid = cevent->stream; 75762306a36Sopenharmony_ci cssn = cevent->ssn; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci /* Have we gone too far? */ 76062306a36Sopenharmony_ci if (csid > sid) 76162306a36Sopenharmony_ci break; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci /* Have we not gone far enough? */ 76462306a36Sopenharmony_ci if (csid < sid) 76562306a36Sopenharmony_ci continue; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci if (cssn != sctp_ssn_peek(stream, in, sid)) 76862306a36Sopenharmony_ci break; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci /* Found it, so mark in the stream. */ 77162306a36Sopenharmony_ci sctp_ssn_next(stream, in, sid); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci __skb_unlink(pos, &ulpq->lobby); 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci /* Attach all gathered skbs to the event. */ 77662306a36Sopenharmony_ci __skb_queue_tail(event_list, pos); 77762306a36Sopenharmony_ci } 77862306a36Sopenharmony_ci} 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci/* Helper function to store chunks needing ordering. */ 78162306a36Sopenharmony_cistatic void sctp_ulpq_store_ordered(struct sctp_ulpq *ulpq, 78262306a36Sopenharmony_ci struct sctp_ulpevent *event) 78362306a36Sopenharmony_ci{ 78462306a36Sopenharmony_ci struct sk_buff *pos; 78562306a36Sopenharmony_ci struct sctp_ulpevent *cevent; 78662306a36Sopenharmony_ci __u16 sid, csid; 78762306a36Sopenharmony_ci __u16 ssn, cssn; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci pos = skb_peek_tail(&ulpq->lobby); 79062306a36Sopenharmony_ci if (!pos) { 79162306a36Sopenharmony_ci __skb_queue_tail(&ulpq->lobby, sctp_event2skb(event)); 79262306a36Sopenharmony_ci return; 79362306a36Sopenharmony_ci } 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci sid = event->stream; 79662306a36Sopenharmony_ci ssn = event->ssn; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci cevent = (struct sctp_ulpevent *) pos->cb; 79962306a36Sopenharmony_ci csid = cevent->stream; 80062306a36Sopenharmony_ci cssn = cevent->ssn; 80162306a36Sopenharmony_ci if (sid > csid) { 80262306a36Sopenharmony_ci __skb_queue_tail(&ulpq->lobby, sctp_event2skb(event)); 80362306a36Sopenharmony_ci return; 80462306a36Sopenharmony_ci } 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci if ((sid == csid) && SSN_lt(cssn, ssn)) { 80762306a36Sopenharmony_ci __skb_queue_tail(&ulpq->lobby, sctp_event2skb(event)); 80862306a36Sopenharmony_ci return; 80962306a36Sopenharmony_ci } 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci /* Find the right place in this list. We store them by 81262306a36Sopenharmony_ci * stream ID and then by SSN. 81362306a36Sopenharmony_ci */ 81462306a36Sopenharmony_ci skb_queue_walk(&ulpq->lobby, pos) { 81562306a36Sopenharmony_ci cevent = (struct sctp_ulpevent *) pos->cb; 81662306a36Sopenharmony_ci csid = cevent->stream; 81762306a36Sopenharmony_ci cssn = cevent->ssn; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci if (csid > sid) 82062306a36Sopenharmony_ci break; 82162306a36Sopenharmony_ci if (csid == sid && SSN_lt(ssn, cssn)) 82262306a36Sopenharmony_ci break; 82362306a36Sopenharmony_ci } 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci /* Insert before pos. */ 82762306a36Sopenharmony_ci __skb_queue_before(&ulpq->lobby, pos, sctp_event2skb(event)); 82862306a36Sopenharmony_ci} 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_cistatic struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *ulpq, 83162306a36Sopenharmony_ci struct sctp_ulpevent *event) 83262306a36Sopenharmony_ci{ 83362306a36Sopenharmony_ci __u16 sid, ssn; 83462306a36Sopenharmony_ci struct sctp_stream *stream; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci /* Check if this message needs ordering. */ 83762306a36Sopenharmony_ci if (event->msg_flags & SCTP_DATA_UNORDERED) 83862306a36Sopenharmony_ci return event; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci /* Note: The stream ID must be verified before this routine. */ 84162306a36Sopenharmony_ci sid = event->stream; 84262306a36Sopenharmony_ci ssn = event->ssn; 84362306a36Sopenharmony_ci stream = &ulpq->asoc->stream; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci /* Is this the expected SSN for this stream ID? */ 84662306a36Sopenharmony_ci if (ssn != sctp_ssn_peek(stream, in, sid)) { 84762306a36Sopenharmony_ci /* We've received something out of order, so find where it 84862306a36Sopenharmony_ci * needs to be placed. We order by stream and then by SSN. 84962306a36Sopenharmony_ci */ 85062306a36Sopenharmony_ci sctp_ulpq_store_ordered(ulpq, event); 85162306a36Sopenharmony_ci return NULL; 85262306a36Sopenharmony_ci } 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci /* Mark that the next chunk has been found. */ 85562306a36Sopenharmony_ci sctp_ssn_next(stream, in, sid); 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci /* Go find any other chunks that were waiting for 85862306a36Sopenharmony_ci * ordering. 85962306a36Sopenharmony_ci */ 86062306a36Sopenharmony_ci sctp_ulpq_retrieve_ordered(ulpq, event); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci return event; 86362306a36Sopenharmony_ci} 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci/* Helper function to gather skbs that have possibly become 86662306a36Sopenharmony_ci * ordered by forward tsn skipping their dependencies. 86762306a36Sopenharmony_ci */ 86862306a36Sopenharmony_cistatic void sctp_ulpq_reap_ordered(struct sctp_ulpq *ulpq, __u16 sid) 86962306a36Sopenharmony_ci{ 87062306a36Sopenharmony_ci struct sk_buff *pos, *tmp; 87162306a36Sopenharmony_ci struct sctp_ulpevent *cevent; 87262306a36Sopenharmony_ci struct sctp_ulpevent *event; 87362306a36Sopenharmony_ci struct sctp_stream *stream; 87462306a36Sopenharmony_ci struct sk_buff_head temp; 87562306a36Sopenharmony_ci struct sk_buff_head *lobby = &ulpq->lobby; 87662306a36Sopenharmony_ci __u16 csid, cssn; 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci stream = &ulpq->asoc->stream; 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci /* We are holding the chunks by stream, by SSN. */ 88162306a36Sopenharmony_ci skb_queue_head_init(&temp); 88262306a36Sopenharmony_ci event = NULL; 88362306a36Sopenharmony_ci sctp_skb_for_each(pos, lobby, tmp) { 88462306a36Sopenharmony_ci cevent = (struct sctp_ulpevent *) pos->cb; 88562306a36Sopenharmony_ci csid = cevent->stream; 88662306a36Sopenharmony_ci cssn = cevent->ssn; 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci /* Have we gone too far? */ 88962306a36Sopenharmony_ci if (csid > sid) 89062306a36Sopenharmony_ci break; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci /* Have we not gone far enough? */ 89362306a36Sopenharmony_ci if (csid < sid) 89462306a36Sopenharmony_ci continue; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci /* see if this ssn has been marked by skipping */ 89762306a36Sopenharmony_ci if (!SSN_lt(cssn, sctp_ssn_peek(stream, in, csid))) 89862306a36Sopenharmony_ci break; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci __skb_unlink(pos, lobby); 90162306a36Sopenharmony_ci if (!event) 90262306a36Sopenharmony_ci /* Create a temporary list to collect chunks on. */ 90362306a36Sopenharmony_ci event = sctp_skb2event(pos); 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci /* Attach all gathered skbs to the event. */ 90662306a36Sopenharmony_ci __skb_queue_tail(&temp, pos); 90762306a36Sopenharmony_ci } 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci /* If we didn't reap any data, see if the next expected SSN 91062306a36Sopenharmony_ci * is next on the queue and if so, use that. 91162306a36Sopenharmony_ci */ 91262306a36Sopenharmony_ci if (event == NULL && pos != (struct sk_buff *)lobby) { 91362306a36Sopenharmony_ci cevent = (struct sctp_ulpevent *) pos->cb; 91462306a36Sopenharmony_ci csid = cevent->stream; 91562306a36Sopenharmony_ci cssn = cevent->ssn; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci if (csid == sid && cssn == sctp_ssn_peek(stream, in, csid)) { 91862306a36Sopenharmony_ci sctp_ssn_next(stream, in, csid); 91962306a36Sopenharmony_ci __skb_unlink(pos, lobby); 92062306a36Sopenharmony_ci __skb_queue_tail(&temp, pos); 92162306a36Sopenharmony_ci event = sctp_skb2event(pos); 92262306a36Sopenharmony_ci } 92362306a36Sopenharmony_ci } 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci /* Send event to the ULP. 'event' is the sctp_ulpevent for 92662306a36Sopenharmony_ci * very first SKB on the 'temp' list. 92762306a36Sopenharmony_ci */ 92862306a36Sopenharmony_ci if (event) { 92962306a36Sopenharmony_ci /* see if we have more ordered that we can deliver */ 93062306a36Sopenharmony_ci sctp_ulpq_retrieve_ordered(ulpq, event); 93162306a36Sopenharmony_ci sctp_ulpq_tail_event(ulpq, &temp); 93262306a36Sopenharmony_ci } 93362306a36Sopenharmony_ci} 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci/* Skip over an SSN. This is used during the processing of 93662306a36Sopenharmony_ci * Forwared TSN chunk to skip over the abandoned ordered data 93762306a36Sopenharmony_ci */ 93862306a36Sopenharmony_civoid sctp_ulpq_skip(struct sctp_ulpq *ulpq, __u16 sid, __u16 ssn) 93962306a36Sopenharmony_ci{ 94062306a36Sopenharmony_ci struct sctp_stream *stream; 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci /* Note: The stream ID must be verified before this routine. */ 94362306a36Sopenharmony_ci stream = &ulpq->asoc->stream; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci /* Is this an old SSN? If so ignore. */ 94662306a36Sopenharmony_ci if (SSN_lt(ssn, sctp_ssn_peek(stream, in, sid))) 94762306a36Sopenharmony_ci return; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci /* Mark that we are no longer expecting this SSN or lower. */ 95062306a36Sopenharmony_ci sctp_ssn_skip(stream, in, sid, ssn); 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci /* Go find any other chunks that were waiting for 95362306a36Sopenharmony_ci * ordering and deliver them if needed. 95462306a36Sopenharmony_ci */ 95562306a36Sopenharmony_ci sctp_ulpq_reap_ordered(ulpq, sid); 95662306a36Sopenharmony_ci} 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci__u16 sctp_ulpq_renege_list(struct sctp_ulpq *ulpq, struct sk_buff_head *list, 95962306a36Sopenharmony_ci __u16 needed) 96062306a36Sopenharmony_ci{ 96162306a36Sopenharmony_ci __u16 freed = 0; 96262306a36Sopenharmony_ci __u32 tsn, last_tsn; 96362306a36Sopenharmony_ci struct sk_buff *skb, *flist, *last; 96462306a36Sopenharmony_ci struct sctp_ulpevent *event; 96562306a36Sopenharmony_ci struct sctp_tsnmap *tsnmap; 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci tsnmap = &ulpq->asoc->peer.tsn_map; 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci while ((skb = skb_peek_tail(list)) != NULL) { 97062306a36Sopenharmony_ci event = sctp_skb2event(skb); 97162306a36Sopenharmony_ci tsn = event->tsn; 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci /* Don't renege below the Cumulative TSN ACK Point. */ 97462306a36Sopenharmony_ci if (TSN_lte(tsn, sctp_tsnmap_get_ctsn(tsnmap))) 97562306a36Sopenharmony_ci break; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci /* Events in ordering queue may have multiple fragments 97862306a36Sopenharmony_ci * corresponding to additional TSNs. Sum the total 97962306a36Sopenharmony_ci * freed space; find the last TSN. 98062306a36Sopenharmony_ci */ 98162306a36Sopenharmony_ci freed += skb_headlen(skb); 98262306a36Sopenharmony_ci flist = skb_shinfo(skb)->frag_list; 98362306a36Sopenharmony_ci for (last = flist; flist; flist = flist->next) { 98462306a36Sopenharmony_ci last = flist; 98562306a36Sopenharmony_ci freed += skb_headlen(last); 98662306a36Sopenharmony_ci } 98762306a36Sopenharmony_ci if (last) 98862306a36Sopenharmony_ci last_tsn = sctp_skb2event(last)->tsn; 98962306a36Sopenharmony_ci else 99062306a36Sopenharmony_ci last_tsn = tsn; 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci /* Unlink the event, then renege all applicable TSNs. */ 99362306a36Sopenharmony_ci __skb_unlink(skb, list); 99462306a36Sopenharmony_ci sctp_ulpevent_free(event); 99562306a36Sopenharmony_ci while (TSN_lte(tsn, last_tsn)) { 99662306a36Sopenharmony_ci sctp_tsnmap_renege(tsnmap, tsn); 99762306a36Sopenharmony_ci tsn++; 99862306a36Sopenharmony_ci } 99962306a36Sopenharmony_ci if (freed >= needed) 100062306a36Sopenharmony_ci return freed; 100162306a36Sopenharmony_ci } 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci return freed; 100462306a36Sopenharmony_ci} 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci/* Renege 'needed' bytes from the ordering queue. */ 100762306a36Sopenharmony_cistatic __u16 sctp_ulpq_renege_order(struct sctp_ulpq *ulpq, __u16 needed) 100862306a36Sopenharmony_ci{ 100962306a36Sopenharmony_ci return sctp_ulpq_renege_list(ulpq, &ulpq->lobby, needed); 101062306a36Sopenharmony_ci} 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci/* Renege 'needed' bytes from the reassembly queue. */ 101362306a36Sopenharmony_cistatic __u16 sctp_ulpq_renege_frags(struct sctp_ulpq *ulpq, __u16 needed) 101462306a36Sopenharmony_ci{ 101562306a36Sopenharmony_ci return sctp_ulpq_renege_list(ulpq, &ulpq->reasm, needed); 101662306a36Sopenharmony_ci} 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci/* Partial deliver the first message as there is pressure on rwnd. */ 101962306a36Sopenharmony_civoid sctp_ulpq_partial_delivery(struct sctp_ulpq *ulpq, 102062306a36Sopenharmony_ci gfp_t gfp) 102162306a36Sopenharmony_ci{ 102262306a36Sopenharmony_ci struct sctp_ulpevent *event; 102362306a36Sopenharmony_ci struct sctp_association *asoc; 102462306a36Sopenharmony_ci struct sctp_sock *sp; 102562306a36Sopenharmony_ci __u32 ctsn; 102662306a36Sopenharmony_ci struct sk_buff *skb; 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci asoc = ulpq->asoc; 102962306a36Sopenharmony_ci sp = sctp_sk(asoc->base.sk); 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci /* If the association is already in Partial Delivery mode 103262306a36Sopenharmony_ci * we have nothing to do. 103362306a36Sopenharmony_ci */ 103462306a36Sopenharmony_ci if (ulpq->pd_mode) 103562306a36Sopenharmony_ci return; 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci /* Data must be at or below the Cumulative TSN ACK Point to 103862306a36Sopenharmony_ci * start partial delivery. 103962306a36Sopenharmony_ci */ 104062306a36Sopenharmony_ci skb = skb_peek(&asoc->ulpq.reasm); 104162306a36Sopenharmony_ci if (skb != NULL) { 104262306a36Sopenharmony_ci ctsn = sctp_skb2event(skb)->tsn; 104362306a36Sopenharmony_ci if (!TSN_lte(ctsn, sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map))) 104462306a36Sopenharmony_ci return; 104562306a36Sopenharmony_ci } 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci /* If the user enabled fragment interleave socket option, 104862306a36Sopenharmony_ci * multiple associations can enter partial delivery. 104962306a36Sopenharmony_ci * Otherwise, we can only enter partial delivery if the 105062306a36Sopenharmony_ci * socket is not in partial deliver mode. 105162306a36Sopenharmony_ci */ 105262306a36Sopenharmony_ci if (sp->frag_interleave || atomic_read(&sp->pd_mode) == 0) { 105362306a36Sopenharmony_ci /* Is partial delivery possible? */ 105462306a36Sopenharmony_ci event = sctp_ulpq_retrieve_first(ulpq); 105562306a36Sopenharmony_ci /* Send event to the ULP. */ 105662306a36Sopenharmony_ci if (event) { 105762306a36Sopenharmony_ci struct sk_buff_head temp; 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci skb_queue_head_init(&temp); 106062306a36Sopenharmony_ci __skb_queue_tail(&temp, sctp_event2skb(event)); 106162306a36Sopenharmony_ci sctp_ulpq_tail_event(ulpq, &temp); 106262306a36Sopenharmony_ci sctp_ulpq_set_pd(ulpq); 106362306a36Sopenharmony_ci return; 106462306a36Sopenharmony_ci } 106562306a36Sopenharmony_ci } 106662306a36Sopenharmony_ci} 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci/* Renege some packets to make room for an incoming chunk. */ 106962306a36Sopenharmony_civoid sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk, 107062306a36Sopenharmony_ci gfp_t gfp) 107162306a36Sopenharmony_ci{ 107262306a36Sopenharmony_ci struct sctp_association *asoc = ulpq->asoc; 107362306a36Sopenharmony_ci __u32 freed = 0; 107462306a36Sopenharmony_ci __u16 needed; 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci needed = ntohs(chunk->chunk_hdr->length) - 107762306a36Sopenharmony_ci sizeof(struct sctp_data_chunk); 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci if (skb_queue_empty(&asoc->base.sk->sk_receive_queue)) { 108062306a36Sopenharmony_ci freed = sctp_ulpq_renege_order(ulpq, needed); 108162306a36Sopenharmony_ci if (freed < needed) 108262306a36Sopenharmony_ci freed += sctp_ulpq_renege_frags(ulpq, needed - freed); 108362306a36Sopenharmony_ci } 108462306a36Sopenharmony_ci /* If able to free enough room, accept this chunk. */ 108562306a36Sopenharmony_ci if (sk_rmem_schedule(asoc->base.sk, chunk->skb, needed) && 108662306a36Sopenharmony_ci freed >= needed) { 108762306a36Sopenharmony_ci int retval = sctp_ulpq_tail_data(ulpq, chunk, gfp); 108862306a36Sopenharmony_ci /* 108962306a36Sopenharmony_ci * Enter partial delivery if chunk has not been 109062306a36Sopenharmony_ci * delivered; otherwise, drain the reassembly queue. 109162306a36Sopenharmony_ci */ 109262306a36Sopenharmony_ci if (retval <= 0) 109362306a36Sopenharmony_ci sctp_ulpq_partial_delivery(ulpq, gfp); 109462306a36Sopenharmony_ci else if (retval == 1) 109562306a36Sopenharmony_ci sctp_ulpq_reasm_drain(ulpq); 109662306a36Sopenharmony_ci } 109762306a36Sopenharmony_ci} 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci/* Notify the application if an association is aborted and in 110062306a36Sopenharmony_ci * partial delivery mode. Send up any pending received messages. 110162306a36Sopenharmony_ci */ 110262306a36Sopenharmony_civoid sctp_ulpq_abort_pd(struct sctp_ulpq *ulpq, gfp_t gfp) 110362306a36Sopenharmony_ci{ 110462306a36Sopenharmony_ci struct sctp_ulpevent *ev = NULL; 110562306a36Sopenharmony_ci struct sctp_sock *sp; 110662306a36Sopenharmony_ci struct sock *sk; 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci if (!ulpq->pd_mode) 110962306a36Sopenharmony_ci return; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci sk = ulpq->asoc->base.sk; 111262306a36Sopenharmony_ci sp = sctp_sk(sk); 111362306a36Sopenharmony_ci if (sctp_ulpevent_type_enabled(ulpq->asoc->subscribe, 111462306a36Sopenharmony_ci SCTP_PARTIAL_DELIVERY_EVENT)) 111562306a36Sopenharmony_ci ev = sctp_ulpevent_make_pdapi(ulpq->asoc, 111662306a36Sopenharmony_ci SCTP_PARTIAL_DELIVERY_ABORTED, 111762306a36Sopenharmony_ci 0, 0, 0, gfp); 111862306a36Sopenharmony_ci if (ev) 111962306a36Sopenharmony_ci __skb_queue_tail(&sk->sk_receive_queue, sctp_event2skb(ev)); 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci /* If there is data waiting, send it up the socket now. */ 112262306a36Sopenharmony_ci if ((sctp_ulpq_clear_pd(ulpq) || ev) && !sp->data_ready_signalled) { 112362306a36Sopenharmony_ci sp->data_ready_signalled = 1; 112462306a36Sopenharmony_ci sk->sk_data_ready(sk); 112562306a36Sopenharmony_ci } 112662306a36Sopenharmony_ci} 1127