xref: /freebsd/sys/netinet/sctp_indata.c (revision 8f269b8242ddc5fd863deae40a37c200bc90c1dc)
1f8829a4aSRandall Stewart /*-
251369649SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
351369649SPedro F. Giffuni  *
4b1006367SRandall Stewart  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
5807aad63SMichael Tuexen  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
6807aad63SMichael Tuexen  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
7f8829a4aSRandall Stewart  *
8f8829a4aSRandall Stewart  * Redistribution and use in source and binary forms, with or without
9f8829a4aSRandall Stewart  * modification, are permitted provided that the following conditions are met:
10f8829a4aSRandall Stewart  *
11f8829a4aSRandall Stewart  * a) Redistributions of source code must retain the above copyright notice,
12f8829a4aSRandall Stewart  *    this list of conditions and the following disclaimer.
13f8829a4aSRandall Stewart  *
14f8829a4aSRandall Stewart  * b) Redistributions in binary form must reproduce the above copyright
15f8829a4aSRandall Stewart  *    notice, this list of conditions and the following disclaimer in
16f8829a4aSRandall Stewart  *    the documentation and/or other materials provided with the distribution.
17f8829a4aSRandall Stewart  *
18f8829a4aSRandall Stewart  * c) Neither the name of Cisco Systems, Inc. nor the names of its
19f8829a4aSRandall Stewart  *    contributors may be used to endorse or promote products derived
20f8829a4aSRandall Stewart  *    from this software without specific prior written permission.
21f8829a4aSRandall Stewart  *
22f8829a4aSRandall Stewart  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23f8829a4aSRandall Stewart  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
24f8829a4aSRandall Stewart  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25f8829a4aSRandall Stewart  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26f8829a4aSRandall Stewart  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27f8829a4aSRandall Stewart  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28f8829a4aSRandall Stewart  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29f8829a4aSRandall Stewart  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30f8829a4aSRandall Stewart  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31f8829a4aSRandall Stewart  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32f8829a4aSRandall Stewart  * THE POSSIBILITY OF SUCH DAMAGE.
33f8829a4aSRandall Stewart  */
34f8829a4aSRandall Stewart 
35f8829a4aSRandall Stewart #include <sys/cdefs.h>
36f8829a4aSRandall Stewart __FBSDID("$FreeBSD$");
37f8829a4aSRandall Stewart 
38f8829a4aSRandall Stewart #include <netinet/sctp_os.h>
3944249214SRandall Stewart #include <sys/proc.h>
40f8829a4aSRandall Stewart #include <netinet/sctp_var.h>
4142551e99SRandall Stewart #include <netinet/sctp_sysctl.h>
42f8829a4aSRandall Stewart #include <netinet/sctp_header.h>
4344249214SRandall Stewart #include <netinet/sctp_pcb.h>
44f8829a4aSRandall Stewart #include <netinet/sctputil.h>
45f8829a4aSRandall Stewart #include <netinet/sctp_output.h>
46f8829a4aSRandall Stewart #include <netinet/sctp_uio.h>
4744249214SRandall Stewart #include <netinet/sctp_auth.h>
48f8829a4aSRandall Stewart #include <netinet/sctp_timer.h>
4944249214SRandall Stewart #include <netinet/sctp_asconf.h>
5044249214SRandall Stewart #include <netinet/sctp_indata.h>
5144249214SRandall Stewart #include <netinet/sctp_bsd_addr.h>
5244249214SRandall Stewart #include <netinet/sctp_input.h>
5344249214SRandall Stewart #include <netinet/sctp_crc32.h>
5444249214SRandall Stewart #include <netinet/sctp_lock_bsd.h>
55f8829a4aSRandall Stewart /*
56f8829a4aSRandall Stewart  * NOTES: On the outbound side of things I need to check the sack timer to
57f8829a4aSRandall Stewart  * see if I should generate a sack into the chunk queue (if I have data to
58f8829a4aSRandall Stewart  * send that is and will be sending it .. for bundling.
59f8829a4aSRandall Stewart  *
60f8829a4aSRandall Stewart  * The callback in sctp_usrreq.c will get called when the socket is read from.
61f8829a4aSRandall Stewart  * This will cause sctp_service_queues() to get called on the top entry in
62f8829a4aSRandall Stewart  * the list.
63f8829a4aSRandall Stewart  */
6428cd0699SMichael Tuexen static uint32_t
6544249214SRandall Stewart sctp_add_chk_to_control(struct sctp_queued_to_read *control,
6644249214SRandall Stewart     struct sctp_stream_in *strm,
6744249214SRandall Stewart     struct sctp_tcb *stcb,
6844249214SRandall Stewart     struct sctp_association *asoc,
6944710431SMichael Tuexen     struct sctp_tmit_chunk *chk, int hold_rlock);
7044249214SRandall Stewart 
7172fb6fdbSRandall Stewart void
72f8829a4aSRandall Stewart sctp_set_rwnd(struct sctp_tcb *stcb, struct sctp_association *asoc)
73f8829a4aSRandall Stewart {
74b3f1ea41SRandall Stewart 	asoc->my_rwnd = sctp_calc_rwnd(stcb, asoc);
75f8829a4aSRandall Stewart }
76f8829a4aSRandall Stewart 
77f8829a4aSRandall Stewart /* Calculate what the rwnd would be */
7872fb6fdbSRandall Stewart uint32_t
79b0471b4bSMichael Tuexen sctp_calc_rwnd(struct sctp_tcb *stcb, struct sctp_association *asoc)
80b0471b4bSMichael Tuexen {
81b3f1ea41SRandall Stewart 	uint32_t calc = 0;
82f8829a4aSRandall Stewart 
83f8829a4aSRandall Stewart 	/*
84f8829a4aSRandall Stewart 	 * This is really set wrong with respect to a 1-2-m socket. Since
854e88d37aSMichael Tuexen 	 * the sb_cc is the count that everyone as put up. When we re-write
86f8829a4aSRandall Stewart 	 * sctp_soreceive then we will fix this so that ONLY this
87f8829a4aSRandall Stewart 	 * associations data is taken into account.
88f8829a4aSRandall Stewart 	 */
8944249214SRandall Stewart 	if (stcb->sctp_socket == NULL) {
90f8829a4aSRandall Stewart 		return (calc);
9144249214SRandall Stewart 	}
920053ed28SMichael Tuexen 
93253a63b8SMichael Tuexen 	KASSERT(asoc->cnt_on_reasm_queue > 0 || asoc->size_on_reasm_queue == 0,
94253a63b8SMichael Tuexen 	    ("size_on_reasm_queue is %u", asoc->size_on_reasm_queue));
95253a63b8SMichael Tuexen 	KASSERT(asoc->cnt_on_all_streams > 0 || asoc->size_on_all_streams == 0,
96253a63b8SMichael Tuexen 	    ("size_on_all_streams is %u", asoc->size_on_all_streams));
974e88d37aSMichael Tuexen 	if (stcb->asoc.sb_cc == 0 &&
98253a63b8SMichael Tuexen 	    asoc->cnt_on_reasm_queue == 0 &&
99253a63b8SMichael Tuexen 	    asoc->cnt_on_all_streams == 0) {
100f8829a4aSRandall Stewart 		/* Full rwnd granted */
101b3f1ea41SRandall Stewart 		calc = max(SCTP_SB_LIMIT_RCV(stcb->sctp_socket), SCTP_MINIMAL_RWND);
102f8829a4aSRandall Stewart 		return (calc);
103f8829a4aSRandall Stewart 	}
104f8829a4aSRandall Stewart 	/* get actual space */
105f8829a4aSRandall Stewart 	calc = (uint32_t)sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv);
106f8829a4aSRandall Stewart 	/*
107f8829a4aSRandall Stewart 	 * take out what has NOT been put on socket queue and we yet hold
108f8829a4aSRandall Stewart 	 * for putting up.
109f8829a4aSRandall Stewart 	 */
11044fbe462SRandall Stewart 	calc = sctp_sbspace_sub(calc, (uint32_t)(asoc->size_on_reasm_queue +
11144fbe462SRandall Stewart 	    asoc->cnt_on_reasm_queue * MSIZE));
11244fbe462SRandall Stewart 	calc = sctp_sbspace_sub(calc, (uint32_t)(asoc->size_on_all_streams +
11344fbe462SRandall Stewart 	    asoc->cnt_on_all_streams * MSIZE));
114f8829a4aSRandall Stewart 	if (calc == 0) {
115f8829a4aSRandall Stewart 		/* out of space */
116f8829a4aSRandall Stewart 		return (calc);
117f8829a4aSRandall Stewart 	}
1180053ed28SMichael Tuexen 
119f8829a4aSRandall Stewart 	/* what is the overhead of all these rwnd's */
1202afb3e84SRandall Stewart 	calc = sctp_sbspace_sub(calc, stcb->asoc.my_rwnd_control_len);
121b3f1ea41SRandall Stewart 	/*
122b3f1ea41SRandall Stewart 	 * If the window gets too small due to ctrl-stuff, reduce it to 1,
123b3f1ea41SRandall Stewart 	 * even it is 0. SWS engaged
124f8829a4aSRandall Stewart 	 */
125b3f1ea41SRandall Stewart 	if (calc < stcb->asoc.my_rwnd_control_len) {
126b3f1ea41SRandall Stewart 		calc = 1;
1272afb3e84SRandall Stewart 	}
128b3f1ea41SRandall Stewart 	return (calc);
129f8829a4aSRandall Stewart }
130f8829a4aSRandall Stewart 
131f8829a4aSRandall Stewart /*
132f8829a4aSRandall Stewart  * Build out our readq entry based on the incoming packet.
133f8829a4aSRandall Stewart  */
134f8829a4aSRandall Stewart struct sctp_queued_to_read *
135f8829a4aSRandall Stewart sctp_build_readq_entry(struct sctp_tcb *stcb,
136f8829a4aSRandall Stewart     struct sctp_nets *net,
137f8829a4aSRandall Stewart     uint32_t tsn, uint32_t ppid,
13849656eefSMichael Tuexen     uint32_t context, uint16_t sid,
13949656eefSMichael Tuexen     uint32_t mid, uint8_t flags,
140f8829a4aSRandall Stewart     struct mbuf *dm)
141f8829a4aSRandall Stewart {
142f8829a4aSRandall Stewart 	struct sctp_queued_to_read *read_queue_e = NULL;
143f8829a4aSRandall Stewart 
144f8829a4aSRandall Stewart 	sctp_alloc_a_readq(stcb, read_queue_e);
145f8829a4aSRandall Stewart 	if (read_queue_e == NULL) {
146f8829a4aSRandall Stewart 		goto failed_build;
147f8829a4aSRandall Stewart 	}
14844249214SRandall Stewart 	memset(read_queue_e, 0, sizeof(struct sctp_queued_to_read));
14949656eefSMichael Tuexen 	read_queue_e->sinfo_stream = sid;
150f8829a4aSRandall Stewart 	read_queue_e->sinfo_flags = (flags << 8);
151f8829a4aSRandall Stewart 	read_queue_e->sinfo_ppid = ppid;
1527215cc1bSMichael Tuexen 	read_queue_e->sinfo_context = context;
153f8829a4aSRandall Stewart 	read_queue_e->sinfo_tsn = tsn;
154f8829a4aSRandall Stewart 	read_queue_e->sinfo_cumtsn = tsn;
155f8829a4aSRandall Stewart 	read_queue_e->sinfo_assoc_id = sctp_get_associd(stcb);
15649656eefSMichael Tuexen 	read_queue_e->mid = mid;
15744249214SRandall Stewart 	read_queue_e->top_fsn = read_queue_e->fsn_included = 0xffffffff;
15844249214SRandall Stewart 	TAILQ_INIT(&read_queue_e->reasm);
159f8829a4aSRandall Stewart 	read_queue_e->whoFrom = net;
160f8829a4aSRandall Stewart 	atomic_add_int(&net->ref_count, 1);
161f8829a4aSRandall Stewart 	read_queue_e->data = dm;
162f8829a4aSRandall Stewart 	read_queue_e->stcb = stcb;
163f8829a4aSRandall Stewart 	read_queue_e->port_from = stcb->rport;
164daf14341SMichael Tuexen 	if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
165daf14341SMichael Tuexen 		read_queue_e->do_not_ref_stcb = 1;
166daf14341SMichael Tuexen 	}
167f8829a4aSRandall Stewart failed_build:
168f8829a4aSRandall Stewart 	return (read_queue_e);
169f8829a4aSRandall Stewart }
170f8829a4aSRandall Stewart 
171f8829a4aSRandall Stewart struct mbuf *
172e2e7c62eSMichael Tuexen sctp_build_ctl_nchunk(struct sctp_inpcb *inp, struct sctp_sndrcvinfo *sinfo)
173f8829a4aSRandall Stewart {
174e2e7c62eSMichael Tuexen 	struct sctp_extrcvinfo *seinfo;
175f8829a4aSRandall Stewart 	struct sctp_sndrcvinfo *outinfo;
176e2e7c62eSMichael Tuexen 	struct sctp_rcvinfo *rcvinfo;
177e2e7c62eSMichael Tuexen 	struct sctp_nxtinfo *nxtinfo;
178f8829a4aSRandall Stewart 	struct cmsghdr *cmh;
179f8829a4aSRandall Stewart 	struct mbuf *ret;
180f8829a4aSRandall Stewart 	int len;
181e2e7c62eSMichael Tuexen 	int use_extended;
182e2e7c62eSMichael Tuexen 	int provide_nxt;
183f8829a4aSRandall Stewart 
184e2e7c62eSMichael Tuexen 	if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT) &&
185e2e7c62eSMichael Tuexen 	    sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVRCVINFO) &&
186e2e7c62eSMichael Tuexen 	    sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVNXTINFO)) {
187e2e7c62eSMichael Tuexen 		/* user does not want any ancillary data */
188f8829a4aSRandall Stewart 		return (NULL);
189f8829a4aSRandall Stewart 	}
1900053ed28SMichael Tuexen 
191e2e7c62eSMichael Tuexen 	len = 0;
192e2e7c62eSMichael Tuexen 	if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO)) {
193e2e7c62eSMichael Tuexen 		len += CMSG_SPACE(sizeof(struct sctp_rcvinfo));
194e2e7c62eSMichael Tuexen 	}
195e2e7c62eSMichael Tuexen 	seinfo = (struct sctp_extrcvinfo *)sinfo;
196e2e7c62eSMichael Tuexen 	if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO) &&
197b70b526dSMichael Tuexen 	    (seinfo->serinfo_next_flags & SCTP_NEXT_MSG_AVAIL)) {
198e2e7c62eSMichael Tuexen 		provide_nxt = 1;
1990bfc52beSMichael Tuexen 		len += CMSG_SPACE(sizeof(struct sctp_nxtinfo));
200e2e7c62eSMichael Tuexen 	} else {
201e2e7c62eSMichael Tuexen 		provide_nxt = 0;
202e2e7c62eSMichael Tuexen 	}
203e2e7c62eSMichael Tuexen 	if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT)) {
204f8829a4aSRandall Stewart 		if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO)) {
205f8829a4aSRandall Stewart 			use_extended = 1;
206e2e7c62eSMichael Tuexen 			len += CMSG_SPACE(sizeof(struct sctp_extrcvinfo));
207f8829a4aSRandall Stewart 		} else {
208e2e7c62eSMichael Tuexen 			use_extended = 0;
209e2e7c62eSMichael Tuexen 			len += CMSG_SPACE(sizeof(struct sctp_sndrcvinfo));
210e2e7c62eSMichael Tuexen 		}
211e2e7c62eSMichael Tuexen 	} else {
212e2e7c62eSMichael Tuexen 		use_extended = 0;
213f8829a4aSRandall Stewart 	}
214f8829a4aSRandall Stewart 
215eb1b1807SGleb Smirnoff 	ret = sctp_get_mbuf_for_msg(len, 0, M_NOWAIT, 1, MT_DATA);
216f8829a4aSRandall Stewart 	if (ret == NULL) {
217f8829a4aSRandall Stewart 		/* No space */
218f8829a4aSRandall Stewart 		return (ret);
219f8829a4aSRandall Stewart 	}
220e2e7c62eSMichael Tuexen 	SCTP_BUF_LEN(ret) = 0;
221e2e7c62eSMichael Tuexen 
222f8829a4aSRandall Stewart 	/* We need a CMSG header followed by the struct */
223f8829a4aSRandall Stewart 	cmh = mtod(ret, struct cmsghdr *);
224e432298aSXin LI 	/*
225e432298aSXin LI 	 * Make sure that there is no un-initialized padding between the
226e432298aSXin LI 	 * cmsg header and cmsg data and after the cmsg data.
227e432298aSXin LI 	 */
228e432298aSXin LI 	memset(cmh, 0, len);
229e2e7c62eSMichael Tuexen 	if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO)) {
230f8829a4aSRandall Stewart 		cmh->cmsg_level = IPPROTO_SCTP;
231e2e7c62eSMichael Tuexen 		cmh->cmsg_len = CMSG_LEN(sizeof(struct sctp_rcvinfo));
232e2e7c62eSMichael Tuexen 		cmh->cmsg_type = SCTP_RCVINFO;
233e2e7c62eSMichael Tuexen 		rcvinfo = (struct sctp_rcvinfo *)CMSG_DATA(cmh);
234e2e7c62eSMichael Tuexen 		rcvinfo->rcv_sid = sinfo->sinfo_stream;
235e2e7c62eSMichael Tuexen 		rcvinfo->rcv_ssn = sinfo->sinfo_ssn;
236e2e7c62eSMichael Tuexen 		rcvinfo->rcv_flags = sinfo->sinfo_flags;
237e2e7c62eSMichael Tuexen 		rcvinfo->rcv_ppid = sinfo->sinfo_ppid;
238e2e7c62eSMichael Tuexen 		rcvinfo->rcv_tsn = sinfo->sinfo_tsn;
239e2e7c62eSMichael Tuexen 		rcvinfo->rcv_cumtsn = sinfo->sinfo_cumtsn;
240e2e7c62eSMichael Tuexen 		rcvinfo->rcv_context = sinfo->sinfo_context;
241e2e7c62eSMichael Tuexen 		rcvinfo->rcv_assoc_id = sinfo->sinfo_assoc_id;
242e2e7c62eSMichael Tuexen 		cmh = (struct cmsghdr *)((caddr_t)cmh + CMSG_SPACE(sizeof(struct sctp_rcvinfo)));
243e2e7c62eSMichael Tuexen 		SCTP_BUF_LEN(ret) += CMSG_SPACE(sizeof(struct sctp_rcvinfo));
244f8829a4aSRandall Stewart 	}
245e2e7c62eSMichael Tuexen 	if (provide_nxt) {
246e2e7c62eSMichael Tuexen 		cmh->cmsg_level = IPPROTO_SCTP;
247e2e7c62eSMichael Tuexen 		cmh->cmsg_len = CMSG_LEN(sizeof(struct sctp_nxtinfo));
248e2e7c62eSMichael Tuexen 		cmh->cmsg_type = SCTP_NXTINFO;
249e2e7c62eSMichael Tuexen 		nxtinfo = (struct sctp_nxtinfo *)CMSG_DATA(cmh);
250b70b526dSMichael Tuexen 		nxtinfo->nxt_sid = seinfo->serinfo_next_stream;
251e2e7c62eSMichael Tuexen 		nxtinfo->nxt_flags = 0;
252b70b526dSMichael Tuexen 		if (seinfo->serinfo_next_flags & SCTP_NEXT_MSG_IS_UNORDERED) {
253e2e7c62eSMichael Tuexen 			nxtinfo->nxt_flags |= SCTP_UNORDERED;
254e2e7c62eSMichael Tuexen 		}
255b70b526dSMichael Tuexen 		if (seinfo->serinfo_next_flags & SCTP_NEXT_MSG_IS_NOTIFICATION) {
256e2e7c62eSMichael Tuexen 			nxtinfo->nxt_flags |= SCTP_NOTIFICATION;
257e2e7c62eSMichael Tuexen 		}
258b70b526dSMichael Tuexen 		if (seinfo->serinfo_next_flags & SCTP_NEXT_MSG_ISCOMPLETE) {
259e2e7c62eSMichael Tuexen 			nxtinfo->nxt_flags |= SCTP_COMPLETE;
260e2e7c62eSMichael Tuexen 		}
261b70b526dSMichael Tuexen 		nxtinfo->nxt_ppid = seinfo->serinfo_next_ppid;
262b70b526dSMichael Tuexen 		nxtinfo->nxt_length = seinfo->serinfo_next_length;
263b70b526dSMichael Tuexen 		nxtinfo->nxt_assoc_id = seinfo->serinfo_next_aid;
264e2e7c62eSMichael Tuexen 		cmh = (struct cmsghdr *)((caddr_t)cmh + CMSG_SPACE(sizeof(struct sctp_nxtinfo)));
265e2e7c62eSMichael Tuexen 		SCTP_BUF_LEN(ret) += CMSG_SPACE(sizeof(struct sctp_nxtinfo));
266e2e7c62eSMichael Tuexen 	}
267e2e7c62eSMichael Tuexen 	if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT)) {
268e2e7c62eSMichael Tuexen 		cmh->cmsg_level = IPPROTO_SCTP;
269e2e7c62eSMichael Tuexen 		outinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmh);
270e2e7c62eSMichael Tuexen 		if (use_extended) {
271e2e7c62eSMichael Tuexen 			cmh->cmsg_len = CMSG_LEN(sizeof(struct sctp_extrcvinfo));
272e2e7c62eSMichael Tuexen 			cmh->cmsg_type = SCTP_EXTRCV;
273e2e7c62eSMichael Tuexen 			memcpy(outinfo, sinfo, sizeof(struct sctp_extrcvinfo));
274e2e7c62eSMichael Tuexen 			SCTP_BUF_LEN(ret) += CMSG_SPACE(sizeof(struct sctp_extrcvinfo));
275e2e7c62eSMichael Tuexen 		} else {
276e2e7c62eSMichael Tuexen 			cmh->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
277e2e7c62eSMichael Tuexen 			cmh->cmsg_type = SCTP_SNDRCV;
278e2e7c62eSMichael Tuexen 			*outinfo = *sinfo;
279e2e7c62eSMichael Tuexen 			SCTP_BUF_LEN(ret) += CMSG_SPACE(sizeof(struct sctp_sndrcvinfo));
280e2e7c62eSMichael Tuexen 		}
281e2e7c62eSMichael Tuexen 	}
282f8829a4aSRandall Stewart 	return (ret);
283f8829a4aSRandall Stewart }
284f8829a4aSRandall Stewart 
28577acdc25SRandall Stewart static void
28677acdc25SRandall Stewart sctp_mark_non_revokable(struct sctp_association *asoc, uint32_t tsn)
28777acdc25SRandall Stewart {
2889b2e0767SRandall Stewart 	uint32_t gap, i, cumackp1;
28977acdc25SRandall Stewart 	int fnd = 0;
29044249214SRandall Stewart 	int in_r = 0, in_nr = 0;
29177acdc25SRandall Stewart 
29277acdc25SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_do_drain) == 0) {
29377acdc25SRandall Stewart 		return;
29477acdc25SRandall Stewart 	}
2959b2e0767SRandall Stewart 	cumackp1 = asoc->cumulative_tsn + 1;
29620b07a4dSMichael Tuexen 	if (SCTP_TSN_GT(cumackp1, tsn)) {
2979b2e0767SRandall Stewart 		/*
2989b2e0767SRandall Stewart 		 * this tsn is behind the cum ack and thus we don't need to
2999b2e0767SRandall Stewart 		 * worry about it being moved from one to the other.
3009b2e0767SRandall Stewart 		 */
3019b2e0767SRandall Stewart 		return;
3029b2e0767SRandall Stewart 	}
30377acdc25SRandall Stewart 	SCTP_CALC_TSN_TO_GAP(gap, tsn, asoc->mapping_array_base_tsn);
30444249214SRandall Stewart 	in_r = SCTP_IS_TSN_PRESENT(asoc->mapping_array, gap);
30544249214SRandall Stewart 	in_nr = SCTP_IS_TSN_PRESENT(asoc->nr_mapping_array, gap);
30644249214SRandall Stewart 	if ((in_r == 0) && (in_nr == 0)) {
30744249214SRandall Stewart #ifdef INVARIANTS
30844249214SRandall Stewart 		panic("Things are really messed up now");
30944249214SRandall Stewart #else
310cd3fd531SMichael Tuexen 		SCTP_PRINTF("gap:%x tsn:%x\n", gap, tsn);
31177acdc25SRandall Stewart 		sctp_print_mapping_array(asoc);
31277acdc25SRandall Stewart #endif
313b5c16493SMichael Tuexen 	}
31444249214SRandall Stewart 	if (in_nr == 0)
31577acdc25SRandall Stewart 		SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap);
31644249214SRandall Stewart 	if (in_r)
31777acdc25SRandall Stewart 		SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap);
31820b07a4dSMichael Tuexen 	if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) {
31977acdc25SRandall Stewart 		asoc->highest_tsn_inside_nr_map = tsn;
32077acdc25SRandall Stewart 	}
32177acdc25SRandall Stewart 	if (tsn == asoc->highest_tsn_inside_map) {
32277acdc25SRandall Stewart 		/* We must back down to see what the new highest is */
32320b07a4dSMichael Tuexen 		for (i = tsn - 1; SCTP_TSN_GE(i, asoc->mapping_array_base_tsn); i--) {
32477acdc25SRandall Stewart 			SCTP_CALC_TSN_TO_GAP(gap, i, asoc->mapping_array_base_tsn);
32577acdc25SRandall Stewart 			if (SCTP_IS_TSN_PRESENT(asoc->mapping_array, gap)) {
32677acdc25SRandall Stewart 				asoc->highest_tsn_inside_map = i;
32777acdc25SRandall Stewart 				fnd = 1;
32877acdc25SRandall Stewart 				break;
32977acdc25SRandall Stewart 			}
33077acdc25SRandall Stewart 		}
33177acdc25SRandall Stewart 		if (!fnd) {
33277acdc25SRandall Stewart 			asoc->highest_tsn_inside_map = asoc->mapping_array_base_tsn - 1;
33377acdc25SRandall Stewart 		}
33477acdc25SRandall Stewart 	}
33577acdc25SRandall Stewart }
33677acdc25SRandall Stewart 
33744249214SRandall Stewart static int
33844249214SRandall Stewart sctp_place_control_in_stream(struct sctp_stream_in *strm,
33944249214SRandall Stewart     struct sctp_association *asoc,
34044249214SRandall Stewart     struct sctp_queued_to_read *control)
341f8829a4aSRandall Stewart {
34244249214SRandall Stewart 	struct sctp_queued_to_read *at;
34344249214SRandall Stewart 	struct sctp_readhead *q;
3448b9c95f4SMichael Tuexen 	uint8_t flags, unordered;
345f8829a4aSRandall Stewart 
3468b9c95f4SMichael Tuexen 	flags = (control->sinfo_flags >> 8);
3478b9c95f4SMichael Tuexen 	unordered = flags & SCTP_DATA_UNORDERED;
34844249214SRandall Stewart 	if (unordered) {
34944249214SRandall Stewart 		q = &strm->uno_inqueue;
35044249214SRandall Stewart 		if (asoc->idata_supported == 0) {
35144249214SRandall Stewart 			if (!TAILQ_EMPTY(q)) {
352b7b84c0eSMichael Tuexen 				/*
353b7b84c0eSMichael Tuexen 				 * Only one stream can be here in old style
354b7b84c0eSMichael Tuexen 				 * -- abort
355b7b84c0eSMichael Tuexen 				 */
35644249214SRandall Stewart 				return (-1);
35744249214SRandall Stewart 			}
35844249214SRandall Stewart 			TAILQ_INSERT_TAIL(q, control, next_instrm);
35944249214SRandall Stewart 			control->on_strm_q = SCTP_ON_UNORDERED;
36044249214SRandall Stewart 			return (0);
36144249214SRandall Stewart 		}
36244249214SRandall Stewart 	} else {
36344249214SRandall Stewart 		q = &strm->inqueue;
36444249214SRandall Stewart 	}
3658b9c95f4SMichael Tuexen 	if ((flags & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) {
3668b9c95f4SMichael Tuexen 		control->end_added = 1;
3678b9c95f4SMichael Tuexen 		control->first_frag_seen = 1;
3688b9c95f4SMichael Tuexen 		control->last_frag_seen = 1;
36944249214SRandall Stewart 	}
37044249214SRandall Stewart 	if (TAILQ_EMPTY(q)) {
37144249214SRandall Stewart 		/* Empty queue */
37244249214SRandall Stewart 		TAILQ_INSERT_HEAD(q, control, next_instrm);
37344249214SRandall Stewart 		if (unordered) {
37444249214SRandall Stewart 			control->on_strm_q = SCTP_ON_UNORDERED;
37544249214SRandall Stewart 		} else {
37644249214SRandall Stewart 			control->on_strm_q = SCTP_ON_ORDERED;
37744249214SRandall Stewart 		}
37844249214SRandall Stewart 		return (0);
37944249214SRandall Stewart 	} else {
38044249214SRandall Stewart 		TAILQ_FOREACH(at, q, next_instrm) {
38149656eefSMichael Tuexen 			if (SCTP_MID_GT(asoc->idata_supported, at->mid, control->mid)) {
38244249214SRandall Stewart 				/*
38344249214SRandall Stewart 				 * one in queue is bigger than the new one,
38444249214SRandall Stewart 				 * insert before this one
38544249214SRandall Stewart 				 */
38644249214SRandall Stewart 				TAILQ_INSERT_BEFORE(at, control, next_instrm);
38744249214SRandall Stewart 				if (unordered) {
38844249214SRandall Stewart 					control->on_strm_q = SCTP_ON_UNORDERED;
38944249214SRandall Stewart 				} else {
39044249214SRandall Stewart 					control->on_strm_q = SCTP_ON_ORDERED;
39144249214SRandall Stewart 				}
39244249214SRandall Stewart 				break;
39349656eefSMichael Tuexen 			} else if (SCTP_MID_EQ(asoc->idata_supported, at->mid, control->mid)) {
39444249214SRandall Stewart 				/*
39544249214SRandall Stewart 				 * Gak, He sent me a duplicate msg id
39644249214SRandall Stewart 				 * number?? return -1 to abort.
39744249214SRandall Stewart 				 */
39844249214SRandall Stewart 				return (-1);
39944249214SRandall Stewart 			} else {
40044249214SRandall Stewart 				if (TAILQ_NEXT(at, next_instrm) == NULL) {
40144249214SRandall Stewart 					/*
40244249214SRandall Stewart 					 * We are at the end, insert it
40344249214SRandall Stewart 					 * after this one
40444249214SRandall Stewart 					 */
40544249214SRandall Stewart 					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) {
40644249214SRandall Stewart 						sctp_log_strm_del(control, at,
40744249214SRandall Stewart 						    SCTP_STR_LOG_FROM_INSERT_TL);
40844249214SRandall Stewart 					}
4098b9c95f4SMichael Tuexen 					TAILQ_INSERT_AFTER(q, at, control, next_instrm);
41044249214SRandall Stewart 					if (unordered) {
41144249214SRandall Stewart 						control->on_strm_q = SCTP_ON_UNORDERED;
41244249214SRandall Stewart 					} else {
41344249214SRandall Stewart 						control->on_strm_q = SCTP_ON_ORDERED;
41444249214SRandall Stewart 					}
41544249214SRandall Stewart 					break;
41644249214SRandall Stewart 				}
41744249214SRandall Stewart 			}
41844249214SRandall Stewart 		}
41944249214SRandall Stewart 	}
42044249214SRandall Stewart 	return (0);
42144249214SRandall Stewart }
42244249214SRandall Stewart 
42344249214SRandall Stewart static void
42444249214SRandall Stewart sctp_abort_in_reasm(struct sctp_tcb *stcb,
42544249214SRandall Stewart     struct sctp_queued_to_read *control,
42644249214SRandall Stewart     struct sctp_tmit_chunk *chk,
42744249214SRandall Stewart     int *abort_flag, int opspot)
42844249214SRandall Stewart {
42944249214SRandall Stewart 	char msg[SCTP_DIAG_INFO_LEN];
43044249214SRandall Stewart 	struct mbuf *oper;
43144249214SRandall Stewart 
43244249214SRandall Stewart 	if (stcb->asoc.idata_supported) {
433999f86d6SMichael Tuexen 		SCTP_SNPRINTF(msg, sizeof(msg),
43444249214SRandall Stewart 		    "Reass %x,CF:%x,TSN=%8.8x,SID=%4.4x,FSN=%8.8x,MID:%8.8x",
43544249214SRandall Stewart 		    opspot,
43644249214SRandall Stewart 		    control->fsn_included,
43749656eefSMichael Tuexen 		    chk->rec.data.tsn,
43849656eefSMichael Tuexen 		    chk->rec.data.sid,
439821bae7cSMichael Tuexen 		    chk->rec.data.fsn, chk->rec.data.mid);
44044249214SRandall Stewart 	} else {
441999f86d6SMichael Tuexen 		SCTP_SNPRINTF(msg, sizeof(msg),
44244249214SRandall Stewart 		    "Reass %x,CI:%x,TSN=%8.8x,SID=%4.4x,FSN=%4.4x,SSN:%4.4x",
44344249214SRandall Stewart 		    opspot,
44444249214SRandall Stewart 		    control->fsn_included,
44549656eefSMichael Tuexen 		    chk->rec.data.tsn,
44649656eefSMichael Tuexen 		    chk->rec.data.sid,
44749656eefSMichael Tuexen 		    chk->rec.data.fsn,
448821bae7cSMichael Tuexen 		    (uint16_t)chk->rec.data.mid);
44944249214SRandall Stewart 	}
45044249214SRandall Stewart 	oper = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
451f8829a4aSRandall Stewart 	sctp_m_freem(chk->data);
452f8829a4aSRandall Stewart 	chk->data = NULL;
453689e6a5fSMichael Tuexen 	sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
45444249214SRandall Stewart 	stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_1;
45544249214SRandall Stewart 	sctp_abort_an_association(stcb->sctp_ep, stcb, oper, SCTP_SO_NOT_LOCKED);
45644249214SRandall Stewart 	*abort_flag = 1;
457f8829a4aSRandall Stewart }
458f8829a4aSRandall Stewart 
45944249214SRandall Stewart static void
460d1ea5fa9SMichael Tuexen sctp_clean_up_control(struct sctp_tcb *stcb, struct sctp_queued_to_read *control)
46144249214SRandall Stewart {
462f8829a4aSRandall Stewart 	/*
46344249214SRandall Stewart 	 * The control could not be placed and must be cleaned.
464f8829a4aSRandall Stewart 	 */
46544249214SRandall Stewart 	struct sctp_tmit_chunk *chk, *nchk;
466df6e0cc3SRandall Stewart 
46744249214SRandall Stewart 	TAILQ_FOREACH_SAFE(chk, &control->reasm, sctp_next, nchk) {
46844249214SRandall Stewart 		TAILQ_REMOVE(&control->reasm, chk, sctp_next);
46944249214SRandall Stewart 		if (chk->data)
47044249214SRandall Stewart 			sctp_m_freem(chk->data);
471f8829a4aSRandall Stewart 		chk->data = NULL;
472689e6a5fSMichael Tuexen 		sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
473f8829a4aSRandall Stewart 	}
4742b861c15SMichael Tuexen 	sctp_free_remote_addr(control->whoFrom);
4752b861c15SMichael Tuexen 	if (control->data) {
4762b861c15SMichael Tuexen 		sctp_m_freem(control->data);
4772b861c15SMichael Tuexen 		control->data = NULL;
4782b861c15SMichael Tuexen 	}
47944249214SRandall Stewart 	sctp_free_a_readq(stcb, control);
480f8829a4aSRandall Stewart }
481f8829a4aSRandall Stewart 
482f8829a4aSRandall Stewart /*
483f8829a4aSRandall Stewart  * Queue the chunk either right into the socket buffer if it is the next one
484f8829a4aSRandall Stewart  * to go OR put it in the correct place in the delivery queue.  If we do
48544249214SRandall Stewart  * append to the so_buf, keep doing so until we are out of order as
48644249214SRandall Stewart  * long as the control's entered are non-fragmented.
487f8829a4aSRandall Stewart  */
488f8829a4aSRandall Stewart static void
48944249214SRandall Stewart sctp_queue_data_to_stream(struct sctp_tcb *stcb,
49044249214SRandall Stewart     struct sctp_association *asoc,
49144249214SRandall Stewart     struct sctp_queued_to_read *control, int *abort_flag, int *need_reasm)
492f8829a4aSRandall Stewart {
493f8829a4aSRandall Stewart 	/*
494f8829a4aSRandall Stewart 	 * FIX-ME maybe? What happens when the ssn wraps? If we are getting
495f8829a4aSRandall Stewart 	 * all the data in one stream this could happen quite rapidly. One
496f8829a4aSRandall Stewart 	 * could use the TSN to keep track of things, but this scheme breaks
497cd0a4ff6SPedro F. Giffuni 	 * down in the other type of stream usage that could occur. Send a
498f8829a4aSRandall Stewart 	 * single msg to stream 0, send 4Billion messages to stream 1, now
499f8829a4aSRandall Stewart 	 * send a message to stream 0. You have a situation where the TSN
500f8829a4aSRandall Stewart 	 * has wrapped but not in the stream. Is this worth worrying about
501f8829a4aSRandall Stewart 	 * or should we just change our queue sort at the bottom to be by
502f8829a4aSRandall Stewart 	 * TSN.
503f8829a4aSRandall Stewart 	 *
5045b495f17SMichael Tuexen 	 * Could it also be legal for a peer to send ssn 1 with TSN 2 and
5055b495f17SMichael Tuexen 	 * ssn 2 with TSN 1? If the peer is doing some sort of funky TSN/SSN
506f8829a4aSRandall Stewart 	 * assignment this could happen... and I don't see how this would be
507f8829a4aSRandall Stewart 	 * a violation. So for now I am undecided an will leave the sort by
508f8829a4aSRandall Stewart 	 * SSN alone. Maybe a hybred approach is the answer
509f8829a4aSRandall Stewart 	 *
510f8829a4aSRandall Stewart 	 */
511f8829a4aSRandall Stewart 	struct sctp_queued_to_read *at;
512f8829a4aSRandall Stewart 	int queue_needed;
51344249214SRandall Stewart 	uint32_t nxt_todel;
514ff1ffd74SMichael Tuexen 	struct mbuf *op_err;
5153d6fe5d8SMichael Tuexen 	struct sctp_stream_in *strm;
516ff1ffd74SMichael Tuexen 	char msg[SCTP_DIAG_INFO_LEN];
517f8829a4aSRandall Stewart 
5183d6fe5d8SMichael Tuexen 	strm = &asoc->strmin[control->sinfo_stream];
519b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) {
520f8829a4aSRandall Stewart 		sctp_log_strm_del(control, NULL, SCTP_STR_LOG_FROM_INTO_STRD);
52180fefe0aSRandall Stewart 	}
52249656eefSMichael Tuexen 	if (SCTP_MID_GT((asoc->idata_supported), strm->last_mid_delivered, control->mid)) {
523f8829a4aSRandall Stewart 		/* The incoming sseq is behind where we last delivered? */
524f2ea2a2dSMichael Tuexen 		SCTPDBG(SCTP_DEBUG_INDATA1, "Duplicate S-SEQ: %u delivered: %u from peer, Abort association\n",
5253d6fe5d8SMichael Tuexen 		    strm->last_mid_delivered, control->mid);
526f8829a4aSRandall Stewart 		/*
527f8829a4aSRandall Stewart 		 * throw it in the stream so it gets cleaned up in
528f8829a4aSRandall Stewart 		 * association destruction
529f8829a4aSRandall Stewart 		 */
53044249214SRandall Stewart 		TAILQ_INSERT_HEAD(&strm->inqueue, control, next_instrm);
53149656eefSMichael Tuexen 		if (asoc->idata_supported) {
532999f86d6SMichael Tuexen 			SCTP_SNPRINTF(msg, sizeof(msg), "Delivered MID=%8.8x, got TSN=%8.8x, SID=%4.4x, MID=%8.8x",
53349656eefSMichael Tuexen 			    strm->last_mid_delivered, control->sinfo_tsn,
534821bae7cSMichael Tuexen 			    control->sinfo_stream, control->mid);
53549656eefSMichael Tuexen 		} else {
536999f86d6SMichael Tuexen 			SCTP_SNPRINTF(msg, sizeof(msg), "Delivered SSN=%4.4x, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x",
53749656eefSMichael Tuexen 			    (uint16_t)strm->last_mid_delivered,
53849656eefSMichael Tuexen 			    control->sinfo_tsn,
53949656eefSMichael Tuexen 			    control->sinfo_stream,
540821bae7cSMichael Tuexen 			    (uint16_t)control->mid);
54149656eefSMichael Tuexen 		}
542ff1ffd74SMichael Tuexen 		op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
54344249214SRandall Stewart 		stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_2;
544ff1ffd74SMichael Tuexen 		sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
545f8829a4aSRandall Stewart 		*abort_flag = 1;
546f8829a4aSRandall Stewart 		return;
547f8829a4aSRandall Stewart 	}
54844249214SRandall Stewart 	queue_needed = 1;
54944249214SRandall Stewart 	asoc->size_on_all_streams += control->length;
55044249214SRandall Stewart 	sctp_ucount_incr(asoc->cnt_on_all_streams);
55149656eefSMichael Tuexen 	nxt_todel = strm->last_mid_delivered + 1;
55249656eefSMichael Tuexen 	if (SCTP_MID_EQ(asoc->idata_supported, nxt_todel, control->mid)) {
553f8829a4aSRandall Stewart 		/* can be delivered right away? */
554b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) {
555f8829a4aSRandall Stewart 			sctp_log_strm_del(control, NULL, SCTP_STR_LOG_FROM_IMMED_DEL);
55680fefe0aSRandall Stewart 		}
557830d754dSRandall Stewart 		/* EY it wont be queued if it could be delivered directly */
558f8829a4aSRandall Stewart 		queue_needed = 0;
55928cd0699SMichael Tuexen 		if (asoc->size_on_all_streams >= control->length) {
560f8829a4aSRandall Stewart 			asoc->size_on_all_streams -= control->length;
56128cd0699SMichael Tuexen 		} else {
56228cd0699SMichael Tuexen #ifdef INVARIANTS
56328cd0699SMichael Tuexen 			panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
56428cd0699SMichael Tuexen #else
56528cd0699SMichael Tuexen 			asoc->size_on_all_streams = 0;
56628cd0699SMichael Tuexen #endif
56728cd0699SMichael Tuexen 		}
568f8829a4aSRandall Stewart 		sctp_ucount_decr(asoc->cnt_on_all_streams);
56949656eefSMichael Tuexen 		strm->last_mid_delivered++;
570b5c16493SMichael Tuexen 		sctp_mark_non_revokable(asoc, control->sinfo_tsn);
571f8829a4aSRandall Stewart 		sctp_add_to_readq(stcb->sctp_ep, stcb,
572f8829a4aSRandall Stewart 		    control,
573cfde3ff7SRandall Stewart 		    &stcb->sctp_socket->so_rcv, 1,
574574679afSMichael Tuexen 		    SCTP_READ_LOCK_NOT_HELD, SCTP_SO_LOCKED);
57544249214SRandall Stewart 		TAILQ_FOREACH_SAFE(control, &strm->inqueue, next_instrm, at) {
576f8829a4aSRandall Stewart 			/* all delivered */
57749656eefSMichael Tuexen 			nxt_todel = strm->last_mid_delivered + 1;
57849656eefSMichael Tuexen 			if (SCTP_MID_EQ(asoc->idata_supported, nxt_todel, control->mid) &&
57944249214SRandall Stewart 			    (((control->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG)) {
58044249214SRandall Stewart 				if (control->on_strm_q == SCTP_ON_ORDERED) {
58144249214SRandall Stewart 					TAILQ_REMOVE(&strm->inqueue, control, next_instrm);
58228cd0699SMichael Tuexen 					if (asoc->size_on_all_streams >= control->length) {
58328cd0699SMichael Tuexen 						asoc->size_on_all_streams -= control->length;
58428cd0699SMichael Tuexen 					} else {
58528cd0699SMichael Tuexen #ifdef INVARIANTS
58628cd0699SMichael Tuexen 						panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
58728cd0699SMichael Tuexen #else
58828cd0699SMichael Tuexen 						asoc->size_on_all_streams = 0;
58928cd0699SMichael Tuexen #endif
59028cd0699SMichael Tuexen 					}
59128cd0699SMichael Tuexen 					sctp_ucount_decr(asoc->cnt_on_all_streams);
59298d5fd97SMichael Tuexen #ifdef INVARIANTS
59344249214SRandall Stewart 				} else {
59444249214SRandall Stewart 					panic("Huh control: %p is on_strm_q: %d",
59544249214SRandall Stewart 					    control, control->on_strm_q);
59698d5fd97SMichael Tuexen #endif
59744249214SRandall Stewart 				}
59844249214SRandall Stewart 				control->on_strm_q = 0;
59949656eefSMichael Tuexen 				strm->last_mid_delivered++;
600f8829a4aSRandall Stewart 				/*
601f8829a4aSRandall Stewart 				 * We ignore the return of deliver_data here
602f8829a4aSRandall Stewart 				 * since we always can hold the chunk on the
603f8829a4aSRandall Stewart 				 * d-queue. And we have a finite number that
604f8829a4aSRandall Stewart 				 * can be delivered from the strq.
605f8829a4aSRandall Stewart 				 */
606b3f1ea41SRandall Stewart 				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) {
607f8829a4aSRandall Stewart 					sctp_log_strm_del(control, NULL,
608f8829a4aSRandall Stewart 					    SCTP_STR_LOG_FROM_IMMED_DEL);
60980fefe0aSRandall Stewart 				}
610b5c16493SMichael Tuexen 				sctp_mark_non_revokable(asoc, control->sinfo_tsn);
611f8829a4aSRandall Stewart 				sctp_add_to_readq(stcb->sctp_ep, stcb,
612f8829a4aSRandall Stewart 				    control,
613cfde3ff7SRandall Stewart 				    &stcb->sctp_socket->so_rcv, 1,
614cfde3ff7SRandall Stewart 				    SCTP_READ_LOCK_NOT_HELD,
615574679afSMichael Tuexen 				    SCTP_SO_LOCKED);
616f8829a4aSRandall Stewart 				continue;
61749656eefSMichael Tuexen 			} else if (SCTP_MID_EQ(asoc->idata_supported, nxt_todel, control->mid)) {
61844249214SRandall Stewart 				*need_reasm = 1;
619f8829a4aSRandall Stewart 			}
620f8829a4aSRandall Stewart 			break;
621f8829a4aSRandall Stewart 		}
622f8829a4aSRandall Stewart 	}
623f8829a4aSRandall Stewart 	if (queue_needed) {
624f8829a4aSRandall Stewart 		/*
625f8829a4aSRandall Stewart 		 * Ok, we did not deliver this guy, find the correct place
626f8829a4aSRandall Stewart 		 * to put it on the queue.
627f8829a4aSRandall Stewart 		 */
62844249214SRandall Stewart 		if (sctp_place_control_in_stream(strm, asoc, control)) {
629999f86d6SMichael Tuexen 			SCTP_SNPRINTF(msg, sizeof(msg),
630999f86d6SMichael Tuexen 			    "Queue to str MID: %u duplicate", control->mid);
631d1ea5fa9SMichael Tuexen 			sctp_clean_up_control(stcb, control);
632b1deed45SMichael Tuexen 			op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
63344249214SRandall Stewart 			stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_3;
634b1deed45SMichael Tuexen 			sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
63544249214SRandall Stewart 			*abort_flag = 1;
636f8829a4aSRandall Stewart 		}
637f8829a4aSRandall Stewart 	}
638f8829a4aSRandall Stewart }
639f8829a4aSRandall Stewart 
64044249214SRandall Stewart static void
64144249214SRandall Stewart sctp_setup_tail_pointer(struct sctp_queued_to_read *control)
642f8829a4aSRandall Stewart {
64344249214SRandall Stewart 	struct mbuf *m, *prev = NULL;
64444249214SRandall Stewart 	struct sctp_tcb *stcb;
645f8829a4aSRandall Stewart 
64644249214SRandall Stewart 	stcb = control->stcb;
64744249214SRandall Stewart 	control->held_length = 0;
64844249214SRandall Stewart 	control->length = 0;
64944249214SRandall Stewart 	m = control->data;
65044249214SRandall Stewart 	while (m) {
65144249214SRandall Stewart 		if (SCTP_BUF_LEN(m) == 0) {
65244249214SRandall Stewart 			/* Skip mbufs with NO length */
65344249214SRandall Stewart 			if (prev == NULL) {
65444249214SRandall Stewart 				/* First one */
65544249214SRandall Stewart 				control->data = sctp_m_free(m);
65644249214SRandall Stewart 				m = control->data;
65744249214SRandall Stewart 			} else {
65844249214SRandall Stewart 				SCTP_BUF_NEXT(prev) = sctp_m_free(m);
65944249214SRandall Stewart 				m = SCTP_BUF_NEXT(prev);
660f8829a4aSRandall Stewart 			}
66144249214SRandall Stewart 			if (m == NULL) {
66244249214SRandall Stewart 				control->tail_mbuf = prev;
663f8829a4aSRandall Stewart 			}
66444249214SRandall Stewart 			continue;
665f8829a4aSRandall Stewart 		}
66644249214SRandall Stewart 		prev = m;
66744249214SRandall Stewart 		atomic_add_int(&control->length, SCTP_BUF_LEN(m));
66844249214SRandall Stewart 		if (control->on_read_q) {
66944249214SRandall Stewart 			/*
67044249214SRandall Stewart 			 * On read queue so we must increment the SB stuff,
67144249214SRandall Stewart 			 * we assume caller has done any locks of SB.
67244249214SRandall Stewart 			 */
67344249214SRandall Stewart 			sctp_sballoc(stcb, &stcb->sctp_socket->so_rcv, m);
674f8829a4aSRandall Stewart 		}
67544249214SRandall Stewart 		m = SCTP_BUF_NEXT(m);
676f8829a4aSRandall Stewart 	}
67744249214SRandall Stewart 	if (prev) {
67844249214SRandall Stewart 		control->tail_mbuf = prev;
67944249214SRandall Stewart 	}
680f8829a4aSRandall Stewart }
681f8829a4aSRandall Stewart 
682f8829a4aSRandall Stewart static void
68328cd0699SMichael Tuexen sctp_add_to_tail_pointer(struct sctp_queued_to_read *control, struct mbuf *m, uint32_t *added)
684f8829a4aSRandall Stewart {
68544249214SRandall Stewart 	struct mbuf *prev = NULL;
68644249214SRandall Stewart 	struct sctp_tcb *stcb;
687f8829a4aSRandall Stewart 
68844249214SRandall Stewart 	stcb = control->stcb;
68944249214SRandall Stewart 	if (stcb == NULL) {
69098d5fd97SMichael Tuexen #ifdef INVARIANTS
69144249214SRandall Stewart 		panic("Control broken");
69298d5fd97SMichael Tuexen #else
69398d5fd97SMichael Tuexen 		return;
69498d5fd97SMichael Tuexen #endif
69544249214SRandall Stewart 	}
69644249214SRandall Stewart 	if (control->tail_mbuf == NULL) {
69744249214SRandall Stewart 		/* TSNH */
69863fb39baSMichael Tuexen 		sctp_m_freem(control->data);
69944249214SRandall Stewart 		control->data = m;
70044249214SRandall Stewart 		sctp_setup_tail_pointer(control);
701f8829a4aSRandall Stewart 		return;
702f8829a4aSRandall Stewart 	}
70344249214SRandall Stewart 	control->tail_mbuf->m_next = m;
70444249214SRandall Stewart 	while (m) {
70544249214SRandall Stewart 		if (SCTP_BUF_LEN(m) == 0) {
70644249214SRandall Stewart 			/* Skip mbufs with NO length */
70744249214SRandall Stewart 			if (prev == NULL) {
70844249214SRandall Stewart 				/* First one */
70944249214SRandall Stewart 				control->tail_mbuf->m_next = sctp_m_free(m);
71044249214SRandall Stewart 				m = control->tail_mbuf->m_next;
71144249214SRandall Stewart 			} else {
71244249214SRandall Stewart 				SCTP_BUF_NEXT(prev) = sctp_m_free(m);
71344249214SRandall Stewart 				m = SCTP_BUF_NEXT(prev);
71444249214SRandall Stewart 			}
71544249214SRandall Stewart 			if (m == NULL) {
71644249214SRandall Stewart 				control->tail_mbuf = prev;
71744249214SRandall Stewart 			}
71844249214SRandall Stewart 			continue;
71944249214SRandall Stewart 		}
72044249214SRandall Stewart 		prev = m;
72144249214SRandall Stewart 		if (control->on_read_q) {
722f8829a4aSRandall Stewart 			/*
72344249214SRandall Stewart 			 * On read queue so we must increment the SB stuff,
72444249214SRandall Stewart 			 * we assume caller has done any locks of SB.
725f8829a4aSRandall Stewart 			 */
72644249214SRandall Stewart 			sctp_sballoc(stcb, &stcb->sctp_socket->so_rcv, m);
72744249214SRandall Stewart 		}
72828cd0699SMichael Tuexen 		*added += SCTP_BUF_LEN(m);
72944249214SRandall Stewart 		atomic_add_int(&control->length, SCTP_BUF_LEN(m));
73044249214SRandall Stewart 		m = SCTP_BUF_NEXT(m);
73144249214SRandall Stewart 	}
73244249214SRandall Stewart 	if (prev) {
73344249214SRandall Stewart 		control->tail_mbuf = prev;
73444249214SRandall Stewart 	}
73544249214SRandall Stewart }
73644249214SRandall Stewart 
73744249214SRandall Stewart static void
73844249214SRandall Stewart sctp_build_readq_entry_from_ctl(struct sctp_queued_to_read *nc, struct sctp_queued_to_read *control)
73944249214SRandall Stewart {
74044249214SRandall Stewart 	memset(nc, 0, sizeof(struct sctp_queued_to_read));
74144249214SRandall Stewart 	nc->sinfo_stream = control->sinfo_stream;
74249656eefSMichael Tuexen 	nc->mid = control->mid;
74344249214SRandall Stewart 	TAILQ_INIT(&nc->reasm);
74444249214SRandall Stewart 	nc->top_fsn = control->top_fsn;
74549656eefSMichael Tuexen 	nc->mid = control->mid;
74644249214SRandall Stewart 	nc->sinfo_flags = control->sinfo_flags;
74744249214SRandall Stewart 	nc->sinfo_ppid = control->sinfo_ppid;
74844249214SRandall Stewart 	nc->sinfo_context = control->sinfo_context;
74944249214SRandall Stewart 	nc->fsn_included = 0xffffffff;
75044249214SRandall Stewart 	nc->sinfo_tsn = control->sinfo_tsn;
75144249214SRandall Stewart 	nc->sinfo_cumtsn = control->sinfo_cumtsn;
75244249214SRandall Stewart 	nc->sinfo_assoc_id = control->sinfo_assoc_id;
75344249214SRandall Stewart 	nc->whoFrom = control->whoFrom;
75444249214SRandall Stewart 	atomic_add_int(&nc->whoFrom->ref_count, 1);
75544249214SRandall Stewart 	nc->stcb = control->stcb;
75644249214SRandall Stewart 	nc->port_from = control->port_from;
757daf14341SMichael Tuexen 	nc->do_not_ref_stcb = control->do_not_ref_stcb;
75844249214SRandall Stewart }
75944249214SRandall Stewart 
760d1ea5fa9SMichael Tuexen static void
761d1ea5fa9SMichael Tuexen sctp_reset_a_control(struct sctp_queued_to_read *control,
762d1ea5fa9SMichael Tuexen     struct sctp_inpcb *inp, uint32_t tsn)
763d1ea5fa9SMichael Tuexen {
764d1ea5fa9SMichael Tuexen 	control->fsn_included = tsn;
765d1ea5fa9SMichael Tuexen 	if (control->on_read_q) {
766d1ea5fa9SMichael Tuexen 		/*
767d1ea5fa9SMichael Tuexen 		 * We have to purge it from there, hopefully this will work
768d1ea5fa9SMichael Tuexen 		 * :-)
769d1ea5fa9SMichael Tuexen 		 */
770d1ea5fa9SMichael Tuexen 		TAILQ_REMOVE(&inp->read_queue, control, next);
771d1ea5fa9SMichael Tuexen 		control->on_read_q = 0;
772d1ea5fa9SMichael Tuexen 	}
773d1ea5fa9SMichael Tuexen }
774d1ea5fa9SMichael Tuexen 
77544249214SRandall Stewart static int
776d1ea5fa9SMichael Tuexen sctp_handle_old_unordered_data(struct sctp_tcb *stcb,
777d1ea5fa9SMichael Tuexen     struct sctp_association *asoc,
778d1ea5fa9SMichael Tuexen     struct sctp_stream_in *strm,
779d1ea5fa9SMichael Tuexen     struct sctp_queued_to_read *control,
780d1ea5fa9SMichael Tuexen     uint32_t pd_point,
781d1ea5fa9SMichael Tuexen     int inp_read_lock_held)
78244249214SRandall Stewart {
78344249214SRandall Stewart 	/*
78444249214SRandall Stewart 	 * Special handling for the old un-ordered data chunk. All the
78549656eefSMichael Tuexen 	 * chunks/TSN's go to mid 0. So we have to do the old style watching
78649656eefSMichael Tuexen 	 * to see if we have it all. If you return one, no other control
78749656eefSMichael Tuexen 	 * entries on the un-ordered queue will be looked at. In theory
78849656eefSMichael Tuexen 	 * there should be no others entries in reality, unless the guy is
78949656eefSMichael Tuexen 	 * sending both unordered NDATA and unordered DATA...
79044249214SRandall Stewart 	 */
79144249214SRandall Stewart 	struct sctp_tmit_chunk *chk, *lchk, *tchk;
79244249214SRandall Stewart 	uint32_t fsn;
793643fd575SMichael Tuexen 	struct sctp_queued_to_read *nc;
79444249214SRandall Stewart 	int cnt_added;
79544249214SRandall Stewart 
79644249214SRandall Stewart 	if (control->first_frag_seen == 0) {
79744249214SRandall Stewart 		/* Nothing we can do, we have not seen the first piece yet */
79844249214SRandall Stewart 		return (1);
79944249214SRandall Stewart 	}
80044249214SRandall Stewart 	/* Collapse any we can */
80144249214SRandall Stewart 	cnt_added = 0;
80244249214SRandall Stewart restart:
80344249214SRandall Stewart 	fsn = control->fsn_included + 1;
80444249214SRandall Stewart 	/* Now what can we add? */
80544249214SRandall Stewart 	TAILQ_FOREACH_SAFE(chk, &control->reasm, sctp_next, lchk) {
80649656eefSMichael Tuexen 		if (chk->rec.data.fsn == fsn) {
80744249214SRandall Stewart 			/* Ok lets add it */
808643fd575SMichael Tuexen 			sctp_alloc_a_readq(stcb, nc);
809643fd575SMichael Tuexen 			if (nc == NULL) {
810643fd575SMichael Tuexen 				break;
811643fd575SMichael Tuexen 			}
812643fd575SMichael Tuexen 			memset(nc, 0, sizeof(struct sctp_queued_to_read));
81344249214SRandall Stewart 			TAILQ_REMOVE(&control->reasm, chk, sctp_next);
814d1ea5fa9SMichael Tuexen 			sctp_add_chk_to_control(control, strm, stcb, asoc, chk, SCTP_READ_LOCK_NOT_HELD);
81544249214SRandall Stewart 			fsn++;
81644249214SRandall Stewart 			cnt_added++;
81744249214SRandall Stewart 			chk = NULL;
81844249214SRandall Stewart 			if (control->end_added) {
81944249214SRandall Stewart 				/* We are done */
82044249214SRandall Stewart 				if (!TAILQ_EMPTY(&control->reasm)) {
82144249214SRandall Stewart 					/*
82244249214SRandall Stewart 					 * Ok we have to move anything left
82344249214SRandall Stewart 					 * on the control queue to a new
82444249214SRandall Stewart 					 * control.
82544249214SRandall Stewart 					 */
82644249214SRandall Stewart 					sctp_build_readq_entry_from_ctl(nc, control);
82744249214SRandall Stewart 					tchk = TAILQ_FIRST(&control->reasm);
82844249214SRandall Stewart 					if (tchk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) {
82944249214SRandall Stewart 						TAILQ_REMOVE(&control->reasm, tchk, sctp_next);
83028cd0699SMichael Tuexen 						if (asoc->size_on_reasm_queue >= tchk->send_size) {
8315cb91655SMichael Tuexen 							asoc->size_on_reasm_queue -= tchk->send_size;
83228cd0699SMichael Tuexen 						} else {
83328cd0699SMichael Tuexen #ifdef INVARIANTS
83428cd0699SMichael Tuexen 							panic("size_on_reasm_queue = %u smaller than chunk length %u", asoc->size_on_reasm_queue, tchk->send_size);
83528cd0699SMichael Tuexen #else
83628cd0699SMichael Tuexen 							asoc->size_on_reasm_queue = 0;
83728cd0699SMichael Tuexen #endif
83828cd0699SMichael Tuexen 						}
8395cb91655SMichael Tuexen 						sctp_ucount_decr(asoc->cnt_on_reasm_queue);
84044249214SRandall Stewart 						nc->first_frag_seen = 1;
84149656eefSMichael Tuexen 						nc->fsn_included = tchk->rec.data.fsn;
84244249214SRandall Stewart 						nc->data = tchk->data;
84349656eefSMichael Tuexen 						nc->sinfo_ppid = tchk->rec.data.ppid;
84449656eefSMichael Tuexen 						nc->sinfo_tsn = tchk->rec.data.tsn;
84549656eefSMichael Tuexen 						sctp_mark_non_revokable(asoc, tchk->rec.data.tsn);
84644249214SRandall Stewart 						tchk->data = NULL;
84744249214SRandall Stewart 						sctp_free_a_chunk(stcb, tchk, SCTP_SO_NOT_LOCKED);
84844249214SRandall Stewart 						sctp_setup_tail_pointer(nc);
84944249214SRandall Stewart 						tchk = TAILQ_FIRST(&control->reasm);
85044249214SRandall Stewart 					}
85144249214SRandall Stewart 					/* Spin the rest onto the queue */
85244249214SRandall Stewart 					while (tchk) {
85344249214SRandall Stewart 						TAILQ_REMOVE(&control->reasm, tchk, sctp_next);
85444249214SRandall Stewart 						TAILQ_INSERT_TAIL(&nc->reasm, tchk, sctp_next);
85544249214SRandall Stewart 						tchk = TAILQ_FIRST(&control->reasm);
85644249214SRandall Stewart 					}
857b7b84c0eSMichael Tuexen 					/*
858b7b84c0eSMichael Tuexen 					 * Now lets add it to the queue
859b7b84c0eSMichael Tuexen 					 * after removing control
860b7b84c0eSMichael Tuexen 					 */
86144249214SRandall Stewart 					TAILQ_INSERT_TAIL(&strm->uno_inqueue, nc, next_instrm);
86244249214SRandall Stewart 					nc->on_strm_q = SCTP_ON_UNORDERED;
86344249214SRandall Stewart 					if (control->on_strm_q) {
86444249214SRandall Stewart 						TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm);
86544249214SRandall Stewart 						control->on_strm_q = 0;
86644249214SRandall Stewart 					}
86744249214SRandall Stewart 				}
86844249214SRandall Stewart 				if (control->pdapi_started) {
86944249214SRandall Stewart 					strm->pd_api_started = 0;
87044249214SRandall Stewart 					control->pdapi_started = 0;
87144249214SRandall Stewart 				}
87244249214SRandall Stewart 				if (control->on_strm_q) {
87344249214SRandall Stewart 					TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm);
87444249214SRandall Stewart 					control->on_strm_q = 0;
87526f0250aSMichael Tuexen 					SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs);
87644249214SRandall Stewart 				}
877c09a1534SMichael Tuexen 				if (control->on_read_q == 0) {
878c09a1534SMichael Tuexen 					sctp_add_to_readq(stcb->sctp_ep, stcb, control,
879c09a1534SMichael Tuexen 					    &stcb->sctp_socket->so_rcv, control->end_added,
880d1ea5fa9SMichael Tuexen 					    inp_read_lock_held, SCTP_SO_NOT_LOCKED);
881c09a1534SMichael Tuexen 				}
882b1deed45SMichael Tuexen 				sctp_wakeup_the_read_socket(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED);
8830fa7377aSMichael Tuexen 				if ((nc->first_frag_seen) && !TAILQ_EMPTY(&nc->reasm)) {
884b7b84c0eSMichael Tuexen 					/*
885b7b84c0eSMichael Tuexen 					 * Switch to the new guy and
886b7b84c0eSMichael Tuexen 					 * continue
887b7b84c0eSMichael Tuexen 					 */
88844249214SRandall Stewart 					control = nc;
88944249214SRandall Stewart 					goto restart;
890643fd575SMichael Tuexen 				} else {
891d1ea5fa9SMichael Tuexen 					if (nc->on_strm_q == 0) {
892643fd575SMichael Tuexen 						sctp_free_a_readq(stcb, nc);
89344249214SRandall Stewart 					}
894d1ea5fa9SMichael Tuexen 				}
89544249214SRandall Stewart 				return (1);
896643fd575SMichael Tuexen 			} else {
897643fd575SMichael Tuexen 				sctp_free_a_readq(stcb, nc);
89844249214SRandall Stewart 			}
89944249214SRandall Stewart 		} else {
90044249214SRandall Stewart 			/* Can't add more */
90144249214SRandall Stewart 			break;
90244249214SRandall Stewart 		}
90344249214SRandall Stewart 	}
904f1903dc0SMichael Tuexen 	if (cnt_added && strm->pd_api_started) {
905f1903dc0SMichael Tuexen 		sctp_wakeup_the_read_socket(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED);
906f1903dc0SMichael Tuexen 	}
90744249214SRandall Stewart 	if ((control->length > pd_point) && (strm->pd_api_started == 0)) {
908c09a1534SMichael Tuexen 		strm->pd_api_started = 1;
909c09a1534SMichael Tuexen 		control->pdapi_started = 1;
91044249214SRandall Stewart 		sctp_add_to_readq(stcb->sctp_ep, stcb, control,
91144249214SRandall Stewart 		    &stcb->sctp_socket->so_rcv, control->end_added,
912d1ea5fa9SMichael Tuexen 		    inp_read_lock_held, SCTP_SO_NOT_LOCKED);
913b1deed45SMichael Tuexen 		sctp_wakeup_the_read_socket(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED);
91444249214SRandall Stewart 		return (0);
91544249214SRandall Stewart 	} else {
91644249214SRandall Stewart 		return (1);
91744249214SRandall Stewart 	}
91844249214SRandall Stewart }
91944249214SRandall Stewart 
92044249214SRandall Stewart static void
921d1ea5fa9SMichael Tuexen sctp_inject_old_unordered_data(struct sctp_tcb *stcb,
922d1ea5fa9SMichael Tuexen     struct sctp_association *asoc,
92344249214SRandall Stewart     struct sctp_queued_to_read *control,
92444249214SRandall Stewart     struct sctp_tmit_chunk *chk,
92544249214SRandall Stewart     int *abort_flag)
92644249214SRandall Stewart {
92744249214SRandall Stewart 	struct sctp_tmit_chunk *at;
928d1ea5fa9SMichael Tuexen 	int inserted;
92944249214SRandall Stewart 
93044249214SRandall Stewart 	/*
93144249214SRandall Stewart 	 * Here we need to place the chunk into the control structure sorted
93244249214SRandall Stewart 	 * in the correct order.
93344249214SRandall Stewart 	 */
93444249214SRandall Stewart 	if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) {
93544249214SRandall Stewart 		/* Its the very first one. */
93644249214SRandall Stewart 		SCTPDBG(SCTP_DEBUG_XXX,
937f2ea2a2dSMichael Tuexen 		    "chunk is a first fsn: %u becomes fsn_included\n",
93849656eefSMichael Tuexen 		    chk->rec.data.fsn);
9392de5b904SMichael Tuexen 		at = TAILQ_FIRST(&control->reasm);
9402de5b904SMichael Tuexen 		if (at && SCTP_TSN_GT(chk->rec.data.fsn, at->rec.data.fsn)) {
9412de5b904SMichael Tuexen 			/*
9422de5b904SMichael Tuexen 			 * The first chunk in the reassembly is a smaller
9432de5b904SMichael Tuexen 			 * TSN than this one, even though this has a first,
9442de5b904SMichael Tuexen 			 * it must be from a subsequent msg.
9452de5b904SMichael Tuexen 			 */
9462de5b904SMichael Tuexen 			goto place_chunk;
9472de5b904SMichael Tuexen 		}
94844249214SRandall Stewart 		if (control->first_frag_seen) {
94944249214SRandall Stewart 			/*
95044249214SRandall Stewart 			 * In old un-ordered we can reassembly on one
95144249214SRandall Stewart 			 * control multiple messages. As long as the next
95244249214SRandall Stewart 			 * FIRST is greater then the old first (TSN i.e. FSN
95344249214SRandall Stewart 			 * wise)
95444249214SRandall Stewart 			 */
95544249214SRandall Stewart 			struct mbuf *tdata;
95644249214SRandall Stewart 			uint32_t tmp;
95744249214SRandall Stewart 
95849656eefSMichael Tuexen 			if (SCTP_TSN_GT(chk->rec.data.fsn, control->fsn_included)) {
959b7b84c0eSMichael Tuexen 				/*
960b7b84c0eSMichael Tuexen 				 * Easy way the start of a new guy beyond
961b7b84c0eSMichael Tuexen 				 * the lowest
962b7b84c0eSMichael Tuexen 				 */
96344249214SRandall Stewart 				goto place_chunk;
96444249214SRandall Stewart 			}
96549656eefSMichael Tuexen 			if ((chk->rec.data.fsn == control->fsn_included) ||
96644249214SRandall Stewart 			    (control->pdapi_started)) {
96744249214SRandall Stewart 				/*
96844249214SRandall Stewart 				 * Ok this should not happen, if it does we
96944249214SRandall Stewart 				 * started the pd-api on the higher TSN
97044249214SRandall Stewart 				 * (since the equals part is a TSN failure
97144249214SRandall Stewart 				 * it must be that).
97244249214SRandall Stewart 				 *
9735b495f17SMichael Tuexen 				 * We are completly hosed in that case since
9745b495f17SMichael Tuexen 				 * I have no way to recover. This really
9755b495f17SMichael Tuexen 				 * will only happen if we can get more TSN's
97644249214SRandall Stewart 				 * higher before the pd-api-point.
97744249214SRandall Stewart 				 */
978b1deed45SMichael Tuexen 				sctp_abort_in_reasm(stcb, control, chk,
97944249214SRandall Stewart 				    abort_flag,
98044249214SRandall Stewart 				    SCTP_FROM_SCTP_INDATA + SCTP_LOC_4);
98144249214SRandall Stewart 
98244249214SRandall Stewart 				return;
98344249214SRandall Stewart 			}
98444249214SRandall Stewart 			/*
98544249214SRandall Stewart 			 * Ok we have two firsts and the one we just got is
98644249214SRandall Stewart 			 * smaller than the one we previously placed.. yuck!
98744249214SRandall Stewart 			 * We must swap them out.
98844249214SRandall Stewart 			 */
98944249214SRandall Stewart 			/* swap the mbufs */
99044249214SRandall Stewart 			tdata = control->data;
99144249214SRandall Stewart 			control->data = chk->data;
99244249214SRandall Stewart 			chk->data = tdata;
993d1ea5fa9SMichael Tuexen 			/* Save the lengths */
994d1ea5fa9SMichael Tuexen 			chk->send_size = control->length;
995d1ea5fa9SMichael Tuexen 			/* Recompute length of control and tail pointer */
996d1ea5fa9SMichael Tuexen 			sctp_setup_tail_pointer(control);
99744249214SRandall Stewart 			/* Fix the FSN included */
99844249214SRandall Stewart 			tmp = control->fsn_included;
99949656eefSMichael Tuexen 			control->fsn_included = chk->rec.data.fsn;
100049656eefSMichael Tuexen 			chk->rec.data.fsn = tmp;
1001d1ea5fa9SMichael Tuexen 			/* Fix the TSN included */
1002d1ea5fa9SMichael Tuexen 			tmp = control->sinfo_tsn;
100349656eefSMichael Tuexen 			control->sinfo_tsn = chk->rec.data.tsn;
100449656eefSMichael Tuexen 			chk->rec.data.tsn = tmp;
1005d1ea5fa9SMichael Tuexen 			/* Fix the PPID included */
1006d1ea5fa9SMichael Tuexen 			tmp = control->sinfo_ppid;
100749656eefSMichael Tuexen 			control->sinfo_ppid = chk->rec.data.ppid;
100849656eefSMichael Tuexen 			chk->rec.data.ppid = tmp;
1009d1ea5fa9SMichael Tuexen 			/* Fix tail pointer */
101044249214SRandall Stewart 			goto place_chunk;
101144249214SRandall Stewart 		}
101244249214SRandall Stewart 		control->first_frag_seen = 1;
10138b9c95f4SMichael Tuexen 		control->fsn_included = chk->rec.data.fsn;
10148b9c95f4SMichael Tuexen 		control->top_fsn = chk->rec.data.fsn;
101549656eefSMichael Tuexen 		control->sinfo_tsn = chk->rec.data.tsn;
101649656eefSMichael Tuexen 		control->sinfo_ppid = chk->rec.data.ppid;
101744249214SRandall Stewart 		control->data = chk->data;
101849656eefSMichael Tuexen 		sctp_mark_non_revokable(asoc, chk->rec.data.tsn);
101944249214SRandall Stewart 		chk->data = NULL;
102044249214SRandall Stewart 		sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
102144249214SRandall Stewart 		sctp_setup_tail_pointer(control);
102244249214SRandall Stewart 		return;
102344249214SRandall Stewart 	}
102444249214SRandall Stewart place_chunk:
1025d1ea5fa9SMichael Tuexen 	inserted = 0;
102644249214SRandall Stewart 	TAILQ_FOREACH(at, &control->reasm, sctp_next) {
102749656eefSMichael Tuexen 		if (SCTP_TSN_GT(at->rec.data.fsn, chk->rec.data.fsn)) {
102844249214SRandall Stewart 			/*
102944249214SRandall Stewart 			 * This one in queue is bigger than the new one,
103044249214SRandall Stewart 			 * insert the new one before at.
103144249214SRandall Stewart 			 */
103244249214SRandall Stewart 			asoc->size_on_reasm_queue += chk->send_size;
103344249214SRandall Stewart 			sctp_ucount_incr(asoc->cnt_on_reasm_queue);
103444249214SRandall Stewart 			inserted = 1;
103544249214SRandall Stewart 			TAILQ_INSERT_BEFORE(at, chk, sctp_next);
103644249214SRandall Stewart 			break;
103749656eefSMichael Tuexen 		} else if (at->rec.data.fsn == chk->rec.data.fsn) {
103844249214SRandall Stewart 			/*
103944249214SRandall Stewart 			 * They sent a duplicate fsn number. This really
104044249214SRandall Stewart 			 * should not happen since the FSN is a TSN and it
104144249214SRandall Stewart 			 * should have been dropped earlier.
104244249214SRandall Stewart 			 */
1043b1deed45SMichael Tuexen 			sctp_abort_in_reasm(stcb, control, chk,
104444249214SRandall Stewart 			    abort_flag,
104544249214SRandall Stewart 			    SCTP_FROM_SCTP_INDATA + SCTP_LOC_5);
104644249214SRandall Stewart 			return;
104744249214SRandall Stewart 		}
104844249214SRandall Stewart 	}
104944249214SRandall Stewart 	if (inserted == 0) {
105044249214SRandall Stewart 		/* Its at the end */
105144249214SRandall Stewart 		asoc->size_on_reasm_queue += chk->send_size;
105244249214SRandall Stewart 		sctp_ucount_incr(asoc->cnt_on_reasm_queue);
105349656eefSMichael Tuexen 		control->top_fsn = chk->rec.data.fsn;
105444249214SRandall Stewart 		TAILQ_INSERT_TAIL(&control->reasm, chk, sctp_next);
105544249214SRandall Stewart 	}
105644249214SRandall Stewart }
105744249214SRandall Stewart 
105844249214SRandall Stewart static int
1059d1ea5fa9SMichael Tuexen sctp_deliver_reasm_check(struct sctp_tcb *stcb, struct sctp_association *asoc,
1060d1ea5fa9SMichael Tuexen     struct sctp_stream_in *strm, int inp_read_lock_held)
106144249214SRandall Stewart {
106244249214SRandall Stewart 	/*
106344249214SRandall Stewart 	 * Given a stream, strm, see if any of the SSN's on it that are
106444249214SRandall Stewart 	 * fragmented are ready to deliver. If so go ahead and place them on
106544249214SRandall Stewart 	 * the read queue. In so placing if we have hit the end, then we
106644249214SRandall Stewart 	 * need to remove them from the stream's queue.
106744249214SRandall Stewart 	 */
106844249214SRandall Stewart 	struct sctp_queued_to_read *control, *nctl = NULL;
106944249214SRandall Stewart 	uint32_t next_to_del;
107044249214SRandall Stewart 	uint32_t pd_point;
107144249214SRandall Stewart 	int ret = 0;
107244249214SRandall Stewart 
1073810ec536SMichael Tuexen 	if (stcb->sctp_socket) {
1074d4d23375SMichael Tuexen 		pd_point = min(SCTP_SB_LIMIT_RCV(stcb->sctp_socket) >> SCTP_PARTIAL_DELIVERY_SHIFT,
1075810ec536SMichael Tuexen 		    stcb->sctp_ep->partial_delivery_point);
1076810ec536SMichael Tuexen 	} else {
1077810ec536SMichael Tuexen 		pd_point = stcb->sctp_ep->partial_delivery_point;
1078810ec536SMichael Tuexen 	}
107944249214SRandall Stewart 	control = TAILQ_FIRST(&strm->uno_inqueue);
1080d1ea5fa9SMichael Tuexen 
10813d6fe5d8SMichael Tuexen 	if ((control != NULL) &&
108244249214SRandall Stewart 	    (asoc->idata_supported == 0)) {
108344249214SRandall Stewart 		/* Special handling needed for "old" data format */
1084d1ea5fa9SMichael Tuexen 		if (sctp_handle_old_unordered_data(stcb, asoc, strm, control, pd_point, inp_read_lock_held)) {
108544249214SRandall Stewart 			goto done_un;
1086f8829a4aSRandall Stewart 		}
1087f8829a4aSRandall Stewart 	}
108844249214SRandall Stewart 	if (strm->pd_api_started) {
108944249214SRandall Stewart 		/* Can't add more */
109044249214SRandall Stewart 		return (0);
109144249214SRandall Stewart 	}
109244249214SRandall Stewart 	while (control) {
1093f2ea2a2dSMichael Tuexen 		SCTPDBG(SCTP_DEBUG_XXX, "Looking at control: %p e(%d) ssn: %u top_fsn: %u inc_fsn: %u -uo\n",
109449656eefSMichael Tuexen 		    control, control->end_added, control->mid, control->top_fsn, control->fsn_included);
109544249214SRandall Stewart 		nctl = TAILQ_NEXT(control, next_instrm);
109644249214SRandall Stewart 		if (control->end_added) {
109744249214SRandall Stewart 			/* We just put the last bit on */
109844249214SRandall Stewart 			if (control->on_strm_q) {
109998d5fd97SMichael Tuexen #ifdef INVARIANTS
110044249214SRandall Stewart 				if (control->on_strm_q != SCTP_ON_UNORDERED) {
110144249214SRandall Stewart 					panic("Huh control: %p on_q: %d -- not unordered?",
110244249214SRandall Stewart 					    control, control->on_strm_q);
110344249214SRandall Stewart 				}
110498d5fd97SMichael Tuexen #endif
110526f0250aSMichael Tuexen 				SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs);
110644249214SRandall Stewart 				TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm);
1107132c0738SMichael Tuexen 				if (asoc->size_on_all_streams >= control->length) {
1108132c0738SMichael Tuexen 					asoc->size_on_all_streams -= control->length;
1109132c0738SMichael Tuexen 				} else {
1110132c0738SMichael Tuexen #ifdef INVARIANTS
1111132c0738SMichael Tuexen 					panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
1112132c0738SMichael Tuexen #else
1113132c0738SMichael Tuexen 					asoc->size_on_all_streams = 0;
1114132c0738SMichael Tuexen #endif
1115132c0738SMichael Tuexen 				}
1116132c0738SMichael Tuexen 				sctp_ucount_decr(asoc->cnt_on_all_streams);
111744249214SRandall Stewart 				control->on_strm_q = 0;
111844249214SRandall Stewart 			}
111944249214SRandall Stewart 			if (control->on_read_q == 0) {
112044249214SRandall Stewart 				sctp_add_to_readq(stcb->sctp_ep, stcb,
112144249214SRandall Stewart 				    control,
112244249214SRandall Stewart 				    &stcb->sctp_socket->so_rcv, control->end_added,
1123d1ea5fa9SMichael Tuexen 				    inp_read_lock_held, SCTP_SO_NOT_LOCKED);
112444249214SRandall Stewart 			}
1125f8829a4aSRandall Stewart 		} else {
112644249214SRandall Stewart 			/* Can we do a PD-API for this un-ordered guy? */
112744249214SRandall Stewart 			if ((control->length >= pd_point) && (strm->pd_api_started == 0)) {
112844249214SRandall Stewart 				strm->pd_api_started = 1;
112944249214SRandall Stewart 				control->pdapi_started = 1;
113044249214SRandall Stewart 				sctp_add_to_readq(stcb->sctp_ep, stcb,
113144249214SRandall Stewart 				    control,
113244249214SRandall Stewart 				    &stcb->sctp_socket->so_rcv, control->end_added,
1133d1ea5fa9SMichael Tuexen 				    inp_read_lock_held, SCTP_SO_NOT_LOCKED);
113444249214SRandall Stewart 
113544249214SRandall Stewart 				break;
1136139bc87fSRandall Stewart 			}
1137f8829a4aSRandall Stewart 		}
113844249214SRandall Stewart 		control = nctl;
113944249214SRandall Stewart 	}
114044249214SRandall Stewart done_un:
114144249214SRandall Stewart 	control = TAILQ_FIRST(&strm->inqueue);
114244249214SRandall Stewart 	if (strm->pd_api_started) {
114344249214SRandall Stewart 		/* Can't add more */
114444249214SRandall Stewart 		return (0);
114544249214SRandall Stewart 	}
114644249214SRandall Stewart 	if (control == NULL) {
114744249214SRandall Stewart 		return (ret);
114844249214SRandall Stewart 	}
114949656eefSMichael Tuexen 	if (SCTP_MID_EQ(asoc->idata_supported, strm->last_mid_delivered, control->mid)) {
115044249214SRandall Stewart 		/*
115144249214SRandall Stewart 		 * Ok the guy at the top was being partially delivered
115244249214SRandall Stewart 		 * completed, so we remove it. Note the pd_api flag was
115344249214SRandall Stewart 		 * taken off when the chunk was merged on in
115444249214SRandall Stewart 		 * sctp_queue_data_for_reasm below.
115544249214SRandall Stewart 		 */
115644249214SRandall Stewart 		nctl = TAILQ_NEXT(control, next_instrm);
115744249214SRandall Stewart 		SCTPDBG(SCTP_DEBUG_XXX,
1158f2ea2a2dSMichael Tuexen 		    "Looking at control: %p e(%d) ssn: %u top_fsn: %u inc_fsn: %u (lastdel: %u)- o\n",
115949656eefSMichael Tuexen 		    control, control->end_added, control->mid,
116044249214SRandall Stewart 		    control->top_fsn, control->fsn_included,
116149656eefSMichael Tuexen 		    strm->last_mid_delivered);
116244249214SRandall Stewart 		if (control->end_added) {
116344249214SRandall Stewart 			if (control->on_strm_q) {
116498d5fd97SMichael Tuexen #ifdef INVARIANTS
116544249214SRandall Stewart 				if (control->on_strm_q != SCTP_ON_ORDERED) {
116644249214SRandall Stewart 					panic("Huh control: %p on_q: %d -- not ordered?",
116744249214SRandall Stewart 					    control, control->on_strm_q);
116844249214SRandall Stewart 				}
116998d5fd97SMichael Tuexen #endif
117026f0250aSMichael Tuexen 				SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs);
117144249214SRandall Stewart 				TAILQ_REMOVE(&strm->inqueue, control, next_instrm);
117228cd0699SMichael Tuexen 				if (asoc->size_on_all_streams >= control->length) {
117328cd0699SMichael Tuexen 					asoc->size_on_all_streams -= control->length;
117428cd0699SMichael Tuexen 				} else {
117528cd0699SMichael Tuexen #ifdef INVARIANTS
117628cd0699SMichael Tuexen 					panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
117728cd0699SMichael Tuexen #else
117828cd0699SMichael Tuexen 					asoc->size_on_all_streams = 0;
117928cd0699SMichael Tuexen #endif
118028cd0699SMichael Tuexen 				}
118128cd0699SMichael Tuexen 				sctp_ucount_decr(asoc->cnt_on_all_streams);
118244249214SRandall Stewart 				control->on_strm_q = 0;
118344249214SRandall Stewart 			}
1184c09a1534SMichael Tuexen 			if (strm->pd_api_started && control->pdapi_started) {
1185c09a1534SMichael Tuexen 				control->pdapi_started = 0;
1186c09a1534SMichael Tuexen 				strm->pd_api_started = 0;
1187c09a1534SMichael Tuexen 			}
118844249214SRandall Stewart 			if (control->on_read_q == 0) {
118944249214SRandall Stewart 				sctp_add_to_readq(stcb->sctp_ep, stcb,
119044249214SRandall Stewart 				    control,
119144249214SRandall Stewart 				    &stcb->sctp_socket->so_rcv, control->end_added,
1192d1ea5fa9SMichael Tuexen 				    inp_read_lock_held, SCTP_SO_NOT_LOCKED);
119344249214SRandall Stewart 			}
119444249214SRandall Stewart 			control = nctl;
119544249214SRandall Stewart 		}
119644249214SRandall Stewart 	}
119744249214SRandall Stewart 	if (strm->pd_api_started) {
1198b7b84c0eSMichael Tuexen 		/*
1199b7b84c0eSMichael Tuexen 		 * Can't add more must have gotten an un-ordered above being
1200b7b84c0eSMichael Tuexen 		 * partially delivered.
1201b7b84c0eSMichael Tuexen 		 */
120244249214SRandall Stewart 		return (0);
120344249214SRandall Stewart 	}
120444249214SRandall Stewart deliver_more:
120549656eefSMichael Tuexen 	next_to_del = strm->last_mid_delivered + 1;
120644249214SRandall Stewart 	if (control) {
120744249214SRandall Stewart 		SCTPDBG(SCTP_DEBUG_XXX,
1208f2ea2a2dSMichael Tuexen 		    "Looking at control: %p e(%d) ssn: %u top_fsn: %u inc_fsn: %u (nxtdel: %u)- o\n",
120949656eefSMichael Tuexen 		    control, control->end_added, control->mid, control->top_fsn, control->fsn_included,
121044249214SRandall Stewart 		    next_to_del);
121144249214SRandall Stewart 		nctl = TAILQ_NEXT(control, next_instrm);
121249656eefSMichael Tuexen 		if (SCTP_MID_EQ(asoc->idata_supported, control->mid, next_to_del) &&
121344249214SRandall Stewart 		    (control->first_frag_seen)) {
1214c09a1534SMichael Tuexen 			int done;
1215c09a1534SMichael Tuexen 
121644249214SRandall Stewart 			/* Ok we can deliver it onto the stream. */
121744249214SRandall Stewart 			if (control->end_added) {
121844249214SRandall Stewart 				/* We are done with it afterwards */
121944249214SRandall Stewart 				if (control->on_strm_q) {
122098d5fd97SMichael Tuexen #ifdef INVARIANTS
122144249214SRandall Stewart 					if (control->on_strm_q != SCTP_ON_ORDERED) {
122244249214SRandall Stewart 						panic("Huh control: %p on_q: %d -- not ordered?",
122344249214SRandall Stewart 						    control, control->on_strm_q);
122444249214SRandall Stewart 					}
122598d5fd97SMichael Tuexen #endif
122626f0250aSMichael Tuexen 					SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs);
122744249214SRandall Stewart 					TAILQ_REMOVE(&strm->inqueue, control, next_instrm);
122828cd0699SMichael Tuexen 					if (asoc->size_on_all_streams >= control->length) {
122928cd0699SMichael Tuexen 						asoc->size_on_all_streams -= control->length;
123028cd0699SMichael Tuexen 					} else {
123128cd0699SMichael Tuexen #ifdef INVARIANTS
123228cd0699SMichael Tuexen 						panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
123328cd0699SMichael Tuexen #else
123428cd0699SMichael Tuexen 						asoc->size_on_all_streams = 0;
123528cd0699SMichael Tuexen #endif
123628cd0699SMichael Tuexen 					}
123728cd0699SMichael Tuexen 					sctp_ucount_decr(asoc->cnt_on_all_streams);
123844249214SRandall Stewart 					control->on_strm_q = 0;
123944249214SRandall Stewart 				}
124044249214SRandall Stewart 				ret++;
124144249214SRandall Stewart 			}
124244249214SRandall Stewart 			if (((control->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) {
1243b7b84c0eSMichael Tuexen 				/*
1244b7b84c0eSMichael Tuexen 				 * A singleton now slipping through - mark
1245b7b84c0eSMichael Tuexen 				 * it non-revokable too
1246b7b84c0eSMichael Tuexen 				 */
124744249214SRandall Stewart 				sctp_mark_non_revokable(asoc, control->sinfo_tsn);
124844249214SRandall Stewart 			} else if (control->end_added == 0) {
1249b7b84c0eSMichael Tuexen 				/*
1250b7b84c0eSMichael Tuexen 				 * Check if we can defer adding until its
1251b7b84c0eSMichael Tuexen 				 * all there
1252b7b84c0eSMichael Tuexen 				 */
125344249214SRandall Stewart 				if ((control->length < pd_point) || (strm->pd_api_started)) {
1254b7b84c0eSMichael Tuexen 					/*
1255b7b84c0eSMichael Tuexen 					 * Don't need it or cannot add more
1256b7b84c0eSMichael Tuexen 					 * (one being delivered that way)
1257b7b84c0eSMichael Tuexen 					 */
125844249214SRandall Stewart 					goto out;
125944249214SRandall Stewart 				}
126044249214SRandall Stewart 			}
1261c09a1534SMichael Tuexen 			done = (control->end_added) && (control->last_frag_seen);
126244249214SRandall Stewart 			if (control->on_read_q == 0) {
1263253a63b8SMichael Tuexen 				if (!done) {
1264253a63b8SMichael Tuexen 					if (asoc->size_on_all_streams >= control->length) {
1265253a63b8SMichael Tuexen 						asoc->size_on_all_streams -= control->length;
1266253a63b8SMichael Tuexen 					} else {
1267253a63b8SMichael Tuexen #ifdef INVARIANTS
1268253a63b8SMichael Tuexen 						panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
1269253a63b8SMichael Tuexen #else
1270253a63b8SMichael Tuexen 						asoc->size_on_all_streams = 0;
1271253a63b8SMichael Tuexen #endif
1272253a63b8SMichael Tuexen 					}
1273253a63b8SMichael Tuexen 					strm->pd_api_started = 1;
1274253a63b8SMichael Tuexen 					control->pdapi_started = 1;
1275253a63b8SMichael Tuexen 				}
127644249214SRandall Stewart 				sctp_add_to_readq(stcb->sctp_ep, stcb,
127744249214SRandall Stewart 				    control,
127844249214SRandall Stewart 				    &stcb->sctp_socket->so_rcv, control->end_added,
1279d1ea5fa9SMichael Tuexen 				    inp_read_lock_held, SCTP_SO_NOT_LOCKED);
128044249214SRandall Stewart 			}
128149656eefSMichael Tuexen 			strm->last_mid_delivered = next_to_del;
1282c09a1534SMichael Tuexen 			if (done) {
128344249214SRandall Stewart 				control = nctl;
128444249214SRandall Stewart 				goto deliver_more;
128544249214SRandall Stewart 			}
128644249214SRandall Stewart 		}
128744249214SRandall Stewart 	}
128844249214SRandall Stewart out:
128944249214SRandall Stewart 	return (ret);
129044249214SRandall Stewart }
129144249214SRandall Stewart 
129228cd0699SMichael Tuexen uint32_t
129344249214SRandall Stewart sctp_add_chk_to_control(struct sctp_queued_to_read *control,
129444249214SRandall Stewart     struct sctp_stream_in *strm,
129544249214SRandall Stewart     struct sctp_tcb *stcb, struct sctp_association *asoc,
1296b0471b4bSMichael Tuexen     struct sctp_tmit_chunk *chk, int hold_rlock)
1297b0471b4bSMichael Tuexen {
129844249214SRandall Stewart 	/*
129944249214SRandall Stewart 	 * Given a control and a chunk, merge the data from the chk onto the
130044249214SRandall Stewart 	 * control and free up the chunk resources.
130144249214SRandall Stewart 	 */
130228cd0699SMichael Tuexen 	uint32_t added = 0;
130344249214SRandall Stewart 	int i_locked = 0;
130444249214SRandall Stewart 
1305d1ea5fa9SMichael Tuexen 	if (control->on_read_q && (hold_rlock == 0)) {
130644249214SRandall Stewart 		/*
130744249214SRandall Stewart 		 * Its being pd-api'd so we must do some locks.
130844249214SRandall Stewart 		 */
130944249214SRandall Stewart 		SCTP_INP_READ_LOCK(stcb->sctp_ep);
131044249214SRandall Stewart 		i_locked = 1;
131144249214SRandall Stewart 	}
131244249214SRandall Stewart 	if (control->data == NULL) {
131344249214SRandall Stewart 		control->data = chk->data;
131444249214SRandall Stewart 		sctp_setup_tail_pointer(control);
131544249214SRandall Stewart 	} else {
131628cd0699SMichael Tuexen 		sctp_add_to_tail_pointer(control, chk->data, &added);
131744249214SRandall Stewart 	}
131849656eefSMichael Tuexen 	control->fsn_included = chk->rec.data.fsn;
131944249214SRandall Stewart 	asoc->size_on_reasm_queue -= chk->send_size;
132044249214SRandall Stewart 	sctp_ucount_decr(asoc->cnt_on_reasm_queue);
132149656eefSMichael Tuexen 	sctp_mark_non_revokable(asoc, chk->rec.data.tsn);
132244249214SRandall Stewart 	chk->data = NULL;
132344249214SRandall Stewart 	if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) {
132444249214SRandall Stewart 		control->first_frag_seen = 1;
13258b9c95f4SMichael Tuexen 		control->sinfo_tsn = chk->rec.data.tsn;
13268b9c95f4SMichael Tuexen 		control->sinfo_ppid = chk->rec.data.ppid;
132744249214SRandall Stewart 	}
132844249214SRandall Stewart 	if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) {
132944249214SRandall Stewart 		/* Its complete */
133044249214SRandall Stewart 		if ((control->on_strm_q) && (control->on_read_q)) {
133144249214SRandall Stewart 			if (control->pdapi_started) {
133244249214SRandall Stewart 				control->pdapi_started = 0;
133344249214SRandall Stewart 				strm->pd_api_started = 0;
133444249214SRandall Stewart 			}
133544249214SRandall Stewart 			if (control->on_strm_q == SCTP_ON_UNORDERED) {
133644249214SRandall Stewart 				/* Unordered */
133744249214SRandall Stewart 				TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm);
133844249214SRandall Stewart 				control->on_strm_q = 0;
133944249214SRandall Stewart 			} else if (control->on_strm_q == SCTP_ON_ORDERED) {
134044249214SRandall Stewart 				/* Ordered */
134144249214SRandall Stewart 				TAILQ_REMOVE(&strm->inqueue, control, next_instrm);
1342253a63b8SMichael Tuexen 				/*
1343253a63b8SMichael Tuexen 				 * Don't need to decrement
1344253a63b8SMichael Tuexen 				 * size_on_all_streams, since control is on
1345253a63b8SMichael Tuexen 				 * the read queue.
1346253a63b8SMichael Tuexen 				 */
134728cd0699SMichael Tuexen 				sctp_ucount_decr(asoc->cnt_on_all_streams);
134844249214SRandall Stewart 				control->on_strm_q = 0;
134998d5fd97SMichael Tuexen #ifdef INVARIANTS
135044249214SRandall Stewart 			} else if (control->on_strm_q) {
135144249214SRandall Stewart 				panic("Unknown state on ctrl: %p on_strm_q: %d", control,
135244249214SRandall Stewart 				    control->on_strm_q);
135398d5fd97SMichael Tuexen #endif
135444249214SRandall Stewart 			}
135544249214SRandall Stewart 		}
135644249214SRandall Stewart 		control->end_added = 1;
135744249214SRandall Stewart 		control->last_frag_seen = 1;
135844249214SRandall Stewart 	}
135944249214SRandall Stewart 	if (i_locked) {
136044249214SRandall Stewart 		SCTP_INP_READ_UNLOCK(stcb->sctp_ep);
136144249214SRandall Stewart 	}
136244249214SRandall Stewart 	sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
136328cd0699SMichael Tuexen 	return (added);
1364f8829a4aSRandall Stewart }
1365f8829a4aSRandall Stewart 
1366f8829a4aSRandall Stewart /*
1367f8829a4aSRandall Stewart  * Dump onto the re-assembly queue, in its proper place. After dumping on the
1368f8829a4aSRandall Stewart  * queue, see if anthing can be delivered. If so pull it off (or as much as
1369f8829a4aSRandall Stewart  * we can. If we run out of space then we must dump what we can and set the
1370f8829a4aSRandall Stewart  * appropriate flag to say we queued what we could.
1371f8829a4aSRandall Stewart  */
1372f8829a4aSRandall Stewart static void
1373f8829a4aSRandall Stewart sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc,
137444249214SRandall Stewart     struct sctp_queued_to_read *control,
137544249214SRandall Stewart     struct sctp_tmit_chunk *chk,
137644249214SRandall Stewart     int created_control,
137744249214SRandall Stewart     int *abort_flag, uint32_t tsn)
1378f8829a4aSRandall Stewart {
137944249214SRandall Stewart 	uint32_t next_fsn;
138044249214SRandall Stewart 	struct sctp_tmit_chunk *at, *nat;
13813d6fe5d8SMichael Tuexen 	struct sctp_stream_in *strm;
1382c09a1534SMichael Tuexen 	int do_wakeup, unordered;
138328cd0699SMichael Tuexen 	uint32_t lenadded;
1384f8829a4aSRandall Stewart 
13853d6fe5d8SMichael Tuexen 	strm = &asoc->strmin[control->sinfo_stream];
1386f8829a4aSRandall Stewart 	/*
138744249214SRandall Stewart 	 * For old un-ordered data chunks.
1388f8829a4aSRandall Stewart 	 */
138944249214SRandall Stewart 	if ((control->sinfo_flags >> 8) & SCTP_DATA_UNORDERED) {
139044249214SRandall Stewart 		unordered = 1;
1391f8829a4aSRandall Stewart 	} else {
139244249214SRandall Stewart 		unordered = 0;
139344249214SRandall Stewart 	}
139444249214SRandall Stewart 	/* Must be added to the stream-in queue */
139544249214SRandall Stewart 	if (created_control) {
1396132c0738SMichael Tuexen 		if ((unordered == 0) || (asoc->idata_supported)) {
139728cd0699SMichael Tuexen 			sctp_ucount_incr(asoc->cnt_on_all_streams);
139828cd0699SMichael Tuexen 		}
139944249214SRandall Stewart 		if (sctp_place_control_in_stream(strm, asoc, control)) {
140044249214SRandall Stewart 			/* Duplicate SSN? */
1401b1deed45SMichael Tuexen 			sctp_abort_in_reasm(stcb, control, chk,
140244249214SRandall Stewart 			    abort_flag,
140344249214SRandall Stewart 			    SCTP_FROM_SCTP_INDATA + SCTP_LOC_6);
140453999485SMichael Tuexen 			sctp_clean_up_control(stcb, control);
140544249214SRandall Stewart 			return;
140644249214SRandall Stewart 		}
140744249214SRandall Stewart 		if ((tsn == (asoc->cumulative_tsn + 1) && (asoc->idata_supported == 0))) {
1408f8829a4aSRandall Stewart 			/*
140944249214SRandall Stewart 			 * Ok we created this control and now lets validate
141044249214SRandall Stewart 			 * that its legal i.e. there is a B bit set, if not
141144249214SRandall Stewart 			 * and we have up to the cum-ack then its invalid.
141244249214SRandall Stewart 			 */
141344249214SRandall Stewart 			if ((chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) == 0) {
1414b1deed45SMichael Tuexen 				sctp_abort_in_reasm(stcb, control, chk,
141544249214SRandall Stewart 				    abort_flag,
141644249214SRandall Stewart 				    SCTP_FROM_SCTP_INDATA + SCTP_LOC_7);
141744249214SRandall Stewart 				return;
141844249214SRandall Stewart 			}
141944249214SRandall Stewart 		}
142044249214SRandall Stewart 	}
1421a39ddef0SMichael Tuexen 	if ((asoc->idata_supported == 0) && (unordered == 1)) {
1422d1ea5fa9SMichael Tuexen 		sctp_inject_old_unordered_data(stcb, asoc, control, chk, abort_flag);
142344249214SRandall Stewart 		return;
142444249214SRandall Stewart 	}
142544249214SRandall Stewart 	/*
142644249214SRandall Stewart 	 * Ok we must queue the chunk into the reasembly portion: o if its
142744249214SRandall Stewart 	 * the first it goes to the control mbuf. o if its not first but the
142844249214SRandall Stewart 	 * next in sequence it goes to the control, and each succeeding one
142944249214SRandall Stewart 	 * in order also goes. o if its not in order we place it on the list
143044249214SRandall Stewart 	 * in its place.
143144249214SRandall Stewart 	 */
143244249214SRandall Stewart 	if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) {
143344249214SRandall Stewart 		/* Its the very first one. */
143444249214SRandall Stewart 		SCTPDBG(SCTP_DEBUG_XXX,
1435f2ea2a2dSMichael Tuexen 		    "chunk is a first fsn: %u becomes fsn_included\n",
143649656eefSMichael Tuexen 		    chk->rec.data.fsn);
143744249214SRandall Stewart 		if (control->first_frag_seen) {
143844249214SRandall Stewart 			/*
143944249214SRandall Stewart 			 * Error on senders part, they either sent us two
144044249214SRandall Stewart 			 * data chunks with FIRST, or they sent two
144144249214SRandall Stewart 			 * un-ordered chunks that were fragmented at the
144244249214SRandall Stewart 			 * same time in the same stream.
144344249214SRandall Stewart 			 */
1444b1deed45SMichael Tuexen 			sctp_abort_in_reasm(stcb, control, chk,
144544249214SRandall Stewart 			    abort_flag,
144644249214SRandall Stewart 			    SCTP_FROM_SCTP_INDATA + SCTP_LOC_8);
144744249214SRandall Stewart 			return;
144844249214SRandall Stewart 		}
144944249214SRandall Stewart 		control->first_frag_seen = 1;
14508b9c95f4SMichael Tuexen 		control->sinfo_ppid = chk->rec.data.ppid;
14518b9c95f4SMichael Tuexen 		control->sinfo_tsn = chk->rec.data.tsn;
145249656eefSMichael Tuexen 		control->fsn_included = chk->rec.data.fsn;
145344249214SRandall Stewart 		control->data = chk->data;
145449656eefSMichael Tuexen 		sctp_mark_non_revokable(asoc, chk->rec.data.tsn);
145544249214SRandall Stewart 		chk->data = NULL;
145644249214SRandall Stewart 		sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
145744249214SRandall Stewart 		sctp_setup_tail_pointer(control);
145828cd0699SMichael Tuexen 		asoc->size_on_all_streams += control->length;
145944249214SRandall Stewart 	} else {
146044249214SRandall Stewart 		/* Place the chunk in our list */
146144249214SRandall Stewart 		int inserted = 0;
146244249214SRandall Stewart 
146344249214SRandall Stewart 		if (control->last_frag_seen == 0) {
146444249214SRandall Stewart 			/* Still willing to raise highest FSN seen */
146549656eefSMichael Tuexen 			if (SCTP_TSN_GT(chk->rec.data.fsn, control->top_fsn)) {
146644249214SRandall Stewart 				SCTPDBG(SCTP_DEBUG_XXX,
1467f2ea2a2dSMichael Tuexen 				    "We have a new top_fsn: %u\n",
146849656eefSMichael Tuexen 				    chk->rec.data.fsn);
146949656eefSMichael Tuexen 				control->top_fsn = chk->rec.data.fsn;
147044249214SRandall Stewart 			}
147144249214SRandall Stewart 			if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) {
147244249214SRandall Stewart 				SCTPDBG(SCTP_DEBUG_XXX,
1473f2ea2a2dSMichael Tuexen 				    "The last fsn is now in place fsn: %u\n",
147449656eefSMichael Tuexen 				    chk->rec.data.fsn);
147544249214SRandall Stewart 				control->last_frag_seen = 1;
1476ec24a1b6SMichael Tuexen 				if (SCTP_TSN_GT(control->top_fsn, chk->rec.data.fsn)) {
1477ec24a1b6SMichael Tuexen 					SCTPDBG(SCTP_DEBUG_XXX,
1478ec24a1b6SMichael Tuexen 					    "New fsn: %u is not at top_fsn: %u -- abort\n",
1479ec24a1b6SMichael Tuexen 					    chk->rec.data.fsn,
1480ec24a1b6SMichael Tuexen 					    control->top_fsn);
1481ec24a1b6SMichael Tuexen 					sctp_abort_in_reasm(stcb, control, chk,
1482ec24a1b6SMichael Tuexen 					    abort_flag,
1483ec24a1b6SMichael Tuexen 					    SCTP_FROM_SCTP_INDATA + SCTP_LOC_9);
1484ec24a1b6SMichael Tuexen 					return;
1485ec24a1b6SMichael Tuexen 				}
148644249214SRandall Stewart 			}
148744249214SRandall Stewart 			if (asoc->idata_supported || control->first_frag_seen) {
148844249214SRandall Stewart 				/*
148944249214SRandall Stewart 				 * For IDATA we always check since we know
149044249214SRandall Stewart 				 * that the first fragment is 0. For old
149144249214SRandall Stewart 				 * DATA we have to receive the first before
1492cd0a4ff6SPedro F. Giffuni 				 * we know the first FSN (which is the TSN).
149344249214SRandall Stewart 				 */
149449656eefSMichael Tuexen 				if (SCTP_TSN_GE(control->fsn_included, chk->rec.data.fsn)) {
1495b7b84c0eSMichael Tuexen 					/*
1496b7b84c0eSMichael Tuexen 					 * We have already delivered up to
1497b7b84c0eSMichael Tuexen 					 * this so its a dup
1498b7b84c0eSMichael Tuexen 					 */
1499b1deed45SMichael Tuexen 					sctp_abort_in_reasm(stcb, control, chk,
150044249214SRandall Stewart 					    abort_flag,
1501ec24a1b6SMichael Tuexen 					    SCTP_FROM_SCTP_INDATA + SCTP_LOC_10);
150244249214SRandall Stewart 					return;
150344249214SRandall Stewart 				}
150444249214SRandall Stewart 			}
150544249214SRandall Stewart 		} else {
150644249214SRandall Stewart 			if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) {
150744249214SRandall Stewart 				/* Second last? huh? */
150844249214SRandall Stewart 				SCTPDBG(SCTP_DEBUG_XXX,
1509f2ea2a2dSMichael Tuexen 				    "Duplicate last fsn: %u (top: %u) -- abort\n",
151049656eefSMichael Tuexen 				    chk->rec.data.fsn, control->top_fsn);
1511b1deed45SMichael Tuexen 				sctp_abort_in_reasm(stcb, control,
151244249214SRandall Stewart 				    chk, abort_flag,
1513ec24a1b6SMichael Tuexen 				    SCTP_FROM_SCTP_INDATA + SCTP_LOC_11);
151444249214SRandall Stewart 				return;
151544249214SRandall Stewart 			}
151644249214SRandall Stewart 			if (asoc->idata_supported || control->first_frag_seen) {
151744249214SRandall Stewart 				/*
151844249214SRandall Stewart 				 * For IDATA we always check since we know
151944249214SRandall Stewart 				 * that the first fragment is 0. For old
152044249214SRandall Stewart 				 * DATA we have to receive the first before
1521cd0a4ff6SPedro F. Giffuni 				 * we know the first FSN (which is the TSN).
152244249214SRandall Stewart 				 */
152344249214SRandall Stewart 
152449656eefSMichael Tuexen 				if (SCTP_TSN_GE(control->fsn_included, chk->rec.data.fsn)) {
1525b7b84c0eSMichael Tuexen 					/*
1526b7b84c0eSMichael Tuexen 					 * We have already delivered up to
1527b7b84c0eSMichael Tuexen 					 * this so its a dup
1528b7b84c0eSMichael Tuexen 					 */
152944249214SRandall Stewart 					SCTPDBG(SCTP_DEBUG_XXX,
1530f2ea2a2dSMichael Tuexen 					    "New fsn: %u is already seen in included_fsn: %u -- abort\n",
153149656eefSMichael Tuexen 					    chk->rec.data.fsn, control->fsn_included);
1532b1deed45SMichael Tuexen 					sctp_abort_in_reasm(stcb, control, chk,
153344249214SRandall Stewart 					    abort_flag,
1534ec24a1b6SMichael Tuexen 					    SCTP_FROM_SCTP_INDATA + SCTP_LOC_12);
153544249214SRandall Stewart 					return;
153644249214SRandall Stewart 				}
153744249214SRandall Stewart 			}
1538b7b84c0eSMichael Tuexen 			/*
1539b7b84c0eSMichael Tuexen 			 * validate not beyond top FSN if we have seen last
1540b7b84c0eSMichael Tuexen 			 * one
1541b7b84c0eSMichael Tuexen 			 */
154249656eefSMichael Tuexen 			if (SCTP_TSN_GT(chk->rec.data.fsn, control->top_fsn)) {
154344249214SRandall Stewart 				SCTPDBG(SCTP_DEBUG_XXX,
1544f2ea2a2dSMichael Tuexen 				    "New fsn: %u is beyond or at top_fsn: %u -- abort\n",
154549656eefSMichael Tuexen 				    chk->rec.data.fsn,
154644249214SRandall Stewart 				    control->top_fsn);
1547b1deed45SMichael Tuexen 				sctp_abort_in_reasm(stcb, control, chk,
154844249214SRandall Stewart 				    abort_flag,
1549ec24a1b6SMichael Tuexen 				    SCTP_FROM_SCTP_INDATA + SCTP_LOC_13);
155044249214SRandall Stewart 				return;
155144249214SRandall Stewart 			}
155244249214SRandall Stewart 		}
155344249214SRandall Stewart 		/*
155444249214SRandall Stewart 		 * If we reach here, we need to place the new chunk in the
155544249214SRandall Stewart 		 * reassembly for this control.
155644249214SRandall Stewart 		 */
155744249214SRandall Stewart 		SCTPDBG(SCTP_DEBUG_XXX,
1558f2ea2a2dSMichael Tuexen 		    "chunk is a not first fsn: %u needs to be inserted\n",
155949656eefSMichael Tuexen 		    chk->rec.data.fsn);
156044249214SRandall Stewart 		TAILQ_FOREACH(at, &control->reasm, sctp_next) {
156149656eefSMichael Tuexen 			if (SCTP_TSN_GT(at->rec.data.fsn, chk->rec.data.fsn)) {
156291e04f9eSMichael Tuexen 				if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) {
156391e04f9eSMichael Tuexen 					/* Last not at the end? huh? */
156491e04f9eSMichael Tuexen 					SCTPDBG(SCTP_DEBUG_XXX,
156591e04f9eSMichael Tuexen 					    "Last fragment not last in list: -- abort\n");
156691e04f9eSMichael Tuexen 					sctp_abort_in_reasm(stcb, control,
156791e04f9eSMichael Tuexen 					    chk, abort_flag,
156891e04f9eSMichael Tuexen 					    SCTP_FROM_SCTP_INDATA + SCTP_LOC_14);
156991e04f9eSMichael Tuexen 					return;
157091e04f9eSMichael Tuexen 				}
157144249214SRandall Stewart 				/*
157244249214SRandall Stewart 				 * This one in queue is bigger than the new
157344249214SRandall Stewart 				 * one, insert the new one before at.
157444249214SRandall Stewart 				 */
157544249214SRandall Stewart 				SCTPDBG(SCTP_DEBUG_XXX,
1576f2ea2a2dSMichael Tuexen 				    "Insert it before fsn: %u\n",
157749656eefSMichael Tuexen 				    at->rec.data.fsn);
1578f8829a4aSRandall Stewart 				asoc->size_on_reasm_queue += chk->send_size;
1579f8829a4aSRandall Stewart 				sctp_ucount_incr(asoc->cnt_on_reasm_queue);
158044249214SRandall Stewart 				TAILQ_INSERT_BEFORE(at, chk, sctp_next);
158144249214SRandall Stewart 				inserted = 1;
158244249214SRandall Stewart 				break;
158349656eefSMichael Tuexen 			} else if (at->rec.data.fsn == chk->rec.data.fsn) {
1584b7b84c0eSMichael Tuexen 				/*
1585b7b84c0eSMichael Tuexen 				 * Gak, He sent me a duplicate str seq
1586b7b84c0eSMichael Tuexen 				 * number
1587b7b84c0eSMichael Tuexen 				 */
158844249214SRandall Stewart 				/*
158944249214SRandall Stewart 				 * foo bar, I guess I will just free this
159044249214SRandall Stewart 				 * new guy, should we abort too? FIX ME
159144249214SRandall Stewart 				 * MAYBE? Or it COULD be that the SSN's have
159244249214SRandall Stewart 				 * wrapped. Maybe I should compare to TSN
159344249214SRandall Stewart 				 * somehow... sigh for now just blow away
159444249214SRandall Stewart 				 * the chunk!
159544249214SRandall Stewart 				 */
159644249214SRandall Stewart 				SCTPDBG(SCTP_DEBUG_XXX,
1597f2ea2a2dSMichael Tuexen 				    "Duplicate to fsn: %u -- abort\n",
159849656eefSMichael Tuexen 				    at->rec.data.fsn);
1599b1deed45SMichael Tuexen 				sctp_abort_in_reasm(stcb, control,
160044249214SRandall Stewart 				    chk, abort_flag,
160191e04f9eSMichael Tuexen 				    SCTP_FROM_SCTP_INDATA + SCTP_LOC_15);
160244249214SRandall Stewart 				return;
160344249214SRandall Stewart 			}
160444249214SRandall Stewart 		}
160544249214SRandall Stewart 		if (inserted == 0) {
160644249214SRandall Stewart 			/* Goes on the end */
1607f2ea2a2dSMichael Tuexen 			SCTPDBG(SCTP_DEBUG_XXX, "Inserting at tail of list fsn: %u\n",
160849656eefSMichael Tuexen 			    chk->rec.data.fsn);
160944249214SRandall Stewart 			asoc->size_on_reasm_queue += chk->send_size;
161044249214SRandall Stewart 			sctp_ucount_incr(asoc->cnt_on_reasm_queue);
161144249214SRandall Stewart 			TAILQ_INSERT_TAIL(&control->reasm, chk, sctp_next);
161244249214SRandall Stewart 		}
161344249214SRandall Stewart 	}
161444249214SRandall Stewart 	/*
161544249214SRandall Stewart 	 * Ok lets see if we can suck any up into the control structure that
161644249214SRandall Stewart 	 * are in seq if it makes sense.
161744249214SRandall Stewart 	 */
1618c09a1534SMichael Tuexen 	do_wakeup = 0;
161944249214SRandall Stewart 	/*
162044249214SRandall Stewart 	 * If the first fragment has not been seen there is no sense in
162144249214SRandall Stewart 	 * looking.
162244249214SRandall Stewart 	 */
162344249214SRandall Stewart 	if (control->first_frag_seen) {
162444249214SRandall Stewart 		next_fsn = control->fsn_included + 1;
162544249214SRandall Stewart 		TAILQ_FOREACH_SAFE(at, &control->reasm, sctp_next, nat) {
162649656eefSMichael Tuexen 			if (at->rec.data.fsn == next_fsn) {
162744249214SRandall Stewart 				/* We can add this one now to the control */
162844249214SRandall Stewart 				SCTPDBG(SCTP_DEBUG_XXX,
1629f2ea2a2dSMichael Tuexen 				    "Adding more to control: %p at: %p fsn: %u next_fsn: %u included: %u\n",
163044249214SRandall Stewart 				    control, at,
163149656eefSMichael Tuexen 				    at->rec.data.fsn,
163244249214SRandall Stewart 				    next_fsn, control->fsn_included);
163344249214SRandall Stewart 				TAILQ_REMOVE(&control->reasm, at, sctp_next);
163428cd0699SMichael Tuexen 				lenadded = sctp_add_chk_to_control(control, strm, stcb, asoc, at, SCTP_READ_LOCK_NOT_HELD);
1635c09a1534SMichael Tuexen 				if (control->on_read_q) {
1636c09a1534SMichael Tuexen 					do_wakeup = 1;
163772e23abaSMichael Tuexen 				} else {
163872e23abaSMichael Tuexen 					/*
163972e23abaSMichael Tuexen 					 * We only add to the
164072e23abaSMichael Tuexen 					 * size-on-all-streams if its not on
164172e23abaSMichael Tuexen 					 * the read q. The read q flag will
164272e23abaSMichael Tuexen 					 * cause a sballoc so its accounted
164372e23abaSMichael Tuexen 					 * for there.
164472e23abaSMichael Tuexen 					 */
164572e23abaSMichael Tuexen 					asoc->size_on_all_streams += lenadded;
1646c09a1534SMichael Tuexen 				}
164744249214SRandall Stewart 				next_fsn++;
164844249214SRandall Stewart 				if (control->end_added && control->pdapi_started) {
164944249214SRandall Stewart 					if (strm->pd_api_started) {
165044249214SRandall Stewart 						strm->pd_api_started = 0;
165144249214SRandall Stewart 						control->pdapi_started = 0;
165244249214SRandall Stewart 					}
165344249214SRandall Stewart 					if (control->on_read_q == 0) {
165444249214SRandall Stewart 						sctp_add_to_readq(stcb->sctp_ep, stcb,
165544249214SRandall Stewart 						    control,
165644249214SRandall Stewart 						    &stcb->sctp_socket->so_rcv, control->end_added,
165744249214SRandall Stewart 						    SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
165844249214SRandall Stewart 					}
165944249214SRandall Stewart 					break;
166044249214SRandall Stewart 				}
166144249214SRandall Stewart 			} else {
1662f8829a4aSRandall Stewart 				break;
1663f8829a4aSRandall Stewart 			}
1664f8829a4aSRandall Stewart 		}
1665f8829a4aSRandall Stewart 	}
1666c09a1534SMichael Tuexen 	if (do_wakeup) {
166744249214SRandall Stewart 		/* Need to wakeup the reader */
1668b1deed45SMichael Tuexen 		sctp_wakeup_the_read_socket(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED);
1669f8829a4aSRandall Stewart 	}
1670f8829a4aSRandall Stewart }
1671f8829a4aSRandall Stewart 
167244249214SRandall Stewart static struct sctp_queued_to_read *
167349656eefSMichael Tuexen sctp_find_reasm_entry(struct sctp_stream_in *strm, uint32_t mid, int ordered, int idata_supported)
1674f8829a4aSRandall Stewart {
1675c09a1534SMichael Tuexen 	struct sctp_queued_to_read *control;
1676f8829a4aSRandall Stewart 
167744249214SRandall Stewart 	if (ordered) {
1678c09a1534SMichael Tuexen 		TAILQ_FOREACH(control, &strm->inqueue, next_instrm) {
167949656eefSMichael Tuexen 			if (SCTP_MID_EQ(idata_supported, control->mid, mid)) {
168044249214SRandall Stewart 				break;
168144249214SRandall Stewart 			}
168244249214SRandall Stewart 		}
1683f8829a4aSRandall Stewart 	} else {
168449656eefSMichael Tuexen 		if (idata_supported) {
1685c09a1534SMichael Tuexen 			TAILQ_FOREACH(control, &strm->uno_inqueue, next_instrm) {
168649656eefSMichael Tuexen 				if (SCTP_MID_EQ(idata_supported, control->mid, mid)) {
168744249214SRandall Stewart 					break;
1688f8829a4aSRandall Stewart 				}
1689f8829a4aSRandall Stewart 			}
169049656eefSMichael Tuexen 		} else {
169149656eefSMichael Tuexen 			control = TAILQ_FIRST(&strm->uno_inqueue);
169249656eefSMichael Tuexen 		}
1693f8829a4aSRandall Stewart 	}
1694c09a1534SMichael Tuexen 	return (control);
1695f8829a4aSRandall Stewart }
169644249214SRandall Stewart 
1697f8829a4aSRandall Stewart static int
1698f8829a4aSRandall Stewart sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
169944249214SRandall Stewart     struct mbuf **m, int offset, int chk_length,
1700f8829a4aSRandall Stewart     struct sctp_nets *net, uint32_t *high_tsn, int *abort_flag,
17018b9c95f4SMichael Tuexen     int *break_flag, int last_chunk, uint8_t chk_type)
1702f8829a4aSRandall Stewart {
170395844fceSMichael Tuexen 	struct sctp_tmit_chunk *chk = NULL;	/* make gcc happy */
17046ddc8438SMichael Tuexen 	struct sctp_stream_in *strm;
170549656eefSMichael Tuexen 	uint32_t tsn, fsn, gap, mid;
1706f8829a4aSRandall Stewart 	struct mbuf *dmbuf;
17077215cc1bSMichael Tuexen 	int the_len;
1708139bc87fSRandall Stewart 	int need_reasm_check = 0;
170949656eefSMichael Tuexen 	uint16_t sid;
1710ff1ffd74SMichael Tuexen 	struct mbuf *op_err;
1711ff1ffd74SMichael Tuexen 	char msg[SCTP_DIAG_INFO_LEN];
171228cd0699SMichael Tuexen 	struct sctp_queued_to_read *control, *ncontrol;
171349656eefSMichael Tuexen 	uint32_t ppid;
17148b9c95f4SMichael Tuexen 	uint8_t chk_flags;
171517205eccSRandall Stewart 	struct sctp_stream_reset_list *liste;
171644249214SRandall Stewart 	int ordered;
171744249214SRandall Stewart 	size_t clen;
171844249214SRandall Stewart 	int created_control = 0;
1719f8829a4aSRandall Stewart 
17208b9c95f4SMichael Tuexen 	if (chk_type == SCTP_IDATA) {
17218b9c95f4SMichael Tuexen 		struct sctp_idata_chunk *chunk, chunk_buf;
17228b9c95f4SMichael Tuexen 
17238b9c95f4SMichael Tuexen 		chunk = (struct sctp_idata_chunk *)sctp_m_getptr(*m, offset,
172444249214SRandall Stewart 		    sizeof(struct sctp_idata_chunk), (uint8_t *)&chunk_buf);
17258b9c95f4SMichael Tuexen 		chk_flags = chunk->ch.chunk_flags;
172644249214SRandall Stewart 		clen = sizeof(struct sctp_idata_chunk);
17278b9c95f4SMichael Tuexen 		tsn = ntohl(chunk->dp.tsn);
17288b9c95f4SMichael Tuexen 		sid = ntohs(chunk->dp.sid);
17298b9c95f4SMichael Tuexen 		mid = ntohl(chunk->dp.mid);
17308b9c95f4SMichael Tuexen 		if (chk_flags & SCTP_DATA_FIRST_FRAG) {
173144249214SRandall Stewart 			fsn = 0;
17328b9c95f4SMichael Tuexen 			ppid = chunk->dp.ppid_fsn.ppid;
173344249214SRandall Stewart 		} else {
17348b9c95f4SMichael Tuexen 			fsn = ntohl(chunk->dp.ppid_fsn.fsn);
17358b9c95f4SMichael Tuexen 			ppid = 0xffffffff;	/* Use as an invalid value. */
173644249214SRandall Stewart 		}
17378b9c95f4SMichael Tuexen 	} else {
17388b9c95f4SMichael Tuexen 		struct sctp_data_chunk *chunk, chunk_buf;
17398b9c95f4SMichael Tuexen 
17408b9c95f4SMichael Tuexen 		chunk = (struct sctp_data_chunk *)sctp_m_getptr(*m, offset,
17418b9c95f4SMichael Tuexen 		    sizeof(struct sctp_data_chunk), (uint8_t *)&chunk_buf);
17428b9c95f4SMichael Tuexen 		chk_flags = chunk->ch.chunk_flags;
17438b9c95f4SMichael Tuexen 		clen = sizeof(struct sctp_data_chunk);
17448b9c95f4SMichael Tuexen 		tsn = ntohl(chunk->dp.tsn);
17458b9c95f4SMichael Tuexen 		sid = ntohs(chunk->dp.sid);
17468b9c95f4SMichael Tuexen 		mid = (uint32_t)(ntohs(chunk->dp.ssn));
17478b9c95f4SMichael Tuexen 		fsn = tsn;
17488b9c95f4SMichael Tuexen 		ppid = chunk->dp.ppid;
17498b9c95f4SMichael Tuexen 	}
175044249214SRandall Stewart 	if ((size_t)chk_length == clen) {
175144249214SRandall Stewart 		/*
175244249214SRandall Stewart 		 * Need to send an abort since we had a empty data chunk.
175344249214SRandall Stewart 		 */
17548b9c95f4SMichael Tuexen 		op_err = sctp_generate_no_user_data_cause(tsn);
175591e04f9eSMichael Tuexen 		stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_16;
175644249214SRandall Stewart 		sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
175744249214SRandall Stewart 		*abort_flag = 1;
175844249214SRandall Stewart 		return (0);
175944249214SRandall Stewart 	}
17608b9c95f4SMichael Tuexen 	if ((chk_flags & SCTP_DATA_SACK_IMMEDIATELY) == SCTP_DATA_SACK_IMMEDIATELY) {
1761b3f1ea41SRandall Stewart 		asoc->send_sack = 1;
1762b3f1ea41SRandall Stewart 	}
17638b9c95f4SMichael Tuexen 	ordered = ((chk_flags & SCTP_DATA_UNORDERED) == 0);
1764b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
1765c4739e2fSRandall Stewart 		sctp_log_map(tsn, asoc->cumulative_tsn, asoc->highest_tsn_inside_map, SCTP_MAP_TSN_ENTERS);
176680fefe0aSRandall Stewart 	}
1767ad81507eSRandall Stewart 	if (stcb == NULL) {
1768ad81507eSRandall Stewart 		return (0);
1769ad81507eSRandall Stewart 	}
17708b9c95f4SMichael Tuexen 	SCTP_LTRACE_CHK(stcb->sctp_ep, stcb, chk_type, tsn);
177120b07a4dSMichael Tuexen 	if (SCTP_TSN_GE(asoc->cumulative_tsn, tsn)) {
1772f8829a4aSRandall Stewart 		/* It is a duplicate */
1773f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_recvdupdata);
1774f8829a4aSRandall Stewart 		if (asoc->numduptsns < SCTP_MAX_DUP_TSNS) {
1775f8829a4aSRandall Stewart 			/* Record a dup for the next outbound sack */
1776f8829a4aSRandall Stewart 			asoc->dup_tsns[asoc->numduptsns] = tsn;
1777f8829a4aSRandall Stewart 			asoc->numduptsns++;
1778f8829a4aSRandall Stewart 		}
1779b201f536SRandall Stewart 		asoc->send_sack = 1;
1780f8829a4aSRandall Stewart 		return (0);
1781f8829a4aSRandall Stewart 	}
1782f8829a4aSRandall Stewart 	/* Calculate the number of TSN's between the base and this TSN */
1783d50c1d79SRandall Stewart 	SCTP_CALC_TSN_TO_GAP(gap, tsn, asoc->mapping_array_base_tsn);
1784f8829a4aSRandall Stewart 	if (gap >= (SCTP_MAPPING_ARRAY << 3)) {
1785f8829a4aSRandall Stewart 		/* Can't hold the bit in the mapping at max array, toss it */
1786f8829a4aSRandall Stewart 		return (0);
1787f8829a4aSRandall Stewart 	}
1788f8829a4aSRandall Stewart 	if (gap >= (uint32_t)(asoc->mapping_array_size << 3)) {
1789207304d4SRandall Stewart 		SCTP_TCB_LOCK_ASSERT(stcb);
17900696e120SRandall Stewart 		if (sctp_expand_mapping_array(asoc, gap)) {
1791f8829a4aSRandall Stewart 			/* Can't expand, drop it */
1792f8829a4aSRandall Stewart 			return (0);
1793f8829a4aSRandall Stewart 		}
1794f8829a4aSRandall Stewart 	}
179520b07a4dSMichael Tuexen 	if (SCTP_TSN_GT(tsn, *high_tsn)) {
1796f8829a4aSRandall Stewart 		*high_tsn = tsn;
1797f8829a4aSRandall Stewart 	}
1798f8829a4aSRandall Stewart 	/* See if we have received this one already */
179977acdc25SRandall Stewart 	if (SCTP_IS_TSN_PRESENT(asoc->mapping_array, gap) ||
180077acdc25SRandall Stewart 	    SCTP_IS_TSN_PRESENT(asoc->nr_mapping_array, gap)) {
1801f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_recvdupdata);
1802f8829a4aSRandall Stewart 		if (asoc->numduptsns < SCTP_MAX_DUP_TSNS) {
1803f8829a4aSRandall Stewart 			/* Record a dup for the next outbound sack */
1804f8829a4aSRandall Stewart 			asoc->dup_tsns[asoc->numduptsns] = tsn;
1805f8829a4aSRandall Stewart 			asoc->numduptsns++;
1806f8829a4aSRandall Stewart 		}
180742551e99SRandall Stewart 		asoc->send_sack = 1;
1808f8829a4aSRandall Stewart 		return (0);
1809f8829a4aSRandall Stewart 	}
1810f8829a4aSRandall Stewart 	/*
1811f8829a4aSRandall Stewart 	 * Check to see about the GONE flag, duplicates would cause a sack
1812f8829a4aSRandall Stewart 	 * to be sent up above
1813f8829a4aSRandall Stewart 	 */
1814ad81507eSRandall Stewart 	if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
1815f8829a4aSRandall Stewart 	    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
1816ff1ffd74SMichael Tuexen 	    (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET))) {
1817f8829a4aSRandall Stewart 		/*
1818f8829a4aSRandall Stewart 		 * wait a minute, this guy is gone, there is no longer a
1819f8829a4aSRandall Stewart 		 * receiver. Send peer an ABORT!
1820f8829a4aSRandall Stewart 		 */
1821ff1ffd74SMichael Tuexen 		op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, "");
1822a2b42326SMichael Tuexen 		sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
1823f8829a4aSRandall Stewart 		*abort_flag = 1;
1824f8829a4aSRandall Stewart 		return (0);
1825f8829a4aSRandall Stewart 	}
1826f8829a4aSRandall Stewart 	/*
1827f8829a4aSRandall Stewart 	 * Now before going further we see if there is room. If NOT then we
1828f8829a4aSRandall Stewart 	 * MAY let one through only IF this TSN is the one we are waiting
1829f8829a4aSRandall Stewart 	 * for on a partial delivery API.
1830f8829a4aSRandall Stewart 	 */
1831f8829a4aSRandall Stewart 
183244249214SRandall Stewart 	/* Is the stream valid? */
183349656eefSMichael Tuexen 	if (sid >= asoc->streamincnt) {
183486eda749SMichael Tuexen 		struct sctp_error_invalid_stream *cause;
1835f8829a4aSRandall Stewart 
183686eda749SMichael Tuexen 		op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_error_invalid_stream),
1837eb1b1807SGleb Smirnoff 		    0, M_NOWAIT, 1, MT_DATA);
183886eda749SMichael Tuexen 		if (op_err != NULL) {
1839f8829a4aSRandall Stewart 			/* add some space up front so prepend will work well */
184086eda749SMichael Tuexen 			SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr));
184186eda749SMichael Tuexen 			cause = mtod(op_err, struct sctp_error_invalid_stream *);
1842f8829a4aSRandall Stewart 			/*
1843f8829a4aSRandall Stewart 			 * Error causes are just param's and this one has
1844f8829a4aSRandall Stewart 			 * two back to back phdr, one with the error type
1845f8829a4aSRandall Stewart 			 * and size, the other with the streamid and a rsvd
1846f8829a4aSRandall Stewart 			 */
184786eda749SMichael Tuexen 			SCTP_BUF_LEN(op_err) = sizeof(struct sctp_error_invalid_stream);
184886eda749SMichael Tuexen 			cause->cause.code = htons(SCTP_CAUSE_INVALID_STREAM);
184986eda749SMichael Tuexen 			cause->cause.length = htons(sizeof(struct sctp_error_invalid_stream));
18508b9c95f4SMichael Tuexen 			cause->stream_id = htons(sid);
185186eda749SMichael Tuexen 			cause->reserved = htons(0);
185286eda749SMichael Tuexen 			sctp_queue_op_err(stcb, op_err);
1853f8829a4aSRandall Stewart 		}
1854f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_badsid);
1855207304d4SRandall Stewart 		SCTP_TCB_LOCK_ASSERT(stcb);
1856830d754dSRandall Stewart 		SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap);
185720b07a4dSMichael Tuexen 		if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) {
1858830d754dSRandall Stewart 			asoc->highest_tsn_inside_nr_map = tsn;
1859d06c82f1SRandall Stewart 		}
1860d06c82f1SRandall Stewart 		if (tsn == (asoc->cumulative_tsn + 1)) {
1861d06c82f1SRandall Stewart 			/* Update cum-ack */
1862d06c82f1SRandall Stewart 			asoc->cumulative_tsn = tsn;
1863d06c82f1SRandall Stewart 		}
1864f8829a4aSRandall Stewart 		return (0);
1865f8829a4aSRandall Stewart 	}
1866f8829a4aSRandall Stewart 	/*
186744249214SRandall Stewart 	 * If its a fragmented message, lets see if we can find the control
186844249214SRandall Stewart 	 * on the reassembly queues.
1869f8829a4aSRandall Stewart 	 */
18708b9c95f4SMichael Tuexen 	if ((chk_type == SCTP_IDATA) &&
18718b9c95f4SMichael Tuexen 	    ((chk_flags & SCTP_DATA_FIRST_FRAG) == 0) &&
1872be46a7c5SMichael Tuexen 	    (fsn == 0)) {
187344249214SRandall Stewart 		/*
187444249214SRandall Stewart 		 * The first *must* be fsn 0, and other (middle/end) pieces
1875be46a7c5SMichael Tuexen 		 * can *not* be fsn 0. XXX: This can happen in case of a
1876be46a7c5SMichael Tuexen 		 * wrap around. Ignore is for now.
187744249214SRandall Stewart 		 */
1878999f86d6SMichael Tuexen 		SCTP_SNPRINTF(msg, sizeof(msg), "FSN zero for MID=%8.8x, but flags=%2.2x", mid, chk_flags);
187944249214SRandall Stewart 		goto err_out;
188044249214SRandall Stewart 	}
18813d6fe5d8SMichael Tuexen 	control = sctp_find_reasm_entry(&asoc->strmin[sid], mid, ordered, asoc->idata_supported);
188244249214SRandall Stewart 	SCTPDBG(SCTP_DEBUG_XXX, "chunk_flags:0x%x look for control on queues %p\n",
18838b9c95f4SMichael Tuexen 	    chk_flags, control);
18848b9c95f4SMichael Tuexen 	if ((chk_flags & SCTP_DATA_NOT_FRAG) != SCTP_DATA_NOT_FRAG) {
1885be46a7c5SMichael Tuexen 		/* See if we can find the re-assembly entity */
1886be46a7c5SMichael Tuexen 		if (control != NULL) {
188744249214SRandall Stewart 			/* We found something, does it belong? */
188849656eefSMichael Tuexen 			if (ordered && (mid != control->mid)) {
1889999f86d6SMichael Tuexen 				SCTP_SNPRINTF(msg, sizeof(msg), "Reassembly problem (MID=%8.8x)", mid);
189044249214SRandall Stewart 		err_out:
189144249214SRandall Stewart 				op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
189291e04f9eSMichael Tuexen 				stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_17;
189344249214SRandall Stewart 				sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
189444249214SRandall Stewart 				*abort_flag = 1;
189544249214SRandall Stewart 				return (0);
189644249214SRandall Stewart 			}
189744249214SRandall Stewart 			if (ordered && ((control->sinfo_flags >> 8) & SCTP_DATA_UNORDERED)) {
1898b7b84c0eSMichael Tuexen 				/*
1899b7b84c0eSMichael Tuexen 				 * We can't have a switched order with an
1900b7b84c0eSMichael Tuexen 				 * unordered chunk
1901b7b84c0eSMichael Tuexen 				 */
1902999f86d6SMichael Tuexen 				SCTP_SNPRINTF(msg, sizeof(msg),
1903999f86d6SMichael Tuexen 				    "All fragments of a user message must be ordered or unordered (TSN=%8.8x)",
1904821bae7cSMichael Tuexen 				    tsn);
190544249214SRandall Stewart 				goto err_out;
190644249214SRandall Stewart 			}
190744249214SRandall Stewart 			if (!ordered && (((control->sinfo_flags >> 8) & SCTP_DATA_UNORDERED) == 0)) {
1908b7b84c0eSMichael Tuexen 				/*
1909b7b84c0eSMichael Tuexen 				 * We can't have a switched unordered with a
1910b7b84c0eSMichael Tuexen 				 * ordered chunk
1911b7b84c0eSMichael Tuexen 				 */
1912999f86d6SMichael Tuexen 				SCTP_SNPRINTF(msg, sizeof(msg),
1913999f86d6SMichael Tuexen 				    "All fragments of a user message must be ordered or unordered (TSN=%8.8x)",
1914821bae7cSMichael Tuexen 				    tsn);
191544249214SRandall Stewart 				goto err_out;
191644249214SRandall Stewart 			}
191744249214SRandall Stewart 		}
191844249214SRandall Stewart 	} else {
191944249214SRandall Stewart 		/*
192044249214SRandall Stewart 		 * Its a complete segment. Lets validate we don't have a
192144249214SRandall Stewart 		 * re-assembly going on with the same Stream/Seq (for
192244249214SRandall Stewart 		 * ordered) or in the same Stream for unordered.
192344249214SRandall Stewart 		 */
1924be46a7c5SMichael Tuexen 		if (control != NULL) {
192549656eefSMichael Tuexen 			if (ordered || asoc->idata_supported) {
192649656eefSMichael Tuexen 				SCTPDBG(SCTP_DEBUG_XXX, "chunk_flags: 0x%x dup detected on MID: %u\n",
19278b9c95f4SMichael Tuexen 				    chk_flags, mid);
1928999f86d6SMichael Tuexen 				SCTP_SNPRINTF(msg, sizeof(msg), "Duplicate MID=%8.8x detected.", mid);
192944249214SRandall Stewart 				goto err_out;
1930be46a7c5SMichael Tuexen 			} else {
1931be46a7c5SMichael Tuexen 				if ((tsn == control->fsn_included + 1) &&
1932be46a7c5SMichael Tuexen 				    (control->end_added == 0)) {
1933999f86d6SMichael Tuexen 					SCTP_SNPRINTF(msg, sizeof(msg),
1934999f86d6SMichael Tuexen 					    "Illegal message sequence, missing end for MID: %8.8x",
1935999f86d6SMichael Tuexen 					    control->fsn_included);
1936be46a7c5SMichael Tuexen 					goto err_out;
1937be46a7c5SMichael Tuexen 				} else {
1938be46a7c5SMichael Tuexen 					control = NULL;
1939be46a7c5SMichael Tuexen 				}
1940be46a7c5SMichael Tuexen 			}
194144249214SRandall Stewart 		}
194244249214SRandall Stewart 	}
194344249214SRandall Stewart 	/* now do the tests */
194444249214SRandall Stewart 	if (((asoc->cnt_on_all_streams +
194544249214SRandall Stewart 	    asoc->cnt_on_reasm_queue +
194644249214SRandall Stewart 	    asoc->cnt_msg_on_sb) >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue)) ||
194744249214SRandall Stewart 	    (((int)asoc->my_rwnd) <= 0)) {
194844249214SRandall Stewart 		/*
194944249214SRandall Stewart 		 * When we have NO room in the rwnd we check to make sure
195044249214SRandall Stewart 		 * the reader is doing its job...
195144249214SRandall Stewart 		 */
195244249214SRandall Stewart 		if (stcb->sctp_socket->so_rcv.sb_cc) {
195344249214SRandall Stewart 			/* some to read, wake-up */
195444249214SRandall Stewart 			sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
195544249214SRandall Stewart 		}
195644249214SRandall Stewart 		/* now is it in the mapping array of what we have accepted? */
19578b9c95f4SMichael Tuexen 		if (chk_type == SCTP_DATA) {
195844249214SRandall Stewart 			if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_map) &&
195944249214SRandall Stewart 			    SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) {
196044249214SRandall Stewart 				/* Nope not in the valid range dump it */
196144249214SRandall Stewart 		dump_packet:
196244249214SRandall Stewart 				sctp_set_rwnd(stcb, asoc);
196344249214SRandall Stewart 				if ((asoc->cnt_on_all_streams +
196444249214SRandall Stewart 				    asoc->cnt_on_reasm_queue +
196544249214SRandall Stewart 				    asoc->cnt_msg_on_sb) >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue)) {
196644249214SRandall Stewart 					SCTP_STAT_INCR(sctps_datadropchklmt);
196744249214SRandall Stewart 				} else {
196844249214SRandall Stewart 					SCTP_STAT_INCR(sctps_datadroprwnd);
196944249214SRandall Stewart 				}
197044249214SRandall Stewart 				*break_flag = 1;
197144249214SRandall Stewart 				return (0);
197244249214SRandall Stewart 			}
197344249214SRandall Stewart 		} else {
197444249214SRandall Stewart 			if (control == NULL) {
197544249214SRandall Stewart 				goto dump_packet;
197644249214SRandall Stewart 			}
197744249214SRandall Stewart 			if (SCTP_TSN_GT(fsn, control->top_fsn)) {
197844249214SRandall Stewart 				goto dump_packet;
197944249214SRandall Stewart 			}
198044249214SRandall Stewart 		}
198144249214SRandall Stewart 	}
1982f42a358aSRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS
198318e198d3SRandall Stewart 	SCTP_TCB_LOCK_ASSERT(stcb);
198418e198d3SRandall Stewart 	if (asoc->tsn_in_at >= SCTP_TSN_LOG_SIZE) {
198518e198d3SRandall Stewart 		asoc->tsn_in_at = 0;
198618e198d3SRandall Stewart 		asoc->tsn_in_wrapped = 1;
198718e198d3SRandall Stewart 	}
1988f42a358aSRandall Stewart 	asoc->in_tsnlog[asoc->tsn_in_at].tsn = tsn;
198949656eefSMichael Tuexen 	asoc->in_tsnlog[asoc->tsn_in_at].strm = sid;
199049656eefSMichael Tuexen 	asoc->in_tsnlog[asoc->tsn_in_at].seq = mid;
1991f1f73e57SRandall Stewart 	asoc->in_tsnlog[asoc->tsn_in_at].sz = chk_length;
1992f1f73e57SRandall Stewart 	asoc->in_tsnlog[asoc->tsn_in_at].flgs = chunk_flags;
199318e198d3SRandall Stewart 	asoc->in_tsnlog[asoc->tsn_in_at].stcb = (void *)stcb;
199418e198d3SRandall Stewart 	asoc->in_tsnlog[asoc->tsn_in_at].in_pos = asoc->tsn_in_at;
199518e198d3SRandall Stewart 	asoc->in_tsnlog[asoc->tsn_in_at].in_out = 1;
1996f42a358aSRandall Stewart 	asoc->tsn_in_at++;
1997f42a358aSRandall Stewart #endif
199844249214SRandall Stewart 	/*
199944249214SRandall Stewart 	 * Before we continue lets validate that we are not being fooled by
200044249214SRandall Stewart 	 * an evil attacker. We can only have Nk chunks based on our TSN
200144249214SRandall Stewart 	 * spread allowed by the mapping array N * 8 bits, so there is no
200244249214SRandall Stewart 	 * way our stream sequence numbers could have wrapped. We of course
200344249214SRandall Stewart 	 * only validate the FIRST fragment so the bit must be set.
200444249214SRandall Stewart 	 */
20058b9c95f4SMichael Tuexen 	if ((chk_flags & SCTP_DATA_FIRST_FRAG) &&
2006d61a0ae0SRandall Stewart 	    (TAILQ_EMPTY(&asoc->resetHead)) &&
20078b9c95f4SMichael Tuexen 	    (chk_flags & SCTP_DATA_UNORDERED) == 0 &&
200849656eefSMichael Tuexen 	    SCTP_MID_GE(asoc->idata_supported, asoc->strmin[sid].last_mid_delivered, mid)) {
2009f8829a4aSRandall Stewart 		/* The incoming sseq is behind where we last delivered? */
2010f2ea2a2dSMichael Tuexen 		SCTPDBG(SCTP_DEBUG_INDATA1, "EVIL/Broken-Dup S-SEQ: %u delivered: %u from peer, Abort!\n",
201149656eefSMichael Tuexen 		    mid, asoc->strmin[sid].last_mid_delivered);
2012f8829a4aSRandall Stewart 
201349656eefSMichael Tuexen 		if (asoc->idata_supported) {
2014999f86d6SMichael Tuexen 			SCTP_SNPRINTF(msg, sizeof(msg), "Delivered MID=%8.8x, got TSN=%8.8x, SID=%4.4x, MID=%8.8x",
201549656eefSMichael Tuexen 			    asoc->strmin[sid].last_mid_delivered,
201649656eefSMichael Tuexen 			    tsn,
201749656eefSMichael Tuexen 			    sid,
2018821bae7cSMichael Tuexen 			    mid);
201949656eefSMichael Tuexen 		} else {
2020999f86d6SMichael Tuexen 			SCTP_SNPRINTF(msg, sizeof(msg), "Delivered SSN=%4.4x, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x",
202149656eefSMichael Tuexen 			    (uint16_t)asoc->strmin[sid].last_mid_delivered,
202249656eefSMichael Tuexen 			    tsn,
202349656eefSMichael Tuexen 			    sid,
2024821bae7cSMichael Tuexen 			    (uint16_t)mid);
202549656eefSMichael Tuexen 		}
2026ff1ffd74SMichael Tuexen 		op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
202791e04f9eSMichael Tuexen 		stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_18;
2028ff1ffd74SMichael Tuexen 		sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
2029f8829a4aSRandall Stewart 		*abort_flag = 1;
2030f8829a4aSRandall Stewart 		return (0);
2031f8829a4aSRandall Stewart 	}
20328b9c95f4SMichael Tuexen 	if (chk_type == SCTP_IDATA) {
203344249214SRandall Stewart 		the_len = (chk_length - sizeof(struct sctp_idata_chunk));
203444249214SRandall Stewart 	} else {
2035f8829a4aSRandall Stewart 		the_len = (chk_length - sizeof(struct sctp_data_chunk));
203644249214SRandall Stewart 	}
2037f8829a4aSRandall Stewart 	if (last_chunk == 0) {
20388b9c95f4SMichael Tuexen 		if (chk_type == SCTP_IDATA) {
203944249214SRandall Stewart 			dmbuf = SCTP_M_COPYM(*m,
204044249214SRandall Stewart 			    (offset + sizeof(struct sctp_idata_chunk)),
204144249214SRandall Stewart 			    the_len, M_NOWAIT);
204244249214SRandall Stewart 		} else {
204344b7479bSRandall Stewart 			dmbuf = SCTP_M_COPYM(*m,
2044f8829a4aSRandall Stewart 			    (offset + sizeof(struct sctp_data_chunk)),
2045eb1b1807SGleb Smirnoff 			    the_len, M_NOWAIT);
204644249214SRandall Stewart 		}
2047f8829a4aSRandall Stewart #ifdef SCTP_MBUF_LOGGING
2048b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) {
20494be807c4SMichael Tuexen 			sctp_log_mbc(dmbuf, SCTP_MBUF_ICOPY);
2050f8829a4aSRandall Stewart 		}
2051f8829a4aSRandall Stewart #endif
2052f8829a4aSRandall Stewart 	} else {
2053f8829a4aSRandall Stewart 		/* We can steal the last chunk */
2054139bc87fSRandall Stewart 		int l_len;
2055139bc87fSRandall Stewart 
2056f8829a4aSRandall Stewart 		dmbuf = *m;
2057f8829a4aSRandall Stewart 		/* lop off the top part */
20588b9c95f4SMichael Tuexen 		if (chk_type == SCTP_IDATA) {
205944249214SRandall Stewart 			m_adj(dmbuf, (offset + sizeof(struct sctp_idata_chunk)));
206044249214SRandall Stewart 		} else {
2061f8829a4aSRandall Stewart 			m_adj(dmbuf, (offset + sizeof(struct sctp_data_chunk)));
206244249214SRandall Stewart 		}
2063139bc87fSRandall Stewart 		if (SCTP_BUF_NEXT(dmbuf) == NULL) {
2064139bc87fSRandall Stewart 			l_len = SCTP_BUF_LEN(dmbuf);
2065139bc87fSRandall Stewart 		} else {
2066139bc87fSRandall Stewart 			/*
2067139bc87fSRandall Stewart 			 * need to count up the size hopefully does not hit
2068139bc87fSRandall Stewart 			 * this to often :-0
2069139bc87fSRandall Stewart 			 */
2070139bc87fSRandall Stewart 			struct mbuf *lat;
2071139bc87fSRandall Stewart 
2072139bc87fSRandall Stewart 			l_len = 0;
207360990c0cSMichael Tuexen 			for (lat = dmbuf; lat; lat = SCTP_BUF_NEXT(lat)) {
2074139bc87fSRandall Stewart 				l_len += SCTP_BUF_LEN(lat);
2075139bc87fSRandall Stewart 			}
2076139bc87fSRandall Stewart 		}
2077139bc87fSRandall Stewart 		if (l_len > the_len) {
2078f8829a4aSRandall Stewart 			/* Trim the end round bytes off  too */
2079139bc87fSRandall Stewart 			m_adj(dmbuf, -(l_len - the_len));
2080f8829a4aSRandall Stewart 		}
2081f8829a4aSRandall Stewart 	}
2082f8829a4aSRandall Stewart 	if (dmbuf == NULL) {
2083f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_nomem);
2084f8829a4aSRandall Stewart 		return (0);
2085f8829a4aSRandall Stewart 	}
208644249214SRandall Stewart 	/*
20878b9c95f4SMichael Tuexen 	 * Now no matter what, we need a control, get one if we don't have
208844249214SRandall Stewart 	 * one (we may have gotten it above when we found the message was
208944249214SRandall Stewart 	 * fragmented
209044249214SRandall Stewart 	 */
209144249214SRandall Stewart 	if (control == NULL) {
209244249214SRandall Stewart 		sctp_alloc_a_readq(stcb, control);
209344249214SRandall Stewart 		sctp_build_readq_entry_mac(control, stcb, asoc->context, net, tsn,
209449656eefSMichael Tuexen 		    ppid,
209549656eefSMichael Tuexen 		    sid,
20968b9c95f4SMichael Tuexen 		    chk_flags,
209749656eefSMichael Tuexen 		    NULL, fsn, mid);
209844249214SRandall Stewart 		if (control == NULL) {
209944249214SRandall Stewart 			SCTP_STAT_INCR(sctps_nomem);
210044249214SRandall Stewart 			return (0);
210144249214SRandall Stewart 		}
21028b9c95f4SMichael Tuexen 		if ((chk_flags & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) {
21031f76872cSMichael Tuexen 			struct mbuf *mm;
210428cd0699SMichael Tuexen 
210544249214SRandall Stewart 			control->data = dmbuf;
210663fb39baSMichael Tuexen 			control->tail_mbuf = NULL;
21071f76872cSMichael Tuexen 			for (mm = control->data; mm; mm = mm->m_next) {
21081f76872cSMichael Tuexen 				control->length += SCTP_BUF_LEN(mm);
210963fb39baSMichael Tuexen 				if (SCTP_BUF_NEXT(mm) == NULL) {
211063fb39baSMichael Tuexen 					control->tail_mbuf = mm;
211128cd0699SMichael Tuexen 				}
211263fb39baSMichael Tuexen 			}
21138b9c95f4SMichael Tuexen 			control->end_added = 1;
21148b9c95f4SMichael Tuexen 			control->last_frag_seen = 1;
21158b9c95f4SMichael Tuexen 			control->first_frag_seen = 1;
21168b9c95f4SMichael Tuexen 			control->fsn_included = fsn;
21178b9c95f4SMichael Tuexen 			control->top_fsn = fsn;
211844249214SRandall Stewart 		}
211944249214SRandall Stewart 		created_control = 1;
212044249214SRandall Stewart 	}
212149656eefSMichael Tuexen 	SCTPDBG(SCTP_DEBUG_XXX, "chunk_flags: 0x%x ordered: %d MID: %u control: %p\n",
21228b9c95f4SMichael Tuexen 	    chk_flags, ordered, mid, control);
21238b9c95f4SMichael Tuexen 	if ((chk_flags & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG &&
2124f8829a4aSRandall Stewart 	    TAILQ_EMPTY(&asoc->resetHead) &&
2125f42a358aSRandall Stewart 	    ((ordered == 0) ||
212649656eefSMichael Tuexen 	    (SCTP_MID_EQ(asoc->idata_supported, asoc->strmin[sid].last_mid_delivered + 1, mid) &&
212749656eefSMichael Tuexen 	    TAILQ_EMPTY(&asoc->strmin[sid].inqueue)))) {
2128f8829a4aSRandall Stewart 		/* Candidate for express delivery */
2129f8829a4aSRandall Stewart 		/*
2130f8829a4aSRandall Stewart 		 * Its not fragmented, No PD-API is up, Nothing in the
2131f8829a4aSRandall Stewart 		 * delivery queue, Its un-ordered OR ordered and the next to
2132f8829a4aSRandall Stewart 		 * deliver AND nothing else is stuck on the stream queue,
2133f8829a4aSRandall Stewart 		 * And there is room for it in the socket buffer. Lets just
2134f8829a4aSRandall Stewart 		 * stuff it up the buffer....
2135f8829a4aSRandall Stewart 		 */
21361ea735c8SMichael Tuexen 		SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap);
213720b07a4dSMichael Tuexen 		if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) {
21381ea735c8SMichael Tuexen 			asoc->highest_tsn_inside_nr_map = tsn;
21391ea735c8SMichael Tuexen 		}
214049656eefSMichael Tuexen 		SCTPDBG(SCTP_DEBUG_XXX, "Injecting control: %p to be read (MID: %u)\n",
214149656eefSMichael Tuexen 		    control, mid);
214244249214SRandall Stewart 
2143cfde3ff7SRandall Stewart 		sctp_add_to_readq(stcb->sctp_ep, stcb,
2144cfde3ff7SRandall Stewart 		    control, &stcb->sctp_socket->so_rcv,
2145cfde3ff7SRandall Stewart 		    1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
2146830d754dSRandall Stewart 
21478b9c95f4SMichael Tuexen 		if ((chk_flags & SCTP_DATA_UNORDERED) == 0) {
2148f8829a4aSRandall Stewart 			/* for ordered, bump what we delivered */
21493d6fe5d8SMichael Tuexen 			asoc->strmin[sid].last_mid_delivered++;
2150f8829a4aSRandall Stewart 		}
2151f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_recvexpress);
2152b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) {
215349656eefSMichael Tuexen 			sctp_log_strm_del_alt(stcb, tsn, mid, sid,
2154f8829a4aSRandall Stewart 			    SCTP_STR_LOG_FROM_EXPRS_DEL);
215580fefe0aSRandall Stewart 		}
2156f8829a4aSRandall Stewart 		control = NULL;
2157f8829a4aSRandall Stewart 		goto finish_express_del;
2158f8829a4aSRandall Stewart 	}
21590053ed28SMichael Tuexen 
216044249214SRandall Stewart 	/* Now will we need a chunk too? */
21618b9c95f4SMichael Tuexen 	if ((chk_flags & SCTP_DATA_NOT_FRAG) != SCTP_DATA_NOT_FRAG) {
2162f8829a4aSRandall Stewart 		sctp_alloc_a_chunk(stcb, chk);
2163f8829a4aSRandall Stewart 		if (chk == NULL) {
2164f8829a4aSRandall Stewart 			/* No memory so we drop the chunk */
2165f8829a4aSRandall Stewart 			SCTP_STAT_INCR(sctps_nomem);
2166f8829a4aSRandall Stewart 			if (last_chunk == 0) {
2167f8829a4aSRandall Stewart 				/* we copied it, free the copy */
2168f8829a4aSRandall Stewart 				sctp_m_freem(dmbuf);
2169f8829a4aSRandall Stewart 			}
2170f8829a4aSRandall Stewart 			return (0);
2171f8829a4aSRandall Stewart 		}
217249656eefSMichael Tuexen 		chk->rec.data.tsn = tsn;
2173f8829a4aSRandall Stewart 		chk->no_fr_allowed = 0;
217449656eefSMichael Tuexen 		chk->rec.data.fsn = fsn;
217549656eefSMichael Tuexen 		chk->rec.data.mid = mid;
217649656eefSMichael Tuexen 		chk->rec.data.sid = sid;
217749656eefSMichael Tuexen 		chk->rec.data.ppid = ppid;
2178f8829a4aSRandall Stewart 		chk->rec.data.context = stcb->asoc.context;
2179f8829a4aSRandall Stewart 		chk->rec.data.doing_fast_retransmit = 0;
21808b9c95f4SMichael Tuexen 		chk->rec.data.rcv_flags = chk_flags;
2181f8829a4aSRandall Stewart 		chk->asoc = asoc;
2182f8829a4aSRandall Stewart 		chk->send_size = the_len;
2183f8829a4aSRandall Stewart 		chk->whoTo = net;
218449656eefSMichael Tuexen 		SCTPDBG(SCTP_DEBUG_XXX, "Building ck: %p for control: %p to be read (MID: %u)\n",
218544249214SRandall Stewart 		    chk,
218649656eefSMichael Tuexen 		    control, mid);
2187f8829a4aSRandall Stewart 		atomic_add_int(&net->ref_count, 1);
2188f8829a4aSRandall Stewart 		chk->data = dmbuf;
218944249214SRandall Stewart 	}
219044249214SRandall Stewart 	/* Set the appropriate TSN mark */
219144249214SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_do_drain) == 0) {
219244249214SRandall Stewart 		SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap);
219344249214SRandall Stewart 		if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) {
219444249214SRandall Stewart 			asoc->highest_tsn_inside_nr_map = tsn;
219544249214SRandall Stewart 		}
2196f8829a4aSRandall Stewart 	} else {
219744249214SRandall Stewart 		SCTP_SET_TSN_PRESENT(asoc->mapping_array, gap);
219844249214SRandall Stewart 		if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_map)) {
219944249214SRandall Stewart 			asoc->highest_tsn_inside_map = tsn;
2200f8829a4aSRandall Stewart 		}
2201f8829a4aSRandall Stewart 	}
220244249214SRandall Stewart 	/* Now is it complete (i.e. not fragmented)? */
22038b9c95f4SMichael Tuexen 	if ((chk_flags & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) {
2204f8829a4aSRandall Stewart 		/*
220544249214SRandall Stewart 		 * Special check for when streams are resetting. We could be
220644249214SRandall Stewart 		 * more smart about this and check the actual stream to see
220744249214SRandall Stewart 		 * if it is not being reset.. that way we would not create a
220844249214SRandall Stewart 		 * HOLB when amongst streams being reset and those not being
220944249214SRandall Stewart 		 * reset.
2210f8829a4aSRandall Stewart 		 *
2211f8829a4aSRandall Stewart 		 */
2212f8829a4aSRandall Stewart 		if (((liste = TAILQ_FIRST(&asoc->resetHead)) != NULL) &&
221320b07a4dSMichael Tuexen 		    SCTP_TSN_GT(tsn, liste->tsn)) {
2214f8829a4aSRandall Stewart 			/*
221544249214SRandall Stewart 			 * yep its past where we need to reset... go ahead
221644249214SRandall Stewart 			 * and queue it.
2217f8829a4aSRandall Stewart 			 */
2218f8829a4aSRandall Stewart 			if (TAILQ_EMPTY(&asoc->pending_reply_queue)) {
2219f8829a4aSRandall Stewart 				/* first one on */
2220f8829a4aSRandall Stewart 				TAILQ_INSERT_TAIL(&asoc->pending_reply_queue, control, next);
2221f8829a4aSRandall Stewart 			} else {
222228cd0699SMichael Tuexen 				struct sctp_queued_to_read *lcontrol, *nlcontrol;
2223f8829a4aSRandall Stewart 				unsigned char inserted = 0;
2224f8829a4aSRandall Stewart 
222528cd0699SMichael Tuexen 				TAILQ_FOREACH_SAFE(lcontrol, &asoc->pending_reply_queue, next, nlcontrol) {
222628cd0699SMichael Tuexen 					if (SCTP_TSN_GT(control->sinfo_tsn, lcontrol->sinfo_tsn)) {
22274a9ef3f8SMichael Tuexen 						continue;
2228f8829a4aSRandall Stewart 					} else {
2229f8829a4aSRandall Stewart 						/* found it */
223028cd0699SMichael Tuexen 						TAILQ_INSERT_BEFORE(lcontrol, control, next);
2231f8829a4aSRandall Stewart 						inserted = 1;
2232f8829a4aSRandall Stewart 						break;
2233f8829a4aSRandall Stewart 					}
2234f8829a4aSRandall Stewart 				}
2235f8829a4aSRandall Stewart 				if (inserted == 0) {
2236f8829a4aSRandall Stewart 					/*
223744249214SRandall Stewart 					 * must be put at end, use prevP
223844249214SRandall Stewart 					 * (all setup from loop) to setup
223944249214SRandall Stewart 					 * nextP.
2240f8829a4aSRandall Stewart 					 */
2241f8829a4aSRandall Stewart 					TAILQ_INSERT_TAIL(&asoc->pending_reply_queue, control, next);
2242f8829a4aSRandall Stewart 				}
2243f8829a4aSRandall Stewart 			}
224444249214SRandall Stewart 			goto finish_express_del;
224544249214SRandall Stewart 		}
22468b9c95f4SMichael Tuexen 		if (chk_flags & SCTP_DATA_UNORDERED) {
224744249214SRandall Stewart 			/* queue directly into socket buffer */
224849656eefSMichael Tuexen 			SCTPDBG(SCTP_DEBUG_XXX, "Unordered data to be read control: %p MID: %u\n",
224949656eefSMichael Tuexen 			    control, mid);
225044249214SRandall Stewart 			sctp_mark_non_revokable(asoc, control->sinfo_tsn);
225144249214SRandall Stewart 			sctp_add_to_readq(stcb->sctp_ep, stcb,
225244249214SRandall Stewart 			    control,
225344249214SRandall Stewart 			    &stcb->sctp_socket->so_rcv, 1,
225444249214SRandall Stewart 			    SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
225544249214SRandall Stewart 
2256f8829a4aSRandall Stewart 		} else {
225749656eefSMichael Tuexen 			SCTPDBG(SCTP_DEBUG_XXX, "Queue control: %p for reordering MID: %u\n", control,
225849656eefSMichael Tuexen 			    mid);
22593d6fe5d8SMichael Tuexen 			sctp_queue_data_to_stream(stcb, asoc, control, abort_flag, &need_reasm_check);
2260f8829a4aSRandall Stewart 			if (*abort_flag) {
22618be0fd55SMichael Tuexen 				if (last_chunk) {
22628be0fd55SMichael Tuexen 					*m = NULL;
22638be0fd55SMichael Tuexen 				}
2264f8829a4aSRandall Stewart 				return (0);
2265f8829a4aSRandall Stewart 			}
2266f8829a4aSRandall Stewart 		}
226744249214SRandall Stewart 		goto finish_express_del;
2268f8829a4aSRandall Stewart 	}
226944249214SRandall Stewart 	/* If we reach here its a reassembly */
227044249214SRandall Stewart 	need_reasm_check = 1;
227144249214SRandall Stewart 	SCTPDBG(SCTP_DEBUG_XXX,
227249656eefSMichael Tuexen 	    "Queue data to stream for reasm control: %p MID: %u\n",
227349656eefSMichael Tuexen 	    control, mid);
22743d6fe5d8SMichael Tuexen 	sctp_queue_data_for_reasm(stcb, asoc, control, chk, created_control, abort_flag, tsn);
2275f8829a4aSRandall Stewart 	if (*abort_flag) {
2276a5d547adSRandall Stewart 		/*
227744249214SRandall Stewart 		 * the assoc is now gone and chk was put onto the reasm
227844249214SRandall Stewart 		 * queue, which has all been freed.
2279a5d547adSRandall Stewart 		 */
22808be0fd55SMichael Tuexen 		if (last_chunk) {
2281a5d547adSRandall Stewart 			*m = NULL;
22828be0fd55SMichael Tuexen 		}
2283f8829a4aSRandall Stewart 		return (0);
2284f8829a4aSRandall Stewart 	}
2285f8829a4aSRandall Stewart finish_express_del:
228644249214SRandall Stewart 	/* Here we tidy up things */
2287307b49efSMichael Tuexen 	if (tsn == (asoc->cumulative_tsn + 1)) {
2288307b49efSMichael Tuexen 		/* Update cum-ack */
2289307b49efSMichael Tuexen 		asoc->cumulative_tsn = tsn;
2290307b49efSMichael Tuexen 	}
2291f8829a4aSRandall Stewart 	if (last_chunk) {
2292f8829a4aSRandall Stewart 		*m = NULL;
2293f8829a4aSRandall Stewart 	}
2294f42a358aSRandall Stewart 	if (ordered) {
2295f8829a4aSRandall Stewart 		SCTP_STAT_INCR_COUNTER64(sctps_inorderchunks);
2296f8829a4aSRandall Stewart 	} else {
2297f8829a4aSRandall Stewart 		SCTP_STAT_INCR_COUNTER64(sctps_inunorderchunks);
2298f8829a4aSRandall Stewart 	}
2299f8829a4aSRandall Stewart 	SCTP_STAT_INCR(sctps_recvdata);
2300f8829a4aSRandall Stewart 	/* Set it present please */
2301b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) {
230249656eefSMichael Tuexen 		sctp_log_strm_del_alt(stcb, tsn, mid, sid, SCTP_STR_LOG_FROM_MARK_TSN);
230380fefe0aSRandall Stewart 	}
2304b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
2305f8829a4aSRandall Stewart 		sctp_log_map(asoc->mapping_array_base_tsn, asoc->cumulative_tsn,
2306f8829a4aSRandall Stewart 		    asoc->highest_tsn_inside_map, SCTP_MAP_PREPARE_SLIDE);
230780fefe0aSRandall Stewart 	}
23083d6fe5d8SMichael Tuexen 	if (need_reasm_check) {
23093d6fe5d8SMichael Tuexen 		(void)sctp_deliver_reasm_check(stcb, asoc, &asoc->strmin[sid], SCTP_READ_LOCK_NOT_HELD);
23103d6fe5d8SMichael Tuexen 		need_reasm_check = 0;
23113d6fe5d8SMichael Tuexen 	}
231217205eccSRandall Stewart 	/* check the special flag for stream resets */
231317205eccSRandall Stewart 	if (((liste = TAILQ_FIRST(&asoc->resetHead)) != NULL) &&
231420b07a4dSMichael Tuexen 	    SCTP_TSN_GE(asoc->cumulative_tsn, liste->tsn)) {
231517205eccSRandall Stewart 		/*
231617205eccSRandall Stewart 		 * we have finished working through the backlogged TSN's now
231717205eccSRandall Stewart 		 * time to reset streams. 1: call reset function. 2: free
231817205eccSRandall Stewart 		 * pending_reply space 3: distribute any chunks in
231917205eccSRandall Stewart 		 * pending_reply_queue.
232017205eccSRandall Stewart 		 */
2321a169d6ecSMichael Tuexen 		sctp_reset_in_stream(stcb, liste->number_entries, liste->list_of_streams);
232217205eccSRandall Stewart 		TAILQ_REMOVE(&asoc->resetHead, liste, next_resp);
23237cca1775SRandall Stewart 		sctp_send_deferred_reset_response(stcb, liste, SCTP_STREAM_RESET_RESULT_PERFORMED);
2324207304d4SRandall Stewart 		SCTP_FREE(liste, SCTP_M_STRESET);
23253c503c28SRandall Stewart 		/* sa_ignore FREED_MEMORY */
232617205eccSRandall Stewart 		liste = TAILQ_FIRST(&asoc->resetHead);
23274a9ef3f8SMichael Tuexen 		if (TAILQ_EMPTY(&asoc->resetHead)) {
232817205eccSRandall Stewart 			/* All can be removed */
232928cd0699SMichael Tuexen 			TAILQ_FOREACH_SAFE(control, &asoc->pending_reply_queue, next, ncontrol) {
233028cd0699SMichael Tuexen 				TAILQ_REMOVE(&asoc->pending_reply_queue, control, next);
23316ddc8438SMichael Tuexen 				strm = &asoc->strmin[control->sinfo_stream];
233228cd0699SMichael Tuexen 				sctp_queue_data_to_stream(stcb, asoc, control, abort_flag, &need_reasm_check);
233317205eccSRandall Stewart 				if (*abort_flag) {
233417205eccSRandall Stewart 					return (0);
233517205eccSRandall Stewart 				}
23363d6fe5d8SMichael Tuexen 				if (need_reasm_check) {
23376ddc8438SMichael Tuexen 					(void)sctp_deliver_reasm_check(stcb, asoc, strm, SCTP_READ_LOCK_NOT_HELD);
23383d6fe5d8SMichael Tuexen 					need_reasm_check = 0;
23393d6fe5d8SMichael Tuexen 				}
234017205eccSRandall Stewart 			}
23414a9ef3f8SMichael Tuexen 		} else {
234228cd0699SMichael Tuexen 			TAILQ_FOREACH_SAFE(control, &asoc->pending_reply_queue, next, ncontrol) {
234328cd0699SMichael Tuexen 				if (SCTP_TSN_GT(control->sinfo_tsn, liste->tsn)) {
23444a9ef3f8SMichael Tuexen 					break;
23454a9ef3f8SMichael Tuexen 				}
234617205eccSRandall Stewart 				/*
234728cd0699SMichael Tuexen 				 * if control->sinfo_tsn is <= liste->tsn we
234828cd0699SMichael Tuexen 				 * can process it which is the NOT of
234928cd0699SMichael Tuexen 				 * control->sinfo_tsn > liste->tsn
235017205eccSRandall Stewart 				 */
235128cd0699SMichael Tuexen 				TAILQ_REMOVE(&asoc->pending_reply_queue, control, next);
23526ddc8438SMichael Tuexen 				strm = &asoc->strmin[control->sinfo_stream];
235328cd0699SMichael Tuexen 				sctp_queue_data_to_stream(stcb, asoc, control, abort_flag, &need_reasm_check);
235417205eccSRandall Stewart 				if (*abort_flag) {
235517205eccSRandall Stewart 					return (0);
235617205eccSRandall Stewart 				}
23573d6fe5d8SMichael Tuexen 				if (need_reasm_check) {
23586ddc8438SMichael Tuexen 					(void)sctp_deliver_reasm_check(stcb, asoc, strm, SCTP_READ_LOCK_NOT_HELD);
235917205eccSRandall Stewart 					need_reasm_check = 0;
236017205eccSRandall Stewart 				}
23613d6fe5d8SMichael Tuexen 			}
23623d6fe5d8SMichael Tuexen 		}
2363139bc87fSRandall Stewart 	}
2364f8829a4aSRandall Stewart 	return (1);
2365f8829a4aSRandall Stewart }
2366f8829a4aSRandall Stewart 
2367ed654363SMichael Tuexen static const int8_t sctp_map_lookup_tab[256] = {
2368b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 3,
2369b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 4,
2370b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 3,
2371b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 5,
2372b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 3,
2373b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 4,
2374b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 3,
2375b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 6,
2376b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 3,
2377b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 4,
2378b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 3,
2379b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 5,
2380b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 3,
2381b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 4,
2382b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 3,
2383b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 7,
2384b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 3,
2385b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 4,
2386b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 3,
2387b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 5,
2388b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 3,
2389b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 4,
2390b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 3,
2391b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 6,
2392b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 3,
2393b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 4,
2394b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 3,
2395b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 5,
2396b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 3,
2397b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 4,
2398b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 3,
2399b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 8
2400f8829a4aSRandall Stewart };
2401f8829a4aSRandall Stewart 
2402f8829a4aSRandall Stewart void
2403b5c16493SMichael Tuexen sctp_slide_mapping_arrays(struct sctp_tcb *stcb)
2404f8829a4aSRandall Stewart {
2405f8829a4aSRandall Stewart 	/*
2406f8829a4aSRandall Stewart 	 * Now we also need to check the mapping array in a couple of ways.
2407f8829a4aSRandall Stewart 	 * 1) Did we move the cum-ack point?
240866bd30bdSRandall Stewart 	 *
24095b495f17SMichael Tuexen 	 * When you first glance at this you might think that all entries
24105b495f17SMichael Tuexen 	 * that make up the position of the cum-ack would be in the
24115b495f17SMichael Tuexen 	 * nr-mapping array only.. i.e. things up to the cum-ack are always
241266bd30bdSRandall Stewart 	 * deliverable. Thats true with one exception, when its a fragmented
241366bd30bdSRandall Stewart 	 * message we may not deliver the data until some threshold (or all
241466bd30bdSRandall Stewart 	 * of it) is in place. So we must OR the nr_mapping_array and
241566bd30bdSRandall Stewart 	 * mapping_array to get a true picture of the cum-ack.
2416f8829a4aSRandall Stewart 	 */
2417f8829a4aSRandall Stewart 	struct sctp_association *asoc;
2418b3f1ea41SRandall Stewart 	int at;
241966bd30bdSRandall Stewart 	uint8_t val;
2420f8829a4aSRandall Stewart 	int slide_from, slide_end, lgap, distance;
242177acdc25SRandall Stewart 	uint32_t old_cumack, old_base, old_highest, highest_tsn;
2422f8829a4aSRandall Stewart 
2423f8829a4aSRandall Stewart 	asoc = &stcb->asoc;
2424f8829a4aSRandall Stewart 
2425f8829a4aSRandall Stewart 	old_cumack = asoc->cumulative_tsn;
2426f8829a4aSRandall Stewart 	old_base = asoc->mapping_array_base_tsn;
2427f8829a4aSRandall Stewart 	old_highest = asoc->highest_tsn_inside_map;
2428f8829a4aSRandall Stewart 	/*
2429f8829a4aSRandall Stewart 	 * We could probably improve this a small bit by calculating the
2430f8829a4aSRandall Stewart 	 * offset of the current cum-ack as the starting point.
2431f8829a4aSRandall Stewart 	 */
2432f8829a4aSRandall Stewart 	at = 0;
2433b5c16493SMichael Tuexen 	for (slide_from = 0; slide_from < stcb->asoc.mapping_array_size; slide_from++) {
243466bd30bdSRandall Stewart 		val = asoc->nr_mapping_array[slide_from] | asoc->mapping_array[slide_from];
243566bd30bdSRandall Stewart 		if (val == 0xff) {
2436f8829a4aSRandall Stewart 			at += 8;
2437f8829a4aSRandall Stewart 		} else {
2438f8829a4aSRandall Stewart 			/* there is a 0 bit */
243966bd30bdSRandall Stewart 			at += sctp_map_lookup_tab[val];
2440f8829a4aSRandall Stewart 			break;
2441f8829a4aSRandall Stewart 		}
2442f8829a4aSRandall Stewart 	}
2443b5c16493SMichael Tuexen 	asoc->cumulative_tsn = asoc->mapping_array_base_tsn + (at - 1);
2444f8829a4aSRandall Stewart 
244520b07a4dSMichael Tuexen 	if (SCTP_TSN_GT(asoc->cumulative_tsn, asoc->highest_tsn_inside_map) &&
244620b07a4dSMichael Tuexen 	    SCTP_TSN_GT(asoc->cumulative_tsn, asoc->highest_tsn_inside_nr_map)) {
2447a5d547adSRandall Stewart #ifdef INVARIANTS
2448ceaad40aSRandall Stewart 		panic("huh, cumack 0x%x greater than high-tsn 0x%x in map",
2449ceaad40aSRandall Stewart 		    asoc->cumulative_tsn, asoc->highest_tsn_inside_map);
2450f8829a4aSRandall Stewart #else
2451ceaad40aSRandall Stewart 		SCTP_PRINTF("huh, cumack 0x%x greater than high-tsn 0x%x in map - should panic?\n",
2452ceaad40aSRandall Stewart 		    asoc->cumulative_tsn, asoc->highest_tsn_inside_map);
24530e13104dSRandall Stewart 		sctp_print_mapping_array(asoc);
2454b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
2455b3f1ea41SRandall Stewart 			sctp_log_map(0, 6, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT);
2456b3f1ea41SRandall Stewart 		}
2457f8829a4aSRandall Stewart 		asoc->highest_tsn_inside_map = asoc->cumulative_tsn;
2458830d754dSRandall Stewart 		asoc->highest_tsn_inside_nr_map = asoc->cumulative_tsn;
2459f8829a4aSRandall Stewart #endif
2460f8829a4aSRandall Stewart 	}
246120b07a4dSMichael Tuexen 	if (SCTP_TSN_GT(asoc->highest_tsn_inside_nr_map, asoc->highest_tsn_inside_map)) {
246277acdc25SRandall Stewart 		highest_tsn = asoc->highest_tsn_inside_nr_map;
246377acdc25SRandall Stewart 	} else {
246477acdc25SRandall Stewart 		highest_tsn = asoc->highest_tsn_inside_map;
246577acdc25SRandall Stewart 	}
246677acdc25SRandall Stewart 	if ((asoc->cumulative_tsn == highest_tsn) && (at >= 8)) {
2467f8829a4aSRandall Stewart 		/* The complete array was completed by a single FR */
246877acdc25SRandall Stewart 		/* highest becomes the cum-ack */
246937f144ebSMichael Tuexen 		int clr;
247037f144ebSMichael Tuexen #ifdef INVARIANTS
247137f144ebSMichael Tuexen 		unsigned int i;
247237f144ebSMichael Tuexen #endif
2473f8829a4aSRandall Stewart 
2474f8829a4aSRandall Stewart 		/* clear the array */
2475b5c16493SMichael Tuexen 		clr = ((at + 7) >> 3);
2476c4739e2fSRandall Stewart 		if (clr > asoc->mapping_array_size) {
2477f8829a4aSRandall Stewart 			clr = asoc->mapping_array_size;
2478f8829a4aSRandall Stewart 		}
2479f8829a4aSRandall Stewart 		memset(asoc->mapping_array, 0, clr);
2480830d754dSRandall Stewart 		memset(asoc->nr_mapping_array, 0, clr);
248137f144ebSMichael Tuexen #ifdef INVARIANTS
2482b5c16493SMichael Tuexen 		for (i = 0; i < asoc->mapping_array_size; i++) {
2483b5c16493SMichael Tuexen 			if ((asoc->mapping_array[i]) || (asoc->nr_mapping_array[i])) {
2484cd3fd531SMichael Tuexen 				SCTP_PRINTF("Error Mapping array's not clean at clear\n");
2485b5c16493SMichael Tuexen 				sctp_print_mapping_array(asoc);
2486b5c16493SMichael Tuexen 			}
2487b5c16493SMichael Tuexen 		}
248837f144ebSMichael Tuexen #endif
248977acdc25SRandall Stewart 		asoc->mapping_array_base_tsn = asoc->cumulative_tsn + 1;
249077acdc25SRandall Stewart 		asoc->highest_tsn_inside_nr_map = asoc->highest_tsn_inside_map = asoc->cumulative_tsn;
2491f8829a4aSRandall Stewart 	} else if (at >= 8) {
2492f8829a4aSRandall Stewart 		/* we can slide the mapping array down */
2493b3f1ea41SRandall Stewart 		/* slide_from holds where we hit the first NON 0xff byte */
2494b3f1ea41SRandall Stewart 
2495f8829a4aSRandall Stewart 		/*
2496f8829a4aSRandall Stewart 		 * now calculate the ceiling of the move using our highest
2497f8829a4aSRandall Stewart 		 * TSN value
2498f8829a4aSRandall Stewart 		 */
249977acdc25SRandall Stewart 		SCTP_CALC_TSN_TO_GAP(lgap, highest_tsn, asoc->mapping_array_base_tsn);
250077acdc25SRandall Stewart 		slide_end = (lgap >> 3);
2501f8829a4aSRandall Stewart 		if (slide_end < slide_from) {
250277acdc25SRandall Stewart 			sctp_print_mapping_array(asoc);
2503d55b0b1bSRandall Stewart #ifdef INVARIANTS
2504f8829a4aSRandall Stewart 			panic("impossible slide");
2505d55b0b1bSRandall Stewart #else
2506cd3fd531SMichael Tuexen 			SCTP_PRINTF("impossible slide lgap: %x slide_end: %x slide_from: %x? at: %d\n",
250777acdc25SRandall Stewart 			    lgap, slide_end, slide_from, at);
2508d55b0b1bSRandall Stewart 			return;
2509d55b0b1bSRandall Stewart #endif
2510f8829a4aSRandall Stewart 		}
2511b3f1ea41SRandall Stewart 		if (slide_end > asoc->mapping_array_size) {
2512b3f1ea41SRandall Stewart #ifdef INVARIANTS
2513b3f1ea41SRandall Stewart 			panic("would overrun buffer");
2514b3f1ea41SRandall Stewart #else
2515cd3fd531SMichael Tuexen 			SCTP_PRINTF("Gak, would have overrun map end: %d slide_end: %d\n",
2516b3f1ea41SRandall Stewart 			    asoc->mapping_array_size, slide_end);
2517b3f1ea41SRandall Stewart 			slide_end = asoc->mapping_array_size;
2518b3f1ea41SRandall Stewart #endif
2519b3f1ea41SRandall Stewart 		}
2520f8829a4aSRandall Stewart 		distance = (slide_end - slide_from) + 1;
2521b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
2522f8829a4aSRandall Stewart 			sctp_log_map(old_base, old_cumack, old_highest,
2523f8829a4aSRandall Stewart 			    SCTP_MAP_PREPARE_SLIDE);
2524f8829a4aSRandall Stewart 			sctp_log_map((uint32_t)slide_from, (uint32_t)slide_end,
2525f8829a4aSRandall Stewart 			    (uint32_t)lgap, SCTP_MAP_SLIDE_FROM);
252680fefe0aSRandall Stewart 		}
2527f8829a4aSRandall Stewart 		if (distance + slide_from > asoc->mapping_array_size ||
2528f8829a4aSRandall Stewart 		    distance < 0) {
2529f8829a4aSRandall Stewart 			/*
2530f8829a4aSRandall Stewart 			 * Here we do NOT slide forward the array so that
2531f8829a4aSRandall Stewart 			 * hopefully when more data comes in to fill it up
2532f8829a4aSRandall Stewart 			 * we will be able to slide it forward. Really I
2533f8829a4aSRandall Stewart 			 * don't think this should happen :-0
2534f8829a4aSRandall Stewart 			 */
2535b3f1ea41SRandall Stewart 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
2536f8829a4aSRandall Stewart 				sctp_log_map((uint32_t)distance, (uint32_t)slide_from,
2537f8829a4aSRandall Stewart 				    (uint32_t)asoc->mapping_array_size,
2538f8829a4aSRandall Stewart 				    SCTP_MAP_SLIDE_NONE);
253980fefe0aSRandall Stewart 			}
2540f8829a4aSRandall Stewart 		} else {
2541f8829a4aSRandall Stewart 			int ii;
2542f8829a4aSRandall Stewart 
2543f8829a4aSRandall Stewart 			for (ii = 0; ii < distance; ii++) {
254437f144ebSMichael Tuexen 				asoc->mapping_array[ii] = asoc->mapping_array[slide_from + ii];
254537f144ebSMichael Tuexen 				asoc->nr_mapping_array[ii] = asoc->nr_mapping_array[slide_from + ii];
2546f8829a4aSRandall Stewart 			}
2547aed5947cSMichael Tuexen 			for (ii = distance; ii < asoc->mapping_array_size; ii++) {
2548f8829a4aSRandall Stewart 				asoc->mapping_array[ii] = 0;
254977acdc25SRandall Stewart 				asoc->nr_mapping_array[ii] = 0;
2550f8829a4aSRandall Stewart 			}
2551ee94f0a2SMichael Tuexen 			if (asoc->highest_tsn_inside_map + 1 == asoc->mapping_array_base_tsn) {
2552ee94f0a2SMichael Tuexen 				asoc->highest_tsn_inside_map += (slide_from << 3);
2553ee94f0a2SMichael Tuexen 			}
2554ee94f0a2SMichael Tuexen 			if (asoc->highest_tsn_inside_nr_map + 1 == asoc->mapping_array_base_tsn) {
2555ee94f0a2SMichael Tuexen 				asoc->highest_tsn_inside_nr_map += (slide_from << 3);
2556ee94f0a2SMichael Tuexen 			}
2557f8829a4aSRandall Stewart 			asoc->mapping_array_base_tsn += (slide_from << 3);
2558b3f1ea41SRandall Stewart 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
2559f8829a4aSRandall Stewart 				sctp_log_map(asoc->mapping_array_base_tsn,
2560f8829a4aSRandall Stewart 				    asoc->cumulative_tsn, asoc->highest_tsn_inside_map,
2561f8829a4aSRandall Stewart 				    SCTP_MAP_SLIDE_RESULT);
256280fefe0aSRandall Stewart 			}
2563830d754dSRandall Stewart 		}
2564830d754dSRandall Stewart 	}
2565b5c16493SMichael Tuexen }
2566b5c16493SMichael Tuexen 
2567b5c16493SMichael Tuexen void
25687215cc1bSMichael Tuexen sctp_sack_check(struct sctp_tcb *stcb, int was_a_gap)
2569b5c16493SMichael Tuexen {
2570b5c16493SMichael Tuexen 	struct sctp_association *asoc;
2571b5c16493SMichael Tuexen 	uint32_t highest_tsn;
2572ebecdad8SMichael Tuexen 	int is_a_gap;
2573b5c16493SMichael Tuexen 
2574ebecdad8SMichael Tuexen 	sctp_slide_mapping_arrays(stcb);
2575b5c16493SMichael Tuexen 	asoc = &stcb->asoc;
257620b07a4dSMichael Tuexen 	if (SCTP_TSN_GT(asoc->highest_tsn_inside_nr_map, asoc->highest_tsn_inside_map)) {
2577b5c16493SMichael Tuexen 		highest_tsn = asoc->highest_tsn_inside_nr_map;
2578b5c16493SMichael Tuexen 	} else {
2579b5c16493SMichael Tuexen 		highest_tsn = asoc->highest_tsn_inside_map;
2580b5c16493SMichael Tuexen 	}
2581ebecdad8SMichael Tuexen 	/* Is there a gap now? */
2582ebecdad8SMichael Tuexen 	is_a_gap = SCTP_TSN_GT(highest_tsn, stcb->asoc.cumulative_tsn);
2583b5c16493SMichael Tuexen 
2584830d754dSRandall Stewart 	/*
2585f8829a4aSRandall Stewart 	 * Now we need to see if we need to queue a sack or just start the
2586f8829a4aSRandall Stewart 	 * timer (if allowed).
2587f8829a4aSRandall Stewart 	 */
2588839d21d6SMichael Tuexen 	if (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_SENT) {
2589f8829a4aSRandall Stewart 		/*
2590b5c16493SMichael Tuexen 		 * Ok special case, in SHUTDOWN-SENT case. here we maker
2591b5c16493SMichael Tuexen 		 * sure SACK timer is off and instead send a SHUTDOWN and a
2592b5c16493SMichael Tuexen 		 * SACK
2593f8829a4aSRandall Stewart 		 */
2594139bc87fSRandall Stewart 		if (SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) {
2595f8829a4aSRandall Stewart 			sctp_timer_stop(SCTP_TIMER_TYPE_RECV,
2596b7d130beSMichael Tuexen 			    stcb->sctp_ep, stcb, NULL,
259791e04f9eSMichael Tuexen 			    SCTP_FROM_SCTP_INDATA + SCTP_LOC_19);
2598f8829a4aSRandall Stewart 		}
2599ca85e948SMichael Tuexen 		sctp_send_shutdown(stcb,
2600ca85e948SMichael Tuexen 		    ((stcb->asoc.alternate) ? stcb->asoc.alternate : stcb->asoc.primary_destination));
2601ebecdad8SMichael Tuexen 		if (is_a_gap) {
2602689e6a5fSMichael Tuexen 			sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED);
2603ebecdad8SMichael Tuexen 		}
2604f8829a4aSRandall Stewart 	} else {
2605f8829a4aSRandall Stewart 		/*
2606b5c16493SMichael Tuexen 		 * CMT DAC algorithm: increase number of packets received
2607b5c16493SMichael Tuexen 		 * since last ack
2608f8829a4aSRandall Stewart 		 */
2609f8829a4aSRandall Stewart 		stcb->asoc.cmt_dac_pkts_rcvd++;
2610f8829a4aSRandall Stewart 
261142551e99SRandall Stewart 		if ((stcb->asoc.send_sack == 1) ||	/* We need to send a
261242551e99SRandall Stewart 							 * SACK */
2613f8829a4aSRandall Stewart 		    ((was_a_gap) && (is_a_gap == 0)) ||	/* was a gap, but no
2614f8829a4aSRandall Stewart 							 * longer is one */
2615f8829a4aSRandall Stewart 		    (stcb->asoc.numduptsns) ||	/* we have dup's */
2616f8829a4aSRandall Stewart 		    (is_a_gap) ||	/* is still a gap */
261742551e99SRandall Stewart 		    (stcb->asoc.delayed_ack == 0) ||	/* Delayed sack disabled */
2618b6db274dSMichael Tuexen 		    (stcb->asoc.data_pkts_seen >= stcb->asoc.sack_freq)) {	/* hit limit of pkts */
26197c99d56fSMichael Tuexen 			if ((stcb->asoc.sctp_cmt_on_off > 0) &&
2620b3f1ea41SRandall Stewart 			    (SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) &&
262142551e99SRandall Stewart 			    (stcb->asoc.send_sack == 0) &&
2622f8829a4aSRandall Stewart 			    (stcb->asoc.numduptsns == 0) &&
2623f8829a4aSRandall Stewart 			    (stcb->asoc.delayed_ack) &&
2624139bc87fSRandall Stewart 			    (!SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer))) {
2625f8829a4aSRandall Stewart 				/*
2626b5c16493SMichael Tuexen 				 * CMT DAC algorithm: With CMT, delay acks
2627b6db274dSMichael Tuexen 				 * even in the face of reordering.
2628b6db274dSMichael Tuexen 				 * Therefore, if acks that do not have to be
2629b6db274dSMichael Tuexen 				 * sent because of the above reasons, will
2630b6db274dSMichael Tuexen 				 * be delayed. That is, acks that would have
2631b6db274dSMichael Tuexen 				 * been sent due to gap reports will be
2632b6db274dSMichael Tuexen 				 * delayed with DAC. Start the delayed ack
2633b6db274dSMichael Tuexen 				 * timer.
2634f8829a4aSRandall Stewart 				 */
2635f8829a4aSRandall Stewart 				sctp_timer_start(SCTP_TIMER_TYPE_RECV,
2636f8829a4aSRandall Stewart 				    stcb->sctp_ep, stcb, NULL);
2637f8829a4aSRandall Stewart 			} else {
2638f8829a4aSRandall Stewart 				/*
2639b5c16493SMichael Tuexen 				 * Ok we must build a SACK since the timer
2640b5c16493SMichael Tuexen 				 * is pending, we got our first packet OR
2641b5c16493SMichael Tuexen 				 * there are gaps or duplicates.
2642f8829a4aSRandall Stewart 				 */
26435555400aSMichael Tuexen 				sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL,
264491e04f9eSMichael Tuexen 				    SCTP_FROM_SCTP_INDATA + SCTP_LOC_20);
2645689e6a5fSMichael Tuexen 				sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED);
2646f8829a4aSRandall Stewart 			}
2647f8829a4aSRandall Stewart 		} else {
264842551e99SRandall Stewart 			if (!SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) {
2649f8829a4aSRandall Stewart 				sctp_timer_start(SCTP_TIMER_TYPE_RECV,
2650f8829a4aSRandall Stewart 				    stcb->sctp_ep, stcb, NULL);
2651f8829a4aSRandall Stewart 			}
2652f8829a4aSRandall Stewart 		}
2653f8829a4aSRandall Stewart 	}
2654f8829a4aSRandall Stewart }
2655f8829a4aSRandall Stewart 
2656f8829a4aSRandall Stewart int
2657f8829a4aSRandall Stewart sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
2658e7e71dd7SMichael Tuexen     struct sctp_inpcb *inp, struct sctp_tcb *stcb,
2659e7e71dd7SMichael Tuexen     struct sctp_nets *net, uint32_t *high_tsn)
2660f8829a4aSRandall Stewart {
266144249214SRandall Stewart 	struct sctp_chunkhdr *ch, chunk_buf;
2662f8829a4aSRandall Stewart 	struct sctp_association *asoc;
2663f8829a4aSRandall Stewart 	int num_chunks = 0;	/* number of control chunks processed */
2664f8829a4aSRandall Stewart 	int stop_proc = 0;
2665af03054cSMichael Tuexen 	int break_flag, last_chunk;
26668f777478SMichael Tuexen 	int abort_flag = 0, was_a_gap;
2667f8829a4aSRandall Stewart 	struct mbuf *m;
26688f777478SMichael Tuexen 	uint32_t highest_tsn;
2669af03054cSMichael Tuexen 	uint16_t chk_length;
2670f8829a4aSRandall Stewart 
2671f8829a4aSRandall Stewart 	/* set the rwnd */
2672f8829a4aSRandall Stewart 	sctp_set_rwnd(stcb, &stcb->asoc);
2673f8829a4aSRandall Stewart 
2674f8829a4aSRandall Stewart 	m = *mm;
2675f8829a4aSRandall Stewart 	SCTP_TCB_LOCK_ASSERT(stcb);
2676f8829a4aSRandall Stewart 	asoc = &stcb->asoc;
267720b07a4dSMichael Tuexen 	if (SCTP_TSN_GT(asoc->highest_tsn_inside_nr_map, asoc->highest_tsn_inside_map)) {
26788f777478SMichael Tuexen 		highest_tsn = asoc->highest_tsn_inside_nr_map;
26798f777478SMichael Tuexen 	} else {
26808f777478SMichael Tuexen 		highest_tsn = asoc->highest_tsn_inside_map;
2681f8829a4aSRandall Stewart 	}
268220b07a4dSMichael Tuexen 	was_a_gap = SCTP_TSN_GT(highest_tsn, stcb->asoc.cumulative_tsn);
2683f8829a4aSRandall Stewart 	/*
2684f8829a4aSRandall Stewart 	 * setup where we got the last DATA packet from for any SACK that
2685f8829a4aSRandall Stewart 	 * may need to go out. Don't bump the net. This is done ONLY when a
2686f8829a4aSRandall Stewart 	 * chunk is assigned.
2687f8829a4aSRandall Stewart 	 */
2688f8829a4aSRandall Stewart 	asoc->last_data_chunk_from = net;
2689f8829a4aSRandall Stewart 
2690d06c82f1SRandall Stewart 	/*-
2691f8829a4aSRandall Stewart 	 * Now before we proceed we must figure out if this is a wasted
2692f8829a4aSRandall Stewart 	 * cluster... i.e. it is a small packet sent in and yet the driver
2693f8829a4aSRandall Stewart 	 * underneath allocated a full cluster for it. If so we must copy it
2694f8829a4aSRandall Stewart 	 * to a smaller mbuf and free up the cluster mbuf. This will help
26952cf33471SMichael Tuexen 	 * with cluster starvation.
2696f8829a4aSRandall Stewart 	 */
269744b7479bSRandall Stewart 	if (SCTP_BUF_LEN(m) < (long)MLEN && SCTP_BUF_NEXT(m) == NULL) {
2698f8829a4aSRandall Stewart 		/* we only handle mbufs that are singletons.. not chains */
2699eb1b1807SGleb Smirnoff 		m = sctp_get_mbuf_for_msg(SCTP_BUF_LEN(m), 0, M_NOWAIT, 1, MT_DATA);
2700f8829a4aSRandall Stewart 		if (m) {
2701f8829a4aSRandall Stewart 			/* ok lets see if we can copy the data up */
2702f8829a4aSRandall Stewart 			caddr_t *from, *to;
2703f8829a4aSRandall Stewart 
2704f8829a4aSRandall Stewart 			/* get the pointers and copy */
2705f8829a4aSRandall Stewart 			to = mtod(m, caddr_t *);
2706f8829a4aSRandall Stewart 			from = mtod((*mm), caddr_t *);
2707139bc87fSRandall Stewart 			memcpy(to, from, SCTP_BUF_LEN((*mm)));
2708f8829a4aSRandall Stewart 			/* copy the length and free up the old */
2709139bc87fSRandall Stewart 			SCTP_BUF_LEN(m) = SCTP_BUF_LEN((*mm));
2710f8829a4aSRandall Stewart 			sctp_m_freem(*mm);
2711cd0a4ff6SPedro F. Giffuni 			/* success, back copy */
2712f8829a4aSRandall Stewart 			*mm = m;
2713f8829a4aSRandall Stewart 		} else {
2714f8829a4aSRandall Stewart 			/* We are in trouble in the mbuf world .. yikes */
2715f8829a4aSRandall Stewart 			m = *mm;
2716f8829a4aSRandall Stewart 		}
2717f8829a4aSRandall Stewart 	}
2718f8829a4aSRandall Stewart 	/* get pointer to the first chunk header */
271944249214SRandall Stewart 	ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset,
27207f75695aSMichael Tuexen 	    sizeof(struct sctp_chunkhdr),
27217f75695aSMichael Tuexen 	    (uint8_t *)&chunk_buf);
2722f8829a4aSRandall Stewart 	if (ch == NULL) {
2723f8829a4aSRandall Stewart 		return (1);
2724f8829a4aSRandall Stewart 	}
2725f8829a4aSRandall Stewart 	/*
2726f8829a4aSRandall Stewart 	 * process all DATA chunks...
2727f8829a4aSRandall Stewart 	 */
2728f8829a4aSRandall Stewart 	*high_tsn = asoc->cumulative_tsn;
2729f8829a4aSRandall Stewart 	break_flag = 0;
273042551e99SRandall Stewart 	asoc->data_pkts_seen++;
2731f8829a4aSRandall Stewart 	while (stop_proc == 0) {
2732f8829a4aSRandall Stewart 		/* validate chunk length */
273344249214SRandall Stewart 		chk_length = ntohs(ch->chunk_length);
2734f8829a4aSRandall Stewart 		if (length - *offset < chk_length) {
2735f8829a4aSRandall Stewart 			/* all done, mutulated chunk */
2736f8829a4aSRandall Stewart 			stop_proc = 1;
273760990c0cSMichael Tuexen 			continue;
2738f8829a4aSRandall Stewart 		}
273944249214SRandall Stewart 		if ((asoc->idata_supported == 1) &&
274044249214SRandall Stewart 		    (ch->chunk_type == SCTP_DATA)) {
274144249214SRandall Stewart 			struct mbuf *op_err;
274244249214SRandall Stewart 			char msg[SCTP_DIAG_INFO_LEN];
274344249214SRandall Stewart 
2744ef9095c7SMichael Tuexen 			SCTP_SNPRINTF(msg, sizeof(msg), "%s", "DATA chunk received when I-DATA was negotiated");
274544249214SRandall Stewart 			op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
274691e04f9eSMichael Tuexen 			stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_21;
274744249214SRandall Stewart 			sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED);
274844249214SRandall Stewart 			return (2);
274944249214SRandall Stewart 		}
275044249214SRandall Stewart 		if ((asoc->idata_supported == 0) &&
275144249214SRandall Stewart 		    (ch->chunk_type == SCTP_IDATA)) {
275244249214SRandall Stewart 			struct mbuf *op_err;
275344249214SRandall Stewart 			char msg[SCTP_DIAG_INFO_LEN];
275444249214SRandall Stewart 
2755ef9095c7SMichael Tuexen 			SCTP_SNPRINTF(msg, sizeof(msg), "%s", "I-DATA chunk received when DATA was negotiated");
275644249214SRandall Stewart 			op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
275791e04f9eSMichael Tuexen 			stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_22;
275844249214SRandall Stewart 			sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED);
275944249214SRandall Stewart 			return (2);
276044249214SRandall Stewart 		}
276144249214SRandall Stewart 		if ((ch->chunk_type == SCTP_DATA) ||
276244249214SRandall Stewart 		    (ch->chunk_type == SCTP_IDATA)) {
2763af03054cSMichael Tuexen 			uint16_t clen;
276444249214SRandall Stewart 
276544249214SRandall Stewart 			if (ch->chunk_type == SCTP_DATA) {
276644249214SRandall Stewart 				clen = sizeof(struct sctp_data_chunk);
276744249214SRandall Stewart 			} else {
276844249214SRandall Stewart 				clen = sizeof(struct sctp_idata_chunk);
276944249214SRandall Stewart 			}
2770f8ee69bfSMichael Tuexen 			if (chk_length < clen) {
2771f8829a4aSRandall Stewart 				/*
2772f8829a4aSRandall Stewart 				 * Need to send an abort since we had a
2773f8829a4aSRandall Stewart 				 * invalid data chunk.
2774f8829a4aSRandall Stewart 				 */
2775f8829a4aSRandall Stewart 				struct mbuf *op_err;
2776ff1ffd74SMichael Tuexen 				char msg[SCTP_DIAG_INFO_LEN];
2777f8829a4aSRandall Stewart 
2778999f86d6SMichael Tuexen 				SCTP_SNPRINTF(msg, sizeof(msg), "%s chunk of length %u",
27797f75695aSMichael Tuexen 				    ch->chunk_type == SCTP_DATA ? "DATA" : "I-DATA",
2780821bae7cSMichael Tuexen 				    chk_length);
2781ff1ffd74SMichael Tuexen 				op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
278291e04f9eSMichael Tuexen 				stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_23;
2783e7e71dd7SMichael Tuexen 				sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED);
278432451da4SMichael Tuexen 				return (2);
278532451da4SMichael Tuexen 			}
2786f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED
2787f8829a4aSRandall Stewart 			sctp_audit_log(0xB1, 0);
2788f8829a4aSRandall Stewart #endif
2789f8829a4aSRandall Stewart 			if (SCTP_SIZE32(chk_length) == (length - *offset)) {
2790f8829a4aSRandall Stewart 				last_chunk = 1;
2791f8829a4aSRandall Stewart 			} else {
2792f8829a4aSRandall Stewart 				last_chunk = 0;
2793f8829a4aSRandall Stewart 			}
279444249214SRandall Stewart 			if (sctp_process_a_data_chunk(stcb, asoc, mm, *offset,
2795f8829a4aSRandall Stewart 			    chk_length, net, high_tsn, &abort_flag, &break_flag,
279644249214SRandall Stewart 			    last_chunk, ch->chunk_type)) {
2797f8829a4aSRandall Stewart 				num_chunks++;
2798f8829a4aSRandall Stewart 			}
2799f8829a4aSRandall Stewart 			if (abort_flag)
2800f8829a4aSRandall Stewart 				return (2);
2801f8829a4aSRandall Stewart 
2802f8829a4aSRandall Stewart 			if (break_flag) {
2803f8829a4aSRandall Stewart 				/*
2804f8829a4aSRandall Stewart 				 * Set because of out of rwnd space and no
2805f8829a4aSRandall Stewart 				 * drop rep space left.
2806f8829a4aSRandall Stewart 				 */
2807f8829a4aSRandall Stewart 				stop_proc = 1;
280860990c0cSMichael Tuexen 				continue;
2809f8829a4aSRandall Stewart 			}
2810f8829a4aSRandall Stewart 		} else {
2811f8829a4aSRandall Stewart 			/* not a data chunk in the data region */
281244249214SRandall Stewart 			switch (ch->chunk_type) {
2813f8829a4aSRandall Stewart 			case SCTP_INITIATION:
2814f8829a4aSRandall Stewart 			case SCTP_INITIATION_ACK:
2815f8829a4aSRandall Stewart 			case SCTP_SELECTIVE_ACK:
281660990c0cSMichael Tuexen 			case SCTP_NR_SELECTIVE_ACK:
2817f8829a4aSRandall Stewart 			case SCTP_HEARTBEAT_REQUEST:
2818f8829a4aSRandall Stewart 			case SCTP_HEARTBEAT_ACK:
2819f8829a4aSRandall Stewart 			case SCTP_ABORT_ASSOCIATION:
2820f8829a4aSRandall Stewart 			case SCTP_SHUTDOWN:
2821f8829a4aSRandall Stewart 			case SCTP_SHUTDOWN_ACK:
2822f8829a4aSRandall Stewart 			case SCTP_OPERATION_ERROR:
2823f8829a4aSRandall Stewart 			case SCTP_COOKIE_ECHO:
2824f8829a4aSRandall Stewart 			case SCTP_COOKIE_ACK:
2825f8829a4aSRandall Stewart 			case SCTP_ECN_ECHO:
2826f8829a4aSRandall Stewart 			case SCTP_ECN_CWR:
2827f8829a4aSRandall Stewart 			case SCTP_SHUTDOWN_COMPLETE:
2828f8829a4aSRandall Stewart 			case SCTP_AUTHENTICATION:
2829f8829a4aSRandall Stewart 			case SCTP_ASCONF_ACK:
2830f8829a4aSRandall Stewart 			case SCTP_PACKET_DROPPED:
2831f8829a4aSRandall Stewart 			case SCTP_STREAM_RESET:
2832f8829a4aSRandall Stewart 			case SCTP_FORWARD_CUM_TSN:
2833f8829a4aSRandall Stewart 			case SCTP_ASCONF:
2834fd60718dSMichael Tuexen 				{
2835f8829a4aSRandall Stewart 					/*
2836fd60718dSMichael Tuexen 					 * Now, what do we do with KNOWN
2837fd60718dSMichael Tuexen 					 * chunks that are NOT in the right
2838fd60718dSMichael Tuexen 					 * place?
2839f8829a4aSRandall Stewart 					 *
2840fd60718dSMichael Tuexen 					 * For now, I do nothing but ignore
2841fd60718dSMichael Tuexen 					 * them. We may later want to add
2842fd60718dSMichael Tuexen 					 * sysctl stuff to switch out and do
2843fd60718dSMichael Tuexen 					 * either an ABORT() or possibly
2844fd60718dSMichael Tuexen 					 * process them.
2845f8829a4aSRandall Stewart 					 */
2846f8829a4aSRandall Stewart 					struct mbuf *op_err;
2847267dbe63SMichael Tuexen 					char msg[SCTP_DIAG_INFO_LEN];
2848f8829a4aSRandall Stewart 
2849999f86d6SMichael Tuexen 					SCTP_SNPRINTF(msg, sizeof(msg), "DATA chunk followed by chunk of type %2.2x",
2850821bae7cSMichael Tuexen 					    ch->chunk_type);
2851267dbe63SMichael Tuexen 					op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
2852e7e71dd7SMichael Tuexen 					sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED);
2853f8829a4aSRandall Stewart 					return (2);
2854f8829a4aSRandall Stewart 				}
2855f8829a4aSRandall Stewart 			default:
28567f75695aSMichael Tuexen 				/*
28577f75695aSMichael Tuexen 				 * Unknown chunk type: use bit rules after
28587f75695aSMichael Tuexen 				 * checking length
28597f75695aSMichael Tuexen 				 */
28607f75695aSMichael Tuexen 				if (chk_length < sizeof(struct sctp_chunkhdr)) {
28617f75695aSMichael Tuexen 					/*
28627f75695aSMichael Tuexen 					 * Need to send an abort since we
28637f75695aSMichael Tuexen 					 * had a invalid chunk.
28647f75695aSMichael Tuexen 					 */
28657f75695aSMichael Tuexen 					struct mbuf *op_err;
28667f75695aSMichael Tuexen 					char msg[SCTP_DIAG_INFO_LEN];
28677f75695aSMichael Tuexen 
2868999f86d6SMichael Tuexen 					SCTP_SNPRINTF(msg, sizeof(msg), "Chunk of length %u", chk_length);
28697f75695aSMichael Tuexen 					op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
287091e04f9eSMichael Tuexen 					stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_24;
28717f75695aSMichael Tuexen 					sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED);
28727f75695aSMichael Tuexen 					return (2);
28737f75695aSMichael Tuexen 				}
287444249214SRandall Stewart 				if (ch->chunk_type & 0x40) {
2875f8829a4aSRandall Stewart 					/* Add a error report to the queue */
287686eda749SMichael Tuexen 					struct mbuf *op_err;
287786eda749SMichael Tuexen 					struct sctp_gen_error_cause *cause;
2878f8829a4aSRandall Stewart 
287986eda749SMichael Tuexen 					op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_gen_error_cause),
288086eda749SMichael Tuexen 					    0, M_NOWAIT, 1, MT_DATA);
288186eda749SMichael Tuexen 					if (op_err != NULL) {
288286eda749SMichael Tuexen 						cause = mtod(op_err, struct sctp_gen_error_cause *);
288386eda749SMichael Tuexen 						cause->code = htons(SCTP_CAUSE_UNRECOG_CHUNK);
28849a8e3088SMichael Tuexen 						cause->length = htons((uint16_t)(chk_length + sizeof(struct sctp_gen_error_cause)));
288586eda749SMichael Tuexen 						SCTP_BUF_LEN(op_err) = sizeof(struct sctp_gen_error_cause);
288686eda749SMichael Tuexen 						SCTP_BUF_NEXT(op_err) = SCTP_M_COPYM(m, *offset, chk_length, M_NOWAIT);
288786eda749SMichael Tuexen 						if (SCTP_BUF_NEXT(op_err) != NULL) {
288886eda749SMichael Tuexen 							sctp_queue_op_err(stcb, op_err);
2889f8829a4aSRandall Stewart 						} else {
289086eda749SMichael Tuexen 							sctp_m_freem(op_err);
2891f8829a4aSRandall Stewart 						}
2892f8829a4aSRandall Stewart 					}
2893f8829a4aSRandall Stewart 				}
289444249214SRandall Stewart 				if ((ch->chunk_type & 0x80) == 0) {
2895f8829a4aSRandall Stewart 					/* discard the rest of this packet */
2896f8829a4aSRandall Stewart 					stop_proc = 1;
2897f8829a4aSRandall Stewart 				}	/* else skip this bad chunk and
2898b7b84c0eSMichael Tuexen 					 * continue... */
2899b7b84c0eSMichael Tuexen 				break;
290060990c0cSMichael Tuexen 			}	/* switch of chunk type */
2901f8829a4aSRandall Stewart 		}
2902f8829a4aSRandall Stewart 		*offset += SCTP_SIZE32(chk_length);
2903f8829a4aSRandall Stewart 		if ((*offset >= length) || stop_proc) {
2904f8829a4aSRandall Stewart 			/* no more data left in the mbuf chain */
2905f8829a4aSRandall Stewart 			stop_proc = 1;
2906f8829a4aSRandall Stewart 			continue;
2907f8829a4aSRandall Stewart 		}
290844249214SRandall Stewart 		ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset,
29097f75695aSMichael Tuexen 		    sizeof(struct sctp_chunkhdr),
29107f75695aSMichael Tuexen 		    (uint8_t *)&chunk_buf);
2911f8829a4aSRandall Stewart 		if (ch == NULL) {
2912f8829a4aSRandall Stewart 			*offset = length;
2913f8829a4aSRandall Stewart 			stop_proc = 1;
291460990c0cSMichael Tuexen 			continue;
2915f8829a4aSRandall Stewart 		}
291660990c0cSMichael Tuexen 	}
2917f8829a4aSRandall Stewart 	if (break_flag) {
2918f8829a4aSRandall Stewart 		/*
2919f8829a4aSRandall Stewart 		 * we need to report rwnd overrun drops.
2920f8829a4aSRandall Stewart 		 */
292120cc2188SMichael Tuexen 		sctp_send_packet_dropped(stcb, net, *mm, length, iphlen, 0);
2922f8829a4aSRandall Stewart 	}
2923f8829a4aSRandall Stewart 	if (num_chunks) {
2924f8829a4aSRandall Stewart 		/*
2925ceaad40aSRandall Stewart 		 * Did we get data, if so update the time for auto-close and
2926f8829a4aSRandall Stewart 		 * give peer credit for being alive.
2927f8829a4aSRandall Stewart 		 */
2928f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_recvpktwithdata);
2929b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) {
2930c4739e2fSRandall Stewart 			sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
2931c4739e2fSRandall Stewart 			    stcb->asoc.overall_error_count,
2932c4739e2fSRandall Stewart 			    0,
2933c4739e2fSRandall Stewart 			    SCTP_FROM_SCTP_INDATA,
2934c4739e2fSRandall Stewart 			    __LINE__);
2935c4739e2fSRandall Stewart 		}
2936f8829a4aSRandall Stewart 		stcb->asoc.overall_error_count = 0;
29376e55db54SRandall Stewart 		(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_last_rcvd);
2938f8829a4aSRandall Stewart 	}
2939f8829a4aSRandall Stewart 	/* now service all of the reassm queue if needed */
2940839d21d6SMichael Tuexen 	if (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_SENT) {
294142551e99SRandall Stewart 		/* Assure that we ack right away */
294242551e99SRandall Stewart 		stcb->asoc.send_sack = 1;
2943f8829a4aSRandall Stewart 	}
2944f8829a4aSRandall Stewart 	/* Start a sack timer or QUEUE a SACK for sending */
29457215cc1bSMichael Tuexen 	sctp_sack_check(stcb, was_a_gap);
2946f8829a4aSRandall Stewart 	return (0);
2947f8829a4aSRandall Stewart }
2948f8829a4aSRandall Stewart 
29490fa753b3SRandall Stewart static int
29500fa753b3SRandall Stewart sctp_process_segment_range(struct sctp_tcb *stcb, struct sctp_tmit_chunk **p_tp1, uint32_t last_tsn,
29510fa753b3SRandall Stewart     uint16_t frag_strt, uint16_t frag_end, int nr_sacking,
29520fa753b3SRandall Stewart     int *num_frs,
29530fa753b3SRandall Stewart     uint32_t *biggest_newly_acked_tsn,
29540fa753b3SRandall Stewart     uint32_t *this_sack_lowest_newack,
29557215cc1bSMichael Tuexen     int *rto_ok)
29560fa753b3SRandall Stewart {
29570fa753b3SRandall Stewart 	struct sctp_tmit_chunk *tp1;
29580fa753b3SRandall Stewart 	unsigned int theTSN;
2959b5c16493SMichael Tuexen 	int j, wake_him = 0, circled = 0;
29600fa753b3SRandall Stewart 
29610fa753b3SRandall Stewart 	/* Recover the tp1 we last saw */
29620fa753b3SRandall Stewart 	tp1 = *p_tp1;
29630fa753b3SRandall Stewart 	if (tp1 == NULL) {
29640fa753b3SRandall Stewart 		tp1 = TAILQ_FIRST(&stcb->asoc.sent_queue);
29650fa753b3SRandall Stewart 	}
29660fa753b3SRandall Stewart 	for (j = frag_strt; j <= frag_end; j++) {
29670fa753b3SRandall Stewart 		theTSN = j + last_tsn;
29680fa753b3SRandall Stewart 		while (tp1) {
29690fa753b3SRandall Stewart 			if (tp1->rec.data.doing_fast_retransmit)
29700fa753b3SRandall Stewart 				(*num_frs) += 1;
29710fa753b3SRandall Stewart 
29720fa753b3SRandall Stewart 			/*-
29730fa753b3SRandall Stewart 			 * CMT: CUCv2 algorithm. For each TSN being
29740fa753b3SRandall Stewart 			 * processed from the sent queue, track the
29750fa753b3SRandall Stewart 			 * next expected pseudo-cumack, or
29760fa753b3SRandall Stewart 			 * rtx_pseudo_cumack, if required. Separate
29770fa753b3SRandall Stewart 			 * cumack trackers for first transmissions,
29780fa753b3SRandall Stewart 			 * and retransmissions.
29790fa753b3SRandall Stewart 			 */
29808427b3fdSMichael Tuexen 			if ((tp1->sent < SCTP_DATAGRAM_RESEND) &&
29818427b3fdSMichael Tuexen 			    (tp1->whoTo->find_pseudo_cumack == 1) &&
29820fa753b3SRandall Stewart 			    (tp1->snd_count == 1)) {
298349656eefSMichael Tuexen 				tp1->whoTo->pseudo_cumack = tp1->rec.data.tsn;
29840fa753b3SRandall Stewart 				tp1->whoTo->find_pseudo_cumack = 0;
29850fa753b3SRandall Stewart 			}
29868427b3fdSMichael Tuexen 			if ((tp1->sent < SCTP_DATAGRAM_RESEND) &&
29878427b3fdSMichael Tuexen 			    (tp1->whoTo->find_rtx_pseudo_cumack == 1) &&
29880fa753b3SRandall Stewart 			    (tp1->snd_count > 1)) {
298949656eefSMichael Tuexen 				tp1->whoTo->rtx_pseudo_cumack = tp1->rec.data.tsn;
29900fa753b3SRandall Stewart 				tp1->whoTo->find_rtx_pseudo_cumack = 0;
29910fa753b3SRandall Stewart 			}
299249656eefSMichael Tuexen 			if (tp1->rec.data.tsn == theTSN) {
29930fa753b3SRandall Stewart 				if (tp1->sent != SCTP_DATAGRAM_UNSENT) {
29940fa753b3SRandall Stewart 					/*-
29950fa753b3SRandall Stewart 					 * must be held until
29960fa753b3SRandall Stewart 					 * cum-ack passes
29970fa753b3SRandall Stewart 					 */
29980fa753b3SRandall Stewart 					if (tp1->sent < SCTP_DATAGRAM_RESEND) {
29990fa753b3SRandall Stewart 						/*-
30000fa753b3SRandall Stewart 						 * If it is less than RESEND, it is
30010fa753b3SRandall Stewart 						 * now no-longer in flight.
30020fa753b3SRandall Stewart 						 * Higher values may already be set
30030fa753b3SRandall Stewart 						 * via previous Gap Ack Blocks...
30040fa753b3SRandall Stewart 						 * i.e. ACKED or RESEND.
30050fa753b3SRandall Stewart 						 */
300649656eefSMichael Tuexen 						if (SCTP_TSN_GT(tp1->rec.data.tsn,
300720b07a4dSMichael Tuexen 						    *biggest_newly_acked_tsn)) {
300849656eefSMichael Tuexen 							*biggest_newly_acked_tsn = tp1->rec.data.tsn;
30090fa753b3SRandall Stewart 						}
30100fa753b3SRandall Stewart 						/*-
30110fa753b3SRandall Stewart 						 * CMT: SFR algo (and HTNA) - set
30120fa753b3SRandall Stewart 						 * saw_newack to 1 for dest being
30130fa753b3SRandall Stewart 						 * newly acked. update
30140fa753b3SRandall Stewart 						 * this_sack_highest_newack if
30150fa753b3SRandall Stewart 						 * appropriate.
30160fa753b3SRandall Stewart 						 */
30170fa753b3SRandall Stewart 						if (tp1->rec.data.chunk_was_revoked == 0)
30180fa753b3SRandall Stewart 							tp1->whoTo->saw_newack = 1;
30190fa753b3SRandall Stewart 
302049656eefSMichael Tuexen 						if (SCTP_TSN_GT(tp1->rec.data.tsn,
302120b07a4dSMichael Tuexen 						    tp1->whoTo->this_sack_highest_newack)) {
30220fa753b3SRandall Stewart 							tp1->whoTo->this_sack_highest_newack =
302349656eefSMichael Tuexen 							    tp1->rec.data.tsn;
30240fa753b3SRandall Stewart 						}
30250fa753b3SRandall Stewart 						/*-
30260fa753b3SRandall Stewart 						 * CMT DAC algo: also update
30270fa753b3SRandall Stewart 						 * this_sack_lowest_newack
30280fa753b3SRandall Stewart 						 */
30290fa753b3SRandall Stewart 						if (*this_sack_lowest_newack == 0) {
30300fa753b3SRandall Stewart 							if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) {
30310fa753b3SRandall Stewart 								sctp_log_sack(*this_sack_lowest_newack,
30320fa753b3SRandall Stewart 								    last_tsn,
303349656eefSMichael Tuexen 								    tp1->rec.data.tsn,
30340fa753b3SRandall Stewart 								    0,
30350fa753b3SRandall Stewart 								    0,
30360fa753b3SRandall Stewart 								    SCTP_LOG_TSN_ACKED);
30370fa753b3SRandall Stewart 							}
303849656eefSMichael Tuexen 							*this_sack_lowest_newack = tp1->rec.data.tsn;
30390fa753b3SRandall Stewart 						}
30400fa753b3SRandall Stewart 						/*-
30410fa753b3SRandall Stewart 						 * CMT: CUCv2 algorithm. If (rtx-)pseudo-cumack for corresp
30420fa753b3SRandall Stewart 						 * dest is being acked, then we have a new (rtx-)pseudo-cumack. Set
30430fa753b3SRandall Stewart 						 * new_(rtx_)pseudo_cumack to TRUE so that the cwnd for this dest can be
30440fa753b3SRandall Stewart 						 * updated. Also trigger search for the next expected (rtx-)pseudo-cumack.
30450fa753b3SRandall Stewart 						 * Separate pseudo_cumack trackers for first transmissions and
30460fa753b3SRandall Stewart 						 * retransmissions.
30470fa753b3SRandall Stewart 						 */
304849656eefSMichael Tuexen 						if (tp1->rec.data.tsn == tp1->whoTo->pseudo_cumack) {
30490fa753b3SRandall Stewart 							if (tp1->rec.data.chunk_was_revoked == 0) {
30500fa753b3SRandall Stewart 								tp1->whoTo->new_pseudo_cumack = 1;
30510fa753b3SRandall Stewart 							}
30520fa753b3SRandall Stewart 							tp1->whoTo->find_pseudo_cumack = 1;
30530fa753b3SRandall Stewart 						}
30540fa753b3SRandall Stewart 						if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
305549656eefSMichael Tuexen 							sctp_log_cwnd(stcb, tp1->whoTo, tp1->rec.data.tsn, SCTP_CWND_LOG_FROM_SACK);
30560fa753b3SRandall Stewart 						}
305749656eefSMichael Tuexen 						if (tp1->rec.data.tsn == tp1->whoTo->rtx_pseudo_cumack) {
30580fa753b3SRandall Stewart 							if (tp1->rec.data.chunk_was_revoked == 0) {
30590fa753b3SRandall Stewart 								tp1->whoTo->new_pseudo_cumack = 1;
30600fa753b3SRandall Stewart 							}
30610fa753b3SRandall Stewart 							tp1->whoTo->find_rtx_pseudo_cumack = 1;
30620fa753b3SRandall Stewart 						}
30630fa753b3SRandall Stewart 						if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) {
30640fa753b3SRandall Stewart 							sctp_log_sack(*biggest_newly_acked_tsn,
30650fa753b3SRandall Stewart 							    last_tsn,
306649656eefSMichael Tuexen 							    tp1->rec.data.tsn,
30670fa753b3SRandall Stewart 							    frag_strt,
30680fa753b3SRandall Stewart 							    frag_end,
30690fa753b3SRandall Stewart 							    SCTP_LOG_TSN_ACKED);
30700fa753b3SRandall Stewart 						}
30710fa753b3SRandall Stewart 						if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) {
30720fa753b3SRandall Stewart 							sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_GAP,
30730fa753b3SRandall Stewart 							    tp1->whoTo->flight_size,
30740fa753b3SRandall Stewart 							    tp1->book_size,
30759a8e3088SMichael Tuexen 							    (uint32_t)(uintptr_t)tp1->whoTo,
307649656eefSMichael Tuexen 							    tp1->rec.data.tsn);
30770fa753b3SRandall Stewart 						}
30780fa753b3SRandall Stewart 						sctp_flight_size_decrease(tp1);
3079299108c5SRandall Stewart 						if (stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) {
3080299108c5SRandall Stewart 							(*stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) (tp1->whoTo,
3081299108c5SRandall Stewart 							    tp1);
3082299108c5SRandall Stewart 						}
30830fa753b3SRandall Stewart 						sctp_total_flight_decrease(stcb, tp1);
30840fa753b3SRandall Stewart 
30850fa753b3SRandall Stewart 						tp1->whoTo->net_ack += tp1->send_size;
30860fa753b3SRandall Stewart 						if (tp1->snd_count < 2) {
30870fa753b3SRandall Stewart 							/*-
3088ab9ed8a1SDevin Teske 							 * True non-retransmitted chunk
30890fa753b3SRandall Stewart 							 */
30900fa753b3SRandall Stewart 							tp1->whoTo->net_ack2 += tp1->send_size;
30910fa753b3SRandall Stewart 
30920fa753b3SRandall Stewart 							/*-
30930fa753b3SRandall Stewart 							 * update RTO too ?
30940fa753b3SRandall Stewart 							 */
30950fa753b3SRandall Stewart 							if (tp1->do_rtt) {
309644f2a327SMichael Tuexen 								if (*rto_ok &&
30970fa753b3SRandall Stewart 								    sctp_calculate_rto(stcb,
30980fa753b3SRandall Stewart 								    &stcb->asoc,
30990fa753b3SRandall Stewart 								    tp1->whoTo,
31000fa753b3SRandall Stewart 								    &tp1->sent_rcv_time,
310144f2a327SMichael Tuexen 								    SCTP_RTT_FROM_DATA)) {
3102f79aab18SRandall Stewart 									*rto_ok = 0;
3103f79aab18SRandall Stewart 								}
3104f79aab18SRandall Stewart 								if (tp1->whoTo->rto_needed == 0) {
3105f79aab18SRandall Stewart 									tp1->whoTo->rto_needed = 1;
3106f79aab18SRandall Stewart 								}
31070fa753b3SRandall Stewart 								tp1->do_rtt = 0;
31080fa753b3SRandall Stewart 							}
31090fa753b3SRandall Stewart 						}
31100fa753b3SRandall Stewart 					}
31110fa753b3SRandall Stewart 					if (tp1->sent <= SCTP_DATAGRAM_RESEND) {
311249656eefSMichael Tuexen 						if (SCTP_TSN_GT(tp1->rec.data.tsn,
311320b07a4dSMichael Tuexen 						    stcb->asoc.this_sack_highest_gap)) {
31140fa753b3SRandall Stewart 							stcb->asoc.this_sack_highest_gap =
311549656eefSMichael Tuexen 							    tp1->rec.data.tsn;
31160fa753b3SRandall Stewart 						}
31170fa753b3SRandall Stewart 						if (tp1->sent == SCTP_DATAGRAM_RESEND) {
31180fa753b3SRandall Stewart 							sctp_ucount_decr(stcb->asoc.sent_queue_retran_cnt);
31190fa753b3SRandall Stewart #ifdef SCTP_AUDITING_ENABLED
31200fa753b3SRandall Stewart 							sctp_audit_log(0xB2,
31210fa753b3SRandall Stewart 							    (stcb->asoc.sent_queue_retran_cnt & 0x000000ff));
31220fa753b3SRandall Stewart #endif
31230fa753b3SRandall Stewart 						}
31240fa753b3SRandall Stewart 					}
31250fa753b3SRandall Stewart 					/*-
31260fa753b3SRandall Stewart 					 * All chunks NOT UNSENT fall through here and are marked
31270fa753b3SRandall Stewart 					 * (leave PR-SCTP ones that are to skip alone though)
31280fa753b3SRandall Stewart 					 */
31292a498584SMichael Tuexen 					if ((tp1->sent != SCTP_FORWARD_TSN_SKIP) &&
3130325c8c46SMichael Tuexen 					    (tp1->sent != SCTP_DATAGRAM_NR_ACKED)) {
31310fa753b3SRandall Stewart 						tp1->sent = SCTP_DATAGRAM_MARKED;
31322a498584SMichael Tuexen 					}
31330fa753b3SRandall Stewart 					if (tp1->rec.data.chunk_was_revoked) {
31340fa753b3SRandall Stewart 						/* deflate the cwnd */
31350fa753b3SRandall Stewart 						tp1->whoTo->cwnd -= tp1->book_size;
31360fa753b3SRandall Stewart 						tp1->rec.data.chunk_was_revoked = 0;
31370fa753b3SRandall Stewart 					}
31380fa753b3SRandall Stewart 					/* NR Sack code here */
3139325c8c46SMichael Tuexen 					if (nr_sacking &&
3140325c8c46SMichael Tuexen 					    (tp1->sent != SCTP_DATAGRAM_NR_ACKED)) {
314149656eefSMichael Tuexen 						if (stcb->asoc.strmout[tp1->rec.data.sid].chunks_on_queues > 0) {
314249656eefSMichael Tuexen 							stcb->asoc.strmout[tp1->rec.data.sid].chunks_on_queues--;
3143325c8c46SMichael Tuexen #ifdef INVARIANTS
3144325c8c46SMichael Tuexen 						} else {
314549656eefSMichael Tuexen 							panic("No chunks on the queues for sid %u.", tp1->rec.data.sid);
3146325c8c46SMichael Tuexen #endif
3147325c8c46SMichael Tuexen 						}
314849656eefSMichael Tuexen 						if ((stcb->asoc.strmout[tp1->rec.data.sid].chunks_on_queues == 0) &&
314949656eefSMichael Tuexen 						    (stcb->asoc.strmout[tp1->rec.data.sid].state == SCTP_STREAM_RESET_PENDING) &&
315049656eefSMichael Tuexen 						    TAILQ_EMPTY(&stcb->asoc.strmout[tp1->rec.data.sid].outqueue)) {
3151d96bef9cSMichael Tuexen 							stcb->asoc.trigger_reset = 1;
3152d96bef9cSMichael Tuexen 						}
3153325c8c46SMichael Tuexen 						tp1->sent = SCTP_DATAGRAM_NR_ACKED;
31540fa753b3SRandall Stewart 						if (tp1->data) {
3155b7b84c0eSMichael Tuexen 							/*
3156b7b84c0eSMichael Tuexen 							 * sa_ignore
3157b7b84c0eSMichael Tuexen 							 * NO_NULL_CHK
3158b7b84c0eSMichael Tuexen 							 */
31590fa753b3SRandall Stewart 							sctp_free_bufspace(stcb, &stcb->asoc, tp1, 1);
31600fa753b3SRandall Stewart 							sctp_m_freem(tp1->data);
31610fa753b3SRandall Stewart 							tp1->data = NULL;
3162b5c16493SMichael Tuexen 						}
31630fa753b3SRandall Stewart 						wake_him++;
31640fa753b3SRandall Stewart 					}
31650fa753b3SRandall Stewart 				}
31660fa753b3SRandall Stewart 				break;
3167b7b84c0eSMichael Tuexen 			}	/* if (tp1->tsn == theTSN) */
3168b7b84c0eSMichael Tuexen 			if (SCTP_TSN_GT(tp1->rec.data.tsn, theTSN)) {
31690fa753b3SRandall Stewart 				break;
317020b07a4dSMichael Tuexen 			}
31710fa753b3SRandall Stewart 			tp1 = TAILQ_NEXT(tp1, sctp_next);
3172b5c16493SMichael Tuexen 			if ((tp1 == NULL) && (circled == 0)) {
3173b5c16493SMichael Tuexen 				circled++;
31740fa753b3SRandall Stewart 				tp1 = TAILQ_FIRST(&stcb->asoc.sent_queue);
31750fa753b3SRandall Stewart 			}
3176b5c16493SMichael Tuexen 		}		/* end while (tp1) */
3177b5c16493SMichael Tuexen 		if (tp1 == NULL) {
3178b5c16493SMichael Tuexen 			circled = 0;
3179b5c16493SMichael Tuexen 			tp1 = TAILQ_FIRST(&stcb->asoc.sent_queue);
3180b5c16493SMichael Tuexen 		}
3181b5c16493SMichael Tuexen 		/* In case the fragments were not in order we must reset */
31820fa753b3SRandall Stewart 	}			/* end for (j = fragStart */
31830fa753b3SRandall Stewart 	*p_tp1 = tp1;
31840fa753b3SRandall Stewart 	return (wake_him);	/* Return value only used for nr-sack */
31850fa753b3SRandall Stewart }
31860fa753b3SRandall Stewart 
3187cd554309SMichael Tuexen static int
3188458303daSRandall Stewart sctp_handle_segments(struct mbuf *m, int *offset, struct sctp_tcb *stcb, struct sctp_association *asoc,
3189cd554309SMichael Tuexen     uint32_t last_tsn, uint32_t *biggest_tsn_acked,
3190139bc87fSRandall Stewart     uint32_t *biggest_newly_acked_tsn, uint32_t *this_sack_lowest_newack,
31917215cc1bSMichael Tuexen     int num_seg, int num_nr_seg, int *rto_ok)
3192f8829a4aSRandall Stewart {
3193458303daSRandall Stewart 	struct sctp_gap_ack_block *frag, block;
3194f8829a4aSRandall Stewart 	struct sctp_tmit_chunk *tp1;
31950fa753b3SRandall Stewart 	int i;
3196f8829a4aSRandall Stewart 	int num_frs = 0;
3197cd554309SMichael Tuexen 	int chunk_freed;
3198cd554309SMichael Tuexen 	int non_revocable;
3199d9c5cfeaSMichael Tuexen 	uint16_t frag_strt, frag_end, prev_frag_end;
3200f8829a4aSRandall Stewart 
3201d9c5cfeaSMichael Tuexen 	tp1 = TAILQ_FIRST(&asoc->sent_queue);
3202d9c5cfeaSMichael Tuexen 	prev_frag_end = 0;
3203cd554309SMichael Tuexen 	chunk_freed = 0;
3204f8829a4aSRandall Stewart 
3205cd554309SMichael Tuexen 	for (i = 0; i < (num_seg + num_nr_seg); i++) {
3206d9c5cfeaSMichael Tuexen 		if (i == num_seg) {
3207d9c5cfeaSMichael Tuexen 			prev_frag_end = 0;
3208d9c5cfeaSMichael Tuexen 			tp1 = TAILQ_FIRST(&asoc->sent_queue);
3209d9c5cfeaSMichael Tuexen 		}
3210458303daSRandall Stewart 		frag = (struct sctp_gap_ack_block *)sctp_m_getptr(m, *offset,
3211458303daSRandall Stewart 		    sizeof(struct sctp_gap_ack_block), (uint8_t *)&block);
3212458303daSRandall Stewart 		*offset += sizeof(block);
3213458303daSRandall Stewart 		if (frag == NULL) {
3214cd554309SMichael Tuexen 			return (chunk_freed);
3215458303daSRandall Stewart 		}
3216f8829a4aSRandall Stewart 		frag_strt = ntohs(frag->start);
3217f8829a4aSRandall Stewart 		frag_end = ntohs(frag->end);
3218d9c5cfeaSMichael Tuexen 
3219f8829a4aSRandall Stewart 		if (frag_strt > frag_end) {
3220d9c5cfeaSMichael Tuexen 			/* This gap report is malformed, skip it. */
3221f8829a4aSRandall Stewart 			continue;
3222f8829a4aSRandall Stewart 		}
3223d9c5cfeaSMichael Tuexen 		if (frag_strt <= prev_frag_end) {
3224d9c5cfeaSMichael Tuexen 			/* This gap report is not in order, so restart. */
3225f8829a4aSRandall Stewart 			tp1 = TAILQ_FIRST(&asoc->sent_queue);
3226f8829a4aSRandall Stewart 		}
322720b07a4dSMichael Tuexen 		if (SCTP_TSN_GT((last_tsn + frag_end), *biggest_tsn_acked)) {
3228d9c5cfeaSMichael Tuexen 			*biggest_tsn_acked = last_tsn + frag_end;
3229f8829a4aSRandall Stewart 		}
3230cd554309SMichael Tuexen 		if (i < num_seg) {
3231cd554309SMichael Tuexen 			non_revocable = 0;
3232cd554309SMichael Tuexen 		} else {
3233cd554309SMichael Tuexen 			non_revocable = 1;
3234cd554309SMichael Tuexen 		}
3235cd554309SMichael Tuexen 		if (sctp_process_segment_range(stcb, &tp1, last_tsn, frag_strt, frag_end,
3236cd554309SMichael Tuexen 		    non_revocable, &num_frs, biggest_newly_acked_tsn,
32377215cc1bSMichael Tuexen 		    this_sack_lowest_newack, rto_ok)) {
3238cd554309SMichael Tuexen 			chunk_freed = 1;
3239458303daSRandall Stewart 		}
3240d9c5cfeaSMichael Tuexen 		prev_frag_end = frag_end;
3241f8829a4aSRandall Stewart 	}
3242b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
324380fefe0aSRandall Stewart 		if (num_frs)
324480fefe0aSRandall Stewart 			sctp_log_fr(*biggest_tsn_acked,
324580fefe0aSRandall Stewart 			    *biggest_newly_acked_tsn,
324680fefe0aSRandall Stewart 			    last_tsn, SCTP_FR_LOG_BIGGEST_TSNS);
324780fefe0aSRandall Stewart 	}
3248cd554309SMichael Tuexen 	return (chunk_freed);
3249f8829a4aSRandall Stewart }
3250f8829a4aSRandall Stewart 
3251f8829a4aSRandall Stewart static void
3252c105859eSRandall Stewart sctp_check_for_revoked(struct sctp_tcb *stcb,
3253c105859eSRandall Stewart     struct sctp_association *asoc, uint32_t cumack,
325463eda93dSMichael Tuexen     uint32_t biggest_tsn_acked)
3255f8829a4aSRandall Stewart {
3256f8829a4aSRandall Stewart 	struct sctp_tmit_chunk *tp1;
3257f8829a4aSRandall Stewart 
32584a9ef3f8SMichael Tuexen 	TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
325949656eefSMichael Tuexen 		if (SCTP_TSN_GT(tp1->rec.data.tsn, cumack)) {
3260f8829a4aSRandall Stewart 			/*
3261f8829a4aSRandall Stewart 			 * ok this guy is either ACK or MARKED. If it is
3262f8829a4aSRandall Stewart 			 * ACKED it has been previously acked but not this
3263f8829a4aSRandall Stewart 			 * time i.e. revoked.  If it is MARKED it was ACK'ed
3264f8829a4aSRandall Stewart 			 * again.
3265f8829a4aSRandall Stewart 			 */
326649656eefSMichael Tuexen 			if (SCTP_TSN_GT(tp1->rec.data.tsn, biggest_tsn_acked)) {
3267d06c82f1SRandall Stewart 				break;
326820b07a4dSMichael Tuexen 			}
3269f8829a4aSRandall Stewart 			if (tp1->sent == SCTP_DATAGRAM_ACKED) {
3270f8829a4aSRandall Stewart 				/* it has been revoked */
3271f8829a4aSRandall Stewart 				tp1->sent = SCTP_DATAGRAM_SENT;
3272f8829a4aSRandall Stewart 				tp1->rec.data.chunk_was_revoked = 1;
3273a5d547adSRandall Stewart 				/*
327442551e99SRandall Stewart 				 * We must add this stuff back in to assure
327542551e99SRandall Stewart 				 * timers and such get started.
3276a5d547adSRandall Stewart 				 */
3277b3f1ea41SRandall Stewart 				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) {
3278c105859eSRandall Stewart 					sctp_misc_ints(SCTP_FLIGHT_LOG_UP_REVOKE,
3279c105859eSRandall Stewart 					    tp1->whoTo->flight_size,
3280c105859eSRandall Stewart 					    tp1->book_size,
32819a8e3088SMichael Tuexen 					    (uint32_t)(uintptr_t)tp1->whoTo,
328249656eefSMichael Tuexen 					    tp1->rec.data.tsn);
328380fefe0aSRandall Stewart 				}
3284c105859eSRandall Stewart 				sctp_flight_size_increase(tp1);
3285c105859eSRandall Stewart 				sctp_total_flight_increase(stcb, tp1);
328642551e99SRandall Stewart 				/*
328742551e99SRandall Stewart 				 * We inflate the cwnd to compensate for our
328842551e99SRandall Stewart 				 * artificial inflation of the flight_size.
328942551e99SRandall Stewart 				 */
329042551e99SRandall Stewart 				tp1->whoTo->cwnd += tp1->book_size;
3291b3f1ea41SRandall Stewart 				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) {
3292f8829a4aSRandall Stewart 					sctp_log_sack(asoc->last_acked_seq,
3293f8829a4aSRandall Stewart 					    cumack,
329449656eefSMichael Tuexen 					    tp1->rec.data.tsn,
3295f8829a4aSRandall Stewart 					    0,
3296f8829a4aSRandall Stewart 					    0,
3297f8829a4aSRandall Stewart 					    SCTP_LOG_TSN_REVOKED);
329880fefe0aSRandall Stewart 				}
3299f8829a4aSRandall Stewart 			} else if (tp1->sent == SCTP_DATAGRAM_MARKED) {
3300f8829a4aSRandall Stewart 				/* it has been re-acked in this SACK */
3301f8829a4aSRandall Stewart 				tp1->sent = SCTP_DATAGRAM_ACKED;
3302f8829a4aSRandall Stewart 			}
3303f8829a4aSRandall Stewart 		}
3304f8829a4aSRandall Stewart 		if (tp1->sent == SCTP_DATAGRAM_UNSENT)
3305f8829a4aSRandall Stewart 			break;
3306f8829a4aSRandall Stewart 	}
3307f8829a4aSRandall Stewart }
3308f8829a4aSRandall Stewart 
3309f8829a4aSRandall Stewart static void
3310f8829a4aSRandall Stewart sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc,
331163eda93dSMichael Tuexen     uint32_t biggest_tsn_acked, uint32_t biggest_tsn_newly_acked, uint32_t this_sack_lowest_newack, int accum_moved)
3312f8829a4aSRandall Stewart {
3313f8829a4aSRandall Stewart 	struct sctp_tmit_chunk *tp1;
3314f8829a4aSRandall Stewart 	int strike_flag = 0;
3315f8829a4aSRandall Stewart 	struct timeval now;
3316f8829a4aSRandall Stewart 	int tot_retrans = 0;
3317f8829a4aSRandall Stewart 	uint32_t sending_seq;
3318f8829a4aSRandall Stewart 	struct sctp_nets *net;
3319f8829a4aSRandall Stewart 	int num_dests_sacked = 0;
3320f8829a4aSRandall Stewart 
3321f8829a4aSRandall Stewart 	/*
3322f8829a4aSRandall Stewart 	 * select the sending_seq, this is either the next thing ready to be
3323f8829a4aSRandall Stewart 	 * sent but not transmitted, OR, the next seq we assign.
3324f8829a4aSRandall Stewart 	 */
3325f8829a4aSRandall Stewart 	tp1 = TAILQ_FIRST(&stcb->asoc.send_queue);
3326f8829a4aSRandall Stewart 	if (tp1 == NULL) {
3327f8829a4aSRandall Stewart 		sending_seq = asoc->sending_seq;
3328f8829a4aSRandall Stewart 	} else {
332949656eefSMichael Tuexen 		sending_seq = tp1->rec.data.tsn;
3330f8829a4aSRandall Stewart 	}
3331f8829a4aSRandall Stewart 
3332f8829a4aSRandall Stewart 	/* CMT DAC algo: finding out if SACK is a mixed SACK */
33337c99d56fSMichael Tuexen 	if ((asoc->sctp_cmt_on_off > 0) &&
333420083c2eSMichael Tuexen 	    SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) {
3335f8829a4aSRandall Stewart 		TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
3336f8829a4aSRandall Stewart 			if (net->saw_newack)
3337f8829a4aSRandall Stewart 				num_dests_sacked++;
3338f8829a4aSRandall Stewart 		}
3339f8829a4aSRandall Stewart 	}
3340dd973b0eSMichael Tuexen 	if (stcb->asoc.prsctp_supported) {
33416e55db54SRandall Stewart 		(void)SCTP_GETTIME_TIMEVAL(&now);
3342f8829a4aSRandall Stewart 	}
33434a9ef3f8SMichael Tuexen 	TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
3344f8829a4aSRandall Stewart 		strike_flag = 0;
3345f8829a4aSRandall Stewart 		if (tp1->no_fr_allowed) {
3346f8829a4aSRandall Stewart 			/* this one had a timeout or something */
3347f8829a4aSRandall Stewart 			continue;
3348f8829a4aSRandall Stewart 		}
3349b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
3350f8829a4aSRandall Stewart 			if (tp1->sent < SCTP_DATAGRAM_RESEND)
3351f8829a4aSRandall Stewart 				sctp_log_fr(biggest_tsn_newly_acked,
335249656eefSMichael Tuexen 				    tp1->rec.data.tsn,
3353f8829a4aSRandall Stewart 				    tp1->sent,
3354f8829a4aSRandall Stewart 				    SCTP_FR_LOG_CHECK_STRIKE);
335580fefe0aSRandall Stewart 		}
335649656eefSMichael Tuexen 		if (SCTP_TSN_GT(tp1->rec.data.tsn, biggest_tsn_acked) ||
3357f8829a4aSRandall Stewart 		    tp1->sent == SCTP_DATAGRAM_UNSENT) {
3358f8829a4aSRandall Stewart 			/* done */
3359f8829a4aSRandall Stewart 			break;
3360f8829a4aSRandall Stewart 		}
3361dd973b0eSMichael Tuexen 		if (stcb->asoc.prsctp_supported) {
3362f8829a4aSRandall Stewart 			if ((PR_SCTP_TTL_ENABLED(tp1->flags)) && tp1->sent < SCTP_DATAGRAM_ACKED) {
3363f8829a4aSRandall Stewart 				/* Is it expired? */
336499ddc825SMichael Tuexen 				if (timevalcmp(&now, &tp1->rec.data.timetodrop, >)) {
3365f8829a4aSRandall Stewart 					/* Yes so drop it */
3366f8829a4aSRandall Stewart 					if (tp1->data != NULL) {
33671edc9dbaSMichael Tuexen 						(void)sctp_release_pr_sctp_chunk(stcb, tp1, 1,
33680c0982b8SRandall Stewart 						    SCTP_SO_NOT_LOCKED);
3369f8829a4aSRandall Stewart 					}
3370f8829a4aSRandall Stewart 					continue;
3371f8829a4aSRandall Stewart 				}
3372f8829a4aSRandall Stewart 			}
3373f8829a4aSRandall Stewart 		}
3374e9a3a1b1SMichael Tuexen 		if (SCTP_TSN_GT(tp1->rec.data.tsn, asoc->this_sack_highest_gap) &&
3375e9a3a1b1SMichael Tuexen 		    !(accum_moved && asoc->fast_retran_loss_recovery)) {
3376f8829a4aSRandall Stewart 			/* we are beyond the tsn in the sack  */
3377f8829a4aSRandall Stewart 			break;
3378f8829a4aSRandall Stewart 		}
3379f8829a4aSRandall Stewart 		if (tp1->sent >= SCTP_DATAGRAM_RESEND) {
3380f8829a4aSRandall Stewart 			/* either a RESEND, ACKED, or MARKED */
3381f8829a4aSRandall Stewart 			/* skip */
338244fbe462SRandall Stewart 			if (tp1->sent == SCTP_FORWARD_TSN_SKIP) {
338344fbe462SRandall Stewart 				/* Continue strikin FWD-TSN chunks */
338444fbe462SRandall Stewart 				tp1->rec.data.fwd_tsn_cnt++;
338544fbe462SRandall Stewart 			}
3386f8829a4aSRandall Stewart 			continue;
3387f8829a4aSRandall Stewart 		}
3388f8829a4aSRandall Stewart 		/*
3389f8829a4aSRandall Stewart 		 * CMT : SFR algo (covers part of DAC and HTNA as well)
3390f8829a4aSRandall Stewart 		 */
3391ad81507eSRandall Stewart 		if (tp1->whoTo && tp1->whoTo->saw_newack == 0) {
3392f8829a4aSRandall Stewart 			/*
3393f8829a4aSRandall Stewart 			 * No new acks were receieved for data sent to this
3394f8829a4aSRandall Stewart 			 * dest. Therefore, according to the SFR algo for
3395f8829a4aSRandall Stewart 			 * CMT, no data sent to this dest can be marked for
3396c105859eSRandall Stewart 			 * FR using this SACK.
3397f8829a4aSRandall Stewart 			 */
3398f8829a4aSRandall Stewart 			continue;
3399e9a3a1b1SMichael Tuexen 		} else if (tp1->whoTo &&
3400e9a3a1b1SMichael Tuexen 			    SCTP_TSN_GT(tp1->rec.data.tsn,
3401e9a3a1b1SMichael Tuexen 			    tp1->whoTo->this_sack_highest_newack) &&
3402e9a3a1b1SMichael Tuexen 		    !(accum_moved && asoc->fast_retran_loss_recovery)) {
3403f8829a4aSRandall Stewart 			/*
3404f8829a4aSRandall Stewart 			 * CMT: New acks were receieved for data sent to
3405f8829a4aSRandall Stewart 			 * this dest. But no new acks were seen for data
3406f8829a4aSRandall Stewart 			 * sent after tp1. Therefore, according to the SFR
3407f8829a4aSRandall Stewart 			 * algo for CMT, tp1 cannot be marked for FR using
3408f8829a4aSRandall Stewart 			 * this SACK. This step covers part of the DAC algo
3409f8829a4aSRandall Stewart 			 * and the HTNA algo as well.
3410f8829a4aSRandall Stewart 			 */
3411f8829a4aSRandall Stewart 			continue;
3412f8829a4aSRandall Stewart 		}
3413f8829a4aSRandall Stewart 		/*
3414f8829a4aSRandall Stewart 		 * Here we check to see if we were have already done a FR
3415f8829a4aSRandall Stewart 		 * and if so we see if the biggest TSN we saw in the sack is
3416f8829a4aSRandall Stewart 		 * smaller than the recovery point. If so we don't strike
3417f8829a4aSRandall Stewart 		 * the tsn... otherwise we CAN strike the TSN.
3418f8829a4aSRandall Stewart 		 */
3419f8829a4aSRandall Stewart 		/*
342042551e99SRandall Stewart 		 * @@@ JRI: Check for CMT if (accum_moved &&
342142551e99SRandall Stewart 		 * asoc->fast_retran_loss_recovery && (sctp_cmt_on_off ==
342242551e99SRandall Stewart 		 * 0)) {
3423f8829a4aSRandall Stewart 		 */
342442551e99SRandall Stewart 		if (accum_moved && asoc->fast_retran_loss_recovery) {
3425f8829a4aSRandall Stewart 			/*
3426f8829a4aSRandall Stewart 			 * Strike the TSN if in fast-recovery and cum-ack
3427f8829a4aSRandall Stewart 			 * moved.
3428f8829a4aSRandall Stewart 			 */
3429b3f1ea41SRandall Stewart 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
3430f8829a4aSRandall Stewart 				sctp_log_fr(biggest_tsn_newly_acked,
343149656eefSMichael Tuexen 				    tp1->rec.data.tsn,
3432f8829a4aSRandall Stewart 				    tp1->sent,
3433f8829a4aSRandall Stewart 				    SCTP_FR_LOG_STRIKE_CHUNK);
343480fefe0aSRandall Stewart 			}
34355e54f665SRandall Stewart 			if (tp1->sent < SCTP_DATAGRAM_RESEND) {
3436f8829a4aSRandall Stewart 				tp1->sent++;
34375e54f665SRandall Stewart 			}
34387c99d56fSMichael Tuexen 			if ((asoc->sctp_cmt_on_off > 0) &&
343920083c2eSMichael Tuexen 			    SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) {
3440f8829a4aSRandall Stewart 				/*
3441f8829a4aSRandall Stewart 				 * CMT DAC algorithm: If SACK flag is set to
3442f8829a4aSRandall Stewart 				 * 0, then lowest_newack test will not pass
3443f8829a4aSRandall Stewart 				 * because it would have been set to the
3444f8829a4aSRandall Stewart 				 * cumack earlier. If not already to be
3445f8829a4aSRandall Stewart 				 * rtx'd, If not a mixed sack and if tp1 is
3446f8829a4aSRandall Stewart 				 * not between two sacked TSNs, then mark by
3447c105859eSRandall Stewart 				 * one more. NOTE that we are marking by one
3448c105859eSRandall Stewart 				 * additional time since the SACK DAC flag
3449c105859eSRandall Stewart 				 * indicates that two packets have been
3450c105859eSRandall Stewart 				 * received after this missing TSN.
34515e54f665SRandall Stewart 				 */
34525e54f665SRandall Stewart 				if ((tp1->sent < SCTP_DATAGRAM_RESEND) && (num_dests_sacked == 1) &&
345349656eefSMichael Tuexen 				    SCTP_TSN_GT(this_sack_lowest_newack, tp1->rec.data.tsn)) {
3454b3f1ea41SRandall Stewart 					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
3455f8829a4aSRandall Stewart 						sctp_log_fr(16 + num_dests_sacked,
345649656eefSMichael Tuexen 						    tp1->rec.data.tsn,
3457f8829a4aSRandall Stewart 						    tp1->sent,
3458f8829a4aSRandall Stewart 						    SCTP_FR_LOG_STRIKE_CHUNK);
345980fefe0aSRandall Stewart 					}
3460f8829a4aSRandall Stewart 					tp1->sent++;
3461f8829a4aSRandall Stewart 				}
3462f8829a4aSRandall Stewart 			}
346320083c2eSMichael Tuexen 		} else if ((tp1->rec.data.doing_fast_retransmit) &&
346420083c2eSMichael Tuexen 		    (asoc->sctp_cmt_on_off == 0)) {
3465f8829a4aSRandall Stewart 			/*
3466f8829a4aSRandall Stewart 			 * For those that have done a FR we must take
3467f8829a4aSRandall Stewart 			 * special consideration if we strike. I.e the
3468f8829a4aSRandall Stewart 			 * biggest_newly_acked must be higher than the
3469f8829a4aSRandall Stewart 			 * sending_seq at the time we did the FR.
3470f8829a4aSRandall Stewart 			 */
34715e54f665SRandall Stewart 			if (
3472f8829a4aSRandall Stewart #ifdef SCTP_FR_TO_ALTERNATE
3473f8829a4aSRandall Stewart 			/*
3474f8829a4aSRandall Stewart 			 * If FR's go to new networks, then we must only do
3475f8829a4aSRandall Stewart 			 * this for singly homed asoc's. However if the FR's
3476f8829a4aSRandall Stewart 			 * go to the same network (Armando's work) then its
3477f8829a4aSRandall Stewart 			 * ok to FR multiple times.
3478f8829a4aSRandall Stewart 			 */
34795e54f665SRandall Stewart 			    (asoc->numnets < 2)
3480f8829a4aSRandall Stewart #else
34815e54f665SRandall Stewart 			    (1)
3482f8829a4aSRandall Stewart #endif
34835e54f665SRandall Stewart 			    ) {
348420b07a4dSMichael Tuexen 				if (SCTP_TSN_GE(biggest_tsn_newly_acked,
3485f8829a4aSRandall Stewart 				    tp1->rec.data.fast_retran_tsn)) {
3486f8829a4aSRandall Stewart 					/*
3487f8829a4aSRandall Stewart 					 * Strike the TSN, since this ack is
3488f8829a4aSRandall Stewart 					 * beyond where things were when we
3489f8829a4aSRandall Stewart 					 * did a FR.
3490f8829a4aSRandall Stewart 					 */
3491b3f1ea41SRandall Stewart 					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
3492f8829a4aSRandall Stewart 						sctp_log_fr(biggest_tsn_newly_acked,
349349656eefSMichael Tuexen 						    tp1->rec.data.tsn,
3494f8829a4aSRandall Stewart 						    tp1->sent,
3495f8829a4aSRandall Stewart 						    SCTP_FR_LOG_STRIKE_CHUNK);
349680fefe0aSRandall Stewart 					}
34975e54f665SRandall Stewart 					if (tp1->sent < SCTP_DATAGRAM_RESEND) {
3498f8829a4aSRandall Stewart 						tp1->sent++;
34995e54f665SRandall Stewart 					}
3500f8829a4aSRandall Stewart 					strike_flag = 1;
35017c99d56fSMichael Tuexen 					if ((asoc->sctp_cmt_on_off > 0) &&
350220083c2eSMichael Tuexen 					    SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) {
3503f8829a4aSRandall Stewart 						/*
3504f8829a4aSRandall Stewart 						 * CMT DAC algorithm: If
3505f8829a4aSRandall Stewart 						 * SACK flag is set to 0,
3506f8829a4aSRandall Stewart 						 * then lowest_newack test
3507f8829a4aSRandall Stewart 						 * will not pass because it
3508f8829a4aSRandall Stewart 						 * would have been set to
3509f8829a4aSRandall Stewart 						 * the cumack earlier. If
3510f8829a4aSRandall Stewart 						 * not already to be rtx'd,
3511f8829a4aSRandall Stewart 						 * If not a mixed sack and
3512f8829a4aSRandall Stewart 						 * if tp1 is not between two
3513f8829a4aSRandall Stewart 						 * sacked TSNs, then mark by
3514c105859eSRandall Stewart 						 * one more. NOTE that we
3515c105859eSRandall Stewart 						 * are marking by one
3516c105859eSRandall Stewart 						 * additional time since the
3517c105859eSRandall Stewart 						 * SACK DAC flag indicates
3518c105859eSRandall Stewart 						 * that two packets have
3519c105859eSRandall Stewart 						 * been received after this
3520c105859eSRandall Stewart 						 * missing TSN.
3521f8829a4aSRandall Stewart 						 */
35225e54f665SRandall Stewart 						if ((tp1->sent < SCTP_DATAGRAM_RESEND) &&
35235e54f665SRandall Stewart 						    (num_dests_sacked == 1) &&
352420b07a4dSMichael Tuexen 						    SCTP_TSN_GT(this_sack_lowest_newack,
352549656eefSMichael Tuexen 						    tp1->rec.data.tsn)) {
3526b3f1ea41SRandall Stewart 							if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
3527f8829a4aSRandall Stewart 								sctp_log_fr(32 + num_dests_sacked,
352849656eefSMichael Tuexen 								    tp1->rec.data.tsn,
3529f8829a4aSRandall Stewart 								    tp1->sent,
3530f8829a4aSRandall Stewart 								    SCTP_FR_LOG_STRIKE_CHUNK);
353180fefe0aSRandall Stewart 							}
35325e54f665SRandall Stewart 							if (tp1->sent < SCTP_DATAGRAM_RESEND) {
3533f8829a4aSRandall Stewart 								tp1->sent++;
35345e54f665SRandall Stewart 							}
3535f8829a4aSRandall Stewart 						}
3536f8829a4aSRandall Stewart 					}
3537f8829a4aSRandall Stewart 				}
3538f8829a4aSRandall Stewart 			}
3539f8829a4aSRandall Stewart 			/*
354042551e99SRandall Stewart 			 * JRI: TODO: remove code for HTNA algo. CMT's SFR
354142551e99SRandall Stewart 			 * algo covers HTNA.
3542f8829a4aSRandall Stewart 			 */
354349656eefSMichael Tuexen 		} else if (SCTP_TSN_GT(tp1->rec.data.tsn,
354420b07a4dSMichael Tuexen 		    biggest_tsn_newly_acked)) {
3545f8829a4aSRandall Stewart 			/*
3546f8829a4aSRandall Stewart 			 * We don't strike these: This is the  HTNA
3547f8829a4aSRandall Stewart 			 * algorithm i.e. we don't strike If our TSN is
3548f8829a4aSRandall Stewart 			 * larger than the Highest TSN Newly Acked.
3549f8829a4aSRandall Stewart 			 */
3550f8829a4aSRandall Stewart 			;
3551f8829a4aSRandall Stewart 		} else {
3552f8829a4aSRandall Stewart 			/* Strike the TSN */
3553b3f1ea41SRandall Stewart 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
3554f8829a4aSRandall Stewart 				sctp_log_fr(biggest_tsn_newly_acked,
355549656eefSMichael Tuexen 				    tp1->rec.data.tsn,
3556f8829a4aSRandall Stewart 				    tp1->sent,
3557f8829a4aSRandall Stewart 				    SCTP_FR_LOG_STRIKE_CHUNK);
355880fefe0aSRandall Stewart 			}
35595e54f665SRandall Stewart 			if (tp1->sent < SCTP_DATAGRAM_RESEND) {
3560f8829a4aSRandall Stewart 				tp1->sent++;
35615e54f665SRandall Stewart 			}
35627c99d56fSMichael Tuexen 			if ((asoc->sctp_cmt_on_off > 0) &&
356320083c2eSMichael Tuexen 			    SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) {
3564f8829a4aSRandall Stewart 				/*
3565f8829a4aSRandall Stewart 				 * CMT DAC algorithm: If SACK flag is set to
3566f8829a4aSRandall Stewart 				 * 0, then lowest_newack test will not pass
3567f8829a4aSRandall Stewart 				 * because it would have been set to the
3568f8829a4aSRandall Stewart 				 * cumack earlier. If not already to be
3569f8829a4aSRandall Stewart 				 * rtx'd, If not a mixed sack and if tp1 is
3570f8829a4aSRandall Stewart 				 * not between two sacked TSNs, then mark by
3571c105859eSRandall Stewart 				 * one more. NOTE that we are marking by one
3572c105859eSRandall Stewart 				 * additional time since the SACK DAC flag
3573c105859eSRandall Stewart 				 * indicates that two packets have been
3574c105859eSRandall Stewart 				 * received after this missing TSN.
3575f8829a4aSRandall Stewart 				 */
35765e54f665SRandall Stewart 				if ((tp1->sent < SCTP_DATAGRAM_RESEND) && (num_dests_sacked == 1) &&
357749656eefSMichael Tuexen 				    SCTP_TSN_GT(this_sack_lowest_newack, tp1->rec.data.tsn)) {
3578b3f1ea41SRandall Stewart 					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
3579f8829a4aSRandall Stewart 						sctp_log_fr(48 + num_dests_sacked,
358049656eefSMichael Tuexen 						    tp1->rec.data.tsn,
3581f8829a4aSRandall Stewart 						    tp1->sent,
3582f8829a4aSRandall Stewart 						    SCTP_FR_LOG_STRIKE_CHUNK);
358380fefe0aSRandall Stewart 					}
3584f8829a4aSRandall Stewart 					tp1->sent++;
3585f8829a4aSRandall Stewart 				}
3586f8829a4aSRandall Stewart 			}
3587f8829a4aSRandall Stewart 		}
3588f8829a4aSRandall Stewart 		if (tp1->sent == SCTP_DATAGRAM_RESEND) {
3589f8829a4aSRandall Stewart 			struct sctp_nets *alt;
3590f8829a4aSRandall Stewart 
3591544e35bdSRandall Stewart 			/* fix counts and things */
3592544e35bdSRandall Stewart 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) {
3593544e35bdSRandall Stewart 				sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_RSND,
3594544e35bdSRandall Stewart 				    (tp1->whoTo ? (tp1->whoTo->flight_size) : 0),
3595544e35bdSRandall Stewart 				    tp1->book_size,
35969a8e3088SMichael Tuexen 				    (uint32_t)(uintptr_t)tp1->whoTo,
359749656eefSMichael Tuexen 				    tp1->rec.data.tsn);
3598544e35bdSRandall Stewart 			}
3599544e35bdSRandall Stewart 			if (tp1->whoTo) {
3600544e35bdSRandall Stewart 				tp1->whoTo->net_ack++;
3601544e35bdSRandall Stewart 				sctp_flight_size_decrease(tp1);
3602299108c5SRandall Stewart 				if (stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) {
3603299108c5SRandall Stewart 					(*stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) (tp1->whoTo,
3604299108c5SRandall Stewart 					    tp1);
3605299108c5SRandall Stewart 				}
3606544e35bdSRandall Stewart 			}
36070053ed28SMichael Tuexen 
3608544e35bdSRandall Stewart 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_RWND_ENABLE) {
3609544e35bdSRandall Stewart 				sctp_log_rwnd(SCTP_INCREASE_PEER_RWND,
3610544e35bdSRandall Stewart 				    asoc->peers_rwnd, tp1->send_size, SCTP_BASE_SYSCTL(sctp_peer_chunk_oh));
3611544e35bdSRandall Stewart 			}
3612544e35bdSRandall Stewart 			/* add back to the rwnd */
3613544e35bdSRandall Stewart 			asoc->peers_rwnd += (tp1->send_size + SCTP_BASE_SYSCTL(sctp_peer_chunk_oh));
3614544e35bdSRandall Stewart 
3615544e35bdSRandall Stewart 			/* remove from the total flight */
3616544e35bdSRandall Stewart 			sctp_total_flight_decrease(stcb, tp1);
3617544e35bdSRandall Stewart 
3618dd973b0eSMichael Tuexen 			if ((stcb->asoc.prsctp_supported) &&
3619475d0674SMichael Tuexen 			    (PR_SCTP_RTX_ENABLED(tp1->flags))) {
3620b7b84c0eSMichael Tuexen 				/*
3621b7b84c0eSMichael Tuexen 				 * Has it been retransmitted tv_sec times? -
3622b7b84c0eSMichael Tuexen 				 * we store the retran count there.
3623b7b84c0eSMichael Tuexen 				 */
3624475d0674SMichael Tuexen 				if (tp1->snd_count > tp1->rec.data.timetodrop.tv_sec) {
3625475d0674SMichael Tuexen 					/* Yes, so drop it */
3626475d0674SMichael Tuexen 					if (tp1->data != NULL) {
36271edc9dbaSMichael Tuexen 						(void)sctp_release_pr_sctp_chunk(stcb, tp1, 1,
3628475d0674SMichael Tuexen 						    SCTP_SO_NOT_LOCKED);
3629475d0674SMichael Tuexen 					}
3630475d0674SMichael Tuexen 					/* Make sure to flag we had a FR */
363167e8b08bSMichael Tuexen 					if (tp1->whoTo != NULL) {
3632475d0674SMichael Tuexen 						tp1->whoTo->net_ack++;
363367e8b08bSMichael Tuexen 					}
3634475d0674SMichael Tuexen 					continue;
3635475d0674SMichael Tuexen 				}
3636475d0674SMichael Tuexen 			}
3637b7b84c0eSMichael Tuexen 			/*
3638b7b84c0eSMichael Tuexen 			 * SCTP_PRINTF("OK, we are now ready to FR this
3639b7b84c0eSMichael Tuexen 			 * guy\n");
3640b7b84c0eSMichael Tuexen 			 */
3641b3f1ea41SRandall Stewart 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
364249656eefSMichael Tuexen 				sctp_log_fr(tp1->rec.data.tsn, tp1->snd_count,
3643f8829a4aSRandall Stewart 				    0, SCTP_FR_MARKED);
364480fefe0aSRandall Stewart 			}
3645f8829a4aSRandall Stewart 			if (strike_flag) {
3646f8829a4aSRandall Stewart 				/* This is a subsequent FR */
3647f8829a4aSRandall Stewart 				SCTP_STAT_INCR(sctps_sendmultfastretrans);
3648f8829a4aSRandall Stewart 			}
36495e54f665SRandall Stewart 			sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
36507c99d56fSMichael Tuexen 			if (asoc->sctp_cmt_on_off > 0) {
3651f8829a4aSRandall Stewart 				/*
3652f8829a4aSRandall Stewart 				 * CMT: Using RTX_SSTHRESH policy for CMT.
3653f8829a4aSRandall Stewart 				 * If CMT is being used, then pick dest with
3654f8829a4aSRandall Stewart 				 * largest ssthresh for any retransmission.
3655f8829a4aSRandall Stewart 				 */
3656f8829a4aSRandall Stewart 				tp1->no_fr_allowed = 1;
3657f8829a4aSRandall Stewart 				alt = tp1->whoTo;
36583c503c28SRandall Stewart 				/* sa_ignore NO_NULL_CHK */
365920083c2eSMichael Tuexen 				if (asoc->sctp_cmt_pf > 0) {
3660b7b84c0eSMichael Tuexen 					/*
3661b7b84c0eSMichael Tuexen 					 * JRS 5/18/07 - If CMT PF is on,
3662b54d3a6cSRandall Stewart 					 * use the PF version of
3663b7b84c0eSMichael Tuexen 					 * find_alt_net()
3664b7b84c0eSMichael Tuexen 					 */
3665b54d3a6cSRandall Stewart 					alt = sctp_find_alternate_net(stcb, alt, 2);
3666b54d3a6cSRandall Stewart 				} else {
3667b7b84c0eSMichael Tuexen 					/*
3668b7b84c0eSMichael Tuexen 					 * JRS 5/18/07 - If only CMT is on,
3669b54d3a6cSRandall Stewart 					 * use the CMT version of
3670b7b84c0eSMichael Tuexen 					 * find_alt_net()
3671b7b84c0eSMichael Tuexen 					 */
367252be287eSRandall Stewart 					/* sa_ignore NO_NULL_CHK */
3673f8829a4aSRandall Stewart 					alt = sctp_find_alternate_net(stcb, alt, 1);
3674b54d3a6cSRandall Stewart 				}
3675ad81507eSRandall Stewart 				if (alt == NULL) {
3676ad81507eSRandall Stewart 					alt = tp1->whoTo;
3677ad81507eSRandall Stewart 				}
3678f8829a4aSRandall Stewart 				/*
3679f8829a4aSRandall Stewart 				 * CUCv2: If a different dest is picked for
3680f8829a4aSRandall Stewart 				 * the retransmission, then new
3681f8829a4aSRandall Stewart 				 * (rtx-)pseudo_cumack needs to be tracked
3682f8829a4aSRandall Stewart 				 * for orig dest. Let CUCv2 track new (rtx-)
3683f8829a4aSRandall Stewart 				 * pseudo-cumack always.
3684f8829a4aSRandall Stewart 				 */
3685ad81507eSRandall Stewart 				if (tp1->whoTo) {
3686f8829a4aSRandall Stewart 					tp1->whoTo->find_pseudo_cumack = 1;
3687f8829a4aSRandall Stewart 					tp1->whoTo->find_rtx_pseudo_cumack = 1;
3688ad81507eSRandall Stewart 				}
3689f8829a4aSRandall Stewart 			} else {	/* CMT is OFF */
3690f8829a4aSRandall Stewart #ifdef SCTP_FR_TO_ALTERNATE
3691f8829a4aSRandall Stewart 				/* Can we find an alternate? */
3692f8829a4aSRandall Stewart 				alt = sctp_find_alternate_net(stcb, tp1->whoTo, 0);
3693f8829a4aSRandall Stewart #else
3694f8829a4aSRandall Stewart 				/*
3695f8829a4aSRandall Stewart 				 * default behavior is to NOT retransmit
3696f8829a4aSRandall Stewart 				 * FR's to an alternate. Armando Caro's
3697f8829a4aSRandall Stewart 				 * paper details why.
3698f8829a4aSRandall Stewart 				 */
3699f8829a4aSRandall Stewart 				alt = tp1->whoTo;
3700f8829a4aSRandall Stewart #endif
3701f8829a4aSRandall Stewart 			}
3702f8829a4aSRandall Stewart 
3703f8829a4aSRandall Stewart 			tp1->rec.data.doing_fast_retransmit = 1;
3704f8829a4aSRandall Stewart 			tot_retrans++;
3705f8829a4aSRandall Stewart 			/* mark the sending seq for possible subsequent FR's */
3706f8829a4aSRandall Stewart 			/*
3707cd3fd531SMichael Tuexen 			 * SCTP_PRINTF("Marking TSN for FR new value %x\n",
370849656eefSMichael Tuexen 			 * (uint32_t)tpi->rec.data.tsn);
3709f8829a4aSRandall Stewart 			 */
3710f8829a4aSRandall Stewart 			if (TAILQ_EMPTY(&asoc->send_queue)) {
3711f8829a4aSRandall Stewart 				/*
3712f8829a4aSRandall Stewart 				 * If the queue of send is empty then its
3713f8829a4aSRandall Stewart 				 * the next sequence number that will be
3714f8829a4aSRandall Stewart 				 * assigned so we subtract one from this to
3715f8829a4aSRandall Stewart 				 * get the one we last sent.
3716f8829a4aSRandall Stewart 				 */
3717f8829a4aSRandall Stewart 				tp1->rec.data.fast_retran_tsn = sending_seq;
3718f8829a4aSRandall Stewart 			} else {
3719f8829a4aSRandall Stewart 				/*
3720f8829a4aSRandall Stewart 				 * If there are chunks on the send queue
3721f8829a4aSRandall Stewart 				 * (unsent data that has made it from the
3722f8829a4aSRandall Stewart 				 * stream queues but not out the door, we
3723f8829a4aSRandall Stewart 				 * take the first one (which will have the
3724f8829a4aSRandall Stewart 				 * lowest TSN) and subtract one to get the
3725f8829a4aSRandall Stewart 				 * one we last sent.
3726f8829a4aSRandall Stewart 				 */
3727f8829a4aSRandall Stewart 				struct sctp_tmit_chunk *ttt;
3728f8829a4aSRandall Stewart 
3729f8829a4aSRandall Stewart 				ttt = TAILQ_FIRST(&asoc->send_queue);
3730f8829a4aSRandall Stewart 				tp1->rec.data.fast_retran_tsn =
373149656eefSMichael Tuexen 				    ttt->rec.data.tsn;
3732f8829a4aSRandall Stewart 			}
3733f8829a4aSRandall Stewart 
3734f8829a4aSRandall Stewart 			if (tp1->do_rtt) {
3735f8829a4aSRandall Stewart 				/*
3736f8829a4aSRandall Stewart 				 * this guy had a RTO calculation pending on
3737f8829a4aSRandall Stewart 				 * it, cancel it
3738f8829a4aSRandall Stewart 				 */
373960990c0cSMichael Tuexen 				if ((tp1->whoTo != NULL) &&
374060990c0cSMichael Tuexen 				    (tp1->whoTo->rto_needed == 0)) {
3741f79aab18SRandall Stewart 					tp1->whoTo->rto_needed = 1;
3742f79aab18SRandall Stewart 				}
3743f8829a4aSRandall Stewart 				tp1->do_rtt = 0;
3744f8829a4aSRandall Stewart 			}
3745f8829a4aSRandall Stewart 			if (alt != tp1->whoTo) {
3746f8829a4aSRandall Stewart 				/* yes, there is an alternate. */
3747f8829a4aSRandall Stewart 				sctp_free_remote_addr(tp1->whoTo);
37483c503c28SRandall Stewart 				/* sa_ignore FREED_MEMORY */
3749f8829a4aSRandall Stewart 				tp1->whoTo = alt;
3750f8829a4aSRandall Stewart 				atomic_add_int(&alt->ref_count, 1);
3751f8829a4aSRandall Stewart 			}
3752f8829a4aSRandall Stewart 		}
37534a9ef3f8SMichael Tuexen 	}
3754f8829a4aSRandall Stewart }
3755f8829a4aSRandall Stewart 
3756f8829a4aSRandall Stewart struct sctp_tmit_chunk *
3757f8829a4aSRandall Stewart sctp_try_advance_peer_ack_point(struct sctp_tcb *stcb,
3758f8829a4aSRandall Stewart     struct sctp_association *asoc)
3759f8829a4aSRandall Stewart {
3760f8829a4aSRandall Stewart 	struct sctp_tmit_chunk *tp1, *tp2, *a_adv = NULL;
3761f8829a4aSRandall Stewart 	struct timeval now;
3762f8829a4aSRandall Stewart 	int now_filled = 0;
3763f8829a4aSRandall Stewart 
3764dd973b0eSMichael Tuexen 	if (asoc->prsctp_supported == 0) {
3765f8829a4aSRandall Stewart 		return (NULL);
3766f8829a4aSRandall Stewart 	}
37674a9ef3f8SMichael Tuexen 	TAILQ_FOREACH_SAFE(tp1, &asoc->sent_queue, sctp_next, tp2) {
3768f8829a4aSRandall Stewart 		if (tp1->sent != SCTP_FORWARD_TSN_SKIP &&
376998f2956cSMichael Tuexen 		    tp1->sent != SCTP_DATAGRAM_RESEND &&
3770325c8c46SMichael Tuexen 		    tp1->sent != SCTP_DATAGRAM_NR_ACKED) {
3771f8829a4aSRandall Stewart 			/* no chance to advance, out of here */
3772f8829a4aSRandall Stewart 			break;
3773f8829a4aSRandall Stewart 		}
37740c0982b8SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) {
37752a498584SMichael Tuexen 			if ((tp1->sent == SCTP_FORWARD_TSN_SKIP) ||
3776325c8c46SMichael Tuexen 			    (tp1->sent == SCTP_DATAGRAM_NR_ACKED)) {
37770c0982b8SRandall Stewart 				sctp_misc_ints(SCTP_FWD_TSN_CHECK,
37780c0982b8SRandall Stewart 				    asoc->advanced_peer_ack_point,
377949656eefSMichael Tuexen 				    tp1->rec.data.tsn, 0, 0);
37800c0982b8SRandall Stewart 			}
37810c0982b8SRandall Stewart 		}
3782f8829a4aSRandall Stewart 		if (!PR_SCTP_ENABLED(tp1->flags)) {
3783f8829a4aSRandall Stewart 			/*
3784f8829a4aSRandall Stewart 			 * We can't fwd-tsn past any that are reliable aka
3785f8829a4aSRandall Stewart 			 * retransmitted until the asoc fails.
3786f8829a4aSRandall Stewart 			 */
3787f8829a4aSRandall Stewart 			break;
3788f8829a4aSRandall Stewart 		}
3789f8829a4aSRandall Stewart 		if (!now_filled) {
37906e55db54SRandall Stewart 			(void)SCTP_GETTIME_TIMEVAL(&now);
3791f8829a4aSRandall Stewart 			now_filled = 1;
3792f8829a4aSRandall Stewart 		}
3793f8829a4aSRandall Stewart 		/*
3794f8829a4aSRandall Stewart 		 * now we got a chunk which is marked for another
3795f8829a4aSRandall Stewart 		 * retransmission to a PR-stream but has run out its chances
3796f8829a4aSRandall Stewart 		 * already maybe OR has been marked to skip now. Can we skip
3797f8829a4aSRandall Stewart 		 * it if its a resend?
3798f8829a4aSRandall Stewart 		 */
3799f8829a4aSRandall Stewart 		if (tp1->sent == SCTP_DATAGRAM_RESEND &&
3800f8829a4aSRandall Stewart 		    (PR_SCTP_TTL_ENABLED(tp1->flags))) {
3801f8829a4aSRandall Stewart 			/*
3802f8829a4aSRandall Stewart 			 * Now is this one marked for resend and its time is
3803f8829a4aSRandall Stewart 			 * now up?
3804f8829a4aSRandall Stewart 			 */
3805f8829a4aSRandall Stewart 			if (timevalcmp(&now, &tp1->rec.data.timetodrop, >)) {
3806f8829a4aSRandall Stewart 				/* Yes so drop it */
3807f8829a4aSRandall Stewart 				if (tp1->data) {
3808ad81507eSRandall Stewart 					(void)sctp_release_pr_sctp_chunk(stcb, tp1,
38091edc9dbaSMichael Tuexen 					    1, SCTP_SO_NOT_LOCKED);
3810f8829a4aSRandall Stewart 				}
3811f8829a4aSRandall Stewart 			} else {
3812f8829a4aSRandall Stewart 				/*
3813f8829a4aSRandall Stewart 				 * No, we are done when hit one for resend
3814f8829a4aSRandall Stewart 				 * whos time as not expired.
3815f8829a4aSRandall Stewart 				 */
3816f8829a4aSRandall Stewart 				break;
3817f8829a4aSRandall Stewart 			}
3818f8829a4aSRandall Stewart 		}
3819f8829a4aSRandall Stewart 		/*
3820f8829a4aSRandall Stewart 		 * Ok now if this chunk is marked to drop it we can clean up
3821f8829a4aSRandall Stewart 		 * the chunk, advance our peer ack point and we can check
3822f8829a4aSRandall Stewart 		 * the next chunk.
3823f8829a4aSRandall Stewart 		 */
382498f2956cSMichael Tuexen 		if ((tp1->sent == SCTP_FORWARD_TSN_SKIP) ||
3825325c8c46SMichael Tuexen 		    (tp1->sent == SCTP_DATAGRAM_NR_ACKED)) {
3826f8829a4aSRandall Stewart 			/* advance PeerAckPoint goes forward */
382749656eefSMichael Tuexen 			if (SCTP_TSN_GT(tp1->rec.data.tsn, asoc->advanced_peer_ack_point)) {
382849656eefSMichael Tuexen 				asoc->advanced_peer_ack_point = tp1->rec.data.tsn;
3829f8829a4aSRandall Stewart 				a_adv = tp1;
383049656eefSMichael Tuexen 			} else if (tp1->rec.data.tsn == asoc->advanced_peer_ack_point) {
38310c0982b8SRandall Stewart 				/* No update but we do save the chk */
38320c0982b8SRandall Stewart 				a_adv = tp1;
38330c0982b8SRandall Stewart 			}
3834f8829a4aSRandall Stewart 		} else {
3835f8829a4aSRandall Stewart 			/*
3836f8829a4aSRandall Stewart 			 * If it is still in RESEND we can advance no
3837f8829a4aSRandall Stewart 			 * further
3838f8829a4aSRandall Stewart 			 */
3839f8829a4aSRandall Stewart 			break;
3840f8829a4aSRandall Stewart 		}
3841f8829a4aSRandall Stewart 	}
3842f8829a4aSRandall Stewart 	return (a_adv);
3843f8829a4aSRandall Stewart }
3844f8829a4aSRandall Stewart 
38450c0982b8SRandall Stewart static int
3846c105859eSRandall Stewart sctp_fs_audit(struct sctp_association *asoc)
3847bff64a4dSRandall Stewart {
3848bff64a4dSRandall Stewart 	struct sctp_tmit_chunk *chk;
3849afd67482SMichael Tuexen 	int inflight = 0, resend = 0, inbetween = 0, acked = 0, above = 0;
3850548f47a8SMichael Tuexen 	int ret;
3851548f47a8SMichael Tuexen #ifndef INVARIANTS
3852548f47a8SMichael Tuexen 	int entry_flight, entry_cnt;
3853548f47a8SMichael Tuexen #endif
3854548f47a8SMichael Tuexen 
3855548f47a8SMichael Tuexen 	ret = 0;
3856548f47a8SMichael Tuexen #ifndef INVARIANTS
38570c0982b8SRandall Stewart 	entry_flight = asoc->total_flight;
38580c0982b8SRandall Stewart 	entry_cnt = asoc->total_flight_count;
3859548f47a8SMichael Tuexen #endif
38600c0982b8SRandall Stewart 	if (asoc->pr_sctp_cnt >= asoc->sent_queue_cnt)
38610c0982b8SRandall Stewart 		return (0);
3862bff64a4dSRandall Stewart 
3863bff64a4dSRandall Stewart 	TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) {
3864bff64a4dSRandall Stewart 		if (chk->sent < SCTP_DATAGRAM_RESEND) {
3865cd3fd531SMichael Tuexen 			SCTP_PRINTF("Chk TSN: %u size: %d inflight cnt: %d\n",
386649656eefSMichael Tuexen 			    chk->rec.data.tsn,
38670c0982b8SRandall Stewart 			    chk->send_size,
3868cd3fd531SMichael Tuexen 			    chk->snd_count);
3869bff64a4dSRandall Stewart 			inflight++;
3870bff64a4dSRandall Stewart 		} else if (chk->sent == SCTP_DATAGRAM_RESEND) {
3871bff64a4dSRandall Stewart 			resend++;
3872bff64a4dSRandall Stewart 		} else if (chk->sent < SCTP_DATAGRAM_ACKED) {
3873bff64a4dSRandall Stewart 			inbetween++;
3874bff64a4dSRandall Stewart 		} else if (chk->sent > SCTP_DATAGRAM_ACKED) {
3875bff64a4dSRandall Stewart 			above++;
3876bff64a4dSRandall Stewart 		} else {
3877bff64a4dSRandall Stewart 			acked++;
3878bff64a4dSRandall Stewart 		}
3879bff64a4dSRandall Stewart 	}
3880f1f73e57SRandall Stewart 
3881c105859eSRandall Stewart 	if ((inflight > 0) || (inbetween > 0)) {
3882f1f73e57SRandall Stewart #ifdef INVARIANTS
3883c105859eSRandall Stewart 		panic("Flight size-express incorrect? \n");
3884f1f73e57SRandall Stewart #else
3885cd3fd531SMichael Tuexen 		SCTP_PRINTF("asoc->total_flight: %d cnt: %d\n",
38860c0982b8SRandall Stewart 		    entry_flight, entry_cnt);
38870c0982b8SRandall Stewart 
38880c0982b8SRandall Stewart 		SCTP_PRINTF("Flight size-express incorrect F: %d I: %d R: %d Ab: %d ACK: %d\n",
38890c0982b8SRandall Stewart 		    inflight, inbetween, resend, above, acked);
38900c0982b8SRandall Stewart 		ret = 1;
3891f1f73e57SRandall Stewart #endif
3892bff64a4dSRandall Stewart 	}
38930c0982b8SRandall Stewart 	return (ret);
3894c105859eSRandall Stewart }
3895c105859eSRandall Stewart 
3896c105859eSRandall Stewart static void
3897c105859eSRandall Stewart sctp_window_probe_recovery(struct sctp_tcb *stcb,
3898c105859eSRandall Stewart     struct sctp_association *asoc,
3899c105859eSRandall Stewart     struct sctp_tmit_chunk *tp1)
3900c105859eSRandall Stewart {
3901dfb11ef8SRandall Stewart 	tp1->window_probe = 0;
39025171328bSRandall Stewart 	if ((tp1->sent >= SCTP_DATAGRAM_ACKED) || (tp1->data == NULL)) {
3903dfb11ef8SRandall Stewart 		/* TSN's skipped we do NOT move back. */
3904dfb11ef8SRandall Stewart 		sctp_misc_ints(SCTP_FLIGHT_LOG_DWN_WP_FWD,
39058427b3fdSMichael Tuexen 		    tp1->whoTo ? tp1->whoTo->flight_size : 0,
3906dfb11ef8SRandall Stewart 		    tp1->book_size,
39079a8e3088SMichael Tuexen 		    (uint32_t)(uintptr_t)tp1->whoTo,
390849656eefSMichael Tuexen 		    tp1->rec.data.tsn);
3909dfb11ef8SRandall Stewart 		return;
3910dfb11ef8SRandall Stewart 	}
39115171328bSRandall Stewart 	/* First setup this by shrinking flight */
3912299108c5SRandall Stewart 	if (stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) {
3913299108c5SRandall Stewart 		(*stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) (tp1->whoTo,
3914299108c5SRandall Stewart 		    tp1);
3915299108c5SRandall Stewart 	}
39165171328bSRandall Stewart 	sctp_flight_size_decrease(tp1);
39175171328bSRandall Stewart 	sctp_total_flight_decrease(stcb, tp1);
39185171328bSRandall Stewart 	/* Now mark for resend */
39195171328bSRandall Stewart 	tp1->sent = SCTP_DATAGRAM_RESEND;
3920791437b5SRandall Stewart 	sctp_ucount_incr(asoc->sent_queue_retran_cnt);
3921791437b5SRandall Stewart 
3922b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) {
3923c105859eSRandall Stewart 		sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_WP,
3924c105859eSRandall Stewart 		    tp1->whoTo->flight_size,
3925c105859eSRandall Stewart 		    tp1->book_size,
39269a8e3088SMichael Tuexen 		    (uint32_t)(uintptr_t)tp1->whoTo,
392749656eefSMichael Tuexen 		    tp1->rec.data.tsn);
392880fefe0aSRandall Stewart 	}
3929c105859eSRandall Stewart }
3930c105859eSRandall Stewart 
3931f8829a4aSRandall Stewart void
3932f8829a4aSRandall Stewart sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
3933899288aeSRandall Stewart     uint32_t rwnd, int *abort_now, int ecne_seen)
3934f8829a4aSRandall Stewart {
3935f8829a4aSRandall Stewart 	struct sctp_nets *net;
3936f8829a4aSRandall Stewart 	struct sctp_association *asoc;
3937f8829a4aSRandall Stewart 	struct sctp_tmit_chunk *tp1, *tp2;
39385e54f665SRandall Stewart 	uint32_t old_rwnd;
39395e54f665SRandall Stewart 	int win_probe_recovery = 0;
3940c105859eSRandall Stewart 	int win_probe_recovered = 0;
3941d06c82f1SRandall Stewart 	int j, done_once = 0;
3942f79aab18SRandall Stewart 	int rto_ok = 1;
3943fd60718dSMichael Tuexen 	uint32_t send_s;
3944f8829a4aSRandall Stewart 
3945b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_SACK_ARRIVALS_ENABLE) {
3946d06c82f1SRandall Stewart 		sctp_misc_ints(SCTP_SACK_LOG_EXPRESS, cumack,
3947d06c82f1SRandall Stewart 		    rwnd, stcb->asoc.last_acked_seq, stcb->asoc.peers_rwnd);
394880fefe0aSRandall Stewart 	}
3949f8829a4aSRandall Stewart 	SCTP_TCB_LOCK_ASSERT(stcb);
395018e198d3SRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS
395118e198d3SRandall Stewart 	stcb->asoc.cumack_log[stcb->asoc.cumack_log_at] = cumack;
395218e198d3SRandall Stewart 	stcb->asoc.cumack_log_at++;
395318e198d3SRandall Stewart 	if (stcb->asoc.cumack_log_at > SCTP_TSN_LOG_SIZE) {
395418e198d3SRandall Stewart 		stcb->asoc.cumack_log_at = 0;
395518e198d3SRandall Stewart 	}
395618e198d3SRandall Stewart #endif
3957f8829a4aSRandall Stewart 	asoc = &stcb->asoc;
3958d06c82f1SRandall Stewart 	old_rwnd = asoc->peers_rwnd;
395920b07a4dSMichael Tuexen 	if (SCTP_TSN_GT(asoc->last_acked_seq, cumack)) {
39605e54f665SRandall Stewart 		/* old ack */
39615e54f665SRandall Stewart 		return;
3962d06c82f1SRandall Stewart 	} else if (asoc->last_acked_seq == cumack) {
3963d06c82f1SRandall Stewart 		/* Window update sack */
3964d06c82f1SRandall Stewart 		asoc->peers_rwnd = sctp_sbspace_sub(rwnd,
396544fbe462SRandall Stewart 		    (uint32_t)(asoc->total_flight + (asoc->total_flight_count * SCTP_BASE_SYSCTL(sctp_peer_chunk_oh))));
3966d06c82f1SRandall Stewart 		if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) {
3967d06c82f1SRandall Stewart 			/* SWS sender side engages */
3968d06c82f1SRandall Stewart 			asoc->peers_rwnd = 0;
3969d06c82f1SRandall Stewart 		}
3970d06c82f1SRandall Stewart 		if (asoc->peers_rwnd > old_rwnd) {
3971d06c82f1SRandall Stewart 			goto again;
3972d06c82f1SRandall Stewart 		}
3973d06c82f1SRandall Stewart 		return;
39745e54f665SRandall Stewart 	}
39750053ed28SMichael Tuexen 
3976f8829a4aSRandall Stewart 	/* First setup for CC stuff */
3977f8829a4aSRandall Stewart 	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
3978a21779f0SRandall Stewart 		if (SCTP_TSN_GT(cumack, net->cwr_window_tsn)) {
3979a21779f0SRandall Stewart 			/* Drag along the window_tsn for cwr's */
3980a21779f0SRandall Stewart 			net->cwr_window_tsn = cumack;
3981a21779f0SRandall Stewart 		}
3982f8829a4aSRandall Stewart 		net->prev_cwnd = net->cwnd;
3983f8829a4aSRandall Stewart 		net->net_ack = 0;
3984f8829a4aSRandall Stewart 		net->net_ack2 = 0;
3985132dea7dSRandall Stewart 
3986132dea7dSRandall Stewart 		/*
3987132dea7dSRandall Stewart 		 * CMT: Reset CUC and Fast recovery algo variables before
3988132dea7dSRandall Stewart 		 * SACK processing
3989132dea7dSRandall Stewart 		 */
3990132dea7dSRandall Stewart 		net->new_pseudo_cumack = 0;
3991132dea7dSRandall Stewart 		net->will_exit_fast_recovery = 0;
3992299108c5SRandall Stewart 		if (stcb->asoc.cc_functions.sctp_cwnd_prepare_net_for_sack) {
3993299108c5SRandall Stewart 			(*stcb->asoc.cc_functions.sctp_cwnd_prepare_net_for_sack) (stcb, net);
3994299108c5SRandall Stewart 		}
3995f8829a4aSRandall Stewart 	}
3996c105859eSRandall Stewart 	if (!TAILQ_EMPTY(&asoc->sent_queue)) {
3997c105859eSRandall Stewart 		tp1 = TAILQ_LAST(&asoc->sent_queue,
3998c105859eSRandall Stewart 		    sctpchunk_listhead);
399949656eefSMichael Tuexen 		send_s = tp1->rec.data.tsn + 1;
4000139bc87fSRandall Stewart 	} else {
4001c105859eSRandall Stewart 		send_s = asoc->sending_seq;
4002139bc87fSRandall Stewart 	}
400320b07a4dSMichael Tuexen 	if (SCTP_TSN_GE(cumack, send_s)) {
4004ff1ffd74SMichael Tuexen 		struct mbuf *op_err;
4005ff1ffd74SMichael Tuexen 		char msg[SCTP_DIAG_INFO_LEN];
4006139bc87fSRandall Stewart 
4007139bc87fSRandall Stewart 		*abort_now = 1;
4008139bc87fSRandall Stewart 		/* XXX */
4009999f86d6SMichael Tuexen 		SCTP_SNPRINTF(msg, sizeof(msg),
4010999f86d6SMichael Tuexen 		    "Cum ack %8.8x greater or equal than TSN %8.8x",
4011821bae7cSMichael Tuexen 		    cumack, send_s);
4012ff1ffd74SMichael Tuexen 		op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
401391e04f9eSMichael Tuexen 		stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_25;
4014ff1ffd74SMichael Tuexen 		sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
4015139bc87fSRandall Stewart 		return;
4016139bc87fSRandall Stewart 	}
4017f8829a4aSRandall Stewart 	asoc->this_sack_highest_gap = cumack;
4018b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) {
4019c4739e2fSRandall Stewart 		sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
4020c4739e2fSRandall Stewart 		    stcb->asoc.overall_error_count,
4021c4739e2fSRandall Stewart 		    0,
4022c4739e2fSRandall Stewart 		    SCTP_FROM_SCTP_INDATA,
4023c4739e2fSRandall Stewart 		    __LINE__);
4024c4739e2fSRandall Stewart 	}
4025f8829a4aSRandall Stewart 	stcb->asoc.overall_error_count = 0;
402620b07a4dSMichael Tuexen 	if (SCTP_TSN_GT(cumack, asoc->last_acked_seq)) {
4027f8829a4aSRandall Stewart 		/* process the new consecutive TSN first */
40284a9ef3f8SMichael Tuexen 		TAILQ_FOREACH_SAFE(tp1, &asoc->sent_queue, sctp_next, tp2) {
402949656eefSMichael Tuexen 			if (SCTP_TSN_GE(cumack, tp1->rec.data.tsn)) {
403018e198d3SRandall Stewart 				if (tp1->sent == SCTP_DATAGRAM_UNSENT) {
4031cd3fd531SMichael Tuexen 					SCTP_PRINTF("Warning, an unsent is now acked?\n");
403218e198d3SRandall Stewart 				}
4033f8829a4aSRandall Stewart 				if (tp1->sent < SCTP_DATAGRAM_ACKED) {
4034f8829a4aSRandall Stewart 					/*
403518e198d3SRandall Stewart 					 * If it is less than ACKED, it is
403618e198d3SRandall Stewart 					 * now no-longer in flight. Higher
403718e198d3SRandall Stewart 					 * values may occur during marking
4038f8829a4aSRandall Stewart 					 */
4039c105859eSRandall Stewart 					if (tp1->sent < SCTP_DATAGRAM_RESEND) {
4040b3f1ea41SRandall Stewart 						if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) {
4041c105859eSRandall Stewart 							sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_CA,
4042a5d547adSRandall Stewart 							    tp1->whoTo->flight_size,
4043a5d547adSRandall Stewart 							    tp1->book_size,
40449a8e3088SMichael Tuexen 							    (uint32_t)(uintptr_t)tp1->whoTo,
404549656eefSMichael Tuexen 							    tp1->rec.data.tsn);
404680fefe0aSRandall Stewart 						}
4047c105859eSRandall Stewart 						sctp_flight_size_decrease(tp1);
4048299108c5SRandall Stewart 						if (stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) {
4049299108c5SRandall Stewart 							(*stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) (tp1->whoTo,
4050299108c5SRandall Stewart 							    tp1);
4051299108c5SRandall Stewart 						}
405204ee05e8SRandall Stewart 						/* sa_ignore NO_NULL_CHK */
4053c105859eSRandall Stewart 						sctp_total_flight_decrease(stcb, tp1);
4054f8829a4aSRandall Stewart 					}
4055f8829a4aSRandall Stewart 					tp1->whoTo->net_ack += tp1->send_size;
4056f8829a4aSRandall Stewart 					if (tp1->snd_count < 2) {
4057f8829a4aSRandall Stewart 						/*
4058ab9ed8a1SDevin Teske 						 * True non-retransmitted
4059f8829a4aSRandall Stewart 						 * chunk
4060f8829a4aSRandall Stewart 						 */
4061f8829a4aSRandall Stewart 						tp1->whoTo->net_ack2 +=
4062f8829a4aSRandall Stewart 						    tp1->send_size;
4063f8829a4aSRandall Stewart 
4064f8829a4aSRandall Stewart 						/* update RTO too? */
406562c1ff9cSRandall Stewart 						if (tp1->do_rtt) {
406644f2a327SMichael Tuexen 							if (rto_ok &&
4067f8829a4aSRandall Stewart 							    sctp_calculate_rto(stcb,
406844f2a327SMichael Tuexen 							    &stcb->asoc,
406944f2a327SMichael Tuexen 							    tp1->whoTo,
407018e198d3SRandall Stewart 							    &tp1->sent_rcv_time,
407144f2a327SMichael Tuexen 							    SCTP_RTT_FROM_DATA)) {
4072f79aab18SRandall Stewart 								rto_ok = 0;
4073f79aab18SRandall Stewart 							}
4074f79aab18SRandall Stewart 							if (tp1->whoTo->rto_needed == 0) {
4075f79aab18SRandall Stewart 								tp1->whoTo->rto_needed = 1;
4076f79aab18SRandall Stewart 							}
4077f8829a4aSRandall Stewart 							tp1->do_rtt = 0;
4078f8829a4aSRandall Stewart 						}
4079f8829a4aSRandall Stewart 					}
4080132dea7dSRandall Stewart 					/*
408118e198d3SRandall Stewart 					 * CMT: CUCv2 algorithm. From the
408218e198d3SRandall Stewart 					 * cumack'd TSNs, for each TSN being
408318e198d3SRandall Stewart 					 * acked for the first time, set the
408418e198d3SRandall Stewart 					 * following variables for the
408518e198d3SRandall Stewart 					 * corresp destination.
408618e198d3SRandall Stewart 					 * new_pseudo_cumack will trigger a
408718e198d3SRandall Stewart 					 * cwnd update.
408818e198d3SRandall Stewart 					 * find_(rtx_)pseudo_cumack will
408918e198d3SRandall Stewart 					 * trigger search for the next
409018e198d3SRandall Stewart 					 * expected (rtx-)pseudo-cumack.
4091132dea7dSRandall Stewart 					 */
4092132dea7dSRandall Stewart 					tp1->whoTo->new_pseudo_cumack = 1;
4093132dea7dSRandall Stewart 					tp1->whoTo->find_pseudo_cumack = 1;
4094132dea7dSRandall Stewart 					tp1->whoTo->find_rtx_pseudo_cumack = 1;
4095b3f1ea41SRandall Stewart 					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
409604ee05e8SRandall Stewart 						/* sa_ignore NO_NULL_CHK */
409749656eefSMichael Tuexen 						sctp_log_cwnd(stcb, tp1->whoTo, tp1->rec.data.tsn, SCTP_CWND_LOG_FROM_SACK);
409880fefe0aSRandall Stewart 					}
4099f8829a4aSRandall Stewart 				}
4100f8829a4aSRandall Stewart 				if (tp1->sent == SCTP_DATAGRAM_RESEND) {
4101f8829a4aSRandall Stewart 					sctp_ucount_decr(asoc->sent_queue_retran_cnt);
4102f8829a4aSRandall Stewart 				}
410342551e99SRandall Stewart 				if (tp1->rec.data.chunk_was_revoked) {
410442551e99SRandall Stewart 					/* deflate the cwnd */
410542551e99SRandall Stewart 					tp1->whoTo->cwnd -= tp1->book_size;
410642551e99SRandall Stewart 					tp1->rec.data.chunk_was_revoked = 0;
410742551e99SRandall Stewart 				}
4108325c8c46SMichael Tuexen 				if (tp1->sent != SCTP_DATAGRAM_NR_ACKED) {
410949656eefSMichael Tuexen 					if (asoc->strmout[tp1->rec.data.sid].chunks_on_queues > 0) {
411049656eefSMichael Tuexen 						asoc->strmout[tp1->rec.data.sid].chunks_on_queues--;
4111a7ad6026SMichael Tuexen #ifdef INVARIANTS
4112a7ad6026SMichael Tuexen 					} else {
411349656eefSMichael Tuexen 						panic("No chunks on the queues for sid %u.", tp1->rec.data.sid);
4114a7ad6026SMichael Tuexen #endif
4115a7ad6026SMichael Tuexen 					}
4116a7ad6026SMichael Tuexen 				}
411749656eefSMichael Tuexen 				if ((asoc->strmout[tp1->rec.data.sid].chunks_on_queues == 0) &&
411849656eefSMichael Tuexen 				    (asoc->strmout[tp1->rec.data.sid].state == SCTP_STREAM_RESET_PENDING) &&
411949656eefSMichael Tuexen 				    TAILQ_EMPTY(&asoc->strmout[tp1->rec.data.sid].outqueue)) {
4120d96bef9cSMichael Tuexen 					asoc->trigger_reset = 1;
4121d96bef9cSMichael Tuexen 				}
4122f8829a4aSRandall Stewart 				TAILQ_REMOVE(&asoc->sent_queue, tp1, sctp_next);
4123f8829a4aSRandall Stewart 				if (tp1->data) {
412404ee05e8SRandall Stewart 					/* sa_ignore NO_NULL_CHK */
4125f8829a4aSRandall Stewart 					sctp_free_bufspace(stcb, asoc, tp1, 1);
4126f8829a4aSRandall Stewart 					sctp_m_freem(tp1->data);
41274a9ef3f8SMichael Tuexen 					tp1->data = NULL;
4128f8829a4aSRandall Stewart 				}
4129b3f1ea41SRandall Stewart 				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) {
4130f8829a4aSRandall Stewart 					sctp_log_sack(asoc->last_acked_seq,
4131f8829a4aSRandall Stewart 					    cumack,
413249656eefSMichael Tuexen 					    tp1->rec.data.tsn,
4133f8829a4aSRandall Stewart 					    0,
4134f8829a4aSRandall Stewart 					    0,
4135f8829a4aSRandall Stewart 					    SCTP_LOG_FREE_SENT);
413680fefe0aSRandall Stewart 				}
4137f8829a4aSRandall Stewart 				asoc->sent_queue_cnt--;
4138689e6a5fSMichael Tuexen 				sctp_free_a_chunk(stcb, tp1, SCTP_SO_NOT_LOCKED);
413918e198d3SRandall Stewart 			} else {
414018e198d3SRandall Stewart 				break;
4141f8829a4aSRandall Stewart 			}
41425e54f665SRandall Stewart 		}
414318e198d3SRandall Stewart 	}
414404ee05e8SRandall Stewart 	/* sa_ignore NO_NULL_CHK */
4145f8829a4aSRandall Stewart 	if (stcb->sctp_socket) {
4146f8829a4aSRandall Stewart 		SOCKBUF_LOCK(&stcb->sctp_socket->so_snd);
4147b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_WAKE_LOGGING_ENABLE) {
414804ee05e8SRandall Stewart 			/* sa_ignore NO_NULL_CHK */
41497215cc1bSMichael Tuexen 			sctp_wakeup_log(stcb, 1, SCTP_WAKESND_FROM_SACK);
415080fefe0aSRandall Stewart 		}
4151f8829a4aSRandall Stewart 		sctp_sowwakeup_locked(stcb->sctp_ep, stcb->sctp_socket);
4152f8829a4aSRandall Stewart 	} else {
4153b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_WAKE_LOGGING_ENABLE) {
41547215cc1bSMichael Tuexen 			sctp_wakeup_log(stcb, 1, SCTP_NOWAKE_FROM_SACK);
415580fefe0aSRandall Stewart 		}
4156f8829a4aSRandall Stewart 	}
4157f8829a4aSRandall Stewart 
4158b54d3a6cSRandall Stewart 	/* JRS - Use the congestion control given in the CC module */
4159ca85e948SMichael Tuexen 	if ((asoc->last_acked_seq != cumack) && (ecne_seen == 0)) {
4160ca85e948SMichael Tuexen 		TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
4161ca85e948SMichael Tuexen 			if (net->net_ack2 > 0) {
4162ca85e948SMichael Tuexen 				/*
4163ca85e948SMichael Tuexen 				 * Karn's rule applies to clearing error
4164ca85e948SMichael Tuexen 				 * count, this is optional.
4165ca85e948SMichael Tuexen 				 */
4166ca85e948SMichael Tuexen 				net->error_count = 0;
4167ca85e948SMichael Tuexen 				if (!(net->dest_state & SCTP_ADDR_REACHABLE)) {
4168ca85e948SMichael Tuexen 					/* addr came good */
4169ca85e948SMichael Tuexen 					net->dest_state |= SCTP_ADDR_REACHABLE;
4170ca85e948SMichael Tuexen 					sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb,
41714b1f78e1SMichael Tuexen 					    0, (void *)net, SCTP_SO_NOT_LOCKED);
4172ca85e948SMichael Tuexen 				}
4173ca85e948SMichael Tuexen 				if (net == stcb->asoc.primary_destination) {
4174ca85e948SMichael Tuexen 					if (stcb->asoc.alternate) {
4175b7b84c0eSMichael Tuexen 						/*
4176b7b84c0eSMichael Tuexen 						 * release the alternate,
4177b7b84c0eSMichael Tuexen 						 * primary is good
4178b7b84c0eSMichael Tuexen 						 */
4179ca85e948SMichael Tuexen 						sctp_free_remote_addr(stcb->asoc.alternate);
4180ca85e948SMichael Tuexen 						stcb->asoc.alternate = NULL;
4181ca85e948SMichael Tuexen 					}
4182ca85e948SMichael Tuexen 				}
4183ca85e948SMichael Tuexen 				if (net->dest_state & SCTP_ADDR_PF) {
4184ca85e948SMichael Tuexen 					net->dest_state &= ~SCTP_ADDR_PF;
4185b7d130beSMichael Tuexen 					sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT,
4186b7d130beSMichael Tuexen 					    stcb->sctp_ep, stcb, net,
418791e04f9eSMichael Tuexen 					    SCTP_FROM_SCTP_INDATA + SCTP_LOC_26);
4188ca85e948SMichael Tuexen 					sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
4189ca85e948SMichael Tuexen 					asoc->cc_functions.sctp_cwnd_update_exit_pf(stcb, net);
4190ca85e948SMichael Tuexen 					/* Done with this net */
4191ca85e948SMichael Tuexen 					net->net_ack = 0;
4192ca85e948SMichael Tuexen 				}
4193ca85e948SMichael Tuexen 				/* restore any doubled timers */
4194ca85e948SMichael Tuexen 				net->RTO = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv;
4195ca85e948SMichael Tuexen 				if (net->RTO < stcb->asoc.minrto) {
4196ca85e948SMichael Tuexen 					net->RTO = stcb->asoc.minrto;
4197ca85e948SMichael Tuexen 				}
4198ca85e948SMichael Tuexen 				if (net->RTO > stcb->asoc.maxrto) {
4199ca85e948SMichael Tuexen 					net->RTO = stcb->asoc.maxrto;
4200ca85e948SMichael Tuexen 				}
4201ca85e948SMichael Tuexen 			}
4202ca85e948SMichael Tuexen 		}
4203b54d3a6cSRandall Stewart 		asoc->cc_functions.sctp_cwnd_update_after_sack(stcb, asoc, 1, 0, 0);
4204ca85e948SMichael Tuexen 	}
4205f8829a4aSRandall Stewart 	asoc->last_acked_seq = cumack;
42065e54f665SRandall Stewart 
4207f8829a4aSRandall Stewart 	if (TAILQ_EMPTY(&asoc->sent_queue)) {
4208f8829a4aSRandall Stewart 		/* nothing left in-flight */
4209f8829a4aSRandall Stewart 		TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
4210f8829a4aSRandall Stewart 			net->flight_size = 0;
4211f8829a4aSRandall Stewart 			net->partial_bytes_acked = 0;
4212f8829a4aSRandall Stewart 		}
4213f8829a4aSRandall Stewart 		asoc->total_flight = 0;
4214f8829a4aSRandall Stewart 		asoc->total_flight_count = 0;
4215f8829a4aSRandall Stewart 	}
42160053ed28SMichael Tuexen 
4217f8829a4aSRandall Stewart 	/* RWND update */
4218f8829a4aSRandall Stewart 	asoc->peers_rwnd = sctp_sbspace_sub(rwnd,
421944fbe462SRandall Stewart 	    (uint32_t)(asoc->total_flight + (asoc->total_flight_count * SCTP_BASE_SYSCTL(sctp_peer_chunk_oh))));
4220f8829a4aSRandall Stewart 	if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) {
4221f8829a4aSRandall Stewart 		/* SWS sender side engages */
4222f8829a4aSRandall Stewart 		asoc->peers_rwnd = 0;
4223f8829a4aSRandall Stewart 	}
42245e54f665SRandall Stewart 	if (asoc->peers_rwnd > old_rwnd) {
42255e54f665SRandall Stewart 		win_probe_recovery = 1;
42265e54f665SRandall Stewart 	}
4227f8829a4aSRandall Stewart 	/* Now assure a timer where data is queued at */
4228a5d547adSRandall Stewart again:
4229a5d547adSRandall Stewart 	j = 0;
4230f8829a4aSRandall Stewart 	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
42315e54f665SRandall Stewart 		if (win_probe_recovery && (net->window_probe)) {
4232c105859eSRandall Stewart 			win_probe_recovered = 1;
42335e54f665SRandall Stewart 			/*
42345e54f665SRandall Stewart 			 * Find first chunk that was used with window probe
42355e54f665SRandall Stewart 			 * and clear the sent
42365e54f665SRandall Stewart 			 */
42373c503c28SRandall Stewart 			/* sa_ignore FREED_MEMORY */
42385e54f665SRandall Stewart 			TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
42395e54f665SRandall Stewart 				if (tp1->window_probe) {
4240cd554309SMichael Tuexen 					/* move back to data send queue */
42417215cc1bSMichael Tuexen 					sctp_window_probe_recovery(stcb, asoc, tp1);
42425e54f665SRandall Stewart 					break;
42435e54f665SRandall Stewart 				}
42445e54f665SRandall Stewart 			}
42455e54f665SRandall Stewart 		}
42465171328bSRandall Stewart 		if (net->flight_size) {
4247a5d547adSRandall Stewart 			j++;
424872e23abaSMichael Tuexen 			sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net);
42495171328bSRandall Stewart 			if (net->window_probe) {
42505171328bSRandall Stewart 				net->window_probe = 0;
42515171328bSRandall Stewart 			}
4252f8829a4aSRandall Stewart 		} else {
42535171328bSRandall Stewart 			if (net->window_probe) {
4254b7b84c0eSMichael Tuexen 				/*
4255b7b84c0eSMichael Tuexen 				 * In window probes we must assure a timer
4256b7b84c0eSMichael Tuexen 				 * is still running there
4257b7b84c0eSMichael Tuexen 				 */
42585171328bSRandall Stewart 				net->window_probe = 0;
42595171328bSRandall Stewart 				if (!SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) {
426072e23abaSMichael Tuexen 					sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net);
42615171328bSRandall Stewart 				}
42625171328bSRandall Stewart 			} else if (SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) {
4263f8829a4aSRandall Stewart 				sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
4264a5d547adSRandall Stewart 				    stcb, net,
426591e04f9eSMichael Tuexen 				    SCTP_FROM_SCTP_INDATA + SCTP_LOC_27);
4266f8829a4aSRandall Stewart 			}
4267f8829a4aSRandall Stewart 		}
4268f8829a4aSRandall Stewart 	}
4269bff64a4dSRandall Stewart 	if ((j == 0) &&
4270bff64a4dSRandall Stewart 	    (!TAILQ_EMPTY(&asoc->sent_queue)) &&
4271bff64a4dSRandall Stewart 	    (asoc->sent_queue_retran_cnt == 0) &&
4272c105859eSRandall Stewart 	    (win_probe_recovered == 0) &&
4273bff64a4dSRandall Stewart 	    (done_once == 0)) {
42740c0982b8SRandall Stewart 		/*
42750c0982b8SRandall Stewart 		 * huh, this should not happen unless all packets are
42760c0982b8SRandall Stewart 		 * PR-SCTP and marked to skip of course.
42770c0982b8SRandall Stewart 		 */
42780c0982b8SRandall Stewart 		if (sctp_fs_audit(asoc)) {
4279a5d547adSRandall Stewart 			TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
4280a5d547adSRandall Stewart 				net->flight_size = 0;
4281a5d547adSRandall Stewart 			}
4282a5d547adSRandall Stewart 			asoc->total_flight = 0;
4283a5d547adSRandall Stewart 			asoc->total_flight_count = 0;
4284a5d547adSRandall Stewart 			asoc->sent_queue_retran_cnt = 0;
4285a5d547adSRandall Stewart 			TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
4286a5d547adSRandall Stewart 				if (tp1->sent < SCTP_DATAGRAM_RESEND) {
4287c105859eSRandall Stewart 					sctp_flight_size_increase(tp1);
4288c105859eSRandall Stewart 					sctp_total_flight_increase(stcb, tp1);
4289a5d547adSRandall Stewart 				} else if (tp1->sent == SCTP_DATAGRAM_RESEND) {
4290791437b5SRandall Stewart 					sctp_ucount_incr(asoc->sent_queue_retran_cnt);
4291a5d547adSRandall Stewart 				}
4292a5d547adSRandall Stewart 			}
42930c0982b8SRandall Stewart 		}
4294bff64a4dSRandall Stewart 		done_once = 1;
4295a5d547adSRandall Stewart 		goto again;
4296a5d547adSRandall Stewart 	}
4297f8829a4aSRandall Stewart 	/**********************************/
4298f8829a4aSRandall Stewart 	/* Now what about shutdown issues */
4299f8829a4aSRandall Stewart 	/**********************************/
4300f8829a4aSRandall Stewart 	if (TAILQ_EMPTY(&asoc->send_queue) && TAILQ_EMPTY(&asoc->sent_queue)) {
4301f8829a4aSRandall Stewart 		/* nothing left on sendqueue.. consider done */
4302f8829a4aSRandall Stewart 		/* clean up */
4303f8829a4aSRandall Stewart 		if ((asoc->stream_queue_cnt == 1) &&
4304f8829a4aSRandall Stewart 		    ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) ||
4305839d21d6SMichael Tuexen 		    (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) &&
4306d1ea5fa9SMichael Tuexen 		    ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) (stcb, asoc))) {
4307839d21d6SMichael Tuexen 			SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_PARTIAL_MSG_LEFT);
43082afb3e84SRandall Stewart 		}
4309bbc9dfbcSMichael Tuexen 		if (((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) ||
4310839d21d6SMichael Tuexen 		    (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) &&
4311bbc9dfbcSMichael Tuexen 		    (asoc->stream_queue_cnt == 1) &&
4312bbc9dfbcSMichael Tuexen 		    (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) {
4313ff1ffd74SMichael Tuexen 			struct mbuf *op_err;
4314f8829a4aSRandall Stewart 
4315f8829a4aSRandall Stewart 			*abort_now = 1;
4316f8829a4aSRandall Stewart 			/* XXX */
4317ff1ffd74SMichael Tuexen 			op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
431891e04f9eSMichael Tuexen 			stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_28;
4319ff1ffd74SMichael Tuexen 			sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
4320fe4a59b3SMichael Tuexen 			return;
4321bbc9dfbcSMichael Tuexen 		}
4322bbc9dfbcSMichael Tuexen 		if ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) &&
4323bbc9dfbcSMichael Tuexen 		    (asoc->stream_queue_cnt == 0)) {
4324ca85e948SMichael Tuexen 			struct sctp_nets *netp;
4325ca85e948SMichael Tuexen 
4326839d21d6SMichael Tuexen 			if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) ||
4327839d21d6SMichael Tuexen 			    (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
4328f8829a4aSRandall Stewart 				SCTP_STAT_DECR_GAUGE32(sctps_currestab);
4329f42a358aSRandall Stewart 			}
4330839d21d6SMichael Tuexen 			SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_SENT);
4331f8829a4aSRandall Stewart 			sctp_stop_timers_for_shutdown(stcb);
4332ca85e948SMichael Tuexen 			if (asoc->alternate) {
4333ca85e948SMichael Tuexen 				netp = asoc->alternate;
4334ca85e948SMichael Tuexen 			} else {
4335ca85e948SMichael Tuexen 				netp = asoc->primary_destination;
4336ca85e948SMichael Tuexen 			}
4337ca85e948SMichael Tuexen 			sctp_send_shutdown(stcb, netp);
4338f8829a4aSRandall Stewart 			sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
4339ca85e948SMichael Tuexen 			    stcb->sctp_ep, stcb, netp);
4340f8829a4aSRandall Stewart 			sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
43416fb7b4fbSMichael Tuexen 			    stcb->sctp_ep, stcb, NULL);
4342839d21d6SMichael Tuexen 		} else if ((SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED) &&
4343f8829a4aSRandall Stewart 		    (asoc->stream_queue_cnt == 0)) {
4344ca85e948SMichael Tuexen 			struct sctp_nets *netp;
4345ca85e948SMichael Tuexen 
4346f8829a4aSRandall Stewart 			SCTP_STAT_DECR_GAUGE32(sctps_currestab);
4347839d21d6SMichael Tuexen 			SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_ACK_SENT);
434812af6654SMichael Tuexen 			sctp_stop_timers_for_shutdown(stcb);
4349c39cfa1fSMichael Tuexen 			if (asoc->alternate) {
4350c39cfa1fSMichael Tuexen 				netp = asoc->alternate;
4351c39cfa1fSMichael Tuexen 			} else {
4352c39cfa1fSMichael Tuexen 				netp = asoc->primary_destination;
4353c39cfa1fSMichael Tuexen 			}
4354c39cfa1fSMichael Tuexen 			sctp_send_shutdown_ack(stcb, netp);
4355f8829a4aSRandall Stewart 			sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK,
4356ca85e948SMichael Tuexen 			    stcb->sctp_ep, stcb, netp);
4357f8829a4aSRandall Stewart 		}
4358f8829a4aSRandall Stewart 	}
4359dfb11ef8SRandall Stewart 	/*********************************************/
4360dfb11ef8SRandall Stewart 	/* Here we perform PR-SCTP procedures        */
4361dfb11ef8SRandall Stewart 	/* (section 4.2)                             */
4362dfb11ef8SRandall Stewart 	/*********************************************/
4363dfb11ef8SRandall Stewart 	/* C1. update advancedPeerAckPoint */
436420b07a4dSMichael Tuexen 	if (SCTP_TSN_GT(cumack, asoc->advanced_peer_ack_point)) {
4365dfb11ef8SRandall Stewart 		asoc->advanced_peer_ack_point = cumack;
4366dfb11ef8SRandall Stewart 	}
4367830d754dSRandall Stewart 	/* PR-Sctp issues need to be addressed too */
4368dd973b0eSMichael Tuexen 	if ((asoc->prsctp_supported) && (asoc->pr_sctp_cnt > 0)) {
4369830d754dSRandall Stewart 		struct sctp_tmit_chunk *lchk;
4370830d754dSRandall Stewart 		uint32_t old_adv_peer_ack_point;
4371830d754dSRandall Stewart 
4372830d754dSRandall Stewart 		old_adv_peer_ack_point = asoc->advanced_peer_ack_point;
4373830d754dSRandall Stewart 		lchk = sctp_try_advance_peer_ack_point(stcb, asoc);
4374830d754dSRandall Stewart 		/* C3. See if we need to send a Fwd-TSN */
437520b07a4dSMichael Tuexen 		if (SCTP_TSN_GT(asoc->advanced_peer_ack_point, cumack)) {
4376830d754dSRandall Stewart 			/*
4377493d8e5aSRandall Stewart 			 * ISSUE with ECN, see FWD-TSN processing.
4378830d754dSRandall Stewart 			 */
437920b07a4dSMichael Tuexen 			if (SCTP_TSN_GT(asoc->advanced_peer_ack_point, old_adv_peer_ack_point)) {
4380830d754dSRandall Stewart 				send_forward_tsn(stcb, asoc);
43810c0982b8SRandall Stewart 			} else if (lchk) {
43820c0982b8SRandall Stewart 				/* try to FR fwd-tsn's that get lost too */
438344fbe462SRandall Stewart 				if (lchk->rec.data.fwd_tsn_cnt >= 3) {
43840c0982b8SRandall Stewart 					send_forward_tsn(stcb, asoc);
43850c0982b8SRandall Stewart 				}
4386830d754dSRandall Stewart 			}
4387830d754dSRandall Stewart 		}
4388efd5e692SMichael Tuexen 		for (; lchk != NULL; lchk = TAILQ_NEXT(lchk, sctp_next)) {
4389efd5e692SMichael Tuexen 			if (lchk->whoTo != NULL) {
4390efd5e692SMichael Tuexen 				break;
4391efd5e692SMichael Tuexen 			}
4392efd5e692SMichael Tuexen 		}
4393efd5e692SMichael Tuexen 		if (lchk != NULL) {
4394830d754dSRandall Stewart 			/* Assure a timer is up */
4395830d754dSRandall Stewart 			sctp_timer_start(SCTP_TIMER_TYPE_SEND,
4396830d754dSRandall Stewart 			    stcb->sctp_ep, stcb, lchk->whoTo);
4397830d754dSRandall Stewart 		}
4398830d754dSRandall Stewart 	}
4399b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_RWND_LOGGING_ENABLE) {
4400f8829a4aSRandall Stewart 		sctp_misc_ints(SCTP_SACK_RWND_UPDATE,
4401f8829a4aSRandall Stewart 		    rwnd,
4402f8829a4aSRandall Stewart 		    stcb->asoc.peers_rwnd,
4403f8829a4aSRandall Stewart 		    stcb->asoc.total_flight,
4404f8829a4aSRandall Stewart 		    stcb->asoc.total_output_queue_size);
440580fefe0aSRandall Stewart 	}
4406f8829a4aSRandall Stewart }
4407f8829a4aSRandall Stewart 
4408f8829a4aSRandall Stewart void
4409cd554309SMichael Tuexen sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
44107215cc1bSMichael Tuexen     struct sctp_tcb *stcb,
4411cd554309SMichael Tuexen     uint16_t num_seg, uint16_t num_nr_seg, uint16_t num_dup,
4412cd554309SMichael Tuexen     int *abort_now, uint8_t flags,
4413899288aeSRandall Stewart     uint32_t cum_ack, uint32_t rwnd, int ecne_seen)
4414f8829a4aSRandall Stewart {
4415f8829a4aSRandall Stewart 	struct sctp_association *asoc;
4416f8829a4aSRandall Stewart 	struct sctp_tmit_chunk *tp1, *tp2;
4417cd554309SMichael Tuexen 	uint32_t last_tsn, biggest_tsn_acked, biggest_tsn_newly_acked, this_sack_lowest_newack;
4418f8829a4aSRandall Stewart 	uint16_t wake_him = 0;
4419c105859eSRandall Stewart 	uint32_t send_s = 0;
4420f8829a4aSRandall Stewart 	long j;
4421f8829a4aSRandall Stewart 	int accum_moved = 0;
4422f8829a4aSRandall Stewart 	int will_exit_fast_recovery = 0;
44235e54f665SRandall Stewart 	uint32_t a_rwnd, old_rwnd;
44245e54f665SRandall Stewart 	int win_probe_recovery = 0;
4425c105859eSRandall Stewart 	int win_probe_recovered = 0;
4426f8829a4aSRandall Stewart 	struct sctp_nets *net = NULL;
4427bff64a4dSRandall Stewart 	int done_once;
4428f79aab18SRandall Stewart 	int rto_ok = 1;
4429f8829a4aSRandall Stewart 	uint8_t reneged_all = 0;
4430f8829a4aSRandall Stewart 	uint8_t cmt_dac_flag;
4431f8829a4aSRandall Stewart 
4432f8829a4aSRandall Stewart 	/*
4433f8829a4aSRandall Stewart 	 * we take any chance we can to service our queues since we cannot
4434f8829a4aSRandall Stewart 	 * get awoken when the socket is read from :<
4435f8829a4aSRandall Stewart 	 */
4436f8829a4aSRandall Stewart 	/*
4437f8829a4aSRandall Stewart 	 * Now perform the actual SACK handling: 1) Verify that it is not an
4438f8829a4aSRandall Stewart 	 * old sack, if so discard. 2) If there is nothing left in the send
4439f8829a4aSRandall Stewart 	 * queue (cum-ack is equal to last acked) then you have a duplicate
4440f8829a4aSRandall Stewart 	 * too, update any rwnd change and verify no timers are running.
4441f8829a4aSRandall Stewart 	 * then return. 3) Process any new consequtive data i.e. cum-ack
4442f8829a4aSRandall Stewart 	 * moved process these first and note that it moved. 4) Process any
4443f8829a4aSRandall Stewart 	 * sack blocks. 5) Drop any acked from the queue. 6) Check for any
4444f8829a4aSRandall Stewart 	 * revoked blocks and mark. 7) Update the cwnd. 8) Nothing left,
4445f8829a4aSRandall Stewart 	 * sync up flightsizes and things, stop all timers and also check
4446f8829a4aSRandall Stewart 	 * for shutdown_pending state. If so then go ahead and send off the
4447f8829a4aSRandall Stewart 	 * shutdown. If in shutdown recv, send off the shutdown-ack and
4448f8829a4aSRandall Stewart 	 * start that timer, Ret. 9) Strike any non-acked things and do FR
4449f8829a4aSRandall Stewart 	 * procedure if needed being sure to set the FR flag. 10) Do pr-sctp
4450f8829a4aSRandall Stewart 	 * procedures. 11) Apply any FR penalties. 12) Assure we will SACK
4451f8829a4aSRandall Stewart 	 * if in shutdown_recv state.
4452f8829a4aSRandall Stewart 	 */
4453f8829a4aSRandall Stewart 	SCTP_TCB_LOCK_ASSERT(stcb);
4454f8829a4aSRandall Stewart 	/* CMT DAC algo */
4455f8829a4aSRandall Stewart 	this_sack_lowest_newack = 0;
4456f8829a4aSRandall Stewart 	SCTP_STAT_INCR(sctps_slowpath_sack);
4457cd554309SMichael Tuexen 	last_tsn = cum_ack;
4458cd554309SMichael Tuexen 	cmt_dac_flag = flags & SCTP_SACK_CMT_DAC;
445918e198d3SRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS
446018e198d3SRandall Stewart 	stcb->asoc.cumack_log[stcb->asoc.cumack_log_at] = cum_ack;
446118e198d3SRandall Stewart 	stcb->asoc.cumack_log_at++;
446218e198d3SRandall Stewart 	if (stcb->asoc.cumack_log_at > SCTP_TSN_LOG_SIZE) {
446318e198d3SRandall Stewart 		stcb->asoc.cumack_log_at = 0;
446418e198d3SRandall Stewart 	}
446518e198d3SRandall Stewart #endif
4466d06c82f1SRandall Stewart 	a_rwnd = rwnd;
4467f8829a4aSRandall Stewart 
4468cd554309SMichael Tuexen 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_SACK_ARRIVALS_ENABLE) {
4469cd554309SMichael Tuexen 		sctp_misc_ints(SCTP_SACK_LOG_NORMAL, cum_ack,
4470cd554309SMichael Tuexen 		    rwnd, stcb->asoc.last_acked_seq, stcb->asoc.peers_rwnd);
4471cd554309SMichael Tuexen 	}
44720053ed28SMichael Tuexen 
44735e54f665SRandall Stewart 	old_rwnd = stcb->asoc.peers_rwnd;
4474b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) {
4475c4739e2fSRandall Stewart 		sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
4476c4739e2fSRandall Stewart 		    stcb->asoc.overall_error_count,
4477c4739e2fSRandall Stewart 		    0,
4478c4739e2fSRandall Stewart 		    SCTP_FROM_SCTP_INDATA,
4479c4739e2fSRandall Stewart 		    __LINE__);
4480c4739e2fSRandall Stewart 	}
4481f8829a4aSRandall Stewart 	stcb->asoc.overall_error_count = 0;
4482f8829a4aSRandall Stewart 	asoc = &stcb->asoc;
4483b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) {
4484f8829a4aSRandall Stewart 		sctp_log_sack(asoc->last_acked_seq,
4485f8829a4aSRandall Stewart 		    cum_ack,
4486f8829a4aSRandall Stewart 		    0,
4487f8829a4aSRandall Stewart 		    num_seg,
4488f8829a4aSRandall Stewart 		    num_dup,
4489f8829a4aSRandall Stewart 		    SCTP_LOG_NEW_SACK);
449080fefe0aSRandall Stewart 	}
4491ca85e948SMichael Tuexen 	if ((num_dup) && (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE)) {
4492cd554309SMichael Tuexen 		uint16_t i;
4493458303daSRandall Stewart 		uint32_t *dupdata, dblock;
4494f8829a4aSRandall Stewart 
4495cd554309SMichael Tuexen 		for (i = 0; i < num_dup; i++) {
4496cd554309SMichael Tuexen 			dupdata = (uint32_t *)sctp_m_getptr(m, offset_dup + i * sizeof(uint32_t),
4497458303daSRandall Stewart 			    sizeof(uint32_t), (uint8_t *)&dblock);
4498cd554309SMichael Tuexen 			if (dupdata == NULL) {
4499458303daSRandall Stewart 				break;
4500458303daSRandall Stewart 			}
4501cd554309SMichael Tuexen 			sctp_log_fr(*dupdata, 0, 0, SCTP_FR_DUPED);
4502f8829a4aSRandall Stewart 		}
4503f8829a4aSRandall Stewart 	}
4504c105859eSRandall Stewart 	/* reality check */
4505c105859eSRandall Stewart 	if (!TAILQ_EMPTY(&asoc->sent_queue)) {
4506c105859eSRandall Stewart 		tp1 = TAILQ_LAST(&asoc->sent_queue,
4507c105859eSRandall Stewart 		    sctpchunk_listhead);
450849656eefSMichael Tuexen 		send_s = tp1->rec.data.tsn + 1;
4509c105859eSRandall Stewart 	} else {
4510b5c16493SMichael Tuexen 		tp1 = NULL;
4511c105859eSRandall Stewart 		send_s = asoc->sending_seq;
4512c105859eSRandall Stewart 	}
451320b07a4dSMichael Tuexen 	if (SCTP_TSN_GE(cum_ack, send_s)) {
4514ff1ffd74SMichael Tuexen 		struct mbuf *op_err;
4515ff1ffd74SMichael Tuexen 		char msg[SCTP_DIAG_INFO_LEN];
4516c105859eSRandall Stewart 
4517f8829a4aSRandall Stewart 		/*
4518fd60718dSMichael Tuexen 		 * no way, we have not even sent this TSN out yet. Peer is
4519fd60718dSMichael Tuexen 		 * hopelessly messed up with us.
4520f8829a4aSRandall Stewart 		 */
4521cd3fd531SMichael Tuexen 		SCTP_PRINTF("NEW cum_ack:%x send_s:%x is smaller or equal\n",
4522b5c16493SMichael Tuexen 		    cum_ack, send_s);
4523b5c16493SMichael Tuexen 		if (tp1) {
4524cd3fd531SMichael Tuexen 			SCTP_PRINTF("Got send_s from tsn:%x + 1 of tp1: %p\n",
452549656eefSMichael Tuexen 			    tp1->rec.data.tsn, (void *)tp1);
4526b5c16493SMichael Tuexen 		}
4527f8829a4aSRandall Stewart hopeless_peer:
4528f8829a4aSRandall Stewart 		*abort_now = 1;
4529f8829a4aSRandall Stewart 		/* XXX */
4530999f86d6SMichael Tuexen 		SCTP_SNPRINTF(msg, sizeof(msg),
4531999f86d6SMichael Tuexen 		    "Cum ack %8.8x greater or equal than TSN %8.8x",
4532821bae7cSMichael Tuexen 		    cum_ack, send_s);
4533ff1ffd74SMichael Tuexen 		op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
453491e04f9eSMichael Tuexen 		stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_29;
4535ff1ffd74SMichael Tuexen 		sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
4536f8829a4aSRandall Stewart 		return;
4537f8829a4aSRandall Stewart 	}
4538f8829a4aSRandall Stewart 	/**********************/
4539f8829a4aSRandall Stewart 	/* 1) check the range */
4540f8829a4aSRandall Stewart 	/**********************/
454120b07a4dSMichael Tuexen 	if (SCTP_TSN_GT(asoc->last_acked_seq, last_tsn)) {
4542f8829a4aSRandall Stewart 		/* acking something behind */
4543f8829a4aSRandall Stewart 		return;
4544f8829a4aSRandall Stewart 	}
45450053ed28SMichael Tuexen 
4546f8829a4aSRandall Stewart 	/* update the Rwnd of the peer */
4547f8829a4aSRandall Stewart 	if (TAILQ_EMPTY(&asoc->sent_queue) &&
4548f8829a4aSRandall Stewart 	    TAILQ_EMPTY(&asoc->send_queue) &&
4549cd554309SMichael Tuexen 	    (asoc->stream_queue_cnt == 0)) {
4550f8829a4aSRandall Stewart 		/* nothing left on send/sent and strmq */
4551b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_RWND_ENABLE) {
4552f8829a4aSRandall Stewart 			sctp_log_rwnd_set(SCTP_SET_PEER_RWND_VIA_SACK,
4553f8829a4aSRandall Stewart 			    asoc->peers_rwnd, 0, 0, a_rwnd);
455480fefe0aSRandall Stewart 		}
4555f8829a4aSRandall Stewart 		asoc->peers_rwnd = a_rwnd;
4556f8829a4aSRandall Stewart 		if (asoc->sent_queue_retran_cnt) {
4557f8829a4aSRandall Stewart 			asoc->sent_queue_retran_cnt = 0;
4558f8829a4aSRandall Stewart 		}
4559f8829a4aSRandall Stewart 		if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) {
4560f8829a4aSRandall Stewart 			/* SWS sender side engages */
4561f8829a4aSRandall Stewart 			asoc->peers_rwnd = 0;
4562f8829a4aSRandall Stewart 		}
4563f8829a4aSRandall Stewart 		/* stop any timers */
4564f8829a4aSRandall Stewart 		TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
4565f8829a4aSRandall Stewart 			sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
456691e04f9eSMichael Tuexen 			    stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_30);
4567f8829a4aSRandall Stewart 			net->partial_bytes_acked = 0;
4568f8829a4aSRandall Stewart 			net->flight_size = 0;
4569f8829a4aSRandall Stewart 		}
4570f8829a4aSRandall Stewart 		asoc->total_flight = 0;
4571f8829a4aSRandall Stewart 		asoc->total_flight_count = 0;
4572f8829a4aSRandall Stewart 		return;
4573f8829a4aSRandall Stewart 	}
4574f8829a4aSRandall Stewart 	/*
4575f8829a4aSRandall Stewart 	 * We init netAckSz and netAckSz2 to 0. These are used to track 2
4576f8829a4aSRandall Stewart 	 * things. The total byte count acked is tracked in netAckSz AND
4577f8829a4aSRandall Stewart 	 * netAck2 is used to track the total bytes acked that are un-
4578f8829a4aSRandall Stewart 	 * amibguious and were never retransmitted. We track these on a per
4579f8829a4aSRandall Stewart 	 * destination address basis.
4580f8829a4aSRandall Stewart 	 */
4581f8829a4aSRandall Stewart 	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
4582a21779f0SRandall Stewart 		if (SCTP_TSN_GT(cum_ack, net->cwr_window_tsn)) {
4583a21779f0SRandall Stewart 			/* Drag along the window_tsn for cwr's */
4584a21779f0SRandall Stewart 			net->cwr_window_tsn = cum_ack;
4585a21779f0SRandall Stewart 		}
4586f8829a4aSRandall Stewart 		net->prev_cwnd = net->cwnd;
4587f8829a4aSRandall Stewart 		net->net_ack = 0;
4588f8829a4aSRandall Stewart 		net->net_ack2 = 0;
4589f8829a4aSRandall Stewart 
4590f8829a4aSRandall Stewart 		/*
459142551e99SRandall Stewart 		 * CMT: Reset CUC and Fast recovery algo variables before
459242551e99SRandall Stewart 		 * SACK processing
4593f8829a4aSRandall Stewart 		 */
4594f8829a4aSRandall Stewart 		net->new_pseudo_cumack = 0;
4595f8829a4aSRandall Stewart 		net->will_exit_fast_recovery = 0;
4596299108c5SRandall Stewart 		if (stcb->asoc.cc_functions.sctp_cwnd_prepare_net_for_sack) {
4597299108c5SRandall Stewart 			(*stcb->asoc.cc_functions.sctp_cwnd_prepare_net_for_sack) (stcb, net);
4598299108c5SRandall Stewart 		}
45990053ed28SMichael Tuexen 
4600e9a3a1b1SMichael Tuexen 		/*
4601e9a3a1b1SMichael Tuexen 		 * CMT: SFR algo (and HTNA) - this_sack_highest_newack has
4602e9a3a1b1SMichael Tuexen 		 * to be greater than the cumack. Also reset saw_newack to 0
4603e9a3a1b1SMichael Tuexen 		 * for all dests.
4604e9a3a1b1SMichael Tuexen 		 */
4605e9a3a1b1SMichael Tuexen 		net->saw_newack = 0;
4606e9a3a1b1SMichael Tuexen 		net->this_sack_highest_newack = last_tsn;
4607f8829a4aSRandall Stewart 	}
4608f8829a4aSRandall Stewart 	/* process the new consecutive TSN first */
46094a9ef3f8SMichael Tuexen 	TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
461049656eefSMichael Tuexen 		if (SCTP_TSN_GE(last_tsn, tp1->rec.data.tsn)) {
4611f8829a4aSRandall Stewart 			if (tp1->sent != SCTP_DATAGRAM_UNSENT) {
4612f8829a4aSRandall Stewart 				accum_moved = 1;
4613f8829a4aSRandall Stewart 				if (tp1->sent < SCTP_DATAGRAM_ACKED) {
4614f8829a4aSRandall Stewart 					/*
4615f8829a4aSRandall Stewart 					 * If it is less than ACKED, it is
4616f8829a4aSRandall Stewart 					 * now no-longer in flight. Higher
4617f8829a4aSRandall Stewart 					 * values may occur during marking
4618f8829a4aSRandall Stewart 					 */
4619f8829a4aSRandall Stewart 					if ((tp1->whoTo->dest_state &
4620f8829a4aSRandall Stewart 					    SCTP_ADDR_UNCONFIRMED) &&
4621f8829a4aSRandall Stewart 					    (tp1->snd_count < 2)) {
4622f8829a4aSRandall Stewart 						/*
4623f8829a4aSRandall Stewart 						 * If there was no retran
4624f8829a4aSRandall Stewart 						 * and the address is
4625f8829a4aSRandall Stewart 						 * un-confirmed and we sent
4626f8829a4aSRandall Stewart 						 * there and are now
4627f8829a4aSRandall Stewart 						 * sacked.. its confirmed,
4628f8829a4aSRandall Stewart 						 * mark it so.
4629f8829a4aSRandall Stewart 						 */
4630f8829a4aSRandall Stewart 						tp1->whoTo->dest_state &=
4631f8829a4aSRandall Stewart 						    ~SCTP_ADDR_UNCONFIRMED;
4632f8829a4aSRandall Stewart 					}
4633c105859eSRandall Stewart 					if (tp1->sent < SCTP_DATAGRAM_RESEND) {
4634b3f1ea41SRandall Stewart 						if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) {
4635c105859eSRandall Stewart 							sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_CA,
4636a5d547adSRandall Stewart 							    tp1->whoTo->flight_size,
4637a5d547adSRandall Stewart 							    tp1->book_size,
46389a8e3088SMichael Tuexen 							    (uint32_t)(uintptr_t)tp1->whoTo,
463949656eefSMichael Tuexen 							    tp1->rec.data.tsn);
464080fefe0aSRandall Stewart 						}
4641c105859eSRandall Stewart 						sctp_flight_size_decrease(tp1);
4642c105859eSRandall Stewart 						sctp_total_flight_decrease(stcb, tp1);
4643299108c5SRandall Stewart 						if (stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) {
4644299108c5SRandall Stewart 							(*stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) (tp1->whoTo,
4645299108c5SRandall Stewart 							    tp1);
4646299108c5SRandall Stewart 						}
4647f8829a4aSRandall Stewart 					}
4648f8829a4aSRandall Stewart 					tp1->whoTo->net_ack += tp1->send_size;
4649f8829a4aSRandall Stewart 
4650f8829a4aSRandall Stewart 					/* CMT SFR and DAC algos */
465149656eefSMichael Tuexen 					this_sack_lowest_newack = tp1->rec.data.tsn;
4652f8829a4aSRandall Stewart 					tp1->whoTo->saw_newack = 1;
4653f8829a4aSRandall Stewart 
4654f8829a4aSRandall Stewart 					if (tp1->snd_count < 2) {
4655f8829a4aSRandall Stewart 						/*
4656ab9ed8a1SDevin Teske 						 * True non-retransmitted
4657f8829a4aSRandall Stewart 						 * chunk
4658f8829a4aSRandall Stewart 						 */
4659f8829a4aSRandall Stewart 						tp1->whoTo->net_ack2 +=
4660f8829a4aSRandall Stewart 						    tp1->send_size;
4661f8829a4aSRandall Stewart 
4662f8829a4aSRandall Stewart 						/* update RTO too? */
4663f8829a4aSRandall Stewart 						if (tp1->do_rtt) {
466444f2a327SMichael Tuexen 							if (rto_ok &&
4665f8829a4aSRandall Stewart 							    sctp_calculate_rto(stcb,
466644f2a327SMichael Tuexen 							    &stcb->asoc,
466744f2a327SMichael Tuexen 							    tp1->whoTo,
466818e198d3SRandall Stewart 							    &tp1->sent_rcv_time,
466944f2a327SMichael Tuexen 							    SCTP_RTT_FROM_DATA)) {
4670f79aab18SRandall Stewart 								rto_ok = 0;
4671f79aab18SRandall Stewart 							}
4672f79aab18SRandall Stewart 							if (tp1->whoTo->rto_needed == 0) {
4673f79aab18SRandall Stewart 								tp1->whoTo->rto_needed = 1;
4674f79aab18SRandall Stewart 							}
4675f8829a4aSRandall Stewart 							tp1->do_rtt = 0;
4676f8829a4aSRandall Stewart 						}
4677f8829a4aSRandall Stewart 					}
4678f8829a4aSRandall Stewart 					/*
4679f8829a4aSRandall Stewart 					 * CMT: CUCv2 algorithm. From the
4680f8829a4aSRandall Stewart 					 * cumack'd TSNs, for each TSN being
4681f8829a4aSRandall Stewart 					 * acked for the first time, set the
4682f8829a4aSRandall Stewart 					 * following variables for the
4683f8829a4aSRandall Stewart 					 * corresp destination.
4684f8829a4aSRandall Stewart 					 * new_pseudo_cumack will trigger a
4685f8829a4aSRandall Stewart 					 * cwnd update.
4686f8829a4aSRandall Stewart 					 * find_(rtx_)pseudo_cumack will
4687f8829a4aSRandall Stewart 					 * trigger search for the next
4688f8829a4aSRandall Stewart 					 * expected (rtx-)pseudo-cumack.
4689f8829a4aSRandall Stewart 					 */
4690f8829a4aSRandall Stewart 					tp1->whoTo->new_pseudo_cumack = 1;
4691f8829a4aSRandall Stewart 					tp1->whoTo->find_pseudo_cumack = 1;
4692f8829a4aSRandall Stewart 					tp1->whoTo->find_rtx_pseudo_cumack = 1;
4693b3f1ea41SRandall Stewart 					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) {
4694f8829a4aSRandall Stewart 						sctp_log_sack(asoc->last_acked_seq,
4695f8829a4aSRandall Stewart 						    cum_ack,
469649656eefSMichael Tuexen 						    tp1->rec.data.tsn,
4697f8829a4aSRandall Stewart 						    0,
4698f8829a4aSRandall Stewart 						    0,
4699f8829a4aSRandall Stewart 						    SCTP_LOG_TSN_ACKED);
470080fefe0aSRandall Stewart 					}
4701b3f1ea41SRandall Stewart 					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
470249656eefSMichael Tuexen 						sctp_log_cwnd(stcb, tp1->whoTo, tp1->rec.data.tsn, SCTP_CWND_LOG_FROM_SACK);
470380fefe0aSRandall Stewart 					}
4704f8829a4aSRandall Stewart 				}
4705f8829a4aSRandall Stewart 				if (tp1->sent == SCTP_DATAGRAM_RESEND) {
4706f8829a4aSRandall Stewart 					sctp_ucount_decr(asoc->sent_queue_retran_cnt);
4707f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED
4708f8829a4aSRandall Stewart 					sctp_audit_log(0xB3,
4709f8829a4aSRandall Stewart 					    (asoc->sent_queue_retran_cnt & 0x000000ff));
4710f8829a4aSRandall Stewart #endif
4711f8829a4aSRandall Stewart 				}
471242551e99SRandall Stewart 				if (tp1->rec.data.chunk_was_revoked) {
471342551e99SRandall Stewart 					/* deflate the cwnd */
471442551e99SRandall Stewart 					tp1->whoTo->cwnd -= tp1->book_size;
471542551e99SRandall Stewart 					tp1->rec.data.chunk_was_revoked = 0;
471642551e99SRandall Stewart 				}
4717325c8c46SMichael Tuexen 				if (tp1->sent != SCTP_DATAGRAM_NR_ACKED) {
4718f8829a4aSRandall Stewart 					tp1->sent = SCTP_DATAGRAM_ACKED;
4719f8829a4aSRandall Stewart 				}
4720325c8c46SMichael Tuexen 			}
4721f8829a4aSRandall Stewart 		} else {
4722f8829a4aSRandall Stewart 			break;
4723f8829a4aSRandall Stewart 		}
4724f8829a4aSRandall Stewart 	}
4725f8829a4aSRandall Stewart 	biggest_tsn_newly_acked = biggest_tsn_acked = last_tsn;
4726f8829a4aSRandall Stewart 	/* always set this up to cum-ack */
4727f8829a4aSRandall Stewart 	asoc->this_sack_highest_gap = last_tsn;
4728f8829a4aSRandall Stewart 
4729cd554309SMichael Tuexen 	if ((num_seg > 0) || (num_nr_seg > 0)) {
4730f8829a4aSRandall Stewart 		/*
4731f8829a4aSRandall Stewart 		 * thisSackHighestGap will increase while handling NEW
4732f8829a4aSRandall Stewart 		 * segments this_sack_highest_newack will increase while
4733f8829a4aSRandall Stewart 		 * handling NEWLY ACKED chunks. this_sack_lowest_newack is
4734f8829a4aSRandall Stewart 		 * used for CMT DAC algo. saw_newack will also change.
4735f8829a4aSRandall Stewart 		 */
4736cd554309SMichael Tuexen 		if (sctp_handle_segments(m, &offset_seg, stcb, asoc, last_tsn, &biggest_tsn_acked,
4737cd554309SMichael Tuexen 		    &biggest_tsn_newly_acked, &this_sack_lowest_newack,
47387215cc1bSMichael Tuexen 		    num_seg, num_nr_seg, &rto_ok)) {
4739cd554309SMichael Tuexen 			wake_him++;
4740cd554309SMichael Tuexen 		}
4741f8829a4aSRandall Stewart 		/*
4742fd60718dSMichael Tuexen 		 * validate the biggest_tsn_acked in the gap acks if strict
4743fd60718dSMichael Tuexen 		 * adherence is wanted.
4744f8829a4aSRandall Stewart 		 */
474520b07a4dSMichael Tuexen 		if (SCTP_TSN_GE(biggest_tsn_acked, send_s)) {
4746f8829a4aSRandall Stewart 			/*
4747fd60718dSMichael Tuexen 			 * peer is either confused or we are under attack.
4748fd60718dSMichael Tuexen 			 * We must abort.
4749f8829a4aSRandall Stewart 			 */
4750cd3fd531SMichael Tuexen 			SCTP_PRINTF("Hopeless peer! biggest_tsn_acked:%x largest seq:%x\n",
4751cd3fd531SMichael Tuexen 			    biggest_tsn_acked, send_s);
4752f8829a4aSRandall Stewart 			goto hopeless_peer;
4753f8829a4aSRandall Stewart 		}
4754f8829a4aSRandall Stewart 	}
4755f8829a4aSRandall Stewart 	/*******************************************/
4756f8829a4aSRandall Stewart 	/* cancel ALL T3-send timer if accum moved */
4757f8829a4aSRandall Stewart 	/*******************************************/
47587c99d56fSMichael Tuexen 	if (asoc->sctp_cmt_on_off > 0) {
4759f8829a4aSRandall Stewart 		TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
4760f8829a4aSRandall Stewart 			if (net->new_pseudo_cumack)
4761f8829a4aSRandall Stewart 				sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
4762a5d547adSRandall Stewart 				    stcb, net,
476391e04f9eSMichael Tuexen 				    SCTP_FROM_SCTP_INDATA + SCTP_LOC_31);
4764f8829a4aSRandall Stewart 		}
4765f8829a4aSRandall Stewart 	} else {
4766f8829a4aSRandall Stewart 		if (accum_moved) {
4767f8829a4aSRandall Stewart 			TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
4768f8829a4aSRandall Stewart 				sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
476991e04f9eSMichael Tuexen 				    stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_32);
4770f8829a4aSRandall Stewart 			}
4771f8829a4aSRandall Stewart 		}
4772f8829a4aSRandall Stewart 	}
4773f8829a4aSRandall Stewart 	/********************************************/
4774d9c5cfeaSMichael Tuexen 	/* drop the acked chunks from the sentqueue */
4775f8829a4aSRandall Stewart 	/********************************************/
4776f8829a4aSRandall Stewart 	asoc->last_acked_seq = cum_ack;
4777f8829a4aSRandall Stewart 
47787c99d56fSMichael Tuexen 	TAILQ_FOREACH_SAFE(tp1, &asoc->sent_queue, sctp_next, tp2) {
477949656eefSMichael Tuexen 		if (SCTP_TSN_GT(tp1->rec.data.tsn, cum_ack)) {
4780f8829a4aSRandall Stewart 			break;
4781f8829a4aSRandall Stewart 		}
4782325c8c46SMichael Tuexen 		if (tp1->sent != SCTP_DATAGRAM_NR_ACKED) {
478349656eefSMichael Tuexen 			if (asoc->strmout[tp1->rec.data.sid].chunks_on_queues > 0) {
478449656eefSMichael Tuexen 				asoc->strmout[tp1->rec.data.sid].chunks_on_queues--;
4785a7ad6026SMichael Tuexen #ifdef INVARIANTS
4786a7ad6026SMichael Tuexen 			} else {
478749656eefSMichael Tuexen 				panic("No chunks on the queues for sid %u.", tp1->rec.data.sid);
4788a7ad6026SMichael Tuexen #endif
4789a7ad6026SMichael Tuexen 			}
4790f8829a4aSRandall Stewart 		}
479149656eefSMichael Tuexen 		if ((asoc->strmout[tp1->rec.data.sid].chunks_on_queues == 0) &&
479249656eefSMichael Tuexen 		    (asoc->strmout[tp1->rec.data.sid].state == SCTP_STREAM_RESET_PENDING) &&
479349656eefSMichael Tuexen 		    TAILQ_EMPTY(&asoc->strmout[tp1->rec.data.sid].outqueue)) {
4794d96bef9cSMichael Tuexen 			asoc->trigger_reset = 1;
4795d96bef9cSMichael Tuexen 		}
4796f8829a4aSRandall Stewart 		TAILQ_REMOVE(&asoc->sent_queue, tp1, sctp_next);
47970ddb4299SMichael Tuexen 		if (PR_SCTP_ENABLED(tp1->flags)) {
4798f8829a4aSRandall Stewart 			if (asoc->pr_sctp_cnt != 0)
4799f8829a4aSRandall Stewart 				asoc->pr_sctp_cnt--;
4800f8829a4aSRandall Stewart 		}
48017c99d56fSMichael Tuexen 		asoc->sent_queue_cnt--;
4802f8829a4aSRandall Stewart 		if (tp1->data) {
480304ee05e8SRandall Stewart 			/* sa_ignore NO_NULL_CHK */
4804f8829a4aSRandall Stewart 			sctp_free_bufspace(stcb, asoc, tp1, 1);
4805f8829a4aSRandall Stewart 			sctp_m_freem(tp1->data);
48067c99d56fSMichael Tuexen 			tp1->data = NULL;
4807dd973b0eSMichael Tuexen 			if (asoc->prsctp_supported && PR_SCTP_BUF_ENABLED(tp1->flags)) {
4808f8829a4aSRandall Stewart 				asoc->sent_queue_cnt_removeable--;
4809f8829a4aSRandall Stewart 			}
4810f8829a4aSRandall Stewart 		}
4811b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) {
4812f8829a4aSRandall Stewart 			sctp_log_sack(asoc->last_acked_seq,
4813f8829a4aSRandall Stewart 			    cum_ack,
481449656eefSMichael Tuexen 			    tp1->rec.data.tsn,
4815f8829a4aSRandall Stewart 			    0,
4816f8829a4aSRandall Stewart 			    0,
4817f8829a4aSRandall Stewart 			    SCTP_LOG_FREE_SENT);
481880fefe0aSRandall Stewart 		}
4819689e6a5fSMichael Tuexen 		sctp_free_a_chunk(stcb, tp1, SCTP_SO_NOT_LOCKED);
4820f8829a4aSRandall Stewart 		wake_him++;
48217c99d56fSMichael Tuexen 	}
48227c99d56fSMichael Tuexen 	if (TAILQ_EMPTY(&asoc->sent_queue) && (asoc->total_flight > 0)) {
48237c99d56fSMichael Tuexen #ifdef INVARIANTS
4824cd0a4ff6SPedro F. Giffuni 		panic("Warning flight size is positive and should be 0");
48257c99d56fSMichael Tuexen #else
48267c99d56fSMichael Tuexen 		SCTP_PRINTF("Warning flight size incorrect should be 0 is %d\n",
48277c99d56fSMichael Tuexen 		    asoc->total_flight);
48287c99d56fSMichael Tuexen #endif
48297c99d56fSMichael Tuexen 		asoc->total_flight = 0;
48307c99d56fSMichael Tuexen 	}
48310053ed28SMichael Tuexen 
483204ee05e8SRandall Stewart 	/* sa_ignore NO_NULL_CHK */
4833f8829a4aSRandall Stewart 	if ((wake_him) && (stcb->sctp_socket)) {
4834f8829a4aSRandall Stewart 		SOCKBUF_LOCK(&stcb->sctp_socket->so_snd);
4835b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_WAKE_LOGGING_ENABLE) {
48367215cc1bSMichael Tuexen 			sctp_wakeup_log(stcb, wake_him, SCTP_WAKESND_FROM_SACK);
483780fefe0aSRandall Stewart 		}
4838f8829a4aSRandall Stewart 		sctp_sowwakeup_locked(stcb->sctp_ep, stcb->sctp_socket);
4839f8829a4aSRandall Stewart 	} else {
4840b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_WAKE_LOGGING_ENABLE) {
48417215cc1bSMichael Tuexen 			sctp_wakeup_log(stcb, wake_him, SCTP_NOWAKE_FROM_SACK);
484280fefe0aSRandall Stewart 		}
4843f8829a4aSRandall Stewart 	}
4844f8829a4aSRandall Stewart 
484542551e99SRandall Stewart 	if (asoc->fast_retran_loss_recovery && accum_moved) {
484620b07a4dSMichael Tuexen 		if (SCTP_TSN_GE(asoc->last_acked_seq, asoc->fast_recovery_tsn)) {
4847f8829a4aSRandall Stewart 			/* Setup so we will exit RFC2582 fast recovery */
4848f8829a4aSRandall Stewart 			will_exit_fast_recovery = 1;
4849f8829a4aSRandall Stewart 		}
4850f8829a4aSRandall Stewart 	}
4851f8829a4aSRandall Stewart 	/*
4852f8829a4aSRandall Stewart 	 * Check for revoked fragments:
4853f8829a4aSRandall Stewart 	 *
4854f8829a4aSRandall Stewart 	 * if Previous sack - Had no frags then we can't have any revoked if
4855f8829a4aSRandall Stewart 	 * Previous sack - Had frag's then - If we now have frags aka
4856f8829a4aSRandall Stewart 	 * num_seg > 0 call sctp_check_for_revoked() to tell if peer revoked
4857f8829a4aSRandall Stewart 	 * some of them. else - The peer revoked all ACKED fragments, since
4858f8829a4aSRandall Stewart 	 * we had some before and now we have NONE.
4859f8829a4aSRandall Stewart 	 */
4860f8829a4aSRandall Stewart 
4861d9c5cfeaSMichael Tuexen 	if (num_seg) {
4862c105859eSRandall Stewart 		sctp_check_for_revoked(stcb, asoc, cum_ack, biggest_tsn_acked);
4863d9c5cfeaSMichael Tuexen 		asoc->saw_sack_with_frags = 1;
4864d9c5cfeaSMichael Tuexen 	} else if (asoc->saw_sack_with_frags) {
4865f8829a4aSRandall Stewart 		int cnt_revoked = 0;
4866f8829a4aSRandall Stewart 
4867f8829a4aSRandall Stewart 		/* Peer revoked all dg's marked or acked */
4868f8829a4aSRandall Stewart 		TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
4869b5c16493SMichael Tuexen 			if (tp1->sent == SCTP_DATAGRAM_ACKED) {
4870f8829a4aSRandall Stewart 				tp1->sent = SCTP_DATAGRAM_SENT;
4871b3f1ea41SRandall Stewart 				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) {
4872c105859eSRandall Stewart 					sctp_misc_ints(SCTP_FLIGHT_LOG_UP_REVOKE,
4873c105859eSRandall Stewart 					    tp1->whoTo->flight_size,
4874c105859eSRandall Stewart 					    tp1->book_size,
48759a8e3088SMichael Tuexen 					    (uint32_t)(uintptr_t)tp1->whoTo,
487649656eefSMichael Tuexen 					    tp1->rec.data.tsn);
487780fefe0aSRandall Stewart 				}
4878c105859eSRandall Stewart 				sctp_flight_size_increase(tp1);
4879c105859eSRandall Stewart 				sctp_total_flight_increase(stcb, tp1);
4880a5d547adSRandall Stewart 				tp1->rec.data.chunk_was_revoked = 1;
488142551e99SRandall Stewart 				/*
488242551e99SRandall Stewart 				 * To ensure that this increase in
48834a9ef3f8SMichael Tuexen 				 * flightsize, which is artificial, does not
48844a9ef3f8SMichael Tuexen 				 * throttle the sender, we also increase the
48854a9ef3f8SMichael Tuexen 				 * cwnd artificially.
488642551e99SRandall Stewart 				 */
488742551e99SRandall Stewart 				tp1->whoTo->cwnd += tp1->book_size;
4888f8829a4aSRandall Stewart 				cnt_revoked++;
4889f8829a4aSRandall Stewart 			}
4890f8829a4aSRandall Stewart 		}
4891f8829a4aSRandall Stewart 		if (cnt_revoked) {
4892f8829a4aSRandall Stewart 			reneged_all = 1;
4893f8829a4aSRandall Stewart 		}
4894f8829a4aSRandall Stewart 		asoc->saw_sack_with_frags = 0;
4895f8829a4aSRandall Stewart 	}
4896d9c5cfeaSMichael Tuexen 	if (num_nr_seg > 0)
4897d9c5cfeaSMichael Tuexen 		asoc->saw_sack_with_nr_frags = 1;
4898f8829a4aSRandall Stewart 	else
4899d9c5cfeaSMichael Tuexen 		asoc->saw_sack_with_nr_frags = 0;
4900f8829a4aSRandall Stewart 
4901b54d3a6cSRandall Stewart 	/* JRS - Use the congestion control given in the CC module */
4902ca85e948SMichael Tuexen 	if (ecne_seen == 0) {
4903ca85e948SMichael Tuexen 		TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
4904ca85e948SMichael Tuexen 			if (net->net_ack2 > 0) {
4905ca85e948SMichael Tuexen 				/*
4906ca85e948SMichael Tuexen 				 * Karn's rule applies to clearing error
4907ca85e948SMichael Tuexen 				 * count, this is optional.
4908ca85e948SMichael Tuexen 				 */
4909ca85e948SMichael Tuexen 				net->error_count = 0;
4910ca85e948SMichael Tuexen 				if (!(net->dest_state & SCTP_ADDR_REACHABLE)) {
4911ca85e948SMichael Tuexen 					/* addr came good */
4912ca85e948SMichael Tuexen 					net->dest_state |= SCTP_ADDR_REACHABLE;
4913ca85e948SMichael Tuexen 					sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb,
49144b1f78e1SMichael Tuexen 					    0, (void *)net, SCTP_SO_NOT_LOCKED);
4915ca85e948SMichael Tuexen 				}
49160053ed28SMichael Tuexen 
4917ca85e948SMichael Tuexen 				if (net == stcb->asoc.primary_destination) {
4918ca85e948SMichael Tuexen 					if (stcb->asoc.alternate) {
4919b7b84c0eSMichael Tuexen 						/*
4920b7b84c0eSMichael Tuexen 						 * release the alternate,
4921b7b84c0eSMichael Tuexen 						 * primary is good
4922b7b84c0eSMichael Tuexen 						 */
4923ca85e948SMichael Tuexen 						sctp_free_remote_addr(stcb->asoc.alternate);
4924ca85e948SMichael Tuexen 						stcb->asoc.alternate = NULL;
4925ca85e948SMichael Tuexen 					}
4926ca85e948SMichael Tuexen 				}
49270053ed28SMichael Tuexen 
4928ca85e948SMichael Tuexen 				if (net->dest_state & SCTP_ADDR_PF) {
4929ca85e948SMichael Tuexen 					net->dest_state &= ~SCTP_ADDR_PF;
4930b7d130beSMichael Tuexen 					sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT,
4931b7d130beSMichael Tuexen 					    stcb->sctp_ep, stcb, net,
493291e04f9eSMichael Tuexen 					    SCTP_FROM_SCTP_INDATA + SCTP_LOC_33);
4933ca85e948SMichael Tuexen 					sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
4934ca85e948SMichael Tuexen 					asoc->cc_functions.sctp_cwnd_update_exit_pf(stcb, net);
4935ca85e948SMichael Tuexen 					/* Done with this net */
4936ca85e948SMichael Tuexen 					net->net_ack = 0;
4937ca85e948SMichael Tuexen 				}
4938ca85e948SMichael Tuexen 				/* restore any doubled timers */
4939ca85e948SMichael Tuexen 				net->RTO = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv;
4940ca85e948SMichael Tuexen 				if (net->RTO < stcb->asoc.minrto) {
4941ca85e948SMichael Tuexen 					net->RTO = stcb->asoc.minrto;
4942ca85e948SMichael Tuexen 				}
4943ca85e948SMichael Tuexen 				if (net->RTO > stcb->asoc.maxrto) {
4944ca85e948SMichael Tuexen 					net->RTO = stcb->asoc.maxrto;
4945ca85e948SMichael Tuexen 				}
4946ca85e948SMichael Tuexen 			}
4947ca85e948SMichael Tuexen 		}
4948b54d3a6cSRandall Stewart 		asoc->cc_functions.sctp_cwnd_update_after_sack(stcb, asoc, accum_moved, reneged_all, will_exit_fast_recovery);
4949ca85e948SMichael Tuexen 	}
49500053ed28SMichael Tuexen 
4951f8829a4aSRandall Stewart 	if (TAILQ_EMPTY(&asoc->sent_queue)) {
4952f8829a4aSRandall Stewart 		/* nothing left in-flight */
4953f8829a4aSRandall Stewart 		TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
4954f8829a4aSRandall Stewart 			/* stop all timers */
4955f8829a4aSRandall Stewart 			sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
4956b7d130beSMichael Tuexen 			    stcb, net,
495791e04f9eSMichael Tuexen 			    SCTP_FROM_SCTP_INDATA + SCTP_LOC_34);
4958f8829a4aSRandall Stewart 			net->flight_size = 0;
4959f8829a4aSRandall Stewart 			net->partial_bytes_acked = 0;
4960f8829a4aSRandall Stewart 		}
4961f8829a4aSRandall Stewart 		asoc->total_flight = 0;
4962f8829a4aSRandall Stewart 		asoc->total_flight_count = 0;
4963f8829a4aSRandall Stewart 	}
49640053ed28SMichael Tuexen 
4965f8829a4aSRandall Stewart 	/**********************************/
4966f8829a4aSRandall Stewart 	/* Now what about shutdown issues */
4967f8829a4aSRandall Stewart 	/**********************************/
4968f8829a4aSRandall Stewart 	if (TAILQ_EMPTY(&asoc->send_queue) && TAILQ_EMPTY(&asoc->sent_queue)) {
4969f8829a4aSRandall Stewart 		/* nothing left on sendqueue.. consider done */
4970b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_RWND_ENABLE) {
4971f8829a4aSRandall Stewart 			sctp_log_rwnd_set(SCTP_SET_PEER_RWND_VIA_SACK,
4972f8829a4aSRandall Stewart 			    asoc->peers_rwnd, 0, 0, a_rwnd);
497380fefe0aSRandall Stewart 		}
4974f8829a4aSRandall Stewart 		asoc->peers_rwnd = a_rwnd;
4975f8829a4aSRandall Stewart 		if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) {
4976f8829a4aSRandall Stewart 			/* SWS sender side engages */
4977f8829a4aSRandall Stewart 			asoc->peers_rwnd = 0;
4978f8829a4aSRandall Stewart 		}
4979f8829a4aSRandall Stewart 		/* clean up */
4980f8829a4aSRandall Stewart 		if ((asoc->stream_queue_cnt == 1) &&
4981f8829a4aSRandall Stewart 		    ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) ||
4982839d21d6SMichael Tuexen 		    (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) &&
4983d1ea5fa9SMichael Tuexen 		    ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) (stcb, asoc))) {
4984839d21d6SMichael Tuexen 			SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_PARTIAL_MSG_LEFT);
4985f8829a4aSRandall Stewart 		}
4986bbc9dfbcSMichael Tuexen 		if (((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) ||
4987839d21d6SMichael Tuexen 		    (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) &&
4988bbc9dfbcSMichael Tuexen 		    (asoc->stream_queue_cnt == 1) &&
4989bbc9dfbcSMichael Tuexen 		    (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) {
4990ff1ffd74SMichael Tuexen 			struct mbuf *op_err;
4991f8829a4aSRandall Stewart 
4992f8829a4aSRandall Stewart 			*abort_now = 1;
4993f8829a4aSRandall Stewart 			/* XXX */
4994ff1ffd74SMichael Tuexen 			op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
499591e04f9eSMichael Tuexen 			stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_35;
4996ff1ffd74SMichael Tuexen 			sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
4997f8829a4aSRandall Stewart 			return;
4998bbc9dfbcSMichael Tuexen 		}
4999bbc9dfbcSMichael Tuexen 		if ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) &&
5000bbc9dfbcSMichael Tuexen 		    (asoc->stream_queue_cnt == 0)) {
5001ca85e948SMichael Tuexen 			struct sctp_nets *netp;
5002ca85e948SMichael Tuexen 
5003839d21d6SMichael Tuexen 			if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) ||
5004839d21d6SMichael Tuexen 			    (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
5005f8829a4aSRandall Stewart 				SCTP_STAT_DECR_GAUGE32(sctps_currestab);
5006f42a358aSRandall Stewart 			}
5007839d21d6SMichael Tuexen 			SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_SENT);
5008f8829a4aSRandall Stewart 			sctp_stop_timers_for_shutdown(stcb);
5009c39cfa1fSMichael Tuexen 			if (asoc->alternate) {
5010c39cfa1fSMichael Tuexen 				netp = asoc->alternate;
5011c39cfa1fSMichael Tuexen 			} else {
5012c39cfa1fSMichael Tuexen 				netp = asoc->primary_destination;
5013c39cfa1fSMichael Tuexen 			}
5014ca85e948SMichael Tuexen 			sctp_send_shutdown(stcb, netp);
5015f8829a4aSRandall Stewart 			sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
5016ca85e948SMichael Tuexen 			    stcb->sctp_ep, stcb, netp);
5017f8829a4aSRandall Stewart 			sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
50186fb7b4fbSMichael Tuexen 			    stcb->sctp_ep, stcb, NULL);
5019f8829a4aSRandall Stewart 			return;
5020839d21d6SMichael Tuexen 		} else if ((SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED) &&
5021f8829a4aSRandall Stewart 		    (asoc->stream_queue_cnt == 0)) {
5022ca85e948SMichael Tuexen 			struct sctp_nets *netp;
5023ca85e948SMichael Tuexen 
5024f8829a4aSRandall Stewart 			SCTP_STAT_DECR_GAUGE32(sctps_currestab);
5025839d21d6SMichael Tuexen 			SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_ACK_SENT);
502612af6654SMichael Tuexen 			sctp_stop_timers_for_shutdown(stcb);
5027c39cfa1fSMichael Tuexen 			if (asoc->alternate) {
5028c39cfa1fSMichael Tuexen 				netp = asoc->alternate;
5029c39cfa1fSMichael Tuexen 			} else {
5030c39cfa1fSMichael Tuexen 				netp = asoc->primary_destination;
5031c39cfa1fSMichael Tuexen 			}
5032c39cfa1fSMichael Tuexen 			sctp_send_shutdown_ack(stcb, netp);
5033f8829a4aSRandall Stewart 			sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK,
5034ca85e948SMichael Tuexen 			    stcb->sctp_ep, stcb, netp);
5035f8829a4aSRandall Stewart 			return;
5036f8829a4aSRandall Stewart 		}
5037f8829a4aSRandall Stewart 	}
5038f8829a4aSRandall Stewart 	/*
5039f8829a4aSRandall Stewart 	 * Now here we are going to recycle net_ack for a different use...
5040f8829a4aSRandall Stewart 	 * HEADS UP.
5041f8829a4aSRandall Stewart 	 */
5042f8829a4aSRandall Stewart 	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
5043f8829a4aSRandall Stewart 		net->net_ack = 0;
5044f8829a4aSRandall Stewart 	}
5045f8829a4aSRandall Stewart 
5046f8829a4aSRandall Stewart 	/*
5047f8829a4aSRandall Stewart 	 * CMT DAC algorithm: If SACK DAC flag was 0, then no extra marking
5048f8829a4aSRandall Stewart 	 * to be done. Setting this_sack_lowest_newack to the cum_ack will
5049f8829a4aSRandall Stewart 	 * automatically ensure that.
5050f8829a4aSRandall Stewart 	 */
50517c99d56fSMichael Tuexen 	if ((asoc->sctp_cmt_on_off > 0) &&
505220083c2eSMichael Tuexen 	    SCTP_BASE_SYSCTL(sctp_cmt_use_dac) &&
505320083c2eSMichael Tuexen 	    (cmt_dac_flag == 0)) {
5054f8829a4aSRandall Stewart 		this_sack_lowest_newack = cum_ack;
5055f8829a4aSRandall Stewart 	}
5056cd554309SMichael Tuexen 	if ((num_seg > 0) || (num_nr_seg > 0)) {
5057f8829a4aSRandall Stewart 		sctp_strike_gap_ack_chunks(stcb, asoc, biggest_tsn_acked,
5058f8829a4aSRandall Stewart 		    biggest_tsn_newly_acked, this_sack_lowest_newack, accum_moved);
5059f8829a4aSRandall Stewart 	}
5060b54d3a6cSRandall Stewart 	/* JRS - Use the congestion control given in the CC module */
5061b54d3a6cSRandall Stewart 	asoc->cc_functions.sctp_cwnd_update_after_fr(stcb, asoc);
5062f8829a4aSRandall Stewart 
5063f8829a4aSRandall Stewart 	/* Now are we exiting loss recovery ? */
5064f8829a4aSRandall Stewart 	if (will_exit_fast_recovery) {
5065f8829a4aSRandall Stewart 		/* Ok, we must exit fast recovery */
5066f8829a4aSRandall Stewart 		asoc->fast_retran_loss_recovery = 0;
5067f8829a4aSRandall Stewart 	}
5068f8829a4aSRandall Stewart 	if ((asoc->sat_t3_loss_recovery) &&
506920b07a4dSMichael Tuexen 	    SCTP_TSN_GE(asoc->last_acked_seq, asoc->sat_t3_recovery_tsn)) {
5070f8829a4aSRandall Stewart 		/* end satellite t3 loss recovery */
5071f8829a4aSRandall Stewart 		asoc->sat_t3_loss_recovery = 0;
5072f8829a4aSRandall Stewart 	}
507342551e99SRandall Stewart 	/*
507442551e99SRandall Stewart 	 * CMT Fast recovery
507542551e99SRandall Stewart 	 */
5076f8829a4aSRandall Stewart 	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
5077f8829a4aSRandall Stewart 		if (net->will_exit_fast_recovery) {
5078f8829a4aSRandall Stewart 			/* Ok, we must exit fast recovery */
5079f8829a4aSRandall Stewart 			net->fast_retran_loss_recovery = 0;
5080f8829a4aSRandall Stewart 		}
5081f8829a4aSRandall Stewart 	}
5082f8829a4aSRandall Stewart 
5083f8829a4aSRandall Stewart 	/* Adjust and set the new rwnd value */
5084b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_RWND_ENABLE) {
5085f8829a4aSRandall Stewart 		sctp_log_rwnd_set(SCTP_SET_PEER_RWND_VIA_SACK,
508644fbe462SRandall Stewart 		    asoc->peers_rwnd, asoc->total_flight, (asoc->total_flight_count * SCTP_BASE_SYSCTL(sctp_peer_chunk_oh)), a_rwnd);
508780fefe0aSRandall Stewart 	}
5088f8829a4aSRandall Stewart 	asoc->peers_rwnd = sctp_sbspace_sub(a_rwnd,
508944fbe462SRandall Stewart 	    (uint32_t)(asoc->total_flight + (asoc->total_flight_count * SCTP_BASE_SYSCTL(sctp_peer_chunk_oh))));
5090f8829a4aSRandall Stewart 	if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) {
5091f8829a4aSRandall Stewart 		/* SWS sender side engages */
5092f8829a4aSRandall Stewart 		asoc->peers_rwnd = 0;
5093f8829a4aSRandall Stewart 	}
50945e54f665SRandall Stewart 	if (asoc->peers_rwnd > old_rwnd) {
50955e54f665SRandall Stewart 		win_probe_recovery = 1;
50965e54f665SRandall Stewart 	}
50970053ed28SMichael Tuexen 
5098f8829a4aSRandall Stewart 	/*
5099f8829a4aSRandall Stewart 	 * Now we must setup so we have a timer up for anyone with
5100f8829a4aSRandall Stewart 	 * outstanding data.
5101f8829a4aSRandall Stewart 	 */
5102bff64a4dSRandall Stewart 	done_once = 0;
5103a5d547adSRandall Stewart again:
5104a5d547adSRandall Stewart 	j = 0;
5105f8829a4aSRandall Stewart 	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
51065e54f665SRandall Stewart 		if (win_probe_recovery && (net->window_probe)) {
5107c105859eSRandall Stewart 			win_probe_recovered = 1;
51085e54f665SRandall Stewart 			/*-
51095e54f665SRandall Stewart 			 * Find first chunk that was used with
51105e54f665SRandall Stewart 			 * window probe and clear the event. Put
51115e54f665SRandall Stewart 			 * it back into the send queue as if has
51125e54f665SRandall Stewart 			 * not been sent.
51135e54f665SRandall Stewart 			 */
51145e54f665SRandall Stewart 			TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
51155e54f665SRandall Stewart 				if (tp1->window_probe) {
51167215cc1bSMichael Tuexen 					sctp_window_probe_recovery(stcb, asoc, tp1);
51175e54f665SRandall Stewart 					break;
51185e54f665SRandall Stewart 				}
51195e54f665SRandall Stewart 			}
51205e54f665SRandall Stewart 		}
5121f8829a4aSRandall Stewart 		if (net->flight_size) {
5122a5d547adSRandall Stewart 			j++;
5123cd554309SMichael Tuexen 			if (!SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) {
5124f8829a4aSRandall Stewart 				sctp_timer_start(SCTP_TIMER_TYPE_SEND,
5125f8829a4aSRandall Stewart 				    stcb->sctp_ep, stcb, net);
5126cd554309SMichael Tuexen 			}
51275171328bSRandall Stewart 			if (net->window_probe) {
5128cd554309SMichael Tuexen 				net->window_probe = 0;
51295171328bSRandall Stewart 			}
5130c105859eSRandall Stewart 		} else {
51315171328bSRandall Stewart 			if (net->window_probe) {
5132b7b84c0eSMichael Tuexen 				/*
5133b7b84c0eSMichael Tuexen 				 * In window probes we must assure a timer
5134b7b84c0eSMichael Tuexen 				 * is still running there
5135b7b84c0eSMichael Tuexen 				 */
51365171328bSRandall Stewart 				if (!SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) {
51375171328bSRandall Stewart 					sctp_timer_start(SCTP_TIMER_TYPE_SEND,
51385171328bSRandall Stewart 					    stcb->sctp_ep, stcb, net);
51395171328bSRandall Stewart 				}
51405171328bSRandall Stewart 			} else if (SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) {
5141c105859eSRandall Stewart 				sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
5142c105859eSRandall Stewart 				    stcb, net,
514391e04f9eSMichael Tuexen 				    SCTP_FROM_SCTP_INDATA + SCTP_LOC_36);
5144c105859eSRandall Stewart 			}
5145f8829a4aSRandall Stewart 		}
5146f8829a4aSRandall Stewart 	}
5147bff64a4dSRandall Stewart 	if ((j == 0) &&
5148bff64a4dSRandall Stewart 	    (!TAILQ_EMPTY(&asoc->sent_queue)) &&
5149bff64a4dSRandall Stewart 	    (asoc->sent_queue_retran_cnt == 0) &&
5150c105859eSRandall Stewart 	    (win_probe_recovered == 0) &&
5151bff64a4dSRandall Stewart 	    (done_once == 0)) {
51520c0982b8SRandall Stewart 		/*
51530c0982b8SRandall Stewart 		 * huh, this should not happen unless all packets are
51540c0982b8SRandall Stewart 		 * PR-SCTP and marked to skip of course.
51550c0982b8SRandall Stewart 		 */
51560c0982b8SRandall Stewart 		if (sctp_fs_audit(asoc)) {
5157a5d547adSRandall Stewart 			TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
5158a5d547adSRandall Stewart 				net->flight_size = 0;
5159a5d547adSRandall Stewart 			}
5160a5d547adSRandall Stewart 			asoc->total_flight = 0;
5161a5d547adSRandall Stewart 			asoc->total_flight_count = 0;
5162a5d547adSRandall Stewart 			asoc->sent_queue_retran_cnt = 0;
5163a5d547adSRandall Stewart 			TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
5164a5d547adSRandall Stewart 				if (tp1->sent < SCTP_DATAGRAM_RESEND) {
5165c105859eSRandall Stewart 					sctp_flight_size_increase(tp1);
5166c105859eSRandall Stewart 					sctp_total_flight_increase(stcb, tp1);
5167a5d547adSRandall Stewart 				} else if (tp1->sent == SCTP_DATAGRAM_RESEND) {
5168791437b5SRandall Stewart 					sctp_ucount_incr(asoc->sent_queue_retran_cnt);
5169a5d547adSRandall Stewart 				}
5170a5d547adSRandall Stewart 			}
51710c0982b8SRandall Stewart 		}
5172bff64a4dSRandall Stewart 		done_once = 1;
5173a5d547adSRandall Stewart 		goto again;
5174a5d547adSRandall Stewart 	}
5175cd554309SMichael Tuexen 	/*********************************************/
5176cd554309SMichael Tuexen 	/* Here we perform PR-SCTP procedures        */
5177cd554309SMichael Tuexen 	/* (section 4.2)                             */
5178cd554309SMichael Tuexen 	/*********************************************/
5179cd554309SMichael Tuexen 	/* C1. update advancedPeerAckPoint */
518020b07a4dSMichael Tuexen 	if (SCTP_TSN_GT(cum_ack, asoc->advanced_peer_ack_point)) {
5181dfb11ef8SRandall Stewart 		asoc->advanced_peer_ack_point = cum_ack;
5182dfb11ef8SRandall Stewart 	}
5183830d754dSRandall Stewart 	/* C2. try to further move advancedPeerAckPoint ahead */
5184dd973b0eSMichael Tuexen 	if ((asoc->prsctp_supported) && (asoc->pr_sctp_cnt > 0)) {
5185830d754dSRandall Stewart 		struct sctp_tmit_chunk *lchk;
5186830d754dSRandall Stewart 		uint32_t old_adv_peer_ack_point;
5187830d754dSRandall Stewart 
5188830d754dSRandall Stewart 		old_adv_peer_ack_point = asoc->advanced_peer_ack_point;
5189830d754dSRandall Stewart 		lchk = sctp_try_advance_peer_ack_point(stcb, asoc);
5190830d754dSRandall Stewart 		/* C3. See if we need to send a Fwd-TSN */
519120b07a4dSMichael Tuexen 		if (SCTP_TSN_GT(asoc->advanced_peer_ack_point, cum_ack)) {
5192830d754dSRandall Stewart 			/*
5193493d8e5aSRandall Stewart 			 * ISSUE with ECN, see FWD-TSN processing.
5194830d754dSRandall Stewart 			 */
51950c0982b8SRandall Stewart 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) {
51960c0982b8SRandall Stewart 				sctp_misc_ints(SCTP_FWD_TSN_CHECK,
51970c0982b8SRandall Stewart 				    0xee, cum_ack, asoc->advanced_peer_ack_point,
51980c0982b8SRandall Stewart 				    old_adv_peer_ack_point);
51990c0982b8SRandall Stewart 			}
520020b07a4dSMichael Tuexen 			if (SCTP_TSN_GT(asoc->advanced_peer_ack_point, old_adv_peer_ack_point)) {
5201830d754dSRandall Stewart 				send_forward_tsn(stcb, asoc);
52020c0982b8SRandall Stewart 			} else if (lchk) {
52030c0982b8SRandall Stewart 				/* try to FR fwd-tsn's that get lost too */
520444fbe462SRandall Stewart 				if (lchk->rec.data.fwd_tsn_cnt >= 3) {
52050c0982b8SRandall Stewart 					send_forward_tsn(stcb, asoc);
52060c0982b8SRandall Stewart 				}
5207830d754dSRandall Stewart 			}
5208830d754dSRandall Stewart 		}
5209efd5e692SMichael Tuexen 		for (; lchk != NULL; lchk = TAILQ_NEXT(lchk, sctp_next)) {
5210efd5e692SMichael Tuexen 			if (lchk->whoTo != NULL) {
5211efd5e692SMichael Tuexen 				break;
5212efd5e692SMichael Tuexen 			}
5213efd5e692SMichael Tuexen 		}
5214efd5e692SMichael Tuexen 		if (lchk != NULL) {
5215830d754dSRandall Stewart 			/* Assure a timer is up */
5216830d754dSRandall Stewart 			sctp_timer_start(SCTP_TIMER_TYPE_SEND,
5217830d754dSRandall Stewart 			    stcb->sctp_ep, stcb, lchk->whoTo);
5218830d754dSRandall Stewart 		}
5219830d754dSRandall Stewart 	}
5220b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_RWND_LOGGING_ENABLE) {
5221f8829a4aSRandall Stewart 		sctp_misc_ints(SCTP_SACK_RWND_UPDATE,
5222f8829a4aSRandall Stewart 		    a_rwnd,
5223f8829a4aSRandall Stewart 		    stcb->asoc.peers_rwnd,
5224f8829a4aSRandall Stewart 		    stcb->asoc.total_flight,
5225f8829a4aSRandall Stewart 		    stcb->asoc.total_output_queue_size);
522680fefe0aSRandall Stewart 	}
5227f8829a4aSRandall Stewart }
5228f8829a4aSRandall Stewart 
5229f8829a4aSRandall Stewart void
52307215cc1bSMichael Tuexen sctp_update_acked(struct sctp_tcb *stcb, struct sctp_shutdown_chunk *cp, int *abort_flag)
5231f8829a4aSRandall Stewart {
5232f8829a4aSRandall Stewart 	/* Copy cum-ack */
5233f8829a4aSRandall Stewart 	uint32_t cum_ack, a_rwnd;
5234f8829a4aSRandall Stewart 
5235f8829a4aSRandall Stewart 	cum_ack = ntohl(cp->cumulative_tsn_ack);
5236f8829a4aSRandall Stewart 	/* Arrange so a_rwnd does NOT change */
5237f8829a4aSRandall Stewart 	a_rwnd = stcb->asoc.peers_rwnd + stcb->asoc.total_flight;
5238f8829a4aSRandall Stewart 
5239f8829a4aSRandall Stewart 	/* Now call the express sack handling */
5240899288aeSRandall Stewart 	sctp_express_handle_sack(stcb, cum_ack, a_rwnd, abort_flag, 0);
5241f8829a4aSRandall Stewart }
5242f8829a4aSRandall Stewart 
5243f8829a4aSRandall Stewart static void
5244f8829a4aSRandall Stewart sctp_kick_prsctp_reorder_queue(struct sctp_tcb *stcb,
5245f8829a4aSRandall Stewart     struct sctp_stream_in *strmin)
5246f8829a4aSRandall Stewart {
524728cd0699SMichael Tuexen 	struct sctp_queued_to_read *control, *ncontrol;
5248f8829a4aSRandall Stewart 	struct sctp_association *asoc;
524949656eefSMichael Tuexen 	uint32_t mid;
525049656eefSMichael Tuexen 	int need_reasm_check = 0;
5251f8829a4aSRandall Stewart 
5252f8829a4aSRandall Stewart 	asoc = &stcb->asoc;
525349656eefSMichael Tuexen 	mid = strmin->last_mid_delivered;
5254f8829a4aSRandall Stewart 	/*
5255f8829a4aSRandall Stewart 	 * First deliver anything prior to and including the stream no that
525644249214SRandall Stewart 	 * came in.
5257f8829a4aSRandall Stewart 	 */
525828cd0699SMichael Tuexen 	TAILQ_FOREACH_SAFE(control, &strmin->inqueue, next_instrm, ncontrol) {
525928cd0699SMichael Tuexen 		if (SCTP_MID_GE(asoc->idata_supported, mid, control->mid)) {
5260f8829a4aSRandall Stewart 			/* this is deliverable now */
526128cd0699SMichael Tuexen 			if (((control->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) {
526228cd0699SMichael Tuexen 				if (control->on_strm_q) {
526328cd0699SMichael Tuexen 					if (control->on_strm_q == SCTP_ON_ORDERED) {
526428cd0699SMichael Tuexen 						TAILQ_REMOVE(&strmin->inqueue, control, next_instrm);
526528cd0699SMichael Tuexen 					} else if (control->on_strm_q == SCTP_ON_UNORDERED) {
526628cd0699SMichael Tuexen 						TAILQ_REMOVE(&strmin->uno_inqueue, control, next_instrm);
526798d5fd97SMichael Tuexen #ifdef INVARIANTS
526844249214SRandall Stewart 					} else {
526944249214SRandall Stewart 						panic("strmin: %p ctl: %p unknown %d",
527028cd0699SMichael Tuexen 						    strmin, control, control->on_strm_q);
527198d5fd97SMichael Tuexen #endif
527244249214SRandall Stewart 					}
527328cd0699SMichael Tuexen 					control->on_strm_q = 0;
527444249214SRandall Stewart 				}
5275f8829a4aSRandall Stewart 				/* subtract pending on streams */
527628cd0699SMichael Tuexen 				if (asoc->size_on_all_streams >= control->length) {
527728cd0699SMichael Tuexen 					asoc->size_on_all_streams -= control->length;
527828cd0699SMichael Tuexen 				} else {
527928cd0699SMichael Tuexen #ifdef INVARIANTS
528028cd0699SMichael Tuexen 					panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
528128cd0699SMichael Tuexen #else
528228cd0699SMichael Tuexen 					asoc->size_on_all_streams = 0;
528328cd0699SMichael Tuexen #endif
528428cd0699SMichael Tuexen 				}
5285f8829a4aSRandall Stewart 				sctp_ucount_decr(asoc->cnt_on_all_streams);
5286f8829a4aSRandall Stewart 				/* deliver it to at least the delivery-q */
5287f8829a4aSRandall Stewart 				if (stcb->sctp_socket) {
528828cd0699SMichael Tuexen 					sctp_mark_non_revokable(asoc, control->sinfo_tsn);
5289f8829a4aSRandall Stewart 					sctp_add_to_readq(stcb->sctp_ep, stcb,
529028cd0699SMichael Tuexen 					    control,
529144249214SRandall Stewart 					    &stcb->sctp_socket->so_rcv,
529244249214SRandall Stewart 					    1, SCTP_READ_LOCK_HELD,
529344249214SRandall Stewart 					    SCTP_SO_NOT_LOCKED);
529444249214SRandall Stewart 				}
529544249214SRandall Stewart 			} else {
529644249214SRandall Stewart 				/* Its a fragmented message */
529728cd0699SMichael Tuexen 				if (control->first_frag_seen) {
5298b7b84c0eSMichael Tuexen 					/*
5299b7b84c0eSMichael Tuexen 					 * Make it so this is next to
5300b7b84c0eSMichael Tuexen 					 * deliver, we restore later
5301b7b84c0eSMichael Tuexen 					 */
530228cd0699SMichael Tuexen 					strmin->last_mid_delivered = control->mid - 1;
530344249214SRandall Stewart 					need_reasm_check = 1;
530444249214SRandall Stewart 					break;
530544249214SRandall Stewart 				}
5306f8829a4aSRandall Stewart 			}
5307f8829a4aSRandall Stewart 		} else {
5308f8829a4aSRandall Stewart 			/* no more delivery now. */
5309f8829a4aSRandall Stewart 			break;
5310f8829a4aSRandall Stewart 		}
5311f8829a4aSRandall Stewart 	}
531244249214SRandall Stewart 	if (need_reasm_check) {
531344249214SRandall Stewart 		int ret;
531444249214SRandall Stewart 
5315d1ea5fa9SMichael Tuexen 		ret = sctp_deliver_reasm_check(stcb, &stcb->asoc, strmin, SCTP_READ_LOCK_HELD);
531649656eefSMichael Tuexen 		if (SCTP_MID_GT(asoc->idata_supported, mid, strmin->last_mid_delivered)) {
531744249214SRandall Stewart 			/* Restore the next to deliver unless we are ahead */
531849656eefSMichael Tuexen 			strmin->last_mid_delivered = mid;
531944249214SRandall Stewart 		}
532044249214SRandall Stewart 		if (ret == 0) {
532144249214SRandall Stewart 			/* Left the front Partial one on */
532244249214SRandall Stewart 			return;
532344249214SRandall Stewart 		}
532444249214SRandall Stewart 		need_reasm_check = 0;
532544249214SRandall Stewart 	}
5326f8829a4aSRandall Stewart 	/*
5327f8829a4aSRandall Stewart 	 * now we must deliver things in queue the normal way  if any are
5328f8829a4aSRandall Stewart 	 * now ready.
5329f8829a4aSRandall Stewart 	 */
533049656eefSMichael Tuexen 	mid = strmin->last_mid_delivered + 1;
533128cd0699SMichael Tuexen 	TAILQ_FOREACH_SAFE(control, &strmin->inqueue, next_instrm, ncontrol) {
533228cd0699SMichael Tuexen 		if (SCTP_MID_EQ(asoc->idata_supported, mid, control->mid)) {
533328cd0699SMichael Tuexen 			if (((control->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) {
5334f8829a4aSRandall Stewart 				/* this is deliverable now */
533528cd0699SMichael Tuexen 				if (control->on_strm_q) {
533628cd0699SMichael Tuexen 					if (control->on_strm_q == SCTP_ON_ORDERED) {
533728cd0699SMichael Tuexen 						TAILQ_REMOVE(&strmin->inqueue, control, next_instrm);
533828cd0699SMichael Tuexen 					} else if (control->on_strm_q == SCTP_ON_UNORDERED) {
533928cd0699SMichael Tuexen 						TAILQ_REMOVE(&strmin->uno_inqueue, control, next_instrm);
534098d5fd97SMichael Tuexen #ifdef INVARIANTS
534144249214SRandall Stewart 					} else {
534244249214SRandall Stewart 						panic("strmin: %p ctl: %p unknown %d",
534328cd0699SMichael Tuexen 						    strmin, control, control->on_strm_q);
534498d5fd97SMichael Tuexen #endif
534544249214SRandall Stewart 					}
534628cd0699SMichael Tuexen 					control->on_strm_q = 0;
534744249214SRandall Stewart 				}
5348f8829a4aSRandall Stewart 				/* subtract pending on streams */
534928cd0699SMichael Tuexen 				if (asoc->size_on_all_streams >= control->length) {
535028cd0699SMichael Tuexen 					asoc->size_on_all_streams -= control->length;
535128cd0699SMichael Tuexen 				} else {
535228cd0699SMichael Tuexen #ifdef INVARIANTS
535328cd0699SMichael Tuexen 					panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
535428cd0699SMichael Tuexen #else
535528cd0699SMichael Tuexen 					asoc->size_on_all_streams = 0;
535628cd0699SMichael Tuexen #endif
535728cd0699SMichael Tuexen 				}
5358f8829a4aSRandall Stewart 				sctp_ucount_decr(asoc->cnt_on_all_streams);
5359f8829a4aSRandall Stewart 				/* deliver it to at least the delivery-q */
536028cd0699SMichael Tuexen 				strmin->last_mid_delivered = control->mid;
5361f8829a4aSRandall Stewart 				if (stcb->sctp_socket) {
536228cd0699SMichael Tuexen 					sctp_mark_non_revokable(asoc, control->sinfo_tsn);
5363f8829a4aSRandall Stewart 					sctp_add_to_readq(stcb->sctp_ep, stcb,
536428cd0699SMichael Tuexen 					    control,
536544249214SRandall Stewart 					    &stcb->sctp_socket->so_rcv, 1,
536644249214SRandall Stewart 					    SCTP_READ_LOCK_HELD, SCTP_SO_NOT_LOCKED);
5367f8829a4aSRandall Stewart 				}
536849656eefSMichael Tuexen 				mid = strmin->last_mid_delivered + 1;
5369f8829a4aSRandall Stewart 			} else {
537044249214SRandall Stewart 				/* Its a fragmented message */
537128cd0699SMichael Tuexen 				if (control->first_frag_seen) {
5372b7b84c0eSMichael Tuexen 					/*
5373b7b84c0eSMichael Tuexen 					 * Make it so this is next to
5374b7b84c0eSMichael Tuexen 					 * deliver
5375b7b84c0eSMichael Tuexen 					 */
537628cd0699SMichael Tuexen 					strmin->last_mid_delivered = control->mid - 1;
537744249214SRandall Stewart 					need_reasm_check = 1;
5378f8829a4aSRandall Stewart 					break;
5379f8829a4aSRandall Stewart 				}
5380f8829a4aSRandall Stewart 			}
538144249214SRandall Stewart 		} else {
538244249214SRandall Stewart 			break;
538344249214SRandall Stewart 		}
538444249214SRandall Stewart 	}
538544249214SRandall Stewart 	if (need_reasm_check) {
5386d1ea5fa9SMichael Tuexen 		(void)sctp_deliver_reasm_check(stcb, &stcb->asoc, strmin, SCTP_READ_LOCK_HELD);
538744249214SRandall Stewart 	}
5388f8829a4aSRandall Stewart }
5389f8829a4aSRandall Stewart 
53908933fa13SRandall Stewart static void
53918933fa13SRandall Stewart sctp_flush_reassm_for_str_seq(struct sctp_tcb *stcb,
5392b6734d8fSMichael Tuexen     struct sctp_association *asoc, struct sctp_stream_in *strm,
5393b6734d8fSMichael Tuexen     struct sctp_queued_to_read *control, int ordered, uint32_t cumtsn)
53948933fa13SRandall Stewart {
53954a9ef3f8SMichael Tuexen 	struct sctp_tmit_chunk *chk, *nchk;
5396d1ea5fa9SMichael Tuexen 	int cnt_removed = 0;
53978933fa13SRandall Stewart 
53988933fa13SRandall Stewart 	/*
539944249214SRandall Stewart 	 * For now large messages held on the stream reasm that are complete
54004a9ef3f8SMichael Tuexen 	 * will be tossed too. We could in theory do more work to spin
54014a9ef3f8SMichael Tuexen 	 * through and stop after dumping one msg aka seeing the start of a
54024a9ef3f8SMichael Tuexen 	 * new msg at the head, and call the delivery function... to see if
54034a9ef3f8SMichael Tuexen 	 * it can be delivered... But for now we just dump everything on the
54044a9ef3f8SMichael Tuexen 	 * queue.
54058933fa13SRandall Stewart 	 */
5406*8f269b82SMichael Tuexen 	if (!asoc->idata_supported && !ordered &&
5407*8f269b82SMichael Tuexen 	    control->first_frag_seen &&
5408*8f269b82SMichael Tuexen 	    SCTP_TSN_GT(control->fsn_included, cumtsn)) {
54095cb91655SMichael Tuexen 		return;
54105cb91655SMichael Tuexen 	}
541144249214SRandall Stewart 	TAILQ_FOREACH_SAFE(chk, &control->reasm, sctp_next, nchk) {
541244249214SRandall Stewart 		/* Purge hanging chunks */
541349656eefSMichael Tuexen 		if (!asoc->idata_supported && (ordered == 0)) {
541449656eefSMichael Tuexen 			if (SCTP_TSN_GT(chk->rec.data.tsn, cumtsn)) {
5415d1ea5fa9SMichael Tuexen 				break;
5416d1ea5fa9SMichael Tuexen 			}
5417d1ea5fa9SMichael Tuexen 		}
5418d1ea5fa9SMichael Tuexen 		cnt_removed++;
541944249214SRandall Stewart 		TAILQ_REMOVE(&control->reasm, chk, sctp_next);
542028cd0699SMichael Tuexen 		if (asoc->size_on_reasm_queue >= chk->send_size) {
54218933fa13SRandall Stewart 			asoc->size_on_reasm_queue -= chk->send_size;
542228cd0699SMichael Tuexen 		} else {
542328cd0699SMichael Tuexen #ifdef INVARIANTS
542428cd0699SMichael Tuexen 			panic("size_on_reasm_queue = %u smaller than chunk length %u", asoc->size_on_reasm_queue, chk->send_size);
542528cd0699SMichael Tuexen #else
542628cd0699SMichael Tuexen 			asoc->size_on_reasm_queue = 0;
542728cd0699SMichael Tuexen #endif
542828cd0699SMichael Tuexen 		}
54298933fa13SRandall Stewart 		sctp_ucount_decr(asoc->cnt_on_reasm_queue);
54308933fa13SRandall Stewart 		if (chk->data) {
54318933fa13SRandall Stewart 			sctp_m_freem(chk->data);
54328933fa13SRandall Stewart 			chk->data = NULL;
54338933fa13SRandall Stewart 		}
5434689e6a5fSMichael Tuexen 		sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
54358933fa13SRandall Stewart 	}
5436d1ea5fa9SMichael Tuexen 	if (!TAILQ_EMPTY(&control->reasm)) {
5437d1ea5fa9SMichael Tuexen 		/* This has to be old data, unordered */
5438d1ea5fa9SMichael Tuexen 		if (control->data) {
5439d1ea5fa9SMichael Tuexen 			sctp_m_freem(control->data);
5440d1ea5fa9SMichael Tuexen 			control->data = NULL;
5441d1ea5fa9SMichael Tuexen 		}
5442d1ea5fa9SMichael Tuexen 		sctp_reset_a_control(control, stcb->sctp_ep, cumtsn);
5443d1ea5fa9SMichael Tuexen 		chk = TAILQ_FIRST(&control->reasm);
5444d1ea5fa9SMichael Tuexen 		if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) {
5445d1ea5fa9SMichael Tuexen 			TAILQ_REMOVE(&control->reasm, chk, sctp_next);
5446d1ea5fa9SMichael Tuexen 			sctp_add_chk_to_control(control, strm, stcb, asoc,
5447d1ea5fa9SMichael Tuexen 			    chk, SCTP_READ_LOCK_HELD);
5448d1ea5fa9SMichael Tuexen 		}
5449d1ea5fa9SMichael Tuexen 		sctp_deliver_reasm_check(stcb, asoc, strm, SCTP_READ_LOCK_HELD);
5450d1ea5fa9SMichael Tuexen 		return;
5451d1ea5fa9SMichael Tuexen 	}
5452d1ea5fa9SMichael Tuexen 	if (control->on_strm_q == SCTP_ON_ORDERED) {
545344249214SRandall Stewart 		TAILQ_REMOVE(&strm->inqueue, control, next_instrm);
545428cd0699SMichael Tuexen 		if (asoc->size_on_all_streams >= control->length) {
545528cd0699SMichael Tuexen 			asoc->size_on_all_streams -= control->length;
545628cd0699SMichael Tuexen 		} else {
545728cd0699SMichael Tuexen #ifdef INVARIANTS
545828cd0699SMichael Tuexen 			panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
545928cd0699SMichael Tuexen #else
546028cd0699SMichael Tuexen 			asoc->size_on_all_streams = 0;
546128cd0699SMichael Tuexen #endif
546228cd0699SMichael Tuexen 		}
546328cd0699SMichael Tuexen 		sctp_ucount_decr(asoc->cnt_on_all_streams);
5464d1ea5fa9SMichael Tuexen 		control->on_strm_q = 0;
5465d1ea5fa9SMichael Tuexen 	} else if (control->on_strm_q == SCTP_ON_UNORDERED) {
5466d1ea5fa9SMichael Tuexen 		TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm);
5467d1ea5fa9SMichael Tuexen 		control->on_strm_q = 0;
5468d1ea5fa9SMichael Tuexen #ifdef INVARIANTS
5469d1ea5fa9SMichael Tuexen 	} else if (control->on_strm_q) {
5470d1ea5fa9SMichael Tuexen 		panic("strm: %p ctl: %p unknown %d",
5471d1ea5fa9SMichael Tuexen 		    strm, control, control->on_strm_q);
5472d1ea5fa9SMichael Tuexen #endif
5473d1ea5fa9SMichael Tuexen 	}
5474d1ea5fa9SMichael Tuexen 	control->on_strm_q = 0;
547544249214SRandall Stewart 	if (control->on_read_q == 0) {
547644249214SRandall Stewart 		sctp_free_remote_addr(control->whoFrom);
547744249214SRandall Stewart 		if (control->data) {
547844249214SRandall Stewart 			sctp_m_freem(control->data);
547944249214SRandall Stewart 			control->data = NULL;
548044249214SRandall Stewart 		}
548144249214SRandall Stewart 		sctp_free_a_readq(stcb, control);
54828933fa13SRandall Stewart 	}
54838933fa13SRandall Stewart }
54848933fa13SRandall Stewart 
5485f8829a4aSRandall Stewart void
5486f8829a4aSRandall Stewart sctp_handle_forward_tsn(struct sctp_tcb *stcb,
5487b5c16493SMichael Tuexen     struct sctp_forward_tsn_chunk *fwd,
5488b5c16493SMichael Tuexen     int *abort_flag, struct mbuf *m, int offset)
5489f8829a4aSRandall Stewart {
5490f8829a4aSRandall Stewart 	/* The pr-sctp fwd tsn */
5491f8829a4aSRandall Stewart 	/*
5492f8829a4aSRandall Stewart 	 * here we will perform all the data receiver side steps for
5493f8829a4aSRandall Stewart 	 * processing FwdTSN, as required in by pr-sctp draft:
5494f8829a4aSRandall Stewart 	 *
5495f8829a4aSRandall Stewart 	 * Assume we get FwdTSN(x):
5496f8829a4aSRandall Stewart 	 *
54975b495f17SMichael Tuexen 	 * 1) update local cumTSN to x 2) try to further advance cumTSN to x
54985b495f17SMichael Tuexen 	 * + others we have 3) examine and update re-ordering queue on
5499f8829a4aSRandall Stewart 	 * pr-in-streams 4) clean up re-assembly queue 5) Send a sack to
5500f8829a4aSRandall Stewart 	 * report where we are.
5501f8829a4aSRandall Stewart 	 */
5502f8829a4aSRandall Stewart 	struct sctp_association *asoc;
55037898f408SRandall Stewart 	uint32_t new_cum_tsn, gap;
55047215cc1bSMichael Tuexen 	unsigned int i, fwd_sz, m_size;
55058933fa13SRandall Stewart 	uint32_t str_seq;
5506f8829a4aSRandall Stewart 	struct sctp_stream_in *strm;
550728cd0699SMichael Tuexen 	struct sctp_queued_to_read *control, *sv;
5508f8829a4aSRandall Stewart 
5509f8829a4aSRandall Stewart 	asoc = &stcb->asoc;
5510f8829a4aSRandall Stewart 	if ((fwd_sz = ntohs(fwd->ch.chunk_length)) < sizeof(struct sctp_forward_tsn_chunk)) {
5511ad81507eSRandall Stewart 		SCTPDBG(SCTP_DEBUG_INDATA1,
5512ad81507eSRandall Stewart 		    "Bad size too small/big fwd-tsn\n");
5513f8829a4aSRandall Stewart 		return;
5514f8829a4aSRandall Stewart 	}
5515f8829a4aSRandall Stewart 	m_size = (stcb->asoc.mapping_array_size << 3);
5516f8829a4aSRandall Stewart 	/*************************************************************/
5517f8829a4aSRandall Stewart 	/* 1. Here we update local cumTSN and shift the bitmap array */
5518f8829a4aSRandall Stewart 	/*************************************************************/
5519f8829a4aSRandall Stewart 	new_cum_tsn = ntohl(fwd->new_cumulative_tsn);
5520f8829a4aSRandall Stewart 
552120b07a4dSMichael Tuexen 	if (SCTP_TSN_GE(asoc->cumulative_tsn, new_cum_tsn)) {
5522f8829a4aSRandall Stewart 		/* Already got there ... */
5523f8829a4aSRandall Stewart 		return;
5524f8829a4aSRandall Stewart 	}
5525f8829a4aSRandall Stewart 	/*
5526f8829a4aSRandall Stewart 	 * now we know the new TSN is more advanced, let's find the actual
5527f8829a4aSRandall Stewart 	 * gap
5528f8829a4aSRandall Stewart 	 */
5529b5c16493SMichael Tuexen 	SCTP_CALC_TSN_TO_GAP(gap, new_cum_tsn, asoc->mapping_array_base_tsn);
553077acdc25SRandall Stewart 	asoc->cumulative_tsn = new_cum_tsn;
55312afb3e84SRandall Stewart 	if (gap >= m_size) {
5532f8829a4aSRandall Stewart 		if ((long)gap > sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv)) {
5533ff1ffd74SMichael Tuexen 			struct mbuf *op_err;
5534ff1ffd74SMichael Tuexen 			char msg[SCTP_DIAG_INFO_LEN];
553517205eccSRandall Stewart 
5536f8829a4aSRandall Stewart 			/*
5537f8829a4aSRandall Stewart 			 * out of range (of single byte chunks in the rwnd I
553817205eccSRandall Stewart 			 * give out). This must be an attacker.
5539f8829a4aSRandall Stewart 			 */
554017205eccSRandall Stewart 			*abort_flag = 1;
5541999f86d6SMichael Tuexen 			SCTP_SNPRINTF(msg, sizeof(msg),
5542ff1ffd74SMichael Tuexen 			    "New cum ack %8.8x too high, highest TSN %8.8x",
5543821bae7cSMichael Tuexen 			    new_cum_tsn, asoc->highest_tsn_inside_map);
5544ff1ffd74SMichael Tuexen 			op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
554591e04f9eSMichael Tuexen 			stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_37;
5546ff1ffd74SMichael Tuexen 			sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
5547f8829a4aSRandall Stewart 			return;
5548f8829a4aSRandall Stewart 		}
5549207304d4SRandall Stewart 		SCTP_STAT_INCR(sctps_fwdtsn_map_over);
555077acdc25SRandall Stewart 
55512afb3e84SRandall Stewart 		memset(stcb->asoc.mapping_array, 0, stcb->asoc.mapping_array_size);
55522afb3e84SRandall Stewart 		asoc->mapping_array_base_tsn = new_cum_tsn + 1;
555377acdc25SRandall Stewart 		asoc->highest_tsn_inside_map = new_cum_tsn;
555477acdc25SRandall Stewart 
5555b5c16493SMichael Tuexen 		memset(stcb->asoc.nr_mapping_array, 0, stcb->asoc.mapping_array_size);
5556830d754dSRandall Stewart 		asoc->highest_tsn_inside_nr_map = new_cum_tsn;
555777acdc25SRandall Stewart 
5558b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
5559f8829a4aSRandall Stewart 			sctp_log_map(0, 3, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT);
556080fefe0aSRandall Stewart 		}
55612afb3e84SRandall Stewart 	} else {
55622afb3e84SRandall Stewart 		SCTP_TCB_LOCK_ASSERT(stcb);
55632afb3e84SRandall Stewart 		for (i = 0; i <= gap; i++) {
55647898f408SRandall Stewart 			if (!SCTP_IS_TSN_PRESENT(asoc->mapping_array, i) &&
55657898f408SRandall Stewart 			    !SCTP_IS_TSN_PRESENT(asoc->nr_mapping_array, i)) {
55668933fa13SRandall Stewart 				SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, i);
556720b07a4dSMichael Tuexen 				if (SCTP_TSN_GT(asoc->mapping_array_base_tsn + i, asoc->highest_tsn_inside_nr_map)) {
55687898f408SRandall Stewart 					asoc->highest_tsn_inside_nr_map = asoc->mapping_array_base_tsn + i;
5569b5c16493SMichael Tuexen 				}
5570b5c16493SMichael Tuexen 			}
5571b5c16493SMichael Tuexen 		}
5572f8829a4aSRandall Stewart 	}
5573f8829a4aSRandall Stewart 	/*************************************************************/
5574f8829a4aSRandall Stewart 	/* 2. Clear up re-assembly queue                             */
5575f8829a4aSRandall Stewart 	/*************************************************************/
5576f8829a4aSRandall Stewart 
557744249214SRandall Stewart 	/* This is now done as part of clearing up the stream/seq */
5578d1ea5fa9SMichael Tuexen 	if (asoc->idata_supported == 0) {
5579d1ea5fa9SMichael Tuexen 		uint16_t sid;
558044249214SRandall Stewart 
5581d1ea5fa9SMichael Tuexen 		/* Flush all the un-ordered data based on cum-tsn */
5582d1ea5fa9SMichael Tuexen 		SCTP_INP_READ_LOCK(stcb->sctp_ep);
5583d1ea5fa9SMichael Tuexen 		for (sid = 0; sid < asoc->streamincnt; sid++) {
5584b6734d8fSMichael Tuexen 			strm = &asoc->strmin[sid];
5585b6734d8fSMichael Tuexen 			if (!TAILQ_EMPTY(&strm->uno_inqueue)) {
5586b6734d8fSMichael Tuexen 				sctp_flush_reassm_for_str_seq(stcb, asoc, strm, TAILQ_FIRST(&strm->uno_inqueue), 0, new_cum_tsn);
5587b6734d8fSMichael Tuexen 			}
5588d1ea5fa9SMichael Tuexen 		}
5589d1ea5fa9SMichael Tuexen 		SCTP_INP_READ_UNLOCK(stcb->sctp_ep);
5590d1ea5fa9SMichael Tuexen 	}
55918933fa13SRandall Stewart 	/*******************************************************/
55928933fa13SRandall Stewart 	/* 3. Update the PR-stream re-ordering queues and fix  */
55938933fa13SRandall Stewart 	/* delivery issues as needed.                       */
55948933fa13SRandall Stewart 	/*******************************************************/
5595f8829a4aSRandall Stewart 	fwd_sz -= sizeof(*fwd);
5596671d309cSRandall Stewart 	if (m && fwd_sz) {
5597f8829a4aSRandall Stewart 		/* New method. */
5598d61a0ae0SRandall Stewart 		unsigned int num_str;
5599b6734d8fSMichael Tuexen 		uint32_t mid;
560049656eefSMichael Tuexen 		uint16_t sid;
56018e1b295fSMichael Tuexen 		uint16_t ordered, flags;
5602671d309cSRandall Stewart 		struct sctp_strseq *stseq, strseqbuf;
560344249214SRandall Stewart 		struct sctp_strseq_mid *stseq_m, strseqbuf_m;
5604671d309cSRandall Stewart 
5605671d309cSRandall Stewart 		offset += sizeof(*fwd);
5606f8829a4aSRandall Stewart 
56078933fa13SRandall Stewart 		SCTP_INP_READ_LOCK(stcb->sctp_ep);
560844249214SRandall Stewart 		if (asoc->idata_supported) {
560944249214SRandall Stewart 			num_str = fwd_sz / sizeof(struct sctp_strseq_mid);
561044249214SRandall Stewart 		} else {
5611f8829a4aSRandall Stewart 			num_str = fwd_sz / sizeof(struct sctp_strseq);
561244249214SRandall Stewart 		}
5613f8829a4aSRandall Stewart 		for (i = 0; i < num_str; i++) {
561444249214SRandall Stewart 			if (asoc->idata_supported) {
561544249214SRandall Stewart 				stseq_m = (struct sctp_strseq_mid *)sctp_m_getptr(m, offset,
561644249214SRandall Stewart 				    sizeof(struct sctp_strseq_mid),
561744249214SRandall Stewart 				    (uint8_t *)&strseqbuf_m);
561844249214SRandall Stewart 				offset += sizeof(struct sctp_strseq_mid);
561944249214SRandall Stewart 				if (stseq_m == NULL) {
562044249214SRandall Stewart 					break;
562144249214SRandall Stewart 				}
562249656eefSMichael Tuexen 				sid = ntohs(stseq_m->sid);
562349656eefSMichael Tuexen 				mid = ntohl(stseq_m->mid);
56248e1b295fSMichael Tuexen 				flags = ntohs(stseq_m->flags);
56258e1b295fSMichael Tuexen 				if (flags & PR_SCTP_UNORDERED_FLAG) {
56268e1b295fSMichael Tuexen 					ordered = 0;
56278e1b295fSMichael Tuexen 				} else {
56288e1b295fSMichael Tuexen 					ordered = 1;
56298e1b295fSMichael Tuexen 				}
563044249214SRandall Stewart 			} else {
5631671d309cSRandall Stewart 				stseq = (struct sctp_strseq *)sctp_m_getptr(m, offset,
5632671d309cSRandall Stewart 				    sizeof(struct sctp_strseq),
5633671d309cSRandall Stewart 				    (uint8_t *)&strseqbuf);
5634671d309cSRandall Stewart 				offset += sizeof(struct sctp_strseq);
56352afb3e84SRandall Stewart 				if (stseq == NULL) {
5636671d309cSRandall Stewart 					break;
56372afb3e84SRandall Stewart 				}
563849656eefSMichael Tuexen 				sid = ntohs(stseq->sid);
563949656eefSMichael Tuexen 				mid = (uint32_t)ntohs(stseq->ssn);
56408e1b295fSMichael Tuexen 				ordered = 1;
564144249214SRandall Stewart 			}
5642f8829a4aSRandall Stewart 			/* Convert */
56438933fa13SRandall Stewart 
5644f8829a4aSRandall Stewart 			/* now process */
56458933fa13SRandall Stewart 
56468933fa13SRandall Stewart 			/*
56478933fa13SRandall Stewart 			 * Ok we now look for the stream/seq on the read
56488933fa13SRandall Stewart 			 * queue where its not all delivered. If we find it
56498933fa13SRandall Stewart 			 * we transmute the read entry into a PDI_ABORTED.
56508933fa13SRandall Stewart 			 */
565149656eefSMichael Tuexen 			if (sid >= asoc->streamincnt) {
56522afb3e84SRandall Stewart 				/* screwed up streams, stop!  */
56532afb3e84SRandall Stewart 				break;
5654f8829a4aSRandall Stewart 			}
565549656eefSMichael Tuexen 			if ((asoc->str_of_pdapi == sid) &&
565649656eefSMichael Tuexen 			    (asoc->ssn_of_pdapi == mid)) {
56578933fa13SRandall Stewart 				/*
56588933fa13SRandall Stewart 				 * If this is the one we were partially
56598933fa13SRandall Stewart 				 * delivering now then we no longer are.
56608933fa13SRandall Stewart 				 * Note this will change with the reassembly
56618933fa13SRandall Stewart 				 * re-write.
56628933fa13SRandall Stewart 				 */
56638933fa13SRandall Stewart 				asoc->fragmented_delivery_inprogress = 0;
56648933fa13SRandall Stewart 			}
566549656eefSMichael Tuexen 			strm = &asoc->strmin[sid];
5666b6734d8fSMichael Tuexen 			if (ordered) {
5667b6734d8fSMichael Tuexen 				TAILQ_FOREACH(control, &strm->inqueue, next_instrm) {
5668b6734d8fSMichael Tuexen 					if (SCTP_MID_GE(asoc->idata_supported, mid, control->mid)) {
5669b6734d8fSMichael Tuexen 						sctp_flush_reassm_for_str_seq(stcb, asoc, strm, control, ordered, new_cum_tsn);
5670b6734d8fSMichael Tuexen 					}
5671b6734d8fSMichael Tuexen 				}
5672b6734d8fSMichael Tuexen 			} else {
5673b6734d8fSMichael Tuexen 				if (asoc->idata_supported) {
5674b6734d8fSMichael Tuexen 					TAILQ_FOREACH(control, &strm->uno_inqueue, next_instrm) {
5675b6734d8fSMichael Tuexen 						if (SCTP_MID_GE(asoc->idata_supported, mid, control->mid)) {
5676b6734d8fSMichael Tuexen 							sctp_flush_reassm_for_str_seq(stcb, asoc, strm, control, ordered, new_cum_tsn);
5677b6734d8fSMichael Tuexen 						}
5678b6734d8fSMichael Tuexen 					}
5679b6734d8fSMichael Tuexen 				} else {
5680b6734d8fSMichael Tuexen 					if (!TAILQ_EMPTY(&strm->uno_inqueue)) {
5681b6734d8fSMichael Tuexen 						sctp_flush_reassm_for_str_seq(stcb, asoc, strm, TAILQ_FIRST(&strm->uno_inqueue), ordered, new_cum_tsn);
5682b6734d8fSMichael Tuexen 					}
5683b6734d8fSMichael Tuexen 				}
5684d1ea5fa9SMichael Tuexen 			}
568528cd0699SMichael Tuexen 			TAILQ_FOREACH(control, &stcb->sctp_ep->read_queue, next) {
568628cd0699SMichael Tuexen 				if ((control->sinfo_stream == sid) &&
568728cd0699SMichael Tuexen 				    (SCTP_MID_EQ(asoc->idata_supported, control->mid, mid))) {
568849656eefSMichael Tuexen 					str_seq = (sid << 16) | (0x0000ffff & mid);
568928cd0699SMichael Tuexen 					control->pdapi_aborted = 1;
56908933fa13SRandall Stewart 					sv = stcb->asoc.control_pdapi;
569128cd0699SMichael Tuexen 					control->end_added = 1;
569228cd0699SMichael Tuexen 					if (control->on_strm_q == SCTP_ON_ORDERED) {
569328cd0699SMichael Tuexen 						TAILQ_REMOVE(&strm->inqueue, control, next_instrm);
569428cd0699SMichael Tuexen 						if (asoc->size_on_all_streams >= control->length) {
569528cd0699SMichael Tuexen 							asoc->size_on_all_streams -= control->length;
569628cd0699SMichael Tuexen 						} else {
569798d5fd97SMichael Tuexen #ifdef INVARIANTS
569828cd0699SMichael Tuexen 							panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
569928cd0699SMichael Tuexen #else
570028cd0699SMichael Tuexen 							asoc->size_on_all_streams = 0;
570198d5fd97SMichael Tuexen #endif
570244249214SRandall Stewart 						}
570328cd0699SMichael Tuexen 						sctp_ucount_decr(asoc->cnt_on_all_streams);
570428cd0699SMichael Tuexen 					} else if (control->on_strm_q == SCTP_ON_UNORDERED) {
570528cd0699SMichael Tuexen 						TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm);
570628cd0699SMichael Tuexen #ifdef INVARIANTS
570728cd0699SMichael Tuexen 					} else if (control->on_strm_q) {
570828cd0699SMichael Tuexen 						panic("strm: %p ctl: %p unknown %d",
570928cd0699SMichael Tuexen 						    strm, control, control->on_strm_q);
571028cd0699SMichael Tuexen #endif
571128cd0699SMichael Tuexen 					}
571228cd0699SMichael Tuexen 					control->on_strm_q = 0;
571328cd0699SMichael Tuexen 					stcb->asoc.control_pdapi = control;
5714810ec536SMichael Tuexen 					sctp_ulp_notify(SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION,
5715810ec536SMichael Tuexen 					    stcb,
57168933fa13SRandall Stewart 					    SCTP_PARTIAL_DELIVERY_ABORTED,
5717810ec536SMichael Tuexen 					    (void *)&str_seq,
5718810ec536SMichael Tuexen 					    SCTP_SO_NOT_LOCKED);
57198933fa13SRandall Stewart 					stcb->asoc.control_pdapi = sv;
57208933fa13SRandall Stewart 					break;
572128cd0699SMichael Tuexen 				} else if ((control->sinfo_stream == sid) &&
572228cd0699SMichael Tuexen 				    SCTP_MID_GT(asoc->idata_supported, control->mid, mid)) {
57238933fa13SRandall Stewart 					/* We are past our victim SSN */
57248933fa13SRandall Stewart 					break;
57258933fa13SRandall Stewart 				}
57268933fa13SRandall Stewart 			}
572749656eefSMichael Tuexen 			if (SCTP_MID_GT(asoc->idata_supported, mid, strm->last_mid_delivered)) {
5728f8829a4aSRandall Stewart 				/* Update the sequence number */
572949656eefSMichael Tuexen 				strm->last_mid_delivered = mid;
5730f8829a4aSRandall Stewart 			}
5731f8829a4aSRandall Stewart 			/* now kick the stream the new way */
573204ee05e8SRandall Stewart 			/* sa_ignore NO_NULL_CHK */
5733f8829a4aSRandall Stewart 			sctp_kick_prsctp_reorder_queue(stcb, strm);
5734f8829a4aSRandall Stewart 		}
57358933fa13SRandall Stewart 		SCTP_INP_READ_UNLOCK(stcb->sctp_ep);
5736f8829a4aSRandall Stewart 	}
57377898f408SRandall Stewart 	/*
57387898f408SRandall Stewart 	 * Now slide thing forward.
57397898f408SRandall Stewart 	 */
57407898f408SRandall Stewart 	sctp_slide_mapping_arrays(stcb);
5741f8829a4aSRandall Stewart }
5742