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