xref: /freebsd/sys/netinet/sctp_indata.c (revision 5b495f17a57c6736bbf1952dab358facd514adc9)
1f8829a4aSRandall Stewart /*-
2b1006367SRandall Stewart  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
3807aad63SMichael Tuexen  * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
4807aad63SMichael Tuexen  * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
5f8829a4aSRandall Stewart  *
6f8829a4aSRandall Stewart  * Redistribution and use in source and binary forms, with or without
7f8829a4aSRandall Stewart  * modification, are permitted provided that the following conditions are met:
8f8829a4aSRandall Stewart  *
9f8829a4aSRandall Stewart  * a) Redistributions of source code must retain the above copyright notice,
10f8829a4aSRandall Stewart  *    this list of conditions and the following disclaimer.
11f8829a4aSRandall Stewart  *
12f8829a4aSRandall Stewart  * b) Redistributions in binary form must reproduce the above copyright
13f8829a4aSRandall Stewart  *    notice, this list of conditions and the following disclaimer in
14f8829a4aSRandall Stewart  *    the documentation and/or other materials provided with the distribution.
15f8829a4aSRandall Stewart  *
16f8829a4aSRandall Stewart  * c) Neither the name of Cisco Systems, Inc. nor the names of its
17f8829a4aSRandall Stewart  *    contributors may be used to endorse or promote products derived
18f8829a4aSRandall Stewart  *    from this software without specific prior written permission.
19f8829a4aSRandall Stewart  *
20f8829a4aSRandall Stewart  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21f8829a4aSRandall Stewart  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22f8829a4aSRandall Stewart  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23f8829a4aSRandall Stewart  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24f8829a4aSRandall Stewart  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25f8829a4aSRandall Stewart  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26f8829a4aSRandall Stewart  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27f8829a4aSRandall Stewart  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28f8829a4aSRandall Stewart  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29f8829a4aSRandall Stewart  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30f8829a4aSRandall Stewart  * THE POSSIBILITY OF SUCH DAMAGE.
31f8829a4aSRandall Stewart  */
32f8829a4aSRandall Stewart 
33f8829a4aSRandall Stewart #include <sys/cdefs.h>
34f8829a4aSRandall Stewart __FBSDID("$FreeBSD$");
35f8829a4aSRandall Stewart 
36f8829a4aSRandall Stewart #include <netinet/sctp_os.h>
3744249214SRandall Stewart #include <sys/proc.h>
38f8829a4aSRandall Stewart #include <netinet/sctp_var.h>
3942551e99SRandall Stewart #include <netinet/sctp_sysctl.h>
40f8829a4aSRandall Stewart #include <netinet/sctp_header.h>
4144249214SRandall Stewart #include <netinet/sctp_pcb.h>
42f8829a4aSRandall Stewart #include <netinet/sctputil.h>
43f8829a4aSRandall Stewart #include <netinet/sctp_output.h>
44f8829a4aSRandall Stewart #include <netinet/sctp_uio.h>
4544249214SRandall Stewart #include <netinet/sctp_auth.h>
46f8829a4aSRandall Stewart #include <netinet/sctp_timer.h>
4744249214SRandall Stewart #include <netinet/sctp_asconf.h>
4844249214SRandall Stewart #include <netinet/sctp_indata.h>
4944249214SRandall Stewart #include <netinet/sctp_bsd_addr.h>
5044249214SRandall Stewart #include <netinet/sctp_input.h>
5144249214SRandall Stewart #include <netinet/sctp_crc32.h>
5244249214SRandall Stewart #include <netinet/sctp_lock_bsd.h>
53f8829a4aSRandall Stewart /*
54f8829a4aSRandall Stewart  * NOTES: On the outbound side of things I need to check the sack timer to
55f8829a4aSRandall Stewart  * see if I should generate a sack into the chunk queue (if I have data to
56f8829a4aSRandall Stewart  * send that is and will be sending it .. for bundling.
57f8829a4aSRandall Stewart  *
58f8829a4aSRandall Stewart  * The callback in sctp_usrreq.c will get called when the socket is read from.
59f8829a4aSRandall Stewart  * This will cause sctp_service_queues() to get called on the top entry in
60f8829a4aSRandall Stewart  * the list.
61f8829a4aSRandall Stewart  */
6244249214SRandall Stewart static void
6344249214SRandall Stewart sctp_add_chk_to_control(struct sctp_queued_to_read *control,
6444249214SRandall Stewart     struct sctp_stream_in *strm,
6544249214SRandall Stewart     struct sctp_tcb *stcb,
6644249214SRandall Stewart     struct sctp_association *asoc,
67d1ea5fa9SMichael Tuexen     struct sctp_tmit_chunk *chk, int lock_held);
6844249214SRandall Stewart 
69f8829a4aSRandall Stewart 
7072fb6fdbSRandall Stewart void
71f8829a4aSRandall Stewart sctp_set_rwnd(struct sctp_tcb *stcb, struct sctp_association *asoc)
72f8829a4aSRandall Stewart {
73b3f1ea41SRandall Stewart 	asoc->my_rwnd = sctp_calc_rwnd(stcb, asoc);
74f8829a4aSRandall Stewart }
75f8829a4aSRandall Stewart 
76f8829a4aSRandall Stewart /* Calculate what the rwnd would be */
7772fb6fdbSRandall Stewart uint32_t
78f8829a4aSRandall Stewart sctp_calc_rwnd(struct sctp_tcb *stcb, struct sctp_association *asoc)
79f8829a4aSRandall Stewart {
80b3f1ea41SRandall Stewart 	uint32_t calc = 0;
81f8829a4aSRandall Stewart 
82f8829a4aSRandall Stewart 	/*
83f8829a4aSRandall Stewart 	 * This is really set wrong with respect to a 1-2-m socket. Since
844e88d37aSMichael Tuexen 	 * the sb_cc is the count that everyone as put up. When we re-write
85f8829a4aSRandall Stewart 	 * sctp_soreceive then we will fix this so that ONLY this
86f8829a4aSRandall Stewart 	 * associations data is taken into account.
87f8829a4aSRandall Stewart 	 */
8844249214SRandall Stewart 	if (stcb->sctp_socket == NULL) {
89f8829a4aSRandall Stewart 		return (calc);
9044249214SRandall Stewart 	}
914e88d37aSMichael Tuexen 	if (stcb->asoc.sb_cc == 0 &&
92f8829a4aSRandall Stewart 	    asoc->size_on_reasm_queue == 0 &&
93f8829a4aSRandall Stewart 	    asoc->size_on_all_streams == 0) {
94f8829a4aSRandall Stewart 		/* Full rwnd granted */
95b3f1ea41SRandall Stewart 		calc = max(SCTP_SB_LIMIT_RCV(stcb->sctp_socket), SCTP_MINIMAL_RWND);
96f8829a4aSRandall Stewart 		return (calc);
97f8829a4aSRandall Stewart 	}
98f8829a4aSRandall Stewart 	/* get actual space */
99f8829a4aSRandall Stewart 	calc = (uint32_t) sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv);
100f8829a4aSRandall Stewart 	/*
101f8829a4aSRandall Stewart 	 * take out what has NOT been put on socket queue and we yet hold
102f8829a4aSRandall Stewart 	 * for putting up.
103f8829a4aSRandall Stewart 	 */
10444fbe462SRandall Stewart 	calc = sctp_sbspace_sub(calc, (uint32_t) (asoc->size_on_reasm_queue +
10544fbe462SRandall Stewart 	    asoc->cnt_on_reasm_queue * MSIZE));
10644fbe462SRandall Stewart 	calc = sctp_sbspace_sub(calc, (uint32_t) (asoc->size_on_all_streams +
10744fbe462SRandall Stewart 	    asoc->cnt_on_all_streams * MSIZE));
108f8829a4aSRandall Stewart 	if (calc == 0) {
109f8829a4aSRandall Stewart 		/* out of space */
110f8829a4aSRandall Stewart 		return (calc);
111f8829a4aSRandall Stewart 	}
112f8829a4aSRandall Stewart 	/* what is the overhead of all these rwnd's */
1132afb3e84SRandall Stewart 	calc = sctp_sbspace_sub(calc, stcb->asoc.my_rwnd_control_len);
114b3f1ea41SRandall Stewart 	/*
115b3f1ea41SRandall Stewart 	 * If the window gets too small due to ctrl-stuff, reduce it to 1,
116b3f1ea41SRandall Stewart 	 * even it is 0. SWS engaged
117f8829a4aSRandall Stewart 	 */
118b3f1ea41SRandall Stewart 	if (calc < stcb->asoc.my_rwnd_control_len) {
119b3f1ea41SRandall Stewart 		calc = 1;
1202afb3e84SRandall Stewart 	}
121b3f1ea41SRandall Stewart 	return (calc);
122f8829a4aSRandall Stewart }
123f8829a4aSRandall Stewart 
124f8829a4aSRandall Stewart 
125f8829a4aSRandall Stewart 
126f8829a4aSRandall Stewart /*
127f8829a4aSRandall Stewart  * Build out our readq entry based on the incoming packet.
128f8829a4aSRandall Stewart  */
129f8829a4aSRandall Stewart struct sctp_queued_to_read *
130f8829a4aSRandall Stewart sctp_build_readq_entry(struct sctp_tcb *stcb,
131f8829a4aSRandall Stewart     struct sctp_nets *net,
132f8829a4aSRandall Stewart     uint32_t tsn, uint32_t ppid,
133f8829a4aSRandall Stewart     uint32_t context, uint16_t stream_no,
13444249214SRandall Stewart     uint32_t stream_seq, uint8_t flags,
135f8829a4aSRandall Stewart     struct mbuf *dm)
136f8829a4aSRandall Stewart {
137f8829a4aSRandall Stewart 	struct sctp_queued_to_read *read_queue_e = NULL;
138f8829a4aSRandall Stewart 
139f8829a4aSRandall Stewart 	sctp_alloc_a_readq(stcb, read_queue_e);
140f8829a4aSRandall Stewart 	if (read_queue_e == NULL) {
141f8829a4aSRandall Stewart 		goto failed_build;
142f8829a4aSRandall Stewart 	}
14344249214SRandall Stewart 	memset(read_queue_e, 0, sizeof(struct sctp_queued_to_read));
144f8829a4aSRandall Stewart 	read_queue_e->sinfo_stream = stream_no;
145f8829a4aSRandall Stewart 	read_queue_e->sinfo_ssn = stream_seq;
146f8829a4aSRandall Stewart 	read_queue_e->sinfo_flags = (flags << 8);
147f8829a4aSRandall Stewart 	read_queue_e->sinfo_ppid = ppid;
1487215cc1bSMichael Tuexen 	read_queue_e->sinfo_context = context;
149f8829a4aSRandall Stewart 	read_queue_e->sinfo_tsn = tsn;
150f8829a4aSRandall Stewart 	read_queue_e->sinfo_cumtsn = tsn;
151f8829a4aSRandall Stewart 	read_queue_e->sinfo_assoc_id = sctp_get_associd(stcb);
15244249214SRandall Stewart 	read_queue_e->top_fsn = read_queue_e->fsn_included = 0xffffffff;
15344249214SRandall Stewart 	TAILQ_INIT(&read_queue_e->reasm);
154f8829a4aSRandall Stewart 	read_queue_e->whoFrom = net;
155f8829a4aSRandall Stewart 	atomic_add_int(&net->ref_count, 1);
156f8829a4aSRandall Stewart 	read_queue_e->data = dm;
157f8829a4aSRandall Stewart 	read_queue_e->stcb = stcb;
158f8829a4aSRandall Stewart 	read_queue_e->port_from = stcb->rport;
159f8829a4aSRandall Stewart failed_build:
160f8829a4aSRandall Stewart 	return (read_queue_e);
161f8829a4aSRandall Stewart }
162f8829a4aSRandall Stewart 
163f8829a4aSRandall Stewart struct mbuf *
164e2e7c62eSMichael Tuexen sctp_build_ctl_nchunk(struct sctp_inpcb *inp, struct sctp_sndrcvinfo *sinfo)
165f8829a4aSRandall Stewart {
166e2e7c62eSMichael Tuexen 	struct sctp_extrcvinfo *seinfo;
167f8829a4aSRandall Stewart 	struct sctp_sndrcvinfo *outinfo;
168e2e7c62eSMichael Tuexen 	struct sctp_rcvinfo *rcvinfo;
169e2e7c62eSMichael Tuexen 	struct sctp_nxtinfo *nxtinfo;
170f8829a4aSRandall Stewart 	struct cmsghdr *cmh;
171f8829a4aSRandall Stewart 	struct mbuf *ret;
172f8829a4aSRandall Stewart 	int len;
173e2e7c62eSMichael Tuexen 	int use_extended;
174e2e7c62eSMichael Tuexen 	int provide_nxt;
175f8829a4aSRandall Stewart 
176e2e7c62eSMichael Tuexen 	if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT) &&
177e2e7c62eSMichael Tuexen 	    sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVRCVINFO) &&
178e2e7c62eSMichael Tuexen 	    sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVNXTINFO)) {
179e2e7c62eSMichael Tuexen 		/* user does not want any ancillary data */
180f8829a4aSRandall Stewart 		return (NULL);
181f8829a4aSRandall Stewart 	}
182e2e7c62eSMichael Tuexen 	len = 0;
183e2e7c62eSMichael Tuexen 	if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO)) {
184e2e7c62eSMichael Tuexen 		len += CMSG_SPACE(sizeof(struct sctp_rcvinfo));
185e2e7c62eSMichael Tuexen 	}
186e2e7c62eSMichael Tuexen 	seinfo = (struct sctp_extrcvinfo *)sinfo;
187e2e7c62eSMichael Tuexen 	if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO) &&
188b70b526dSMichael Tuexen 	    (seinfo->serinfo_next_flags & SCTP_NEXT_MSG_AVAIL)) {
189e2e7c62eSMichael Tuexen 		provide_nxt = 1;
1900bfc52beSMichael Tuexen 		len += CMSG_SPACE(sizeof(struct sctp_nxtinfo));
191e2e7c62eSMichael Tuexen 	} else {
192e2e7c62eSMichael Tuexen 		provide_nxt = 0;
193e2e7c62eSMichael Tuexen 	}
194e2e7c62eSMichael Tuexen 	if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT)) {
195f8829a4aSRandall Stewart 		if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO)) {
196f8829a4aSRandall Stewart 			use_extended = 1;
197e2e7c62eSMichael Tuexen 			len += CMSG_SPACE(sizeof(struct sctp_extrcvinfo));
198f8829a4aSRandall Stewart 		} else {
199e2e7c62eSMichael Tuexen 			use_extended = 0;
200e2e7c62eSMichael Tuexen 			len += CMSG_SPACE(sizeof(struct sctp_sndrcvinfo));
201e2e7c62eSMichael Tuexen 		}
202e2e7c62eSMichael Tuexen 	} else {
203e2e7c62eSMichael Tuexen 		use_extended = 0;
204f8829a4aSRandall Stewart 	}
205f8829a4aSRandall Stewart 
206eb1b1807SGleb Smirnoff 	ret = sctp_get_mbuf_for_msg(len, 0, M_NOWAIT, 1, MT_DATA);
207f8829a4aSRandall Stewart 	if (ret == NULL) {
208f8829a4aSRandall Stewart 		/* No space */
209f8829a4aSRandall Stewart 		return (ret);
210f8829a4aSRandall Stewart 	}
211e2e7c62eSMichael Tuexen 	SCTP_BUF_LEN(ret) = 0;
212e2e7c62eSMichael Tuexen 
213f8829a4aSRandall Stewart 	/* We need a CMSG header followed by the struct */
214f8829a4aSRandall Stewart 	cmh = mtod(ret, struct cmsghdr *);
215e432298aSXin LI 	/*
216e432298aSXin LI 	 * Make sure that there is no un-initialized padding between the
217e432298aSXin LI 	 * cmsg header and cmsg data and after the cmsg data.
218e432298aSXin LI 	 */
219e432298aSXin LI 	memset(cmh, 0, len);
220e2e7c62eSMichael Tuexen 	if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO)) {
221f8829a4aSRandall Stewart 		cmh->cmsg_level = IPPROTO_SCTP;
222e2e7c62eSMichael Tuexen 		cmh->cmsg_len = CMSG_LEN(sizeof(struct sctp_rcvinfo));
223e2e7c62eSMichael Tuexen 		cmh->cmsg_type = SCTP_RCVINFO;
224e2e7c62eSMichael Tuexen 		rcvinfo = (struct sctp_rcvinfo *)CMSG_DATA(cmh);
225e2e7c62eSMichael Tuexen 		rcvinfo->rcv_sid = sinfo->sinfo_stream;
226e2e7c62eSMichael Tuexen 		rcvinfo->rcv_ssn = sinfo->sinfo_ssn;
227e2e7c62eSMichael Tuexen 		rcvinfo->rcv_flags = sinfo->sinfo_flags;
228e2e7c62eSMichael Tuexen 		rcvinfo->rcv_ppid = sinfo->sinfo_ppid;
229e2e7c62eSMichael Tuexen 		rcvinfo->rcv_tsn = sinfo->sinfo_tsn;
230e2e7c62eSMichael Tuexen 		rcvinfo->rcv_cumtsn = sinfo->sinfo_cumtsn;
231e2e7c62eSMichael Tuexen 		rcvinfo->rcv_context = sinfo->sinfo_context;
232e2e7c62eSMichael Tuexen 		rcvinfo->rcv_assoc_id = sinfo->sinfo_assoc_id;
233e2e7c62eSMichael Tuexen 		cmh = (struct cmsghdr *)((caddr_t)cmh + CMSG_SPACE(sizeof(struct sctp_rcvinfo)));
234e2e7c62eSMichael Tuexen 		SCTP_BUF_LEN(ret) += CMSG_SPACE(sizeof(struct sctp_rcvinfo));
235f8829a4aSRandall Stewart 	}
236e2e7c62eSMichael Tuexen 	if (provide_nxt) {
237e2e7c62eSMichael Tuexen 		cmh->cmsg_level = IPPROTO_SCTP;
238e2e7c62eSMichael Tuexen 		cmh->cmsg_len = CMSG_LEN(sizeof(struct sctp_nxtinfo));
239e2e7c62eSMichael Tuexen 		cmh->cmsg_type = SCTP_NXTINFO;
240e2e7c62eSMichael Tuexen 		nxtinfo = (struct sctp_nxtinfo *)CMSG_DATA(cmh);
241b70b526dSMichael Tuexen 		nxtinfo->nxt_sid = seinfo->serinfo_next_stream;
242e2e7c62eSMichael Tuexen 		nxtinfo->nxt_flags = 0;
243b70b526dSMichael Tuexen 		if (seinfo->serinfo_next_flags & SCTP_NEXT_MSG_IS_UNORDERED) {
244e2e7c62eSMichael Tuexen 			nxtinfo->nxt_flags |= SCTP_UNORDERED;
245e2e7c62eSMichael Tuexen 		}
246b70b526dSMichael Tuexen 		if (seinfo->serinfo_next_flags & SCTP_NEXT_MSG_IS_NOTIFICATION) {
247e2e7c62eSMichael Tuexen 			nxtinfo->nxt_flags |= SCTP_NOTIFICATION;
248e2e7c62eSMichael Tuexen 		}
249b70b526dSMichael Tuexen 		if (seinfo->serinfo_next_flags & SCTP_NEXT_MSG_ISCOMPLETE) {
250e2e7c62eSMichael Tuexen 			nxtinfo->nxt_flags |= SCTP_COMPLETE;
251e2e7c62eSMichael Tuexen 		}
252b70b526dSMichael Tuexen 		nxtinfo->nxt_ppid = seinfo->serinfo_next_ppid;
253b70b526dSMichael Tuexen 		nxtinfo->nxt_length = seinfo->serinfo_next_length;
254b70b526dSMichael Tuexen 		nxtinfo->nxt_assoc_id = seinfo->serinfo_next_aid;
255e2e7c62eSMichael Tuexen 		cmh = (struct cmsghdr *)((caddr_t)cmh + CMSG_SPACE(sizeof(struct sctp_nxtinfo)));
256e2e7c62eSMichael Tuexen 		SCTP_BUF_LEN(ret) += CMSG_SPACE(sizeof(struct sctp_nxtinfo));
257e2e7c62eSMichael Tuexen 	}
258e2e7c62eSMichael Tuexen 	if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT)) {
259e2e7c62eSMichael Tuexen 		cmh->cmsg_level = IPPROTO_SCTP;
260e2e7c62eSMichael Tuexen 		outinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmh);
261e2e7c62eSMichael Tuexen 		if (use_extended) {
262e2e7c62eSMichael Tuexen 			cmh->cmsg_len = CMSG_LEN(sizeof(struct sctp_extrcvinfo));
263e2e7c62eSMichael Tuexen 			cmh->cmsg_type = SCTP_EXTRCV;
264e2e7c62eSMichael Tuexen 			memcpy(outinfo, sinfo, sizeof(struct sctp_extrcvinfo));
265e2e7c62eSMichael Tuexen 			SCTP_BUF_LEN(ret) += CMSG_SPACE(sizeof(struct sctp_extrcvinfo));
266e2e7c62eSMichael Tuexen 		} else {
267e2e7c62eSMichael Tuexen 			cmh->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
268e2e7c62eSMichael Tuexen 			cmh->cmsg_type = SCTP_SNDRCV;
269e2e7c62eSMichael Tuexen 			*outinfo = *sinfo;
270e2e7c62eSMichael Tuexen 			SCTP_BUF_LEN(ret) += CMSG_SPACE(sizeof(struct sctp_sndrcvinfo));
271e2e7c62eSMichael Tuexen 		}
272e2e7c62eSMichael Tuexen 	}
273f8829a4aSRandall Stewart 	return (ret);
274f8829a4aSRandall Stewart }
275f8829a4aSRandall Stewart 
276139bc87fSRandall Stewart 
27777acdc25SRandall Stewart static void
27877acdc25SRandall Stewart sctp_mark_non_revokable(struct sctp_association *asoc, uint32_t tsn)
27977acdc25SRandall Stewart {
2809b2e0767SRandall Stewart 	uint32_t gap, i, cumackp1;
28177acdc25SRandall Stewart 	int fnd = 0;
28244249214SRandall Stewart 	int in_r = 0, in_nr = 0;
28377acdc25SRandall Stewart 
28477acdc25SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_do_drain) == 0) {
28577acdc25SRandall Stewart 		return;
28677acdc25SRandall Stewart 	}
2879b2e0767SRandall Stewart 	cumackp1 = asoc->cumulative_tsn + 1;
28820b07a4dSMichael Tuexen 	if (SCTP_TSN_GT(cumackp1, tsn)) {
2899b2e0767SRandall Stewart 		/*
2909b2e0767SRandall Stewart 		 * this tsn is behind the cum ack and thus we don't need to
2919b2e0767SRandall Stewart 		 * worry about it being moved from one to the other.
2929b2e0767SRandall Stewart 		 */
2939b2e0767SRandall Stewart 		return;
2949b2e0767SRandall Stewart 	}
29577acdc25SRandall Stewart 	SCTP_CALC_TSN_TO_GAP(gap, tsn, asoc->mapping_array_base_tsn);
29644249214SRandall Stewart 	in_r = SCTP_IS_TSN_PRESENT(asoc->mapping_array, gap);
29744249214SRandall Stewart 	in_nr = SCTP_IS_TSN_PRESENT(asoc->nr_mapping_array, gap);
29844249214SRandall Stewart 	if ((in_r == 0) && (in_nr == 0)) {
29944249214SRandall Stewart #ifdef INVARIANTS
30044249214SRandall Stewart 		panic("Things are really messed up now");
30144249214SRandall Stewart #else
302cd3fd531SMichael Tuexen 		SCTP_PRINTF("gap:%x tsn:%x\n", gap, tsn);
30377acdc25SRandall Stewart 		sctp_print_mapping_array(asoc);
30477acdc25SRandall Stewart #endif
305b5c16493SMichael Tuexen 	}
30644249214SRandall Stewart 	if (in_nr == 0)
30777acdc25SRandall Stewart 		SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap);
30844249214SRandall Stewart 	if (in_r)
30977acdc25SRandall Stewart 		SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap);
31020b07a4dSMichael Tuexen 	if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) {
31177acdc25SRandall Stewart 		asoc->highest_tsn_inside_nr_map = tsn;
31277acdc25SRandall Stewart 	}
31377acdc25SRandall Stewart 	if (tsn == asoc->highest_tsn_inside_map) {
31477acdc25SRandall Stewart 		/* We must back down to see what the new highest is */
31520b07a4dSMichael Tuexen 		for (i = tsn - 1; SCTP_TSN_GE(i, asoc->mapping_array_base_tsn); i--) {
31677acdc25SRandall Stewart 			SCTP_CALC_TSN_TO_GAP(gap, i, asoc->mapping_array_base_tsn);
31777acdc25SRandall Stewart 			if (SCTP_IS_TSN_PRESENT(asoc->mapping_array, gap)) {
31877acdc25SRandall Stewart 				asoc->highest_tsn_inside_map = i;
31977acdc25SRandall Stewart 				fnd = 1;
32077acdc25SRandall Stewart 				break;
32177acdc25SRandall Stewart 			}
32277acdc25SRandall Stewart 		}
32377acdc25SRandall Stewart 		if (!fnd) {
32477acdc25SRandall Stewart 			asoc->highest_tsn_inside_map = asoc->mapping_array_base_tsn - 1;
32577acdc25SRandall Stewart 		}
32677acdc25SRandall Stewart 	}
32777acdc25SRandall Stewart }
32877acdc25SRandall Stewart 
32944249214SRandall Stewart static int
33044249214SRandall Stewart sctp_place_control_in_stream(struct sctp_stream_in *strm,
33144249214SRandall Stewart     struct sctp_association *asoc,
33244249214SRandall Stewart     struct sctp_queued_to_read *control)
333f8829a4aSRandall Stewart {
33444249214SRandall Stewart 	struct sctp_queued_to_read *at;
33544249214SRandall Stewart 	struct sctp_readhead *q;
33644249214SRandall Stewart 	uint8_t bits, unordered;
337f8829a4aSRandall Stewart 
33844249214SRandall Stewart 	bits = (control->sinfo_flags >> 8);
33944249214SRandall Stewart 	unordered = bits & SCTP_DATA_UNORDERED;
34044249214SRandall Stewart 	if (unordered) {
34144249214SRandall Stewart 		q = &strm->uno_inqueue;
34244249214SRandall Stewart 		if (asoc->idata_supported == 0) {
34344249214SRandall Stewart 			if (!TAILQ_EMPTY(q)) {
344*5b495f17SMichael Tuexen 				/* Only one stream can be here in old style
345*5b495f17SMichael Tuexen 				 * -- abort */
34644249214SRandall Stewart 				return (-1);
34744249214SRandall Stewart 			}
34844249214SRandall Stewart 			TAILQ_INSERT_TAIL(q, control, next_instrm);
34944249214SRandall Stewart 			control->on_strm_q = SCTP_ON_UNORDERED;
35044249214SRandall Stewart 			return (0);
35144249214SRandall Stewart 		}
35244249214SRandall Stewart 	} else {
35344249214SRandall Stewart 		q = &strm->inqueue;
35444249214SRandall Stewart 	}
35544249214SRandall Stewart 	if ((bits & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) {
35644249214SRandall Stewart 		control->end_added = control->last_frag_seen = control->first_frag_seen = 1;
35744249214SRandall Stewart 	}
35844249214SRandall Stewart 	if (TAILQ_EMPTY(q)) {
35944249214SRandall Stewart 		/* Empty queue */
36044249214SRandall Stewart 		TAILQ_INSERT_HEAD(q, control, next_instrm);
36144249214SRandall Stewart 		if (unordered) {
36244249214SRandall Stewart 			control->on_strm_q = SCTP_ON_UNORDERED;
36344249214SRandall Stewart 		} else {
36444249214SRandall Stewart 			control->on_strm_q = SCTP_ON_ORDERED;
36544249214SRandall Stewart 		}
36644249214SRandall Stewart 		return (0);
36744249214SRandall Stewart 	} else {
36844249214SRandall Stewart 		TAILQ_FOREACH(at, q, next_instrm) {
36944249214SRandall Stewart 			if (SCTP_TSN_GT(at->msg_id, control->msg_id)) {
37044249214SRandall Stewart 				/*
37144249214SRandall Stewart 				 * one in queue is bigger than the new one,
37244249214SRandall Stewart 				 * insert before this one
37344249214SRandall Stewart 				 */
37444249214SRandall Stewart 				TAILQ_INSERT_BEFORE(at, control, next_instrm);
37544249214SRandall Stewart 				if (unordered) {
37644249214SRandall Stewart 					control->on_strm_q = SCTP_ON_UNORDERED;
37744249214SRandall Stewart 				} else {
37844249214SRandall Stewart 					control->on_strm_q = SCTP_ON_ORDERED;
37944249214SRandall Stewart 				}
38044249214SRandall Stewart 				break;
38144249214SRandall Stewart 			} else if (at->msg_id == control->msg_id) {
38244249214SRandall Stewart 				/*
38344249214SRandall Stewart 				 * Gak, He sent me a duplicate msg id
38444249214SRandall Stewart 				 * number?? return -1 to abort.
38544249214SRandall Stewart 				 */
38644249214SRandall Stewart 				return (-1);
38744249214SRandall Stewart 			} else {
38844249214SRandall Stewart 				if (TAILQ_NEXT(at, next_instrm) == NULL) {
38944249214SRandall Stewart 					/*
39044249214SRandall Stewart 					 * We are at the end, insert it
39144249214SRandall Stewart 					 * after this one
39244249214SRandall Stewart 					 */
39344249214SRandall Stewart 					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) {
39444249214SRandall Stewart 						sctp_log_strm_del(control, at,
39544249214SRandall Stewart 						    SCTP_STR_LOG_FROM_INSERT_TL);
39644249214SRandall Stewart 					}
39744249214SRandall Stewart 					TAILQ_INSERT_AFTER(q,
39844249214SRandall Stewart 					    at, control, next_instrm);
39944249214SRandall Stewart 					if (unordered) {
40044249214SRandall Stewart 						control->on_strm_q = SCTP_ON_UNORDERED;
40144249214SRandall Stewart 					} else {
40244249214SRandall Stewart 						control->on_strm_q = SCTP_ON_ORDERED;
40344249214SRandall Stewart 					}
40444249214SRandall Stewart 					break;
40544249214SRandall Stewart 				}
40644249214SRandall Stewart 			}
40744249214SRandall Stewart 		}
40844249214SRandall Stewart 	}
40944249214SRandall Stewart 	return (0);
41044249214SRandall Stewart }
41144249214SRandall Stewart 
41244249214SRandall Stewart static void
41344249214SRandall Stewart sctp_abort_in_reasm(struct sctp_tcb *stcb,
41444249214SRandall Stewart     struct sctp_queued_to_read *control,
41544249214SRandall Stewart     struct sctp_tmit_chunk *chk,
41644249214SRandall Stewart     int *abort_flag, int opspot)
41744249214SRandall Stewart {
41844249214SRandall Stewart 	char msg[SCTP_DIAG_INFO_LEN];
41944249214SRandall Stewart 	struct mbuf *oper;
42044249214SRandall Stewart 
42144249214SRandall Stewart 	if (stcb->asoc.idata_supported) {
42244249214SRandall Stewart 		snprintf(msg, sizeof(msg),
42344249214SRandall Stewart 		    "Reass %x,CF:%x,TSN=%8.8x,SID=%4.4x,FSN=%8.8x,MID:%8.8x",
42444249214SRandall Stewart 		    opspot,
42544249214SRandall Stewart 		    control->fsn_included,
42644249214SRandall Stewart 		    chk->rec.data.TSN_seq,
42744249214SRandall Stewart 		    chk->rec.data.stream_number,
42844249214SRandall Stewart 		    chk->rec.data.fsn_num, chk->rec.data.stream_seq);
42944249214SRandall Stewart 	} else {
43044249214SRandall Stewart 		snprintf(msg, sizeof(msg),
43144249214SRandall Stewart 		    "Reass %x,CI:%x,TSN=%8.8x,SID=%4.4x,FSN=%4.4x,SSN:%4.4x",
43244249214SRandall Stewart 		    opspot,
43344249214SRandall Stewart 		    control->fsn_included,
43444249214SRandall Stewart 		    chk->rec.data.TSN_seq,
43544249214SRandall Stewart 		    chk->rec.data.stream_number,
43644249214SRandall Stewart 		    chk->rec.data.fsn_num,
43744249214SRandall Stewart 		    (uint16_t) chk->rec.data.stream_seq);
43844249214SRandall Stewart 	}
43944249214SRandall Stewart 	oper = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
440f8829a4aSRandall Stewart 	sctp_m_freem(chk->data);
441f8829a4aSRandall Stewart 	chk->data = NULL;
442689e6a5fSMichael Tuexen 	sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
44344249214SRandall Stewart 	stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_1;
44444249214SRandall Stewart 	sctp_abort_an_association(stcb->sctp_ep, stcb, oper, SCTP_SO_NOT_LOCKED);
44544249214SRandall Stewart 	*abort_flag = 1;
446f8829a4aSRandall Stewart }
447f8829a4aSRandall Stewart 
44844249214SRandall Stewart static void
449d1ea5fa9SMichael Tuexen sctp_clean_up_control(struct sctp_tcb *stcb, struct sctp_queued_to_read *control)
45044249214SRandall Stewart {
451f8829a4aSRandall Stewart 	/*
45244249214SRandall Stewart 	 * The control could not be placed and must be cleaned.
453f8829a4aSRandall Stewart 	 */
45444249214SRandall Stewart 	struct sctp_tmit_chunk *chk, *nchk;
455df6e0cc3SRandall Stewart 
45644249214SRandall Stewart 	TAILQ_FOREACH_SAFE(chk, &control->reasm, sctp_next, nchk) {
45744249214SRandall Stewart 		TAILQ_REMOVE(&control->reasm, chk, sctp_next);
45844249214SRandall Stewart 		if (chk->data)
45944249214SRandall Stewart 			sctp_m_freem(chk->data);
460f8829a4aSRandall Stewart 		chk->data = NULL;
461689e6a5fSMichael Tuexen 		sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
462f8829a4aSRandall Stewart 	}
46344249214SRandall Stewart 	sctp_free_a_readq(stcb, control);
464f8829a4aSRandall Stewart }
465f8829a4aSRandall Stewart 
466f8829a4aSRandall Stewart /*
467f8829a4aSRandall Stewart  * Queue the chunk either right into the socket buffer if it is the next one
468f8829a4aSRandall Stewart  * to go OR put it in the correct place in the delivery queue.  If we do
46944249214SRandall Stewart  * append to the so_buf, keep doing so until we are out of order as
47044249214SRandall Stewart  * long as the control's entered are non-fragmented.
471f8829a4aSRandall Stewart  */
472f8829a4aSRandall Stewart static void
47344249214SRandall Stewart sctp_queue_data_to_stream(struct sctp_tcb *stcb,
47444249214SRandall Stewart     struct sctp_stream_in *strm,
47544249214SRandall Stewart     struct sctp_association *asoc,
47644249214SRandall Stewart     struct sctp_queued_to_read *control, int *abort_flag, int *need_reasm)
477f8829a4aSRandall Stewart {
478f8829a4aSRandall Stewart 	/*
479f8829a4aSRandall Stewart 	 * FIX-ME maybe? What happens when the ssn wraps? If we are getting
480f8829a4aSRandall Stewart 	 * all the data in one stream this could happen quite rapidly. One
481f8829a4aSRandall Stewart 	 * could use the TSN to keep track of things, but this scheme breaks
482cd0a4ff6SPedro F. Giffuni 	 * down in the other type of stream usage that could occur. Send a
483f8829a4aSRandall Stewart 	 * single msg to stream 0, send 4Billion messages to stream 1, now
484f8829a4aSRandall Stewart 	 * send a message to stream 0. You have a situation where the TSN
485f8829a4aSRandall Stewart 	 * has wrapped but not in the stream. Is this worth worrying about
486f8829a4aSRandall Stewart 	 * or should we just change our queue sort at the bottom to be by
487f8829a4aSRandall Stewart 	 * TSN.
488f8829a4aSRandall Stewart 	 *
489*5b495f17SMichael Tuexen 	 * Could it also be legal for a peer to send ssn 1 with TSN 2 and
490*5b495f17SMichael Tuexen 	 * ssn 2 with TSN 1? If the peer is doing some sort of funky TSN/SSN
491f8829a4aSRandall Stewart 	 * assignment this could happen... and I don't see how this would be
492f8829a4aSRandall Stewart 	 * a violation. So for now I am undecided an will leave the sort by
493f8829a4aSRandall Stewart 	 * SSN alone. Maybe a hybred approach is the answer
494f8829a4aSRandall Stewart 	 *
495f8829a4aSRandall Stewart 	 */
496f8829a4aSRandall Stewart 	struct sctp_queued_to_read *at;
497f8829a4aSRandall Stewart 	int queue_needed;
49844249214SRandall Stewart 	uint32_t nxt_todel;
499ff1ffd74SMichael Tuexen 	struct mbuf *op_err;
500ff1ffd74SMichael Tuexen 	char msg[SCTP_DIAG_INFO_LEN];
501f8829a4aSRandall Stewart 
502b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) {
503f8829a4aSRandall Stewart 		sctp_log_strm_del(control, NULL, SCTP_STR_LOG_FROM_INTO_STRD);
50480fefe0aSRandall Stewart 	}
50544249214SRandall Stewart 	if (SCTP_MSGID_GT((!asoc->idata_supported), strm->last_sequence_delivered, control->sinfo_ssn)) {
506f8829a4aSRandall Stewart 		/* The incoming sseq is behind where we last delivered? */
507f2ea2a2dSMichael Tuexen 		SCTPDBG(SCTP_DEBUG_INDATA1, "Duplicate S-SEQ: %u delivered: %u from peer, Abort association\n",
508ad81507eSRandall Stewart 		    control->sinfo_ssn, strm->last_sequence_delivered);
509c40e9cf2SRandall Stewart protocol_error:
510f8829a4aSRandall Stewart 		/*
511f8829a4aSRandall Stewart 		 * throw it in the stream so it gets cleaned up in
512f8829a4aSRandall Stewart 		 * association destruction
513f8829a4aSRandall Stewart 		 */
51444249214SRandall Stewart 		TAILQ_INSERT_HEAD(&strm->inqueue, control, next_instrm);
515ff1ffd74SMichael Tuexen 		snprintf(msg, sizeof(msg), "Delivered SSN=%4.4x, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x",
516ff1ffd74SMichael Tuexen 		    strm->last_sequence_delivered, control->sinfo_tsn,
517ff1ffd74SMichael Tuexen 		    control->sinfo_stream, control->sinfo_ssn);
518ff1ffd74SMichael Tuexen 		op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
51944249214SRandall Stewart 		stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_2;
520ff1ffd74SMichael Tuexen 		sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
521f8829a4aSRandall Stewart 		*abort_flag = 1;
522f8829a4aSRandall Stewart 		return;
523f8829a4aSRandall Stewart 
524f8829a4aSRandall Stewart 	}
52544249214SRandall Stewart 	if ((SCTP_TSN_GE(asoc->cumulative_tsn, control->sinfo_tsn)) && (asoc->idata_supported == 0)) {
52644249214SRandall Stewart 		goto protocol_error;
52744249214SRandall Stewart 	}
52844249214SRandall Stewart 	queue_needed = 1;
52944249214SRandall Stewart 	asoc->size_on_all_streams += control->length;
53044249214SRandall Stewart 	sctp_ucount_incr(asoc->cnt_on_all_streams);
53144249214SRandall Stewart 	nxt_todel = strm->last_sequence_delivered + 1;
53244249214SRandall Stewart 	if (nxt_todel == control->sinfo_ssn) {
533cf9e47b2SMichael Tuexen #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
534cf9e47b2SMichael Tuexen 		struct socket *so;
535cf9e47b2SMichael Tuexen 
536cf9e47b2SMichael Tuexen 		so = SCTP_INP_SO(stcb->sctp_ep);
537cf9e47b2SMichael Tuexen 		atomic_add_int(&stcb->asoc.refcnt, 1);
538cf9e47b2SMichael Tuexen 		SCTP_TCB_UNLOCK(stcb);
539cf9e47b2SMichael Tuexen 		SCTP_SOCKET_LOCK(so, 1);
540cf9e47b2SMichael Tuexen 		SCTP_TCB_LOCK(stcb);
541cf9e47b2SMichael Tuexen 		atomic_subtract_int(&stcb->asoc.refcnt, 1);
542cf9e47b2SMichael Tuexen 		if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
543cf9e47b2SMichael Tuexen 			SCTP_SOCKET_UNLOCK(so, 1);
544cf9e47b2SMichael Tuexen 			return;
545cf9e47b2SMichael Tuexen 		}
546cf9e47b2SMichael Tuexen #endif
547f8829a4aSRandall Stewart 		/* can be delivered right away? */
548b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) {
549f8829a4aSRandall Stewart 			sctp_log_strm_del(control, NULL, SCTP_STR_LOG_FROM_IMMED_DEL);
55080fefe0aSRandall Stewart 		}
551830d754dSRandall Stewart 		/* EY it wont be queued if it could be delivered directly */
552f8829a4aSRandall Stewart 		queue_needed = 0;
553f8829a4aSRandall Stewart 		asoc->size_on_all_streams -= control->length;
554f8829a4aSRandall Stewart 		sctp_ucount_decr(asoc->cnt_on_all_streams);
555f8829a4aSRandall Stewart 		strm->last_sequence_delivered++;
556b5c16493SMichael Tuexen 		sctp_mark_non_revokable(asoc, control->sinfo_tsn);
557f8829a4aSRandall Stewart 		sctp_add_to_readq(stcb->sctp_ep, stcb,
558f8829a4aSRandall Stewart 		    control,
559cfde3ff7SRandall Stewart 		    &stcb->sctp_socket->so_rcv, 1,
560574679afSMichael Tuexen 		    SCTP_READ_LOCK_NOT_HELD, SCTP_SO_LOCKED);
56144249214SRandall Stewart 		TAILQ_FOREACH_SAFE(control, &strm->inqueue, next_instrm, at) {
562f8829a4aSRandall Stewart 			/* all delivered */
563f8829a4aSRandall Stewart 			nxt_todel = strm->last_sequence_delivered + 1;
56444249214SRandall Stewart 			if ((nxt_todel == control->sinfo_ssn) &&
56544249214SRandall Stewart 			    (((control->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG)) {
566f8829a4aSRandall Stewart 				asoc->size_on_all_streams -= control->length;
567f8829a4aSRandall Stewart 				sctp_ucount_decr(asoc->cnt_on_all_streams);
56844249214SRandall Stewart 				if (control->on_strm_q == SCTP_ON_ORDERED) {
56944249214SRandall Stewart 					TAILQ_REMOVE(&strm->inqueue, control, next_instrm);
57098d5fd97SMichael Tuexen #ifdef INVARIANTS
57144249214SRandall Stewart 				} else {
57244249214SRandall Stewart 					panic("Huh control: %p is on_strm_q: %d",
57344249214SRandall Stewart 					    control, control->on_strm_q);
57498d5fd97SMichael Tuexen #endif
57544249214SRandall Stewart 				}
57644249214SRandall Stewart 				control->on_strm_q = 0;
577f8829a4aSRandall Stewart 				strm->last_sequence_delivered++;
578f8829a4aSRandall Stewart 				/*
579f8829a4aSRandall Stewart 				 * We ignore the return of deliver_data here
580f8829a4aSRandall Stewart 				 * since we always can hold the chunk on the
581f8829a4aSRandall Stewart 				 * d-queue. And we have a finite number that
582f8829a4aSRandall Stewart 				 * can be delivered from the strq.
583f8829a4aSRandall Stewart 				 */
584b3f1ea41SRandall Stewart 				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) {
585f8829a4aSRandall Stewart 					sctp_log_strm_del(control, NULL,
586f8829a4aSRandall Stewart 					    SCTP_STR_LOG_FROM_IMMED_DEL);
58780fefe0aSRandall Stewart 				}
588b5c16493SMichael Tuexen 				sctp_mark_non_revokable(asoc, control->sinfo_tsn);
589f8829a4aSRandall Stewart 				sctp_add_to_readq(stcb->sctp_ep, stcb,
590f8829a4aSRandall Stewart 				    control,
591cfde3ff7SRandall Stewart 				    &stcb->sctp_socket->so_rcv, 1,
592cfde3ff7SRandall Stewart 				    SCTP_READ_LOCK_NOT_HELD,
593574679afSMichael Tuexen 				    SCTP_SO_LOCKED);
594f8829a4aSRandall Stewart 				continue;
59544249214SRandall Stewart 			} else if (nxt_todel == control->sinfo_ssn) {
59644249214SRandall Stewart 				*need_reasm = 1;
597f8829a4aSRandall Stewart 			}
598f8829a4aSRandall Stewart 			break;
599f8829a4aSRandall Stewart 		}
60044249214SRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
60144249214SRandall Stewart 		SCTP_SOCKET_UNLOCK(so, 1);
60244249214SRandall Stewart #endif
603f8829a4aSRandall Stewart 	}
604f8829a4aSRandall Stewart 	if (queue_needed) {
605f8829a4aSRandall Stewart 		/*
606f8829a4aSRandall Stewart 		 * Ok, we did not deliver this guy, find the correct place
607f8829a4aSRandall Stewart 		 * to put it on the queue.
608f8829a4aSRandall Stewart 		 */
60944249214SRandall Stewart 		if (sctp_place_control_in_stream(strm, asoc, control)) {
61044249214SRandall Stewart 			snprintf(msg, sizeof(msg),
611f2ea2a2dSMichael Tuexen 			    "Queue to str msg_id: %u duplicate",
61244249214SRandall Stewart 			    control->msg_id);
613d1ea5fa9SMichael Tuexen 			sctp_clean_up_control(stcb, control);
614b1deed45SMichael Tuexen 			op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
61544249214SRandall Stewart 			stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_3;
616b1deed45SMichael Tuexen 			sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
61744249214SRandall Stewart 			*abort_flag = 1;
618f8829a4aSRandall Stewart 		}
619f8829a4aSRandall Stewart 	}
620f8829a4aSRandall Stewart }
621f8829a4aSRandall Stewart 
62244249214SRandall Stewart 
62344249214SRandall Stewart static void
62444249214SRandall Stewart sctp_setup_tail_pointer(struct sctp_queued_to_read *control)
625f8829a4aSRandall Stewart {
62644249214SRandall Stewart 	struct mbuf *m, *prev = NULL;
62744249214SRandall Stewart 	struct sctp_tcb *stcb;
628f8829a4aSRandall Stewart 
62944249214SRandall Stewart 	stcb = control->stcb;
63044249214SRandall Stewart 	control->held_length = 0;
63144249214SRandall Stewart 	control->length = 0;
63244249214SRandall Stewart 	m = control->data;
63344249214SRandall Stewart 	while (m) {
63444249214SRandall Stewart 		if (SCTP_BUF_LEN(m) == 0) {
63544249214SRandall Stewart 			/* Skip mbufs with NO length */
63644249214SRandall Stewart 			if (prev == NULL) {
63744249214SRandall Stewart 				/* First one */
63844249214SRandall Stewart 				control->data = sctp_m_free(m);
63944249214SRandall Stewart 				m = control->data;
64044249214SRandall Stewart 			} else {
64144249214SRandall Stewart 				SCTP_BUF_NEXT(prev) = sctp_m_free(m);
64244249214SRandall Stewart 				m = SCTP_BUF_NEXT(prev);
643f8829a4aSRandall Stewart 			}
64444249214SRandall Stewart 			if (m == NULL) {
64544249214SRandall Stewart 				control->tail_mbuf = prev;
646f8829a4aSRandall Stewart 			}
64744249214SRandall Stewart 			continue;
648f8829a4aSRandall Stewart 		}
64944249214SRandall Stewart 		prev = m;
65044249214SRandall Stewart 		atomic_add_int(&control->length, SCTP_BUF_LEN(m));
65144249214SRandall Stewart 		if (control->on_read_q) {
65244249214SRandall Stewart 			/*
65344249214SRandall Stewart 			 * On read queue so we must increment the SB stuff,
65444249214SRandall Stewart 			 * we assume caller has done any locks of SB.
65544249214SRandall Stewart 			 */
65644249214SRandall Stewart 			sctp_sballoc(stcb, &stcb->sctp_socket->so_rcv, m);
657f8829a4aSRandall Stewart 		}
65844249214SRandall Stewart 		m = SCTP_BUF_NEXT(m);
659f8829a4aSRandall Stewart 	}
66044249214SRandall Stewart 	if (prev) {
66144249214SRandall Stewart 		control->tail_mbuf = prev;
66244249214SRandall Stewart 	}
663f8829a4aSRandall Stewart }
664f8829a4aSRandall Stewart 
665f8829a4aSRandall Stewart static void
66644249214SRandall Stewart sctp_add_to_tail_pointer(struct sctp_queued_to_read *control, struct mbuf *m)
667f8829a4aSRandall Stewart {
66844249214SRandall Stewart 	struct mbuf *prev = NULL;
66944249214SRandall Stewart 	struct sctp_tcb *stcb;
670f8829a4aSRandall Stewart 
67144249214SRandall Stewart 	stcb = control->stcb;
67244249214SRandall Stewart 	if (stcb == NULL) {
67398d5fd97SMichael Tuexen #ifdef INVARIANTS
67444249214SRandall Stewart 		panic("Control broken");
67598d5fd97SMichael Tuexen #else
67698d5fd97SMichael Tuexen 		return;
67798d5fd97SMichael Tuexen #endif
67844249214SRandall Stewart 	}
67944249214SRandall Stewart 	if (control->tail_mbuf == NULL) {
68044249214SRandall Stewart 		/* TSNH */
68144249214SRandall Stewart 		control->data = m;
68244249214SRandall Stewart 		sctp_setup_tail_pointer(control);
683f8829a4aSRandall Stewart 		return;
684f8829a4aSRandall Stewart 	}
68544249214SRandall Stewart 	control->tail_mbuf->m_next = m;
68644249214SRandall Stewart 	while (m) {
68744249214SRandall Stewart 		if (SCTP_BUF_LEN(m) == 0) {
68844249214SRandall Stewart 			/* Skip mbufs with NO length */
68944249214SRandall Stewart 			if (prev == NULL) {
69044249214SRandall Stewart 				/* First one */
69144249214SRandall Stewart 				control->tail_mbuf->m_next = sctp_m_free(m);
69244249214SRandall Stewart 				m = control->tail_mbuf->m_next;
69344249214SRandall Stewart 			} else {
69444249214SRandall Stewart 				SCTP_BUF_NEXT(prev) = sctp_m_free(m);
69544249214SRandall Stewart 				m = SCTP_BUF_NEXT(prev);
69644249214SRandall Stewart 			}
69744249214SRandall Stewart 			if (m == NULL) {
69844249214SRandall Stewart 				control->tail_mbuf = prev;
69944249214SRandall Stewart 			}
70044249214SRandall Stewart 			continue;
70144249214SRandall Stewart 		}
70244249214SRandall Stewart 		prev = m;
70344249214SRandall Stewart 		if (control->on_read_q) {
704f8829a4aSRandall Stewart 			/*
70544249214SRandall Stewart 			 * On read queue so we must increment the SB stuff,
70644249214SRandall Stewart 			 * we assume caller has done any locks of SB.
707f8829a4aSRandall Stewart 			 */
70844249214SRandall Stewart 			sctp_sballoc(stcb, &stcb->sctp_socket->so_rcv, m);
70944249214SRandall Stewart 		}
71044249214SRandall Stewart 		atomic_add_int(&control->length, SCTP_BUF_LEN(m));
71144249214SRandall Stewart 		m = SCTP_BUF_NEXT(m);
71244249214SRandall Stewart 	}
71344249214SRandall Stewart 	if (prev) {
71444249214SRandall Stewart 		control->tail_mbuf = prev;
71544249214SRandall Stewart 	}
71644249214SRandall Stewart }
71744249214SRandall Stewart 
71844249214SRandall Stewart static void
71944249214SRandall Stewart sctp_build_readq_entry_from_ctl(struct sctp_queued_to_read *nc, struct sctp_queued_to_read *control)
72044249214SRandall Stewart {
72144249214SRandall Stewart 	memset(nc, 0, sizeof(struct sctp_queued_to_read));
72244249214SRandall Stewart 	nc->sinfo_stream = control->sinfo_stream;
72344249214SRandall Stewart 	nc->sinfo_ssn = control->sinfo_ssn;
72444249214SRandall Stewart 	TAILQ_INIT(&nc->reasm);
72544249214SRandall Stewart 	nc->top_fsn = control->top_fsn;
72644249214SRandall Stewart 	nc->msg_id = control->msg_id;
72744249214SRandall Stewart 	nc->sinfo_flags = control->sinfo_flags;
72844249214SRandall Stewart 	nc->sinfo_ppid = control->sinfo_ppid;
72944249214SRandall Stewart 	nc->sinfo_context = control->sinfo_context;
73044249214SRandall Stewart 	nc->fsn_included = 0xffffffff;
73144249214SRandall Stewart 	nc->sinfo_tsn = control->sinfo_tsn;
73244249214SRandall Stewart 	nc->sinfo_cumtsn = control->sinfo_cumtsn;
73344249214SRandall Stewart 	nc->sinfo_assoc_id = control->sinfo_assoc_id;
73444249214SRandall Stewart 	nc->whoFrom = control->whoFrom;
73544249214SRandall Stewart 	atomic_add_int(&nc->whoFrom->ref_count, 1);
73644249214SRandall Stewart 	nc->stcb = control->stcb;
73744249214SRandall Stewart 	nc->port_from = control->port_from;
73844249214SRandall Stewart }
73944249214SRandall Stewart 
740d1ea5fa9SMichael Tuexen static void
741d1ea5fa9SMichael Tuexen sctp_reset_a_control(struct sctp_queued_to_read *control,
742d1ea5fa9SMichael Tuexen     struct sctp_inpcb *inp, uint32_t tsn)
743d1ea5fa9SMichael Tuexen {
744d1ea5fa9SMichael Tuexen 	control->fsn_included = tsn;
745d1ea5fa9SMichael Tuexen 	if (control->on_read_q) {
746d1ea5fa9SMichael Tuexen 		/*
747d1ea5fa9SMichael Tuexen 		 * We have to purge it from there, hopefully this will work
748d1ea5fa9SMichael Tuexen 		 * :-)
749d1ea5fa9SMichael Tuexen 		 */
750d1ea5fa9SMichael Tuexen 		TAILQ_REMOVE(&inp->read_queue, control, next);
751d1ea5fa9SMichael Tuexen 		control->on_read_q = 0;
752d1ea5fa9SMichael Tuexen 	}
753d1ea5fa9SMichael Tuexen }
754d1ea5fa9SMichael Tuexen 
75544249214SRandall Stewart static int
756d1ea5fa9SMichael Tuexen sctp_handle_old_unordered_data(struct sctp_tcb *stcb,
757d1ea5fa9SMichael Tuexen     struct sctp_association *asoc,
758d1ea5fa9SMichael Tuexen     struct sctp_stream_in *strm,
759d1ea5fa9SMichael Tuexen     struct sctp_queued_to_read *control,
760d1ea5fa9SMichael Tuexen     uint32_t pd_point,
761d1ea5fa9SMichael Tuexen     int inp_read_lock_held)
76244249214SRandall Stewart {
76344249214SRandall Stewart 	/*
76444249214SRandall Stewart 	 * Special handling for the old un-ordered data chunk. All the
76544249214SRandall Stewart 	 * chunks/TSN's go to msg_id 0. So we have to do the old style
76644249214SRandall Stewart 	 * watching to see if we have it all. If you return one, no other
76744249214SRandall Stewart 	 * control entries on the un-ordered queue will be looked at. In
76844249214SRandall Stewart 	 * theory there should be no others entries in reality, unless the
76944249214SRandall Stewart 	 * guy is sending both unordered NDATA and unordered DATA...
77044249214SRandall Stewart 	 */
77144249214SRandall Stewart 	struct sctp_tmit_chunk *chk, *lchk, *tchk;
77244249214SRandall Stewart 	uint32_t fsn;
773643fd575SMichael Tuexen 	struct sctp_queued_to_read *nc;
77444249214SRandall Stewart 	int cnt_added;
77544249214SRandall Stewart 
77644249214SRandall Stewart 	if (control->first_frag_seen == 0) {
77744249214SRandall Stewart 		/* Nothing we can do, we have not seen the first piece yet */
77844249214SRandall Stewart 		return (1);
77944249214SRandall Stewart 	}
78044249214SRandall Stewart 	/* Collapse any we can */
78144249214SRandall Stewart 	cnt_added = 0;
78244249214SRandall Stewart restart:
78344249214SRandall Stewart 	fsn = control->fsn_included + 1;
78444249214SRandall Stewart 	/* Now what can we add? */
78544249214SRandall Stewart 	TAILQ_FOREACH_SAFE(chk, &control->reasm, sctp_next, lchk) {
78644249214SRandall Stewart 		if (chk->rec.data.fsn_num == fsn) {
78744249214SRandall Stewart 			/* Ok lets add it */
788643fd575SMichael Tuexen 			sctp_alloc_a_readq(stcb, nc);
789643fd575SMichael Tuexen 			if (nc == NULL) {
790643fd575SMichael Tuexen 				break;
791643fd575SMichael Tuexen 			}
792643fd575SMichael Tuexen 			memset(nc, 0, sizeof(struct sctp_queued_to_read));
79344249214SRandall Stewart 			TAILQ_REMOVE(&control->reasm, chk, sctp_next);
794d1ea5fa9SMichael Tuexen 			sctp_add_chk_to_control(control, strm, stcb, asoc, chk, SCTP_READ_LOCK_NOT_HELD);
79544249214SRandall Stewart 			fsn++;
79644249214SRandall Stewart 			cnt_added++;
79744249214SRandall Stewart 			chk = NULL;
79844249214SRandall Stewart 			if (control->end_added) {
79944249214SRandall Stewart 				/* We are done */
80044249214SRandall Stewart 				if (!TAILQ_EMPTY(&control->reasm)) {
80144249214SRandall Stewart 					/*
80244249214SRandall Stewart 					 * Ok we have to move anything left
80344249214SRandall Stewart 					 * on the control queue to a new
80444249214SRandall Stewart 					 * control.
80544249214SRandall Stewart 					 */
80644249214SRandall Stewart 					sctp_build_readq_entry_from_ctl(nc, control);
80744249214SRandall Stewart 					tchk = TAILQ_FIRST(&control->reasm);
80844249214SRandall Stewart 					if (tchk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) {
80944249214SRandall Stewart 						TAILQ_REMOVE(&control->reasm, tchk, sctp_next);
8105cb91655SMichael Tuexen 						asoc->size_on_reasm_queue -= tchk->send_size;
8115cb91655SMichael Tuexen 						sctp_ucount_decr(asoc->cnt_on_reasm_queue);
81244249214SRandall Stewart 						nc->first_frag_seen = 1;
81344249214SRandall Stewart 						nc->fsn_included = tchk->rec.data.fsn_num;
81444249214SRandall Stewart 						nc->data = tchk->data;
815d1ea5fa9SMichael Tuexen 						nc->sinfo_ppid = tchk->rec.data.payloadtype;
816d1ea5fa9SMichael Tuexen 						nc->sinfo_tsn = tchk->rec.data.TSN_seq;
81744249214SRandall Stewart 						sctp_mark_non_revokable(asoc, tchk->rec.data.TSN_seq);
81844249214SRandall Stewart 						tchk->data = NULL;
81944249214SRandall Stewart 						sctp_free_a_chunk(stcb, tchk, SCTP_SO_NOT_LOCKED);
82044249214SRandall Stewart 						sctp_setup_tail_pointer(nc);
82144249214SRandall Stewart 						tchk = TAILQ_FIRST(&control->reasm);
82244249214SRandall Stewart 					}
82344249214SRandall Stewart 					/* Spin the rest onto the queue */
82444249214SRandall Stewart 					while (tchk) {
82544249214SRandall Stewart 						TAILQ_REMOVE(&control->reasm, tchk, sctp_next);
82644249214SRandall Stewart 						TAILQ_INSERT_TAIL(&nc->reasm, tchk, sctp_next);
82744249214SRandall Stewart 						tchk = TAILQ_FIRST(&control->reasm);
82844249214SRandall Stewart 					}
829*5b495f17SMichael Tuexen 					/* Now lets add it to the queue
830*5b495f17SMichael Tuexen 					 * after removing control */
83144249214SRandall Stewart 					TAILQ_INSERT_TAIL(&strm->uno_inqueue, nc, next_instrm);
83244249214SRandall Stewart 					nc->on_strm_q = SCTP_ON_UNORDERED;
83344249214SRandall Stewart 					if (control->on_strm_q) {
83444249214SRandall Stewart 						TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm);
83544249214SRandall Stewart 						control->on_strm_q = 0;
83644249214SRandall Stewart 					}
83744249214SRandall Stewart 				}
83844249214SRandall Stewart 				if (control->pdapi_started) {
83944249214SRandall Stewart 					strm->pd_api_started = 0;
84044249214SRandall Stewart 					control->pdapi_started = 0;
84144249214SRandall Stewart 				}
84244249214SRandall Stewart 				if (control->on_strm_q) {
84344249214SRandall Stewart 					TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm);
84444249214SRandall Stewart 					control->on_strm_q = 0;
84526f0250aSMichael Tuexen 					SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs);
84644249214SRandall Stewart 				}
847c09a1534SMichael Tuexen 				if (control->on_read_q == 0) {
848c09a1534SMichael Tuexen 					sctp_add_to_readq(stcb->sctp_ep, stcb, control,
849c09a1534SMichael Tuexen 					    &stcb->sctp_socket->so_rcv, control->end_added,
850d1ea5fa9SMichael Tuexen 					    inp_read_lock_held, SCTP_SO_NOT_LOCKED);
851c09a1534SMichael Tuexen 				}
852b1deed45SMichael Tuexen 				sctp_wakeup_the_read_socket(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED);
8530fa7377aSMichael Tuexen 				if ((nc->first_frag_seen) && !TAILQ_EMPTY(&nc->reasm)) {
854*5b495f17SMichael Tuexen 					/* Switch to the new guy and
855*5b495f17SMichael Tuexen 					 * continue */
85644249214SRandall Stewart 					control = nc;
85744249214SRandall Stewart 					goto restart;
858643fd575SMichael Tuexen 				} else {
859d1ea5fa9SMichael Tuexen 					if (nc->on_strm_q == 0) {
860643fd575SMichael Tuexen 						sctp_free_a_readq(stcb, nc);
86144249214SRandall Stewart 					}
862d1ea5fa9SMichael Tuexen 				}
86344249214SRandall Stewart 				return (1);
864643fd575SMichael Tuexen 			} else {
865643fd575SMichael Tuexen 				sctp_free_a_readq(stcb, nc);
86644249214SRandall Stewart 			}
86744249214SRandall Stewart 		} else {
86844249214SRandall Stewart 			/* Can't add more */
86944249214SRandall Stewart 			break;
87044249214SRandall Stewart 		}
87144249214SRandall Stewart 	}
87244249214SRandall Stewart 	if ((control->length > pd_point) && (strm->pd_api_started == 0)) {
873c09a1534SMichael Tuexen 		strm->pd_api_started = 1;
874c09a1534SMichael Tuexen 		control->pdapi_started = 1;
87544249214SRandall Stewart 		sctp_add_to_readq(stcb->sctp_ep, stcb, control,
87644249214SRandall Stewart 		    &stcb->sctp_socket->so_rcv, control->end_added,
877d1ea5fa9SMichael Tuexen 		    inp_read_lock_held, SCTP_SO_NOT_LOCKED);
878b1deed45SMichael Tuexen 		sctp_wakeup_the_read_socket(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED);
87944249214SRandall Stewart 		return (0);
88044249214SRandall Stewart 	} else {
88144249214SRandall Stewart 		return (1);
88244249214SRandall Stewart 	}
88344249214SRandall Stewart }
88444249214SRandall Stewart 
88544249214SRandall Stewart static void
886d1ea5fa9SMichael Tuexen sctp_inject_old_unordered_data(struct sctp_tcb *stcb,
887d1ea5fa9SMichael Tuexen     struct sctp_association *asoc,
88844249214SRandall Stewart     struct sctp_queued_to_read *control,
88944249214SRandall Stewart     struct sctp_tmit_chunk *chk,
89044249214SRandall Stewart     int *abort_flag)
89144249214SRandall Stewart {
89244249214SRandall Stewart 	struct sctp_tmit_chunk *at;
893d1ea5fa9SMichael Tuexen 	int inserted;
89444249214SRandall Stewart 
89544249214SRandall Stewart 	/*
89644249214SRandall Stewart 	 * Here we need to place the chunk into the control structure sorted
89744249214SRandall Stewart 	 * in the correct order.
89844249214SRandall Stewart 	 */
89944249214SRandall Stewart 	if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) {
90044249214SRandall Stewart 		/* Its the very first one. */
90144249214SRandall Stewart 		SCTPDBG(SCTP_DEBUG_XXX,
902f2ea2a2dSMichael Tuexen 		    "chunk is a first fsn: %u becomes fsn_included\n",
90344249214SRandall Stewart 		    chk->rec.data.fsn_num);
90444249214SRandall Stewart 		if (control->first_frag_seen) {
90544249214SRandall Stewart 			/*
90644249214SRandall Stewart 			 * In old un-ordered we can reassembly on one
90744249214SRandall Stewart 			 * control multiple messages. As long as the next
90844249214SRandall Stewart 			 * FIRST is greater then the old first (TSN i.e. FSN
90944249214SRandall Stewart 			 * wise)
91044249214SRandall Stewart 			 */
91144249214SRandall Stewart 			struct mbuf *tdata;
91244249214SRandall Stewart 			uint32_t tmp;
91344249214SRandall Stewart 
91444249214SRandall Stewart 			if (SCTP_TSN_GT(chk->rec.data.fsn_num, control->fsn_included)) {
915*5b495f17SMichael Tuexen 				/* Easy way the start of a new guy beyond
916*5b495f17SMichael Tuexen 				 * the lowest */
91744249214SRandall Stewart 				goto place_chunk;
91844249214SRandall Stewart 			}
91944249214SRandall Stewart 			if ((chk->rec.data.fsn_num == control->fsn_included) ||
92044249214SRandall Stewart 			    (control->pdapi_started)) {
92144249214SRandall Stewart 				/*
92244249214SRandall Stewart 				 * Ok this should not happen, if it does we
92344249214SRandall Stewart 				 * started the pd-api on the higher TSN
92444249214SRandall Stewart 				 * (since the equals part is a TSN failure
92544249214SRandall Stewart 				 * it must be that).
92644249214SRandall Stewart 				 *
927*5b495f17SMichael Tuexen 				 * We are completly hosed in that case since
928*5b495f17SMichael Tuexen 				 * I have no way to recover. This really
929*5b495f17SMichael Tuexen 				 * will only happen if we can get more TSN's
93044249214SRandall Stewart 				 * higher before the pd-api-point.
93144249214SRandall Stewart 				 */
932b1deed45SMichael Tuexen 				sctp_abort_in_reasm(stcb, control, chk,
93344249214SRandall Stewart 				    abort_flag,
93444249214SRandall Stewart 				    SCTP_FROM_SCTP_INDATA + SCTP_LOC_4);
93544249214SRandall Stewart 
93644249214SRandall Stewart 				return;
93744249214SRandall Stewart 			}
93844249214SRandall Stewart 			/*
93944249214SRandall Stewart 			 * Ok we have two firsts and the one we just got is
94044249214SRandall Stewart 			 * smaller than the one we previously placed.. yuck!
94144249214SRandall Stewart 			 * We must swap them out.
94244249214SRandall Stewart 			 */
94344249214SRandall Stewart 			/* swap the mbufs */
94444249214SRandall Stewart 			tdata = control->data;
94544249214SRandall Stewart 			control->data = chk->data;
94644249214SRandall Stewart 			chk->data = tdata;
947d1ea5fa9SMichael Tuexen 			/* Save the lengths */
948d1ea5fa9SMichael Tuexen 			chk->send_size = control->length;
949d1ea5fa9SMichael Tuexen 			/* Recompute length of control and tail pointer */
950d1ea5fa9SMichael Tuexen 			sctp_setup_tail_pointer(control);
95144249214SRandall Stewart 			/* Fix the FSN included */
95244249214SRandall Stewart 			tmp = control->fsn_included;
95344249214SRandall Stewart 			control->fsn_included = chk->rec.data.fsn_num;
95444249214SRandall Stewart 			chk->rec.data.fsn_num = tmp;
955d1ea5fa9SMichael Tuexen 			/* Fix the TSN included */
956d1ea5fa9SMichael Tuexen 			tmp = control->sinfo_tsn;
957d1ea5fa9SMichael Tuexen 			control->sinfo_tsn = chk->rec.data.TSN_seq;
958d1ea5fa9SMichael Tuexen 			chk->rec.data.TSN_seq = tmp;
959d1ea5fa9SMichael Tuexen 			/* Fix the PPID included */
960d1ea5fa9SMichael Tuexen 			tmp = control->sinfo_ppid;
961d1ea5fa9SMichael Tuexen 			control->sinfo_ppid = chk->rec.data.payloadtype;
962d1ea5fa9SMichael Tuexen 			chk->rec.data.payloadtype = tmp;
963d1ea5fa9SMichael Tuexen 			/* Fix tail pointer */
96444249214SRandall Stewart 			goto place_chunk;
96544249214SRandall Stewart 		}
96644249214SRandall Stewart 		control->first_frag_seen = 1;
96744249214SRandall Stewart 		control->top_fsn = control->fsn_included = chk->rec.data.fsn_num;
968d1ea5fa9SMichael Tuexen 		control->sinfo_tsn = chk->rec.data.TSN_seq;
969d1ea5fa9SMichael Tuexen 		control->sinfo_ppid = chk->rec.data.payloadtype;
97044249214SRandall Stewart 		control->data = chk->data;
97144249214SRandall Stewart 		sctp_mark_non_revokable(asoc, chk->rec.data.TSN_seq);
97244249214SRandall Stewart 		chk->data = NULL;
97344249214SRandall Stewart 		sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
97444249214SRandall Stewart 		sctp_setup_tail_pointer(control);
97544249214SRandall Stewart 		return;
97644249214SRandall Stewart 	}
97744249214SRandall Stewart place_chunk:
978d1ea5fa9SMichael Tuexen 	inserted = 0;
97944249214SRandall Stewart 	TAILQ_FOREACH(at, &control->reasm, sctp_next) {
98044249214SRandall Stewart 		if (SCTP_TSN_GT(at->rec.data.fsn_num, chk->rec.data.fsn_num)) {
98144249214SRandall Stewart 			/*
98244249214SRandall Stewart 			 * This one in queue is bigger than the new one,
98344249214SRandall Stewart 			 * insert the new one before at.
98444249214SRandall Stewart 			 */
98544249214SRandall Stewart 			asoc->size_on_reasm_queue += chk->send_size;
98644249214SRandall Stewart 			sctp_ucount_incr(asoc->cnt_on_reasm_queue);
98744249214SRandall Stewart 			inserted = 1;
98844249214SRandall Stewart 			TAILQ_INSERT_BEFORE(at, chk, sctp_next);
98944249214SRandall Stewart 			break;
99044249214SRandall Stewart 		} else if (at->rec.data.fsn_num == chk->rec.data.fsn_num) {
99144249214SRandall Stewart 			/*
99244249214SRandall Stewart 			 * They sent a duplicate fsn number. This really
99344249214SRandall Stewart 			 * should not happen since the FSN is a TSN and it
99444249214SRandall Stewart 			 * should have been dropped earlier.
99544249214SRandall Stewart 			 */
996b1deed45SMichael Tuexen 			sctp_abort_in_reasm(stcb, control, chk,
99744249214SRandall Stewart 			    abort_flag,
99844249214SRandall Stewart 			    SCTP_FROM_SCTP_INDATA + SCTP_LOC_5);
99944249214SRandall Stewart 			return;
100044249214SRandall Stewart 		}
100144249214SRandall Stewart 	}
100244249214SRandall Stewart 	if (inserted == 0) {
100344249214SRandall Stewart 		/* Its at the end */
100444249214SRandall Stewart 		asoc->size_on_reasm_queue += chk->send_size;
100544249214SRandall Stewart 		sctp_ucount_incr(asoc->cnt_on_reasm_queue);
100644249214SRandall Stewart 		control->top_fsn = chk->rec.data.fsn_num;
100744249214SRandall Stewart 		TAILQ_INSERT_TAIL(&control->reasm, chk, sctp_next);
100844249214SRandall Stewart 	}
100944249214SRandall Stewart }
101044249214SRandall Stewart 
101144249214SRandall Stewart static int
1012d1ea5fa9SMichael Tuexen sctp_deliver_reasm_check(struct sctp_tcb *stcb, struct sctp_association *asoc,
1013d1ea5fa9SMichael Tuexen     struct sctp_stream_in *strm, int inp_read_lock_held)
101444249214SRandall Stewart {
101544249214SRandall Stewart 	/*
101644249214SRandall Stewart 	 * Given a stream, strm, see if any of the SSN's on it that are
101744249214SRandall Stewart 	 * fragmented are ready to deliver. If so go ahead and place them on
101844249214SRandall Stewart 	 * the read queue. In so placing if we have hit the end, then we
101944249214SRandall Stewart 	 * need to remove them from the stream's queue.
102044249214SRandall Stewart 	 */
102144249214SRandall Stewart 	struct sctp_queued_to_read *control, *nctl = NULL;
102244249214SRandall Stewart 	uint32_t next_to_del;
102344249214SRandall Stewart 	uint32_t pd_point;
102444249214SRandall Stewart 	int ret = 0;
102544249214SRandall Stewart 
1026810ec536SMichael Tuexen 	if (stcb->sctp_socket) {
1027d4d23375SMichael Tuexen 		pd_point = min(SCTP_SB_LIMIT_RCV(stcb->sctp_socket) >> SCTP_PARTIAL_DELIVERY_SHIFT,
1028810ec536SMichael Tuexen 		    stcb->sctp_ep->partial_delivery_point);
1029810ec536SMichael Tuexen 	} else {
1030810ec536SMichael Tuexen 		pd_point = stcb->sctp_ep->partial_delivery_point;
1031810ec536SMichael Tuexen 	}
103244249214SRandall Stewart 	control = TAILQ_FIRST(&strm->uno_inqueue);
1033d1ea5fa9SMichael Tuexen 
103444249214SRandall Stewart 	if ((control) &&
103544249214SRandall Stewart 	    (asoc->idata_supported == 0)) {
103644249214SRandall Stewart 		/* Special handling needed for "old" data format */
1037d1ea5fa9SMichael Tuexen 		if (sctp_handle_old_unordered_data(stcb, asoc, strm, control, pd_point, inp_read_lock_held)) {
103844249214SRandall Stewart 			goto done_un;
1039f8829a4aSRandall Stewart 		}
1040f8829a4aSRandall Stewart 	}
104144249214SRandall Stewart 	if (strm->pd_api_started) {
104244249214SRandall Stewart 		/* Can't add more */
104344249214SRandall Stewart 		return (0);
104444249214SRandall Stewart 	}
104544249214SRandall Stewart 	while (control) {
1046f2ea2a2dSMichael Tuexen 		SCTPDBG(SCTP_DEBUG_XXX, "Looking at control: %p e(%d) ssn: %u top_fsn: %u inc_fsn: %u -uo\n",
104744249214SRandall Stewart 		    control, control->end_added, control->sinfo_ssn, control->top_fsn, control->fsn_included);
104844249214SRandall Stewart 		nctl = TAILQ_NEXT(control, next_instrm);
104944249214SRandall Stewart 		if (control->end_added) {
105044249214SRandall Stewart 			/* We just put the last bit on */
105144249214SRandall Stewart 			if (control->on_strm_q) {
105298d5fd97SMichael Tuexen #ifdef INVARIANTS
105344249214SRandall Stewart 				if (control->on_strm_q != SCTP_ON_UNORDERED) {
105444249214SRandall Stewart 					panic("Huh control: %p on_q: %d -- not unordered?",
105544249214SRandall Stewart 					    control, control->on_strm_q);
105644249214SRandall Stewart 				}
105798d5fd97SMichael Tuexen #endif
105826f0250aSMichael Tuexen 				SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs);
105944249214SRandall Stewart 				TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm);
106044249214SRandall Stewart 				control->on_strm_q = 0;
106144249214SRandall Stewart 			}
106244249214SRandall Stewart 			if (control->on_read_q == 0) {
106344249214SRandall Stewart 				sctp_add_to_readq(stcb->sctp_ep, stcb,
106444249214SRandall Stewart 				    control,
106544249214SRandall Stewart 				    &stcb->sctp_socket->so_rcv, control->end_added,
1066d1ea5fa9SMichael Tuexen 				    inp_read_lock_held, SCTP_SO_NOT_LOCKED);
106744249214SRandall Stewart 			}
1068f8829a4aSRandall Stewart 		} else {
106944249214SRandall Stewart 			/* Can we do a PD-API for this un-ordered guy? */
107044249214SRandall Stewart 			if ((control->length >= pd_point) && (strm->pd_api_started == 0)) {
107144249214SRandall Stewart 				strm->pd_api_started = 1;
107244249214SRandall Stewart 				control->pdapi_started = 1;
107344249214SRandall Stewart 				sctp_add_to_readq(stcb->sctp_ep, stcb,
107444249214SRandall Stewart 				    control,
107544249214SRandall Stewart 				    &stcb->sctp_socket->so_rcv, control->end_added,
1076d1ea5fa9SMichael Tuexen 				    inp_read_lock_held, SCTP_SO_NOT_LOCKED);
107744249214SRandall Stewart 
107844249214SRandall Stewart 				break;
1079139bc87fSRandall Stewart 			}
1080f8829a4aSRandall Stewart 		}
108144249214SRandall Stewart 		control = nctl;
108244249214SRandall Stewart 	}
108344249214SRandall Stewart done_un:
108444249214SRandall Stewart 	control = TAILQ_FIRST(&strm->inqueue);
108544249214SRandall Stewart 	if (strm->pd_api_started) {
108644249214SRandall Stewart 		/* Can't add more */
108744249214SRandall Stewart 		return (0);
108844249214SRandall Stewart 	}
108944249214SRandall Stewart 	if (control == NULL) {
109044249214SRandall Stewart 		return (ret);
109144249214SRandall Stewart 	}
109244249214SRandall Stewart 	if (strm->last_sequence_delivered == control->sinfo_ssn) {
109344249214SRandall Stewart 		/*
109444249214SRandall Stewart 		 * Ok the guy at the top was being partially delivered
109544249214SRandall Stewart 		 * completed, so we remove it. Note the pd_api flag was
109644249214SRandall Stewart 		 * taken off when the chunk was merged on in
109744249214SRandall Stewart 		 * sctp_queue_data_for_reasm below.
109844249214SRandall Stewart 		 */
109944249214SRandall Stewart 		nctl = TAILQ_NEXT(control, next_instrm);
110044249214SRandall Stewart 		SCTPDBG(SCTP_DEBUG_XXX,
1101f2ea2a2dSMichael Tuexen 		    "Looking at control: %p e(%d) ssn: %u top_fsn: %u inc_fsn: %u (lastdel: %u)- o\n",
110244249214SRandall Stewart 		    control, control->end_added, control->sinfo_ssn,
110344249214SRandall Stewart 		    control->top_fsn, control->fsn_included,
110444249214SRandall Stewart 		    strm->last_sequence_delivered);
110544249214SRandall Stewart 		if (control->end_added) {
110644249214SRandall Stewart 			if (control->on_strm_q) {
110798d5fd97SMichael Tuexen #ifdef INVARIANTS
110844249214SRandall Stewart 				if (control->on_strm_q != SCTP_ON_ORDERED) {
110944249214SRandall Stewart 					panic("Huh control: %p on_q: %d -- not ordered?",
111044249214SRandall Stewart 					    control, control->on_strm_q);
111144249214SRandall Stewart 				}
111298d5fd97SMichael Tuexen #endif
111326f0250aSMichael Tuexen 				SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs);
111444249214SRandall Stewart 				TAILQ_REMOVE(&strm->inqueue, control, next_instrm);
111544249214SRandall Stewart 				control->on_strm_q = 0;
111644249214SRandall Stewart 			}
1117c09a1534SMichael Tuexen 			if (strm->pd_api_started && control->pdapi_started) {
1118c09a1534SMichael Tuexen 				control->pdapi_started = 0;
1119c09a1534SMichael Tuexen 				strm->pd_api_started = 0;
1120c09a1534SMichael Tuexen 			}
112144249214SRandall Stewart 			if (control->on_read_q == 0) {
112244249214SRandall Stewart 				sctp_add_to_readq(stcb->sctp_ep, stcb,
112344249214SRandall Stewart 				    control,
112444249214SRandall Stewart 				    &stcb->sctp_socket->so_rcv, control->end_added,
1125d1ea5fa9SMichael Tuexen 				    inp_read_lock_held, SCTP_SO_NOT_LOCKED);
112644249214SRandall Stewart 			}
112744249214SRandall Stewart 			control = nctl;
112844249214SRandall Stewart 		}
112944249214SRandall Stewart 	}
113044249214SRandall Stewart 	if (strm->pd_api_started) {
1131*5b495f17SMichael Tuexen 		/* Can't add more must have gotten an un-ordered above being
1132*5b495f17SMichael Tuexen 		 * partially delivered. */
113344249214SRandall Stewart 		return (0);
113444249214SRandall Stewart 	}
113544249214SRandall Stewart deliver_more:
113644249214SRandall Stewart 	next_to_del = strm->last_sequence_delivered + 1;
113744249214SRandall Stewart 	if (control) {
113844249214SRandall Stewart 		SCTPDBG(SCTP_DEBUG_XXX,
1139f2ea2a2dSMichael Tuexen 		    "Looking at control: %p e(%d) ssn: %u top_fsn: %u inc_fsn: %u (nxtdel: %u)- o\n",
114044249214SRandall Stewart 		    control, control->end_added, control->sinfo_ssn, control->top_fsn, control->fsn_included,
114144249214SRandall Stewart 		    next_to_del);
114244249214SRandall Stewart 		nctl = TAILQ_NEXT(control, next_instrm);
114344249214SRandall Stewart 		if ((control->sinfo_ssn == next_to_del) &&
114444249214SRandall Stewart 		    (control->first_frag_seen)) {
1145c09a1534SMichael Tuexen 			int done;
1146c09a1534SMichael Tuexen 
114744249214SRandall Stewart 			/* Ok we can deliver it onto the stream. */
114844249214SRandall Stewart 			if (control->end_added) {
114944249214SRandall Stewart 				/* We are done with it afterwards */
115044249214SRandall Stewart 				if (control->on_strm_q) {
115198d5fd97SMichael Tuexen #ifdef INVARIANTS
115244249214SRandall Stewart 					if (control->on_strm_q != SCTP_ON_ORDERED) {
115344249214SRandall Stewart 						panic("Huh control: %p on_q: %d -- not ordered?",
115444249214SRandall Stewart 						    control, control->on_strm_q);
115544249214SRandall Stewart 					}
115698d5fd97SMichael Tuexen #endif
115726f0250aSMichael Tuexen 					SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs);
115844249214SRandall Stewart 					TAILQ_REMOVE(&strm->inqueue, control, next_instrm);
115944249214SRandall Stewart 					control->on_strm_q = 0;
116044249214SRandall Stewart 				}
116144249214SRandall Stewart 				ret++;
116244249214SRandall Stewart 			}
116344249214SRandall Stewart 			if (((control->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) {
1164*5b495f17SMichael Tuexen 				/* A singleton now slipping through - mark
1165*5b495f17SMichael Tuexen 				 * it non-revokable too */
116644249214SRandall Stewart 				sctp_mark_non_revokable(asoc, control->sinfo_tsn);
116744249214SRandall Stewart 			} else if (control->end_added == 0) {
1168*5b495f17SMichael Tuexen 				/* Check if we can defer adding until its
1169*5b495f17SMichael Tuexen 				 * all there */
117044249214SRandall Stewart 				if ((control->length < pd_point) || (strm->pd_api_started)) {
1171*5b495f17SMichael Tuexen 					/* Don't need it or cannot add more
1172*5b495f17SMichael Tuexen 					 * (one being delivered that way) */
117344249214SRandall Stewart 					goto out;
117444249214SRandall Stewart 				}
117544249214SRandall Stewart 			}
1176c09a1534SMichael Tuexen 			done = (control->end_added) && (control->last_frag_seen);
117744249214SRandall Stewart 			if (control->on_read_q == 0) {
117844249214SRandall Stewart 				sctp_add_to_readq(stcb->sctp_ep, stcb,
117944249214SRandall Stewart 				    control,
118044249214SRandall Stewart 				    &stcb->sctp_socket->so_rcv, control->end_added,
1181d1ea5fa9SMichael Tuexen 				    inp_read_lock_held, SCTP_SO_NOT_LOCKED);
118244249214SRandall Stewart 			}
118344249214SRandall Stewart 			strm->last_sequence_delivered = next_to_del;
1184c09a1534SMichael Tuexen 			if (done) {
118544249214SRandall Stewart 				control = nctl;
118644249214SRandall Stewart 				goto deliver_more;
118744249214SRandall Stewart 			} else {
118844249214SRandall Stewart 				/* We are now doing PD API */
118944249214SRandall Stewart 				strm->pd_api_started = 1;
119044249214SRandall Stewart 				control->pdapi_started = 1;
119144249214SRandall Stewart 			}
119244249214SRandall Stewart 		}
119344249214SRandall Stewart 	}
119444249214SRandall Stewart out:
119544249214SRandall Stewart 	return (ret);
119644249214SRandall Stewart }
119744249214SRandall Stewart 
1198d1ea5fa9SMichael Tuexen 
119944249214SRandall Stewart void
120044249214SRandall Stewart sctp_add_chk_to_control(struct sctp_queued_to_read *control,
120144249214SRandall Stewart     struct sctp_stream_in *strm,
120244249214SRandall Stewart     struct sctp_tcb *stcb, struct sctp_association *asoc,
1203d1ea5fa9SMichael Tuexen     struct sctp_tmit_chunk *chk, int hold_rlock)
120444249214SRandall Stewart {
120544249214SRandall Stewart 	/*
120644249214SRandall Stewart 	 * Given a control and a chunk, merge the data from the chk onto the
120744249214SRandall Stewart 	 * control and free up the chunk resources.
120844249214SRandall Stewart 	 */
120944249214SRandall Stewart 	int i_locked = 0;
121044249214SRandall Stewart 
1211d1ea5fa9SMichael Tuexen 	if (control->on_read_q && (hold_rlock == 0)) {
121244249214SRandall Stewart 		/*
121344249214SRandall Stewart 		 * Its being pd-api'd so we must do some locks.
121444249214SRandall Stewart 		 */
121544249214SRandall Stewart 		SCTP_INP_READ_LOCK(stcb->sctp_ep);
121644249214SRandall Stewart 		i_locked = 1;
121744249214SRandall Stewart 	}
121844249214SRandall Stewart 	if (control->data == NULL) {
121944249214SRandall Stewart 		control->data = chk->data;
122044249214SRandall Stewart 		sctp_setup_tail_pointer(control);
122144249214SRandall Stewart 	} else {
122244249214SRandall Stewart 		sctp_add_to_tail_pointer(control, chk->data);
122344249214SRandall Stewart 	}
122444249214SRandall Stewart 	control->fsn_included = chk->rec.data.fsn_num;
122544249214SRandall Stewart 	asoc->size_on_reasm_queue -= chk->send_size;
122644249214SRandall Stewart 	sctp_ucount_decr(asoc->cnt_on_reasm_queue);
122744249214SRandall Stewart 	sctp_mark_non_revokable(asoc, chk->rec.data.TSN_seq);
122844249214SRandall Stewart 	chk->data = NULL;
122944249214SRandall Stewart 	if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) {
123044249214SRandall Stewart 		control->first_frag_seen = 1;
123144249214SRandall Stewart 	}
123244249214SRandall Stewart 	if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) {
123344249214SRandall Stewart 		/* Its complete */
123444249214SRandall Stewart 		if ((control->on_strm_q) && (control->on_read_q)) {
123544249214SRandall Stewart 			if (control->pdapi_started) {
123644249214SRandall Stewart 				control->pdapi_started = 0;
123744249214SRandall Stewart 				strm->pd_api_started = 0;
123844249214SRandall Stewart 			}
123944249214SRandall Stewart 			if (control->on_strm_q == SCTP_ON_UNORDERED) {
124044249214SRandall Stewart 				/* Unordered */
124144249214SRandall Stewart 				TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm);
124244249214SRandall Stewart 				control->on_strm_q = 0;
124344249214SRandall Stewart 			} else if (control->on_strm_q == SCTP_ON_ORDERED) {
124444249214SRandall Stewart 				/* Ordered */
124544249214SRandall Stewart 				TAILQ_REMOVE(&strm->inqueue, control, next_instrm);
124644249214SRandall Stewart 				control->on_strm_q = 0;
124798d5fd97SMichael Tuexen #ifdef INVARIANTS
124844249214SRandall Stewart 			} else if (control->on_strm_q) {
124944249214SRandall Stewart 				panic("Unknown state on ctrl: %p on_strm_q: %d", control,
125044249214SRandall Stewart 				    control->on_strm_q);
125198d5fd97SMichael Tuexen #endif
125244249214SRandall Stewart 			}
125344249214SRandall Stewart 		}
125444249214SRandall Stewart 		control->end_added = 1;
125544249214SRandall Stewart 		control->last_frag_seen = 1;
125644249214SRandall Stewart 	}
125744249214SRandall Stewart 	if (i_locked) {
125844249214SRandall Stewart 		SCTP_INP_READ_UNLOCK(stcb->sctp_ep);
125944249214SRandall Stewart 	}
126044249214SRandall Stewart 	sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
1261f8829a4aSRandall Stewart }
1262f8829a4aSRandall Stewart 
1263f8829a4aSRandall Stewart /*
1264f8829a4aSRandall Stewart  * Dump onto the re-assembly queue, in its proper place. After dumping on the
1265f8829a4aSRandall Stewart  * queue, see if anthing can be delivered. If so pull it off (or as much as
1266f8829a4aSRandall Stewart  * we can. If we run out of space then we must dump what we can and set the
1267f8829a4aSRandall Stewart  * appropriate flag to say we queued what we could.
1268f8829a4aSRandall Stewart  */
1269f8829a4aSRandall Stewart static void
1270f8829a4aSRandall Stewart sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc,
127144249214SRandall Stewart     struct sctp_stream_in *strm,
127244249214SRandall Stewart     struct sctp_queued_to_read *control,
127344249214SRandall Stewart     struct sctp_tmit_chunk *chk,
127444249214SRandall Stewart     int created_control,
127544249214SRandall Stewart     int *abort_flag, uint32_t tsn)
1276f8829a4aSRandall Stewart {
127744249214SRandall Stewart 	uint32_t next_fsn;
127844249214SRandall Stewart 	struct sctp_tmit_chunk *at, *nat;
1279c09a1534SMichael Tuexen 	int do_wakeup, unordered;
1280f8829a4aSRandall Stewart 
1281f8829a4aSRandall Stewart 	/*
128244249214SRandall Stewart 	 * For old un-ordered data chunks.
1283f8829a4aSRandall Stewart 	 */
128444249214SRandall Stewart 	if ((control->sinfo_flags >> 8) & SCTP_DATA_UNORDERED) {
128544249214SRandall Stewart 		unordered = 1;
1286f8829a4aSRandall Stewart 	} else {
128744249214SRandall Stewart 		unordered = 0;
128844249214SRandall Stewart 	}
128944249214SRandall Stewart 	/* Must be added to the stream-in queue */
129044249214SRandall Stewart 	if (created_control) {
129144249214SRandall Stewart 		if (sctp_place_control_in_stream(strm, asoc, control)) {
129244249214SRandall Stewart 			/* Duplicate SSN? */
1293d1ea5fa9SMichael Tuexen 			sctp_clean_up_control(stcb, control);
1294b1deed45SMichael Tuexen 			sctp_abort_in_reasm(stcb, control, chk,
129544249214SRandall Stewart 			    abort_flag,
129644249214SRandall Stewart 			    SCTP_FROM_SCTP_INDATA + SCTP_LOC_6);
129744249214SRandall Stewart 			return;
129844249214SRandall Stewart 		}
129944249214SRandall Stewart 		if ((tsn == (asoc->cumulative_tsn + 1) && (asoc->idata_supported == 0))) {
1300f8829a4aSRandall Stewart 			/*
130144249214SRandall Stewart 			 * Ok we created this control and now lets validate
130244249214SRandall Stewart 			 * that its legal i.e. there is a B bit set, if not
130344249214SRandall Stewart 			 * and we have up to the cum-ack then its invalid.
130444249214SRandall Stewart 			 */
130544249214SRandall Stewart 			if ((chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) == 0) {
1306b1deed45SMichael Tuexen 				sctp_abort_in_reasm(stcb, control, chk,
130744249214SRandall Stewart 				    abort_flag,
130844249214SRandall Stewart 				    SCTP_FROM_SCTP_INDATA + SCTP_LOC_7);
130944249214SRandall Stewart 				return;
131044249214SRandall Stewart 			}
131144249214SRandall Stewart 		}
131244249214SRandall Stewart 	}
1313a39ddef0SMichael Tuexen 	if ((asoc->idata_supported == 0) && (unordered == 1)) {
1314d1ea5fa9SMichael Tuexen 		sctp_inject_old_unordered_data(stcb, asoc, control, chk, abort_flag);
131544249214SRandall Stewart 		return;
131644249214SRandall Stewart 	}
131744249214SRandall Stewart 	/*
131844249214SRandall Stewart 	 * Ok we must queue the chunk into the reasembly portion: o if its
131944249214SRandall Stewart 	 * the first it goes to the control mbuf. o if its not first but the
132044249214SRandall Stewart 	 * next in sequence it goes to the control, and each succeeding one
132144249214SRandall Stewart 	 * in order also goes. o if its not in order we place it on the list
132244249214SRandall Stewart 	 * in its place.
132344249214SRandall Stewart 	 */
132444249214SRandall Stewart 	if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) {
132544249214SRandall Stewart 		/* Its the very first one. */
132644249214SRandall Stewart 		SCTPDBG(SCTP_DEBUG_XXX,
1327f2ea2a2dSMichael Tuexen 		    "chunk is a first fsn: %u becomes fsn_included\n",
132844249214SRandall Stewart 		    chk->rec.data.fsn_num);
132944249214SRandall Stewart 		if (control->first_frag_seen) {
133044249214SRandall Stewart 			/*
133144249214SRandall Stewart 			 * Error on senders part, they either sent us two
133244249214SRandall Stewart 			 * data chunks with FIRST, or they sent two
133344249214SRandall Stewart 			 * un-ordered chunks that were fragmented at the
133444249214SRandall Stewart 			 * same time in the same stream.
133544249214SRandall Stewart 			 */
1336b1deed45SMichael Tuexen 			sctp_abort_in_reasm(stcb, control, chk,
133744249214SRandall Stewart 			    abort_flag,
133844249214SRandall Stewart 			    SCTP_FROM_SCTP_INDATA + SCTP_LOC_8);
133944249214SRandall Stewart 			return;
134044249214SRandall Stewart 		}
134144249214SRandall Stewart 		control->first_frag_seen = 1;
134244249214SRandall Stewart 		control->fsn_included = chk->rec.data.fsn_num;
134344249214SRandall Stewart 		control->data = chk->data;
134444249214SRandall Stewart 		sctp_mark_non_revokable(asoc, chk->rec.data.TSN_seq);
134544249214SRandall Stewart 		chk->data = NULL;
134644249214SRandall Stewart 		sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
134744249214SRandall Stewart 		sctp_setup_tail_pointer(control);
134844249214SRandall Stewart 	} else {
134944249214SRandall Stewart 		/* Place the chunk in our list */
135044249214SRandall Stewart 		int inserted = 0;
135144249214SRandall Stewart 
135244249214SRandall Stewart 		if (control->last_frag_seen == 0) {
135344249214SRandall Stewart 			/* Still willing to raise highest FSN seen */
135444249214SRandall Stewart 			if (SCTP_TSN_GT(chk->rec.data.fsn_num, control->top_fsn)) {
135544249214SRandall Stewart 				SCTPDBG(SCTP_DEBUG_XXX,
1356f2ea2a2dSMichael Tuexen 				    "We have a new top_fsn: %u\n",
135744249214SRandall Stewart 				    chk->rec.data.fsn_num);
135844249214SRandall Stewart 				control->top_fsn = chk->rec.data.fsn_num;
135944249214SRandall Stewart 			}
136044249214SRandall Stewart 			if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) {
136144249214SRandall Stewart 				SCTPDBG(SCTP_DEBUG_XXX,
1362f2ea2a2dSMichael Tuexen 				    "The last fsn is now in place fsn: %u\n",
136344249214SRandall Stewart 				    chk->rec.data.fsn_num);
136444249214SRandall Stewart 				control->last_frag_seen = 1;
136544249214SRandall Stewart 			}
136644249214SRandall Stewart 			if (asoc->idata_supported || control->first_frag_seen) {
136744249214SRandall Stewart 				/*
136844249214SRandall Stewart 				 * For IDATA we always check since we know
136944249214SRandall Stewart 				 * that the first fragment is 0. For old
137044249214SRandall Stewart 				 * DATA we have to receive the first before
1371cd0a4ff6SPedro F. Giffuni 				 * we know the first FSN (which is the TSN).
137244249214SRandall Stewart 				 */
137344249214SRandall Stewart 				if (SCTP_TSN_GE(control->fsn_included, chk->rec.data.fsn_num)) {
1374*5b495f17SMichael Tuexen 					/* We have already delivered up to
1375*5b495f17SMichael Tuexen 					 * this so its a dup */
1376b1deed45SMichael Tuexen 					sctp_abort_in_reasm(stcb, control, chk,
137744249214SRandall Stewart 					    abort_flag,
137844249214SRandall Stewart 					    SCTP_FROM_SCTP_INDATA + SCTP_LOC_9);
137944249214SRandall Stewart 					return;
138044249214SRandall Stewart 				}
138144249214SRandall Stewart 			}
138244249214SRandall Stewart 		} else {
138344249214SRandall Stewart 			if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) {
138444249214SRandall Stewart 				/* Second last? huh? */
138544249214SRandall Stewart 				SCTPDBG(SCTP_DEBUG_XXX,
1386f2ea2a2dSMichael Tuexen 				    "Duplicate last fsn: %u (top: %u) -- abort\n",
138744249214SRandall Stewart 				    chk->rec.data.fsn_num, control->top_fsn);
1388b1deed45SMichael Tuexen 				sctp_abort_in_reasm(stcb, control,
138944249214SRandall Stewart 				    chk, abort_flag,
139044249214SRandall Stewart 				    SCTP_FROM_SCTP_INDATA + SCTP_LOC_10);
139144249214SRandall Stewart 				return;
139244249214SRandall Stewart 			}
139344249214SRandall Stewart 			if (asoc->idata_supported || control->first_frag_seen) {
139444249214SRandall Stewart 				/*
139544249214SRandall Stewart 				 * For IDATA we always check since we know
139644249214SRandall Stewart 				 * that the first fragment is 0. For old
139744249214SRandall Stewart 				 * DATA we have to receive the first before
1398cd0a4ff6SPedro F. Giffuni 				 * we know the first FSN (which is the TSN).
139944249214SRandall Stewart 				 */
140044249214SRandall Stewart 
140144249214SRandall Stewart 				if (SCTP_TSN_GE(control->fsn_included, chk->rec.data.fsn_num)) {
1402*5b495f17SMichael Tuexen 					/* We have already delivered up to
1403*5b495f17SMichael Tuexen 					 * this so its a dup */
140444249214SRandall Stewart 					SCTPDBG(SCTP_DEBUG_XXX,
1405f2ea2a2dSMichael Tuexen 					    "New fsn: %u is already seen in included_fsn: %u -- abort\n",
140644249214SRandall Stewart 					    chk->rec.data.fsn_num, control->fsn_included);
1407b1deed45SMichael Tuexen 					sctp_abort_in_reasm(stcb, control, chk,
140844249214SRandall Stewart 					    abort_flag,
140944249214SRandall Stewart 					    SCTP_FROM_SCTP_INDATA + SCTP_LOC_11);
141044249214SRandall Stewart 					return;
141144249214SRandall Stewart 				}
141244249214SRandall Stewart 			}
1413*5b495f17SMichael Tuexen 			/* validate not beyond top FSN if we have seen last
1414*5b495f17SMichael Tuexen 			 * one */
141544249214SRandall Stewart 			if (SCTP_TSN_GT(chk->rec.data.fsn_num, control->top_fsn)) {
141644249214SRandall Stewart 				SCTPDBG(SCTP_DEBUG_XXX,
1417f2ea2a2dSMichael Tuexen 				    "New fsn: %u is beyond or at top_fsn: %u -- abort\n",
141844249214SRandall Stewart 				    chk->rec.data.fsn_num,
141944249214SRandall Stewart 				    control->top_fsn);
1420b1deed45SMichael Tuexen 				sctp_abort_in_reasm(stcb, control, chk,
142144249214SRandall Stewart 				    abort_flag,
142244249214SRandall Stewart 				    SCTP_FROM_SCTP_INDATA + SCTP_LOC_12);
142344249214SRandall Stewart 				return;
142444249214SRandall Stewart 			}
142544249214SRandall Stewart 		}
142644249214SRandall Stewart 		/*
142744249214SRandall Stewart 		 * If we reach here, we need to place the new chunk in the
142844249214SRandall Stewart 		 * reassembly for this control.
142944249214SRandall Stewart 		 */
143044249214SRandall Stewart 		SCTPDBG(SCTP_DEBUG_XXX,
1431f2ea2a2dSMichael Tuexen 		    "chunk is a not first fsn: %u needs to be inserted\n",
143244249214SRandall Stewart 		    chk->rec.data.fsn_num);
143344249214SRandall Stewart 		TAILQ_FOREACH(at, &control->reasm, sctp_next) {
143444249214SRandall Stewart 			if (SCTP_TSN_GT(at->rec.data.fsn_num, chk->rec.data.fsn_num)) {
143544249214SRandall Stewart 				/*
143644249214SRandall Stewart 				 * This one in queue is bigger than the new
143744249214SRandall Stewart 				 * one, insert the new one before at.
143844249214SRandall Stewart 				 */
143944249214SRandall Stewart 				SCTPDBG(SCTP_DEBUG_XXX,
1440f2ea2a2dSMichael Tuexen 				    "Insert it before fsn: %u\n",
144144249214SRandall Stewart 				    at->rec.data.fsn_num);
1442f8829a4aSRandall Stewart 				asoc->size_on_reasm_queue += chk->send_size;
1443f8829a4aSRandall Stewart 				sctp_ucount_incr(asoc->cnt_on_reasm_queue);
144444249214SRandall Stewart 				TAILQ_INSERT_BEFORE(at, chk, sctp_next);
144544249214SRandall Stewart 				inserted = 1;
144644249214SRandall Stewart 				break;
144744249214SRandall Stewart 			} else if (at->rec.data.fsn_num == chk->rec.data.fsn_num) {
1448*5b495f17SMichael Tuexen 				/* Gak, He sent me a duplicate str seq
1449*5b495f17SMichael Tuexen 				 * number */
145044249214SRandall Stewart 				/*
145144249214SRandall Stewart 				 * foo bar, I guess I will just free this
145244249214SRandall Stewart 				 * new guy, should we abort too? FIX ME
145344249214SRandall Stewart 				 * MAYBE? Or it COULD be that the SSN's have
145444249214SRandall Stewart 				 * wrapped. Maybe I should compare to TSN
145544249214SRandall Stewart 				 * somehow... sigh for now just blow away
145644249214SRandall Stewart 				 * the chunk!
145744249214SRandall Stewart 				 */
145844249214SRandall Stewart 				SCTPDBG(SCTP_DEBUG_XXX,
1459f2ea2a2dSMichael Tuexen 				    "Duplicate to fsn: %u -- abort\n",
146044249214SRandall Stewart 				    at->rec.data.fsn_num);
1461b1deed45SMichael Tuexen 				sctp_abort_in_reasm(stcb, control,
146244249214SRandall Stewart 				    chk, abort_flag,
146344249214SRandall Stewart 				    SCTP_FROM_SCTP_INDATA + SCTP_LOC_13);
146444249214SRandall Stewart 				return;
146544249214SRandall Stewart 			}
146644249214SRandall Stewart 		}
146744249214SRandall Stewart 		if (inserted == 0) {
146844249214SRandall Stewart 			/* Goes on the end */
1469f2ea2a2dSMichael Tuexen 			SCTPDBG(SCTP_DEBUG_XXX, "Inserting at tail of list fsn: %u\n",
147044249214SRandall Stewart 			    chk->rec.data.fsn_num);
147144249214SRandall Stewart 			asoc->size_on_reasm_queue += chk->send_size;
147244249214SRandall Stewart 			sctp_ucount_incr(asoc->cnt_on_reasm_queue);
147344249214SRandall Stewart 			TAILQ_INSERT_TAIL(&control->reasm, chk, sctp_next);
147444249214SRandall Stewart 		}
147544249214SRandall Stewart 	}
147644249214SRandall Stewart 	/*
147744249214SRandall Stewart 	 * Ok lets see if we can suck any up into the control structure that
147844249214SRandall Stewart 	 * are in seq if it makes sense.
147944249214SRandall Stewart 	 */
1480c09a1534SMichael Tuexen 	do_wakeup = 0;
148144249214SRandall Stewart 	/*
148244249214SRandall Stewart 	 * If the first fragment has not been seen there is no sense in
148344249214SRandall Stewart 	 * looking.
148444249214SRandall Stewart 	 */
148544249214SRandall Stewart 	if (control->first_frag_seen) {
148644249214SRandall Stewart 		next_fsn = control->fsn_included + 1;
148744249214SRandall Stewart 		TAILQ_FOREACH_SAFE(at, &control->reasm, sctp_next, nat) {
148844249214SRandall Stewart 			if (at->rec.data.fsn_num == next_fsn) {
148944249214SRandall Stewart 				/* We can add this one now to the control */
149044249214SRandall Stewart 				SCTPDBG(SCTP_DEBUG_XXX,
1491f2ea2a2dSMichael Tuexen 				    "Adding more to control: %p at: %p fsn: %u next_fsn: %u included: %u\n",
149244249214SRandall Stewart 				    control, at,
149344249214SRandall Stewart 				    at->rec.data.fsn_num,
149444249214SRandall Stewart 				    next_fsn, control->fsn_included);
149544249214SRandall Stewart 				TAILQ_REMOVE(&control->reasm, at, sctp_next);
1496d1ea5fa9SMichael Tuexen 				sctp_add_chk_to_control(control, strm, stcb, asoc, at, SCTP_READ_LOCK_NOT_HELD);
1497c09a1534SMichael Tuexen 				if (control->on_read_q) {
1498c09a1534SMichael Tuexen 					do_wakeup = 1;
1499c09a1534SMichael Tuexen 				}
150044249214SRandall Stewart 				next_fsn++;
150144249214SRandall Stewart 				if (control->end_added && control->pdapi_started) {
150244249214SRandall Stewart 					if (strm->pd_api_started) {
150344249214SRandall Stewart 						strm->pd_api_started = 0;
150444249214SRandall Stewart 						control->pdapi_started = 0;
150544249214SRandall Stewart 					}
150644249214SRandall Stewart 					if (control->on_read_q == 0) {
150744249214SRandall Stewart 						sctp_add_to_readq(stcb->sctp_ep, stcb,
150844249214SRandall Stewart 						    control,
150944249214SRandall Stewart 						    &stcb->sctp_socket->so_rcv, control->end_added,
151044249214SRandall Stewart 						    SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
1511c09a1534SMichael Tuexen 						do_wakeup = 1;
151244249214SRandall Stewart 					}
151344249214SRandall Stewart 					break;
151444249214SRandall Stewart 				}
151544249214SRandall Stewart 			} else {
1516f8829a4aSRandall Stewart 				break;
1517f8829a4aSRandall Stewart 			}
1518f8829a4aSRandall Stewart 		}
1519f8829a4aSRandall Stewart 	}
1520c09a1534SMichael Tuexen 	if (do_wakeup) {
152144249214SRandall Stewart 		/* Need to wakeup the reader */
1522b1deed45SMichael Tuexen 		sctp_wakeup_the_read_socket(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED);
1523f8829a4aSRandall Stewart 	}
1524f8829a4aSRandall Stewart }
1525f8829a4aSRandall Stewart 
152644249214SRandall Stewart static struct sctp_queued_to_read *
1527d1ea5fa9SMichael Tuexen sctp_find_reasm_entry(struct sctp_stream_in *strm, uint32_t msg_id, int ordered, int old)
1528f8829a4aSRandall Stewart {
1529c09a1534SMichael Tuexen 	struct sctp_queued_to_read *control;
1530f8829a4aSRandall Stewart 
153144249214SRandall Stewart 	if (ordered) {
1532c09a1534SMichael Tuexen 		TAILQ_FOREACH(control, &strm->inqueue, next_instrm) {
1533c09a1534SMichael Tuexen 			if (control->msg_id == msg_id) {
153444249214SRandall Stewart 				break;
153544249214SRandall Stewart 			}
153644249214SRandall Stewart 		}
1537f8829a4aSRandall Stewart 	} else {
153844249214SRandall Stewart 		if (old) {
1539c09a1534SMichael Tuexen 			control = TAILQ_FIRST(&strm->uno_inqueue);
1540c09a1534SMichael Tuexen 			return (control);
1541f8829a4aSRandall Stewart 		}
1542c09a1534SMichael Tuexen 		TAILQ_FOREACH(control, &strm->uno_inqueue, next_instrm) {
1543c09a1534SMichael Tuexen 			if (control->msg_id == msg_id) {
154444249214SRandall Stewart 				break;
1545f8829a4aSRandall Stewart 			}
1546f8829a4aSRandall Stewart 		}
1547f8829a4aSRandall Stewart 	}
1548c09a1534SMichael Tuexen 	return (control);
1549f8829a4aSRandall Stewart }
155044249214SRandall Stewart 
1551f8829a4aSRandall Stewart static int
1552f8829a4aSRandall Stewart sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
155344249214SRandall Stewart     struct mbuf **m, int offset, int chk_length,
1554f8829a4aSRandall Stewart     struct sctp_nets *net, uint32_t * high_tsn, int *abort_flag,
155544249214SRandall Stewart     int *break_flag, int last_chunk, uint8_t chtype)
1556f8829a4aSRandall Stewart {
1557f8829a4aSRandall Stewart 	/* Process a data chunk */
1558f8829a4aSRandall Stewart 	/* struct sctp_tmit_chunk *chk; */
155944249214SRandall Stewart 	struct sctp_data_chunk *ch;
156044249214SRandall Stewart 	struct sctp_idata_chunk *nch, chunk_buf;
1561f8829a4aSRandall Stewart 	struct sctp_tmit_chunk *chk;
156244249214SRandall Stewart 	uint32_t tsn, fsn, gap, msg_id;
1563f8829a4aSRandall Stewart 	struct mbuf *dmbuf;
15647215cc1bSMichael Tuexen 	int the_len;
1565139bc87fSRandall Stewart 	int need_reasm_check = 0;
156644249214SRandall Stewart 	uint16_t strmno;
1567ff1ffd74SMichael Tuexen 	struct mbuf *op_err;
1568ff1ffd74SMichael Tuexen 	char msg[SCTP_DIAG_INFO_LEN];
156944249214SRandall Stewart 	struct sctp_queued_to_read *control = NULL;
1570f42a358aSRandall Stewart 	uint32_t protocol_id;
1571f42a358aSRandall Stewart 	uint8_t chunk_flags;
157217205eccSRandall Stewart 	struct sctp_stream_reset_list *liste;
157344249214SRandall Stewart 	struct sctp_stream_in *strm;
157444249214SRandall Stewart 	int ordered;
157544249214SRandall Stewart 	size_t clen;
157644249214SRandall Stewart 	int created_control = 0;
157744249214SRandall Stewart 	uint8_t old_data;
1578f8829a4aSRandall Stewart 
1579f8829a4aSRandall Stewart 	chk = NULL;
158044249214SRandall Stewart 	if (chtype == SCTP_IDATA) {
158144249214SRandall Stewart 		nch = (struct sctp_idata_chunk *)sctp_m_getptr(*m, offset,
158244249214SRandall Stewart 		    sizeof(struct sctp_idata_chunk), (uint8_t *) & chunk_buf);
158344249214SRandall Stewart 		ch = (struct sctp_data_chunk *)nch;
158444249214SRandall Stewart 		clen = sizeof(struct sctp_idata_chunk);
1585f8829a4aSRandall Stewart 		tsn = ntohl(ch->dp.tsn);
158644249214SRandall Stewart 		msg_id = ntohl(nch->dp.msg_id);
1587d1ea5fa9SMichael Tuexen 		protocol_id = nch->dp.ppid_fsn.protocol_id;
158844249214SRandall Stewart 		if (ch->ch.chunk_flags & SCTP_DATA_FIRST_FRAG)
158944249214SRandall Stewart 			fsn = 0;
159044249214SRandall Stewart 		else
1591e187bac2SMichael Tuexen 			fsn = ntohl(nch->dp.ppid_fsn.fsn);
159244249214SRandall Stewart 		old_data = 0;
159344249214SRandall Stewart 	} else {
159444249214SRandall Stewart 		ch = (struct sctp_data_chunk *)sctp_m_getptr(*m, offset,
159544249214SRandall Stewart 		    sizeof(struct sctp_data_chunk), (uint8_t *) & chunk_buf);
159644249214SRandall Stewart 		tsn = ntohl(ch->dp.tsn);
1597d1ea5fa9SMichael Tuexen 		protocol_id = ch->dp.protocol_id;
159844249214SRandall Stewart 		clen = sizeof(struct sctp_data_chunk);
159944249214SRandall Stewart 		fsn = tsn;
160044249214SRandall Stewart 		msg_id = (uint32_t) (ntohs(ch->dp.stream_sequence));
160144249214SRandall Stewart 		nch = NULL;
160244249214SRandall Stewart 		old_data = 1;
160344249214SRandall Stewart 	}
1604f42a358aSRandall Stewart 	chunk_flags = ch->ch.chunk_flags;
160544249214SRandall Stewart 	if ((size_t)chk_length == clen) {
160644249214SRandall Stewart 		/*
160744249214SRandall Stewart 		 * Need to send an abort since we had a empty data chunk.
160844249214SRandall Stewart 		 */
160944249214SRandall Stewart 		op_err = sctp_generate_no_user_data_cause(ch->dp.tsn);
161044249214SRandall Stewart 		stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_14;
161144249214SRandall Stewart 		sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
161244249214SRandall Stewart 		*abort_flag = 1;
161344249214SRandall Stewart 		return (0);
161444249214SRandall Stewart 	}
1615b3f1ea41SRandall Stewart 	if ((chunk_flags & SCTP_DATA_SACK_IMMEDIATELY) == SCTP_DATA_SACK_IMMEDIATELY) {
1616b3f1ea41SRandall Stewart 		asoc->send_sack = 1;
1617b3f1ea41SRandall Stewart 	}
161837f144ebSMichael Tuexen 	ordered = ((chunk_flags & SCTP_DATA_UNORDERED) == 0);
1619b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
1620c4739e2fSRandall Stewart 		sctp_log_map(tsn, asoc->cumulative_tsn, asoc->highest_tsn_inside_map, SCTP_MAP_TSN_ENTERS);
162180fefe0aSRandall Stewart 	}
1622ad81507eSRandall Stewart 	if (stcb == NULL) {
1623ad81507eSRandall Stewart 		return (0);
1624ad81507eSRandall Stewart 	}
162580fefe0aSRandall Stewart 	SCTP_LTRACE_CHK(stcb->sctp_ep, stcb, ch->ch.chunk_type, tsn);
162620b07a4dSMichael Tuexen 	if (SCTP_TSN_GE(asoc->cumulative_tsn, tsn)) {
1627f8829a4aSRandall Stewart 		/* It is a duplicate */
1628f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_recvdupdata);
1629f8829a4aSRandall Stewart 		if (asoc->numduptsns < SCTP_MAX_DUP_TSNS) {
1630f8829a4aSRandall Stewart 			/* Record a dup for the next outbound sack */
1631f8829a4aSRandall Stewart 			asoc->dup_tsns[asoc->numduptsns] = tsn;
1632f8829a4aSRandall Stewart 			asoc->numduptsns++;
1633f8829a4aSRandall Stewart 		}
1634b201f536SRandall Stewart 		asoc->send_sack = 1;
1635f8829a4aSRandall Stewart 		return (0);
1636f8829a4aSRandall Stewart 	}
1637f8829a4aSRandall Stewart 	/* Calculate the number of TSN's between the base and this TSN */
1638d50c1d79SRandall Stewart 	SCTP_CALC_TSN_TO_GAP(gap, tsn, asoc->mapping_array_base_tsn);
1639f8829a4aSRandall Stewart 	if (gap >= (SCTP_MAPPING_ARRAY << 3)) {
1640f8829a4aSRandall Stewart 		/* Can't hold the bit in the mapping at max array, toss it */
1641f8829a4aSRandall Stewart 		return (0);
1642f8829a4aSRandall Stewart 	}
1643f8829a4aSRandall Stewart 	if (gap >= (uint32_t) (asoc->mapping_array_size << 3)) {
1644207304d4SRandall Stewart 		SCTP_TCB_LOCK_ASSERT(stcb);
16450696e120SRandall Stewart 		if (sctp_expand_mapping_array(asoc, gap)) {
1646f8829a4aSRandall Stewart 			/* Can't expand, drop it */
1647f8829a4aSRandall Stewart 			return (0);
1648f8829a4aSRandall Stewart 		}
1649f8829a4aSRandall Stewart 	}
165020b07a4dSMichael Tuexen 	if (SCTP_TSN_GT(tsn, *high_tsn)) {
1651f8829a4aSRandall Stewart 		*high_tsn = tsn;
1652f8829a4aSRandall Stewart 	}
1653f8829a4aSRandall Stewart 	/* See if we have received this one already */
165477acdc25SRandall Stewart 	if (SCTP_IS_TSN_PRESENT(asoc->mapping_array, gap) ||
165577acdc25SRandall Stewart 	    SCTP_IS_TSN_PRESENT(asoc->nr_mapping_array, gap)) {
1656f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_recvdupdata);
1657f8829a4aSRandall Stewart 		if (asoc->numduptsns < SCTP_MAX_DUP_TSNS) {
1658f8829a4aSRandall Stewart 			/* Record a dup for the next outbound sack */
1659f8829a4aSRandall Stewart 			asoc->dup_tsns[asoc->numduptsns] = tsn;
1660f8829a4aSRandall Stewart 			asoc->numduptsns++;
1661f8829a4aSRandall Stewart 		}
166242551e99SRandall Stewart 		asoc->send_sack = 1;
1663f8829a4aSRandall Stewart 		return (0);
1664f8829a4aSRandall Stewart 	}
1665f8829a4aSRandall Stewart 	/*
1666f8829a4aSRandall Stewart 	 * Check to see about the GONE flag, duplicates would cause a sack
1667f8829a4aSRandall Stewart 	 * to be sent up above
1668f8829a4aSRandall Stewart 	 */
1669ad81507eSRandall Stewart 	if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
1670f8829a4aSRandall Stewart 	    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
1671ff1ffd74SMichael Tuexen 	    (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET))) {
1672f8829a4aSRandall Stewart 		/*
1673f8829a4aSRandall Stewart 		 * wait a minute, this guy is gone, there is no longer a
1674f8829a4aSRandall Stewart 		 * receiver. Send peer an ABORT!
1675f8829a4aSRandall Stewart 		 */
1676ff1ffd74SMichael Tuexen 		op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, "");
1677a2b42326SMichael Tuexen 		sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
1678f8829a4aSRandall Stewart 		*abort_flag = 1;
1679f8829a4aSRandall Stewart 		return (0);
1680f8829a4aSRandall Stewart 	}
1681f8829a4aSRandall Stewart 	/*
1682f8829a4aSRandall Stewart 	 * Now before going further we see if there is room. If NOT then we
1683f8829a4aSRandall Stewart 	 * MAY let one through only IF this TSN is the one we are waiting
1684f8829a4aSRandall Stewart 	 * for on a partial delivery API.
1685f8829a4aSRandall Stewart 	 */
1686f8829a4aSRandall Stewart 
168744249214SRandall Stewart 	/* Is the stream valid? */
1688f8829a4aSRandall Stewart 	strmno = ntohs(ch->dp.stream_id);
168944249214SRandall Stewart 
1690f8829a4aSRandall Stewart 	if (strmno >= asoc->streamincnt) {
169186eda749SMichael Tuexen 		struct sctp_error_invalid_stream *cause;
1692f8829a4aSRandall Stewart 
169386eda749SMichael Tuexen 		op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_error_invalid_stream),
1694eb1b1807SGleb Smirnoff 		    0, M_NOWAIT, 1, MT_DATA);
169586eda749SMichael Tuexen 		if (op_err != NULL) {
1696f8829a4aSRandall Stewart 			/* add some space up front so prepend will work well */
169786eda749SMichael Tuexen 			SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr));
169886eda749SMichael Tuexen 			cause = mtod(op_err, struct sctp_error_invalid_stream *);
1699f8829a4aSRandall Stewart 			/*
1700f8829a4aSRandall Stewart 			 * Error causes are just param's and this one has
1701f8829a4aSRandall Stewart 			 * two back to back phdr, one with the error type
1702f8829a4aSRandall Stewart 			 * and size, the other with the streamid and a rsvd
1703f8829a4aSRandall Stewart 			 */
170486eda749SMichael Tuexen 			SCTP_BUF_LEN(op_err) = sizeof(struct sctp_error_invalid_stream);
170586eda749SMichael Tuexen 			cause->cause.code = htons(SCTP_CAUSE_INVALID_STREAM);
170686eda749SMichael Tuexen 			cause->cause.length = htons(sizeof(struct sctp_error_invalid_stream));
170786eda749SMichael Tuexen 			cause->stream_id = ch->dp.stream_id;
170886eda749SMichael Tuexen 			cause->reserved = htons(0);
170986eda749SMichael Tuexen 			sctp_queue_op_err(stcb, op_err);
1710f8829a4aSRandall Stewart 		}
1711f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_badsid);
1712207304d4SRandall Stewart 		SCTP_TCB_LOCK_ASSERT(stcb);
1713830d754dSRandall Stewart 		SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap);
171420b07a4dSMichael Tuexen 		if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) {
1715830d754dSRandall Stewart 			asoc->highest_tsn_inside_nr_map = tsn;
1716d06c82f1SRandall Stewart 		}
1717d06c82f1SRandall Stewart 		if (tsn == (asoc->cumulative_tsn + 1)) {
1718d06c82f1SRandall Stewart 			/* Update cum-ack */
1719d06c82f1SRandall Stewart 			asoc->cumulative_tsn = tsn;
1720d06c82f1SRandall Stewart 		}
1721f8829a4aSRandall Stewart 		return (0);
1722f8829a4aSRandall Stewart 	}
172344249214SRandall Stewart 	strm = &asoc->strmin[strmno];
1724f8829a4aSRandall Stewart 	/*
172544249214SRandall Stewart 	 * If its a fragmented message, lets see if we can find the control
172644249214SRandall Stewart 	 * on the reassembly queues.
1727f8829a4aSRandall Stewart 	 */
1728be46a7c5SMichael Tuexen 	if ((chtype == SCTP_IDATA) &&
1729be46a7c5SMichael Tuexen 	    ((chunk_flags & SCTP_DATA_FIRST_FRAG) == 0) &&
1730be46a7c5SMichael Tuexen 	    (fsn == 0)) {
173144249214SRandall Stewart 		/*
173244249214SRandall Stewart 		 * The first *must* be fsn 0, and other (middle/end) pieces
1733be46a7c5SMichael Tuexen 		 * can *not* be fsn 0. XXX: This can happen in case of a
1734be46a7c5SMichael Tuexen 		 * wrap around. Ignore is for now.
173544249214SRandall Stewart 		 */
1736be46a7c5SMichael Tuexen 		snprintf(msg, sizeof(msg), "FSN zero for MID=%8.8x, but flags=%2.2x",
1737be46a7c5SMichael Tuexen 		    msg_id, chunk_flags);
173844249214SRandall Stewart 		goto err_out;
173944249214SRandall Stewart 	}
1740d1ea5fa9SMichael Tuexen 	control = sctp_find_reasm_entry(strm, msg_id, ordered, old_data);
174144249214SRandall Stewart 	SCTPDBG(SCTP_DEBUG_XXX, "chunk_flags:0x%x look for control on queues %p\n",
174244249214SRandall Stewart 	    chunk_flags, control);
1743be46a7c5SMichael Tuexen 	if ((chunk_flags & SCTP_DATA_NOT_FRAG) != SCTP_DATA_NOT_FRAG) {
1744be46a7c5SMichael Tuexen 		/* See if we can find the re-assembly entity */
1745be46a7c5SMichael Tuexen 		if (control != NULL) {
174644249214SRandall Stewart 			/* We found something, does it belong? */
174744249214SRandall Stewart 			if (ordered && (msg_id != control->sinfo_ssn)) {
1748be46a7c5SMichael Tuexen 				snprintf(msg, sizeof(msg), "Reassembly problem (MID=%8.8x)", msg_id);
174944249214SRandall Stewart 		err_out:
175044249214SRandall Stewart 				op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
175144249214SRandall Stewart 				stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_15;
175244249214SRandall Stewart 				sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
175344249214SRandall Stewart 				*abort_flag = 1;
175444249214SRandall Stewart 				return (0);
175544249214SRandall Stewart 			}
175644249214SRandall Stewart 			if (ordered && ((control->sinfo_flags >> 8) & SCTP_DATA_UNORDERED)) {
1757*5b495f17SMichael Tuexen 				/* We can't have a switched order with an
1758*5b495f17SMichael Tuexen 				 * unordered chunk */
1759be46a7c5SMichael Tuexen 				snprintf(msg, sizeof(msg), "All fragments of a user message must be ordered or unordered (TSN=%8.8x)",
1760be46a7c5SMichael Tuexen 				    tsn);
176144249214SRandall Stewart 				goto err_out;
176244249214SRandall Stewart 			}
176344249214SRandall Stewart 			if (!ordered && (((control->sinfo_flags >> 8) & SCTP_DATA_UNORDERED) == 0)) {
1764*5b495f17SMichael Tuexen 				/* We can't have a switched unordered with a
1765*5b495f17SMichael Tuexen 				 * ordered chunk */
1766be46a7c5SMichael Tuexen 				snprintf(msg, sizeof(msg), "All fragments of a user message must be ordered or unordered (TSN=%8.8x)",
1767be46a7c5SMichael Tuexen 				    tsn);
176844249214SRandall Stewart 				goto err_out;
176944249214SRandall Stewart 			}
177044249214SRandall Stewart 		}
177144249214SRandall Stewart 	} else {
177244249214SRandall Stewart 		/*
177344249214SRandall Stewart 		 * Its a complete segment. Lets validate we don't have a
177444249214SRandall Stewart 		 * re-assembly going on with the same Stream/Seq (for
177544249214SRandall Stewart 		 * ordered) or in the same Stream for unordered.
177644249214SRandall Stewart 		 */
1777be46a7c5SMichael Tuexen 		if (control != NULL) {
1778be46a7c5SMichael Tuexen 			if (ordered || (old_data == 0)) {
1779f2ea2a2dSMichael Tuexen 				SCTPDBG(SCTP_DEBUG_XXX, "chunk_flags: 0x%x dup detected on msg_id: %u\n",
1780be46a7c5SMichael Tuexen 				    chunk_flags, msg_id);
1781be46a7c5SMichael Tuexen 				snprintf(msg, sizeof(msg), "Duplicate MID=%8.8x detected.", msg_id);
178244249214SRandall Stewart 				goto err_out;
1783be46a7c5SMichael Tuexen 			} else {
1784be46a7c5SMichael Tuexen 				if ((tsn == control->fsn_included + 1) &&
1785be46a7c5SMichael Tuexen 				    (control->end_added == 0)) {
1786be46a7c5SMichael Tuexen 					snprintf(msg, sizeof(msg), "Illegal message sequence, missing end for MID: %8.8x", control->fsn_included);
1787be46a7c5SMichael Tuexen 					goto err_out;
1788be46a7c5SMichael Tuexen 				} else {
1789be46a7c5SMichael Tuexen 					control = NULL;
1790be46a7c5SMichael Tuexen 				}
1791be46a7c5SMichael Tuexen 			}
179244249214SRandall Stewart 		}
179344249214SRandall Stewart 	}
179444249214SRandall Stewart 	/* now do the tests */
179544249214SRandall Stewart 	if (((asoc->cnt_on_all_streams +
179644249214SRandall Stewart 	    asoc->cnt_on_reasm_queue +
179744249214SRandall Stewart 	    asoc->cnt_msg_on_sb) >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue)) ||
179844249214SRandall Stewart 	    (((int)asoc->my_rwnd) <= 0)) {
179944249214SRandall Stewart 		/*
180044249214SRandall Stewart 		 * When we have NO room in the rwnd we check to make sure
180144249214SRandall Stewart 		 * the reader is doing its job...
180244249214SRandall Stewart 		 */
180344249214SRandall Stewart 		if (stcb->sctp_socket->so_rcv.sb_cc) {
180444249214SRandall Stewart 			/* some to read, wake-up */
180544249214SRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
180644249214SRandall Stewart 			struct socket *so;
180744249214SRandall Stewart 
180844249214SRandall Stewart 			so = SCTP_INP_SO(stcb->sctp_ep);
180944249214SRandall Stewart 			atomic_add_int(&stcb->asoc.refcnt, 1);
181044249214SRandall Stewart 			SCTP_TCB_UNLOCK(stcb);
181144249214SRandall Stewart 			SCTP_SOCKET_LOCK(so, 1);
181244249214SRandall Stewart 			SCTP_TCB_LOCK(stcb);
181344249214SRandall Stewart 			atomic_subtract_int(&stcb->asoc.refcnt, 1);
181444249214SRandall Stewart 			if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
181544249214SRandall Stewart 				/* assoc was freed while we were unlocked */
181644249214SRandall Stewart 				SCTP_SOCKET_UNLOCK(so, 1);
181744249214SRandall Stewart 				return (0);
181844249214SRandall Stewart 			}
181944249214SRandall Stewart #endif
182044249214SRandall Stewart 			sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
182144249214SRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
182244249214SRandall Stewart 			SCTP_SOCKET_UNLOCK(so, 1);
182344249214SRandall Stewart #endif
182444249214SRandall Stewart 		}
182544249214SRandall Stewart 		/* now is it in the mapping array of what we have accepted? */
182644249214SRandall Stewart 		if (nch == NULL) {
182744249214SRandall Stewart 			if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_map) &&
182844249214SRandall Stewart 			    SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) {
182944249214SRandall Stewart 				/* Nope not in the valid range dump it */
183044249214SRandall Stewart 		dump_packet:
183144249214SRandall Stewart 				sctp_set_rwnd(stcb, asoc);
183244249214SRandall Stewart 				if ((asoc->cnt_on_all_streams +
183344249214SRandall Stewart 				    asoc->cnt_on_reasm_queue +
183444249214SRandall Stewart 				    asoc->cnt_msg_on_sb) >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue)) {
183544249214SRandall Stewart 					SCTP_STAT_INCR(sctps_datadropchklmt);
183644249214SRandall Stewart 				} else {
183744249214SRandall Stewart 					SCTP_STAT_INCR(sctps_datadroprwnd);
183844249214SRandall Stewart 				}
183944249214SRandall Stewart 				*break_flag = 1;
184044249214SRandall Stewart 				return (0);
184144249214SRandall Stewart 			}
184244249214SRandall Stewart 		} else {
184344249214SRandall Stewart 			if (control == NULL) {
184444249214SRandall Stewart 				goto dump_packet;
184544249214SRandall Stewart 			}
184644249214SRandall Stewart 			if (SCTP_TSN_GT(fsn, control->top_fsn)) {
184744249214SRandall Stewart 				goto dump_packet;
184844249214SRandall Stewart 			}
184944249214SRandall Stewart 		}
185044249214SRandall Stewart 	}
1851f42a358aSRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS
185218e198d3SRandall Stewart 	SCTP_TCB_LOCK_ASSERT(stcb);
185318e198d3SRandall Stewart 	if (asoc->tsn_in_at >= SCTP_TSN_LOG_SIZE) {
185418e198d3SRandall Stewart 		asoc->tsn_in_at = 0;
185518e198d3SRandall Stewart 		asoc->tsn_in_wrapped = 1;
185618e198d3SRandall Stewart 	}
1857f42a358aSRandall Stewart 	asoc->in_tsnlog[asoc->tsn_in_at].tsn = tsn;
1858f42a358aSRandall Stewart 	asoc->in_tsnlog[asoc->tsn_in_at].strm = strmno;
185944249214SRandall Stewart 	asoc->in_tsnlog[asoc->tsn_in_at].seq = msg_id;
1860f1f73e57SRandall Stewart 	asoc->in_tsnlog[asoc->tsn_in_at].sz = chk_length;
1861f1f73e57SRandall Stewart 	asoc->in_tsnlog[asoc->tsn_in_at].flgs = chunk_flags;
186218e198d3SRandall Stewart 	asoc->in_tsnlog[asoc->tsn_in_at].stcb = (void *)stcb;
186318e198d3SRandall Stewart 	asoc->in_tsnlog[asoc->tsn_in_at].in_pos = asoc->tsn_in_at;
186418e198d3SRandall Stewart 	asoc->in_tsnlog[asoc->tsn_in_at].in_out = 1;
1865f42a358aSRandall Stewart 	asoc->tsn_in_at++;
1866f42a358aSRandall Stewart #endif
186744249214SRandall Stewart 	/*
186844249214SRandall Stewart 	 * Before we continue lets validate that we are not being fooled by
186944249214SRandall Stewart 	 * an evil attacker. We can only have Nk chunks based on our TSN
187044249214SRandall Stewart 	 * spread allowed by the mapping array N * 8 bits, so there is no
187144249214SRandall Stewart 	 * way our stream sequence numbers could have wrapped. We of course
187244249214SRandall Stewart 	 * only validate the FIRST fragment so the bit must be set.
187344249214SRandall Stewart 	 */
1874f42a358aSRandall Stewart 	if ((chunk_flags & SCTP_DATA_FIRST_FRAG) &&
1875d61a0ae0SRandall Stewart 	    (TAILQ_EMPTY(&asoc->resetHead)) &&
1876f42a358aSRandall Stewart 	    (chunk_flags & SCTP_DATA_UNORDERED) == 0 &&
187744249214SRandall Stewart 	    SCTP_MSGID_GE(old_data, asoc->strmin[strmno].last_sequence_delivered, msg_id)) {
1878f8829a4aSRandall Stewart 		/* The incoming sseq is behind where we last delivered? */
1879f2ea2a2dSMichael Tuexen 		SCTPDBG(SCTP_DEBUG_INDATA1, "EVIL/Broken-Dup S-SEQ: %u delivered: %u from peer, Abort!\n",
188044249214SRandall Stewart 		    msg_id, asoc->strmin[strmno].last_sequence_delivered);
1881f8829a4aSRandall Stewart 
1882ff1ffd74SMichael Tuexen 		snprintf(msg, sizeof(msg), "Delivered SSN=%4.4x, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x",
1883ff1ffd74SMichael Tuexen 		    asoc->strmin[strmno].last_sequence_delivered,
188444249214SRandall Stewart 		    tsn, strmno, msg_id);
1885ff1ffd74SMichael Tuexen 		op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
1886b7d130beSMichael Tuexen 		stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_16;
1887ff1ffd74SMichael Tuexen 		sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
1888f8829a4aSRandall Stewart 		*abort_flag = 1;
1889f8829a4aSRandall Stewart 		return (0);
1890f8829a4aSRandall Stewart 	}
1891f42a358aSRandall Stewart 	/************************************
1892f42a358aSRandall Stewart 	 * From here down we may find ch-> invalid
1893f42a358aSRandall Stewart 	 * so its a good idea NOT to use it.
1894f42a358aSRandall Stewart 	 *************************************/
189544249214SRandall Stewart 	if (nch) {
189644249214SRandall Stewart 		the_len = (chk_length - sizeof(struct sctp_idata_chunk));
189744249214SRandall Stewart 	} else {
1898f8829a4aSRandall Stewart 		the_len = (chk_length - sizeof(struct sctp_data_chunk));
189944249214SRandall Stewart 	}
1900f8829a4aSRandall Stewart 	if (last_chunk == 0) {
190144249214SRandall Stewart 		if (nch) {
190244249214SRandall Stewart 			dmbuf = SCTP_M_COPYM(*m,
190344249214SRandall Stewart 			    (offset + sizeof(struct sctp_idata_chunk)),
190444249214SRandall Stewart 			    the_len, M_NOWAIT);
190544249214SRandall Stewart 		} else {
190644b7479bSRandall Stewart 			dmbuf = SCTP_M_COPYM(*m,
1907f8829a4aSRandall Stewart 			    (offset + sizeof(struct sctp_data_chunk)),
1908eb1b1807SGleb Smirnoff 			    the_len, M_NOWAIT);
190944249214SRandall Stewart 		}
1910f8829a4aSRandall Stewart #ifdef SCTP_MBUF_LOGGING
1911b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) {
19124be807c4SMichael Tuexen 			sctp_log_mbc(dmbuf, SCTP_MBUF_ICOPY);
1913f8829a4aSRandall Stewart 		}
1914f8829a4aSRandall Stewart #endif
1915f8829a4aSRandall Stewart 	} else {
1916f8829a4aSRandall Stewart 		/* We can steal the last chunk */
1917139bc87fSRandall Stewart 		int l_len;
1918139bc87fSRandall Stewart 
1919f8829a4aSRandall Stewart 		dmbuf = *m;
1920f8829a4aSRandall Stewart 		/* lop off the top part */
192144249214SRandall Stewart 		if (nch) {
192244249214SRandall Stewart 			m_adj(dmbuf, (offset + sizeof(struct sctp_idata_chunk)));
192344249214SRandall Stewart 		} else {
1924f8829a4aSRandall Stewart 			m_adj(dmbuf, (offset + sizeof(struct sctp_data_chunk)));
192544249214SRandall Stewart 		}
1926139bc87fSRandall Stewart 		if (SCTP_BUF_NEXT(dmbuf) == NULL) {
1927139bc87fSRandall Stewart 			l_len = SCTP_BUF_LEN(dmbuf);
1928139bc87fSRandall Stewart 		} else {
1929139bc87fSRandall Stewart 			/*
1930139bc87fSRandall Stewart 			 * need to count up the size hopefully does not hit
1931139bc87fSRandall Stewart 			 * this to often :-0
1932139bc87fSRandall Stewart 			 */
1933139bc87fSRandall Stewart 			struct mbuf *lat;
1934139bc87fSRandall Stewart 
1935139bc87fSRandall Stewart 			l_len = 0;
193660990c0cSMichael Tuexen 			for (lat = dmbuf; lat; lat = SCTP_BUF_NEXT(lat)) {
1937139bc87fSRandall Stewart 				l_len += SCTP_BUF_LEN(lat);
1938139bc87fSRandall Stewart 			}
1939139bc87fSRandall Stewart 		}
1940139bc87fSRandall Stewart 		if (l_len > the_len) {
1941f8829a4aSRandall Stewart 			/* Trim the end round bytes off  too */
1942139bc87fSRandall Stewart 			m_adj(dmbuf, -(l_len - the_len));
1943f8829a4aSRandall Stewart 		}
1944f8829a4aSRandall Stewart 	}
1945f8829a4aSRandall Stewart 	if (dmbuf == NULL) {
1946f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_nomem);
1947f8829a4aSRandall Stewart 		return (0);
1948f8829a4aSRandall Stewart 	}
194944249214SRandall Stewart 	/*
195044249214SRandall Stewart 	 * Now no matter what we need a control, get one if we don't have
195144249214SRandall Stewart 	 * one (we may have gotten it above when we found the message was
195244249214SRandall Stewart 	 * fragmented
195344249214SRandall Stewart 	 */
195444249214SRandall Stewart 	if (control == NULL) {
195544249214SRandall Stewart 		sctp_alloc_a_readq(stcb, control);
195644249214SRandall Stewart 		sctp_build_readq_entry_mac(control, stcb, asoc->context, net, tsn,
195744249214SRandall Stewart 		    protocol_id,
195844249214SRandall Stewart 		    strmno, msg_id,
195944249214SRandall Stewart 		    chunk_flags,
196044249214SRandall Stewart 		    NULL, fsn, msg_id);
196144249214SRandall Stewart 		if (control == NULL) {
196244249214SRandall Stewart 			SCTP_STAT_INCR(sctps_nomem);
196344249214SRandall Stewart 			return (0);
196444249214SRandall Stewart 		}
196544249214SRandall Stewart 		if ((chunk_flags & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) {
196644249214SRandall Stewart 			control->data = dmbuf;
196744249214SRandall Stewart 			control->tail_mbuf = NULL;
196844249214SRandall Stewart 			control->end_added = control->last_frag_seen = control->first_frag_seen = 1;
196944249214SRandall Stewart 			control->top_fsn = control->fsn_included = fsn;
197044249214SRandall Stewart 		}
197144249214SRandall Stewart 		created_control = 1;
197244249214SRandall Stewart 	}
1973f2ea2a2dSMichael Tuexen 	SCTPDBG(SCTP_DEBUG_XXX, "chunk_flags: 0x%x ordered: %d msgid: %u control: %p\n",
197444249214SRandall Stewart 	    chunk_flags, ordered, msg_id, control);
1975f42a358aSRandall Stewart 	if ((chunk_flags & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG &&
1976f8829a4aSRandall Stewart 	    TAILQ_EMPTY(&asoc->resetHead) &&
1977f42a358aSRandall Stewart 	    ((ordered == 0) ||
197844249214SRandall Stewart 	    ((uint16_t) (asoc->strmin[strmno].last_sequence_delivered + 1) == msg_id &&
1979f8829a4aSRandall Stewart 	    TAILQ_EMPTY(&asoc->strmin[strmno].inqueue)))) {
1980f8829a4aSRandall Stewart 		/* Candidate for express delivery */
1981f8829a4aSRandall Stewart 		/*
1982f8829a4aSRandall Stewart 		 * Its not fragmented, No PD-API is up, Nothing in the
1983f8829a4aSRandall Stewart 		 * delivery queue, Its un-ordered OR ordered and the next to
1984f8829a4aSRandall Stewart 		 * deliver AND nothing else is stuck on the stream queue,
1985f8829a4aSRandall Stewart 		 * And there is room for it in the socket buffer. Lets just
1986f8829a4aSRandall Stewart 		 * stuff it up the buffer....
1987f8829a4aSRandall Stewart 		 */
19881ea735c8SMichael Tuexen 		SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap);
198920b07a4dSMichael Tuexen 		if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) {
19901ea735c8SMichael Tuexen 			asoc->highest_tsn_inside_nr_map = tsn;
19911ea735c8SMichael Tuexen 		}
1992f2ea2a2dSMichael Tuexen 		SCTPDBG(SCTP_DEBUG_XXX, "Injecting control: %p to be read (msg_id: %u)\n",
199344249214SRandall Stewart 		    control, msg_id);
199444249214SRandall Stewart 
1995cfde3ff7SRandall Stewart 		sctp_add_to_readq(stcb->sctp_ep, stcb,
1996cfde3ff7SRandall Stewart 		    control, &stcb->sctp_socket->so_rcv,
1997cfde3ff7SRandall Stewart 		    1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
1998830d754dSRandall Stewart 
1999f42a358aSRandall Stewart 		if ((chunk_flags & SCTP_DATA_UNORDERED) == 0) {
2000f8829a4aSRandall Stewart 			/* for ordered, bump what we delivered */
200144249214SRandall Stewart 			strm->last_sequence_delivered++;
2002f8829a4aSRandall Stewart 		}
2003f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_recvexpress);
2004b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) {
200544249214SRandall Stewart 			sctp_log_strm_del_alt(stcb, tsn, msg_id, strmno,
2006f8829a4aSRandall Stewart 			    SCTP_STR_LOG_FROM_EXPRS_DEL);
200780fefe0aSRandall Stewart 		}
2008f8829a4aSRandall Stewart 		control = NULL;
2009f8829a4aSRandall Stewart 		goto finish_express_del;
2010f8829a4aSRandall Stewart 	}
201144249214SRandall Stewart 	/* Now will we need a chunk too? */
2012f42a358aSRandall Stewart 	if ((chunk_flags & SCTP_DATA_NOT_FRAG) != SCTP_DATA_NOT_FRAG) {
2013f8829a4aSRandall Stewart 		sctp_alloc_a_chunk(stcb, chk);
2014f8829a4aSRandall Stewart 		if (chk == NULL) {
2015f8829a4aSRandall Stewart 			/* No memory so we drop the chunk */
2016f8829a4aSRandall Stewart 			SCTP_STAT_INCR(sctps_nomem);
2017f8829a4aSRandall Stewart 			if (last_chunk == 0) {
2018f8829a4aSRandall Stewart 				/* we copied it, free the copy */
2019f8829a4aSRandall Stewart 				sctp_m_freem(dmbuf);
2020f8829a4aSRandall Stewart 			}
2021f8829a4aSRandall Stewart 			return (0);
2022f8829a4aSRandall Stewart 		}
2023f8829a4aSRandall Stewart 		chk->rec.data.TSN_seq = tsn;
2024f8829a4aSRandall Stewart 		chk->no_fr_allowed = 0;
202544249214SRandall Stewart 		chk->rec.data.fsn_num = fsn;
202644249214SRandall Stewart 		chk->rec.data.stream_seq = msg_id;
2027f8829a4aSRandall Stewart 		chk->rec.data.stream_number = strmno;
2028f42a358aSRandall Stewart 		chk->rec.data.payloadtype = protocol_id;
2029f8829a4aSRandall Stewart 		chk->rec.data.context = stcb->asoc.context;
2030f8829a4aSRandall Stewart 		chk->rec.data.doing_fast_retransmit = 0;
2031f42a358aSRandall Stewart 		chk->rec.data.rcv_flags = chunk_flags;
2032f8829a4aSRandall Stewart 		chk->asoc = asoc;
2033f8829a4aSRandall Stewart 		chk->send_size = the_len;
2034f8829a4aSRandall Stewart 		chk->whoTo = net;
2035f2ea2a2dSMichael Tuexen 		SCTPDBG(SCTP_DEBUG_XXX, "Building ck: %p for control: %p to be read (msg_id: %u)\n",
203644249214SRandall Stewart 		    chk,
203744249214SRandall Stewart 		    control, msg_id);
2038f8829a4aSRandall Stewart 		atomic_add_int(&net->ref_count, 1);
2039f8829a4aSRandall Stewart 		chk->data = dmbuf;
204044249214SRandall Stewart 	}
204144249214SRandall Stewart 	/* Set the appropriate TSN mark */
204244249214SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_do_drain) == 0) {
204344249214SRandall Stewart 		SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap);
204444249214SRandall Stewart 		if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) {
204544249214SRandall Stewart 			asoc->highest_tsn_inside_nr_map = tsn;
204644249214SRandall Stewart 		}
2047f8829a4aSRandall Stewart 	} else {
204844249214SRandall Stewart 		SCTP_SET_TSN_PRESENT(asoc->mapping_array, gap);
204944249214SRandall Stewart 		if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_map)) {
205044249214SRandall Stewart 			asoc->highest_tsn_inside_map = tsn;
2051f8829a4aSRandall Stewart 		}
2052f8829a4aSRandall Stewart 	}
205344249214SRandall Stewart 	/* Now is it complete (i.e. not fragmented)? */
205444249214SRandall Stewart 	if ((chunk_flags & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) {
2055f8829a4aSRandall Stewart 		/*
205644249214SRandall Stewart 		 * Special check for when streams are resetting. We could be
205744249214SRandall Stewart 		 * more smart about this and check the actual stream to see
205844249214SRandall Stewart 		 * if it is not being reset.. that way we would not create a
205944249214SRandall Stewart 		 * HOLB when amongst streams being reset and those not being
206044249214SRandall Stewart 		 * reset.
2061f8829a4aSRandall Stewart 		 *
2062f8829a4aSRandall Stewart 		 */
2063f8829a4aSRandall Stewart 		if (((liste = TAILQ_FIRST(&asoc->resetHead)) != NULL) &&
206420b07a4dSMichael Tuexen 		    SCTP_TSN_GT(tsn, liste->tsn)) {
2065f8829a4aSRandall Stewart 			/*
206644249214SRandall Stewart 			 * yep its past where we need to reset... go ahead
206744249214SRandall Stewart 			 * and queue it.
2068f8829a4aSRandall Stewart 			 */
2069f8829a4aSRandall Stewart 			if (TAILQ_EMPTY(&asoc->pending_reply_queue)) {
2070f8829a4aSRandall Stewart 				/* first one on */
2071f8829a4aSRandall Stewart 				TAILQ_INSERT_TAIL(&asoc->pending_reply_queue, control, next);
2072f8829a4aSRandall Stewart 			} else {
207344249214SRandall Stewart 				struct sctp_queued_to_read *ctlOn, *nctlOn;
2074f8829a4aSRandall Stewart 				unsigned char inserted = 0;
2075f8829a4aSRandall Stewart 
20764a9ef3f8SMichael Tuexen 				TAILQ_FOREACH_SAFE(ctlOn, &asoc->pending_reply_queue, next, nctlOn) {
207720b07a4dSMichael Tuexen 					if (SCTP_TSN_GT(control->sinfo_tsn, ctlOn->sinfo_tsn)) {
207844249214SRandall Stewart 
20794a9ef3f8SMichael Tuexen 						continue;
2080f8829a4aSRandall Stewart 					} else {
2081f8829a4aSRandall Stewart 						/* found it */
2082f8829a4aSRandall Stewart 						TAILQ_INSERT_BEFORE(ctlOn, control, next);
2083f8829a4aSRandall Stewart 						inserted = 1;
2084f8829a4aSRandall Stewart 						break;
2085f8829a4aSRandall Stewart 					}
2086f8829a4aSRandall Stewart 				}
2087f8829a4aSRandall Stewart 				if (inserted == 0) {
2088f8829a4aSRandall Stewart 					/*
208944249214SRandall Stewart 					 * must be put at end, use prevP
209044249214SRandall Stewart 					 * (all setup from loop) to setup
209144249214SRandall Stewart 					 * nextP.
2092f8829a4aSRandall Stewart 					 */
2093f8829a4aSRandall Stewart 					TAILQ_INSERT_TAIL(&asoc->pending_reply_queue, control, next);
2094f8829a4aSRandall Stewart 				}
2095f8829a4aSRandall Stewart 			}
209644249214SRandall Stewart 			goto finish_express_del;
209744249214SRandall Stewart 		}
209844249214SRandall Stewart 		if (chunk_flags & SCTP_DATA_UNORDERED) {
209944249214SRandall Stewart 			/* queue directly into socket buffer */
2100f2ea2a2dSMichael Tuexen 			SCTPDBG(SCTP_DEBUG_XXX, "Unordered data to be read control: %p msg_id: %u\n",
210144249214SRandall Stewart 			    control, msg_id);
210244249214SRandall Stewart 			sctp_mark_non_revokable(asoc, control->sinfo_tsn);
210344249214SRandall Stewart 			sctp_add_to_readq(stcb->sctp_ep, stcb,
210444249214SRandall Stewart 			    control,
210544249214SRandall Stewart 			    &stcb->sctp_socket->so_rcv, 1,
210644249214SRandall Stewart 			    SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
210744249214SRandall Stewart 
2108f8829a4aSRandall Stewart 		} else {
2109f2ea2a2dSMichael Tuexen 			SCTPDBG(SCTP_DEBUG_XXX, "Queue control: %p for reordering msg_id: %u\n", control,
211044249214SRandall Stewart 			    msg_id);
211144249214SRandall Stewart 			sctp_queue_data_to_stream(stcb, strm, asoc, control, abort_flag, &need_reasm_check);
2112f8829a4aSRandall Stewart 			if (*abort_flag) {
21138be0fd55SMichael Tuexen 				if (last_chunk) {
21148be0fd55SMichael Tuexen 					*m = NULL;
21158be0fd55SMichael Tuexen 				}
2116f8829a4aSRandall Stewart 				return (0);
2117f8829a4aSRandall Stewart 			}
2118f8829a4aSRandall Stewart 		}
211944249214SRandall Stewart 		goto finish_express_del;
2120f8829a4aSRandall Stewart 	}
212144249214SRandall Stewart 	/* If we reach here its a reassembly */
212244249214SRandall Stewart 	need_reasm_check = 1;
212344249214SRandall Stewart 	SCTPDBG(SCTP_DEBUG_XXX,
2124f2ea2a2dSMichael Tuexen 	    "Queue data to stream for reasm control: %p msg_id: %u\n",
212544249214SRandall Stewart 	    control, msg_id);
212644249214SRandall Stewart 	sctp_queue_data_for_reasm(stcb, asoc, strm, control, chk, created_control, abort_flag, tsn);
2127f8829a4aSRandall Stewart 	if (*abort_flag) {
2128a5d547adSRandall Stewart 		/*
212944249214SRandall Stewart 		 * the assoc is now gone and chk was put onto the reasm
213044249214SRandall Stewart 		 * queue, which has all been freed.
2131a5d547adSRandall Stewart 		 */
21328be0fd55SMichael Tuexen 		if (last_chunk) {
2133a5d547adSRandall Stewart 			*m = NULL;
21348be0fd55SMichael Tuexen 		}
2135f8829a4aSRandall Stewart 		return (0);
2136f8829a4aSRandall Stewart 	}
2137f8829a4aSRandall Stewart finish_express_del:
213844249214SRandall Stewart 	/* Here we tidy up things */
2139307b49efSMichael Tuexen 	if (tsn == (asoc->cumulative_tsn + 1)) {
2140307b49efSMichael Tuexen 		/* Update cum-ack */
2141307b49efSMichael Tuexen 		asoc->cumulative_tsn = tsn;
2142307b49efSMichael Tuexen 	}
2143f8829a4aSRandall Stewart 	if (last_chunk) {
2144f8829a4aSRandall Stewart 		*m = NULL;
2145f8829a4aSRandall Stewart 	}
2146f42a358aSRandall Stewart 	if (ordered) {
2147f8829a4aSRandall Stewart 		SCTP_STAT_INCR_COUNTER64(sctps_inorderchunks);
2148f8829a4aSRandall Stewart 	} else {
2149f8829a4aSRandall Stewart 		SCTP_STAT_INCR_COUNTER64(sctps_inunorderchunks);
2150f8829a4aSRandall Stewart 	}
2151f8829a4aSRandall Stewart 	SCTP_STAT_INCR(sctps_recvdata);
2152f8829a4aSRandall Stewart 	/* Set it present please */
2153b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) {
215444249214SRandall Stewart 		sctp_log_strm_del_alt(stcb, tsn, msg_id, strmno, SCTP_STR_LOG_FROM_MARK_TSN);
215580fefe0aSRandall Stewart 	}
2156b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
2157f8829a4aSRandall Stewart 		sctp_log_map(asoc->mapping_array_base_tsn, asoc->cumulative_tsn,
2158f8829a4aSRandall Stewart 		    asoc->highest_tsn_inside_map, SCTP_MAP_PREPARE_SLIDE);
215980fefe0aSRandall Stewart 	}
216017205eccSRandall Stewart 	/* check the special flag for stream resets */
216117205eccSRandall Stewart 	if (((liste = TAILQ_FIRST(&asoc->resetHead)) != NULL) &&
216220b07a4dSMichael Tuexen 	    SCTP_TSN_GE(asoc->cumulative_tsn, liste->tsn)) {
216317205eccSRandall Stewart 		/*
216417205eccSRandall Stewart 		 * we have finished working through the backlogged TSN's now
216517205eccSRandall Stewart 		 * time to reset streams. 1: call reset function. 2: free
216617205eccSRandall Stewart 		 * pending_reply space 3: distribute any chunks in
216717205eccSRandall Stewart 		 * pending_reply_queue.
216817205eccSRandall Stewart 		 */
21694a9ef3f8SMichael Tuexen 		struct sctp_queued_to_read *ctl, *nctl;
217017205eccSRandall Stewart 
2171a169d6ecSMichael Tuexen 		sctp_reset_in_stream(stcb, liste->number_entries, liste->list_of_streams);
217217205eccSRandall Stewart 		TAILQ_REMOVE(&asoc->resetHead, liste, next_resp);
21737cca1775SRandall Stewart 		sctp_send_deferred_reset_response(stcb, liste, SCTP_STREAM_RESET_RESULT_PERFORMED);
2174207304d4SRandall Stewart 		SCTP_FREE(liste, SCTP_M_STRESET);
21753c503c28SRandall Stewart 		/* sa_ignore FREED_MEMORY */
217617205eccSRandall Stewart 		liste = TAILQ_FIRST(&asoc->resetHead);
21774a9ef3f8SMichael Tuexen 		if (TAILQ_EMPTY(&asoc->resetHead)) {
217817205eccSRandall Stewart 			/* All can be removed */
21794a9ef3f8SMichael Tuexen 			TAILQ_FOREACH_SAFE(ctl, &asoc->pending_reply_queue, next, nctl) {
218017205eccSRandall Stewart 				TAILQ_REMOVE(&asoc->pending_reply_queue, ctl, next);
218144249214SRandall Stewart 				sctp_queue_data_to_stream(stcb, strm, asoc, ctl, abort_flag, &need_reasm_check);
218217205eccSRandall Stewart 				if (*abort_flag) {
218317205eccSRandall Stewart 					return (0);
218417205eccSRandall Stewart 				}
218517205eccSRandall Stewart 			}
21864a9ef3f8SMichael Tuexen 		} else {
21874a9ef3f8SMichael Tuexen 			TAILQ_FOREACH_SAFE(ctl, &asoc->pending_reply_queue, next, nctl) {
218820b07a4dSMichael Tuexen 				if (SCTP_TSN_GT(ctl->sinfo_tsn, liste->tsn)) {
21894a9ef3f8SMichael Tuexen 					break;
21904a9ef3f8SMichael Tuexen 				}
219117205eccSRandall Stewart 				/*
219217205eccSRandall Stewart 				 * if ctl->sinfo_tsn is <= liste->tsn we can
219317205eccSRandall Stewart 				 * process it which is the NOT of
219417205eccSRandall Stewart 				 * ctl->sinfo_tsn > liste->tsn
219517205eccSRandall Stewart 				 */
219617205eccSRandall Stewart 				TAILQ_REMOVE(&asoc->pending_reply_queue, ctl, next);
219744249214SRandall Stewart 				sctp_queue_data_to_stream(stcb, strm, asoc, ctl, abort_flag, &need_reasm_check);
219817205eccSRandall Stewart 				if (*abort_flag) {
219917205eccSRandall Stewart 					return (0);
220017205eccSRandall Stewart 				}
220117205eccSRandall Stewart 			}
220217205eccSRandall Stewart 		}
220317205eccSRandall Stewart 		/*
220417205eccSRandall Stewart 		 * Now service re-assembly to pick up anything that has been
220517205eccSRandall Stewart 		 * held on reassembly queue?
220617205eccSRandall Stewart 		 */
2207d1ea5fa9SMichael Tuexen 		(void)sctp_deliver_reasm_check(stcb, asoc, strm, SCTP_READ_LOCK_NOT_HELD);
220817205eccSRandall Stewart 		need_reasm_check = 0;
220917205eccSRandall Stewart 	}
2210139bc87fSRandall Stewart 	if (need_reasm_check) {
2211139bc87fSRandall Stewart 		/* Another one waits ? */
2212d1ea5fa9SMichael Tuexen 		(void)sctp_deliver_reasm_check(stcb, asoc, strm, SCTP_READ_LOCK_NOT_HELD);
2213139bc87fSRandall Stewart 	}
2214f8829a4aSRandall Stewart 	return (1);
2215f8829a4aSRandall Stewart }
2216f8829a4aSRandall Stewart 
2217ed654363SMichael Tuexen static const int8_t sctp_map_lookup_tab[256] = {
2218b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 3,
2219b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 4,
2220b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 3,
2221b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 5,
2222b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 3,
2223b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 4,
2224b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 3,
2225b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 6,
2226b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 3,
2227b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 4,
2228b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 3,
2229b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 5,
2230b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 3,
2231b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 4,
2232b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 3,
2233b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 7,
2234b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 3,
2235b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 4,
2236b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 3,
2237b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 5,
2238b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 3,
2239b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 4,
2240b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 3,
2241b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 6,
2242b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 3,
2243b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 4,
2244b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 3,
2245b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 5,
2246b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 3,
2247b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 4,
2248b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 3,
2249b5c16493SMichael Tuexen 	0, 1, 0, 2, 0, 1, 0, 8
2250f8829a4aSRandall Stewart };
2251f8829a4aSRandall Stewart 
2252f8829a4aSRandall Stewart 
2253f8829a4aSRandall Stewart void
2254b5c16493SMichael Tuexen sctp_slide_mapping_arrays(struct sctp_tcb *stcb)
2255f8829a4aSRandall Stewart {
2256f8829a4aSRandall Stewart 	/*
2257f8829a4aSRandall Stewart 	 * Now we also need to check the mapping array in a couple of ways.
2258f8829a4aSRandall Stewart 	 * 1) Did we move the cum-ack point?
225966bd30bdSRandall Stewart 	 *
2260*5b495f17SMichael Tuexen 	 * When you first glance at this you might think that all entries
2261*5b495f17SMichael Tuexen 	 * that make up the position of the cum-ack would be in the
2262*5b495f17SMichael Tuexen 	 * nr-mapping array only.. i.e. things up to the cum-ack are always
226366bd30bdSRandall Stewart 	 * deliverable. Thats true with one exception, when its a fragmented
226466bd30bdSRandall Stewart 	 * message we may not deliver the data until some threshold (or all
226566bd30bdSRandall Stewart 	 * of it) is in place. So we must OR the nr_mapping_array and
226666bd30bdSRandall Stewart 	 * mapping_array to get a true picture of the cum-ack.
2267f8829a4aSRandall Stewart 	 */
2268f8829a4aSRandall Stewart 	struct sctp_association *asoc;
2269b3f1ea41SRandall Stewart 	int at;
227066bd30bdSRandall Stewart 	uint8_t val;
2271f8829a4aSRandall Stewart 	int slide_from, slide_end, lgap, distance;
227277acdc25SRandall Stewart 	uint32_t old_cumack, old_base, old_highest, highest_tsn;
2273f8829a4aSRandall Stewart 
2274f8829a4aSRandall Stewart 	asoc = &stcb->asoc;
2275f8829a4aSRandall Stewart 
2276f8829a4aSRandall Stewart 	old_cumack = asoc->cumulative_tsn;
2277f8829a4aSRandall Stewart 	old_base = asoc->mapping_array_base_tsn;
2278f8829a4aSRandall Stewart 	old_highest = asoc->highest_tsn_inside_map;
2279f8829a4aSRandall Stewart 	/*
2280f8829a4aSRandall Stewart 	 * We could probably improve this a small bit by calculating the
2281f8829a4aSRandall Stewart 	 * offset of the current cum-ack as the starting point.
2282f8829a4aSRandall Stewart 	 */
2283f8829a4aSRandall Stewart 	at = 0;
2284b5c16493SMichael Tuexen 	for (slide_from = 0; slide_from < stcb->asoc.mapping_array_size; slide_from++) {
228566bd30bdSRandall Stewart 		val = asoc->nr_mapping_array[slide_from] | asoc->mapping_array[slide_from];
228666bd30bdSRandall Stewart 		if (val == 0xff) {
2287f8829a4aSRandall Stewart 			at += 8;
2288f8829a4aSRandall Stewart 		} else {
2289f8829a4aSRandall Stewart 			/* there is a 0 bit */
229066bd30bdSRandall Stewart 			at += sctp_map_lookup_tab[val];
2291f8829a4aSRandall Stewart 			break;
2292f8829a4aSRandall Stewart 		}
2293f8829a4aSRandall Stewart 	}
2294b5c16493SMichael Tuexen 	asoc->cumulative_tsn = asoc->mapping_array_base_tsn + (at - 1);
2295f8829a4aSRandall Stewart 
229620b07a4dSMichael Tuexen 	if (SCTP_TSN_GT(asoc->cumulative_tsn, asoc->highest_tsn_inside_map) &&
229720b07a4dSMichael Tuexen 	    SCTP_TSN_GT(asoc->cumulative_tsn, asoc->highest_tsn_inside_nr_map)) {
2298a5d547adSRandall Stewart #ifdef INVARIANTS
2299ceaad40aSRandall Stewart 		panic("huh, cumack 0x%x greater than high-tsn 0x%x in map",
2300ceaad40aSRandall Stewart 		    asoc->cumulative_tsn, asoc->highest_tsn_inside_map);
2301f8829a4aSRandall Stewart #else
2302ceaad40aSRandall Stewart 		SCTP_PRINTF("huh, cumack 0x%x greater than high-tsn 0x%x in map - should panic?\n",
2303ceaad40aSRandall Stewart 		    asoc->cumulative_tsn, asoc->highest_tsn_inside_map);
23040e13104dSRandall Stewart 		sctp_print_mapping_array(asoc);
2305b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
2306b3f1ea41SRandall Stewart 			sctp_log_map(0, 6, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT);
2307b3f1ea41SRandall Stewart 		}
2308f8829a4aSRandall Stewart 		asoc->highest_tsn_inside_map = asoc->cumulative_tsn;
2309830d754dSRandall Stewart 		asoc->highest_tsn_inside_nr_map = asoc->cumulative_tsn;
2310f8829a4aSRandall Stewart #endif
2311f8829a4aSRandall Stewart 	}
231220b07a4dSMichael Tuexen 	if (SCTP_TSN_GT(asoc->highest_tsn_inside_nr_map, asoc->highest_tsn_inside_map)) {
231377acdc25SRandall Stewart 		highest_tsn = asoc->highest_tsn_inside_nr_map;
231477acdc25SRandall Stewart 	} else {
231577acdc25SRandall Stewart 		highest_tsn = asoc->highest_tsn_inside_map;
231677acdc25SRandall Stewart 	}
231777acdc25SRandall Stewart 	if ((asoc->cumulative_tsn == highest_tsn) && (at >= 8)) {
2318f8829a4aSRandall Stewart 		/* The complete array was completed by a single FR */
231977acdc25SRandall Stewart 		/* highest becomes the cum-ack */
232037f144ebSMichael Tuexen 		int clr;
232137f144ebSMichael Tuexen #ifdef INVARIANTS
232237f144ebSMichael Tuexen 		unsigned int i;
232337f144ebSMichael Tuexen #endif
2324f8829a4aSRandall Stewart 
2325f8829a4aSRandall Stewart 		/* clear the array */
2326b5c16493SMichael Tuexen 		clr = ((at + 7) >> 3);
2327c4739e2fSRandall Stewart 		if (clr > asoc->mapping_array_size) {
2328f8829a4aSRandall Stewart 			clr = asoc->mapping_array_size;
2329f8829a4aSRandall Stewart 		}
2330f8829a4aSRandall Stewart 		memset(asoc->mapping_array, 0, clr);
2331830d754dSRandall Stewart 		memset(asoc->nr_mapping_array, 0, clr);
233237f144ebSMichael Tuexen #ifdef INVARIANTS
2333b5c16493SMichael Tuexen 		for (i = 0; i < asoc->mapping_array_size; i++) {
2334b5c16493SMichael Tuexen 			if ((asoc->mapping_array[i]) || (asoc->nr_mapping_array[i])) {
2335cd3fd531SMichael Tuexen 				SCTP_PRINTF("Error Mapping array's not clean at clear\n");
2336b5c16493SMichael Tuexen 				sctp_print_mapping_array(asoc);
2337b5c16493SMichael Tuexen 			}
2338b5c16493SMichael Tuexen 		}
233937f144ebSMichael Tuexen #endif
234077acdc25SRandall Stewart 		asoc->mapping_array_base_tsn = asoc->cumulative_tsn + 1;
234177acdc25SRandall Stewart 		asoc->highest_tsn_inside_nr_map = asoc->highest_tsn_inside_map = asoc->cumulative_tsn;
2342f8829a4aSRandall Stewart 	} else if (at >= 8) {
2343f8829a4aSRandall Stewart 		/* we can slide the mapping array down */
2344b3f1ea41SRandall Stewart 		/* slide_from holds where we hit the first NON 0xff byte */
2345b3f1ea41SRandall Stewart 
2346f8829a4aSRandall Stewart 		/*
2347f8829a4aSRandall Stewart 		 * now calculate the ceiling of the move using our highest
2348f8829a4aSRandall Stewart 		 * TSN value
2349f8829a4aSRandall Stewart 		 */
235077acdc25SRandall Stewart 		SCTP_CALC_TSN_TO_GAP(lgap, highest_tsn, asoc->mapping_array_base_tsn);
235177acdc25SRandall Stewart 		slide_end = (lgap >> 3);
2352f8829a4aSRandall Stewart 		if (slide_end < slide_from) {
235377acdc25SRandall Stewart 			sctp_print_mapping_array(asoc);
2354d55b0b1bSRandall Stewart #ifdef INVARIANTS
2355f8829a4aSRandall Stewart 			panic("impossible slide");
2356d55b0b1bSRandall Stewart #else
2357cd3fd531SMichael Tuexen 			SCTP_PRINTF("impossible slide lgap: %x slide_end: %x slide_from: %x? at: %d\n",
235877acdc25SRandall Stewart 			    lgap, slide_end, slide_from, at);
2359d55b0b1bSRandall Stewart 			return;
2360d55b0b1bSRandall Stewart #endif
2361f8829a4aSRandall Stewart 		}
2362b3f1ea41SRandall Stewart 		if (slide_end > asoc->mapping_array_size) {
2363b3f1ea41SRandall Stewart #ifdef INVARIANTS
2364b3f1ea41SRandall Stewart 			panic("would overrun buffer");
2365b3f1ea41SRandall Stewart #else
2366cd3fd531SMichael Tuexen 			SCTP_PRINTF("Gak, would have overrun map end: %d slide_end: %d\n",
2367b3f1ea41SRandall Stewart 			    asoc->mapping_array_size, slide_end);
2368b3f1ea41SRandall Stewart 			slide_end = asoc->mapping_array_size;
2369b3f1ea41SRandall Stewart #endif
2370b3f1ea41SRandall Stewart 		}
2371f8829a4aSRandall Stewart 		distance = (slide_end - slide_from) + 1;
2372b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
2373f8829a4aSRandall Stewart 			sctp_log_map(old_base, old_cumack, old_highest,
2374f8829a4aSRandall Stewart 			    SCTP_MAP_PREPARE_SLIDE);
2375f8829a4aSRandall Stewart 			sctp_log_map((uint32_t) slide_from, (uint32_t) slide_end,
2376f8829a4aSRandall Stewart 			    (uint32_t) lgap, SCTP_MAP_SLIDE_FROM);
237780fefe0aSRandall Stewart 		}
2378f8829a4aSRandall Stewart 		if (distance + slide_from > asoc->mapping_array_size ||
2379f8829a4aSRandall Stewart 		    distance < 0) {
2380f8829a4aSRandall Stewart 			/*
2381f8829a4aSRandall Stewart 			 * Here we do NOT slide forward the array so that
2382f8829a4aSRandall Stewart 			 * hopefully when more data comes in to fill it up
2383f8829a4aSRandall Stewart 			 * we will be able to slide it forward. Really I
2384f8829a4aSRandall Stewart 			 * don't think this should happen :-0
2385f8829a4aSRandall Stewart 			 */
2386f8829a4aSRandall Stewart 
2387b3f1ea41SRandall Stewart 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
2388f8829a4aSRandall Stewart 				sctp_log_map((uint32_t) distance, (uint32_t) slide_from,
2389f8829a4aSRandall Stewart 				    (uint32_t) asoc->mapping_array_size,
2390f8829a4aSRandall Stewart 				    SCTP_MAP_SLIDE_NONE);
239180fefe0aSRandall Stewart 			}
2392f8829a4aSRandall Stewart 		} else {
2393f8829a4aSRandall Stewart 			int ii;
2394f8829a4aSRandall Stewart 
2395f8829a4aSRandall Stewart 			for (ii = 0; ii < distance; ii++) {
239637f144ebSMichael Tuexen 				asoc->mapping_array[ii] = asoc->mapping_array[slide_from + ii];
239737f144ebSMichael Tuexen 				asoc->nr_mapping_array[ii] = asoc->nr_mapping_array[slide_from + ii];
239877acdc25SRandall Stewart 
2399f8829a4aSRandall Stewart 			}
2400aed5947cSMichael Tuexen 			for (ii = distance; ii < asoc->mapping_array_size; ii++) {
2401f8829a4aSRandall Stewart 				asoc->mapping_array[ii] = 0;
240277acdc25SRandall Stewart 				asoc->nr_mapping_array[ii] = 0;
2403f8829a4aSRandall Stewart 			}
2404ee94f0a2SMichael Tuexen 			if (asoc->highest_tsn_inside_map + 1 == asoc->mapping_array_base_tsn) {
2405ee94f0a2SMichael Tuexen 				asoc->highest_tsn_inside_map += (slide_from << 3);
2406ee94f0a2SMichael Tuexen 			}
2407ee94f0a2SMichael Tuexen 			if (asoc->highest_tsn_inside_nr_map + 1 == asoc->mapping_array_base_tsn) {
2408ee94f0a2SMichael Tuexen 				asoc->highest_tsn_inside_nr_map += (slide_from << 3);
2409ee94f0a2SMichael Tuexen 			}
2410f8829a4aSRandall Stewart 			asoc->mapping_array_base_tsn += (slide_from << 3);
2411b3f1ea41SRandall Stewart 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
2412f8829a4aSRandall Stewart 				sctp_log_map(asoc->mapping_array_base_tsn,
2413f8829a4aSRandall Stewart 				    asoc->cumulative_tsn, asoc->highest_tsn_inside_map,
2414f8829a4aSRandall Stewart 				    SCTP_MAP_SLIDE_RESULT);
241580fefe0aSRandall Stewart 			}
2416830d754dSRandall Stewart 		}
2417830d754dSRandall Stewart 	}
2418b5c16493SMichael Tuexen }
2419b5c16493SMichael Tuexen 
2420b5c16493SMichael Tuexen void
24217215cc1bSMichael Tuexen sctp_sack_check(struct sctp_tcb *stcb, int was_a_gap)
2422b5c16493SMichael Tuexen {
2423b5c16493SMichael Tuexen 	struct sctp_association *asoc;
2424b5c16493SMichael Tuexen 	uint32_t highest_tsn;
2425b5c16493SMichael Tuexen 
2426b5c16493SMichael Tuexen 	asoc = &stcb->asoc;
242720b07a4dSMichael Tuexen 	if (SCTP_TSN_GT(asoc->highest_tsn_inside_nr_map, asoc->highest_tsn_inside_map)) {
2428b5c16493SMichael Tuexen 		highest_tsn = asoc->highest_tsn_inside_nr_map;
2429b5c16493SMichael Tuexen 	} else {
2430b5c16493SMichael Tuexen 		highest_tsn = asoc->highest_tsn_inside_map;
2431b5c16493SMichael Tuexen 	}
2432b5c16493SMichael Tuexen 
2433830d754dSRandall Stewart 	/*
2434f8829a4aSRandall Stewart 	 * Now we need to see if we need to queue a sack or just start the
2435f8829a4aSRandall Stewart 	 * timer (if allowed).
2436f8829a4aSRandall Stewart 	 */
2437f8829a4aSRandall Stewart 	if (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_SENT) {
2438f8829a4aSRandall Stewart 		/*
2439b5c16493SMichael Tuexen 		 * Ok special case, in SHUTDOWN-SENT case. here we maker
2440b5c16493SMichael Tuexen 		 * sure SACK timer is off and instead send a SHUTDOWN and a
2441b5c16493SMichael Tuexen 		 * SACK
2442f8829a4aSRandall Stewart 		 */
2443139bc87fSRandall Stewart 		if (SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) {
2444f8829a4aSRandall Stewart 			sctp_timer_stop(SCTP_TIMER_TYPE_RECV,
2445b7d130beSMichael Tuexen 			    stcb->sctp_ep, stcb, NULL,
244644249214SRandall Stewart 			    SCTP_FROM_SCTP_INDATA + SCTP_LOC_17);
2447f8829a4aSRandall Stewart 		}
2448ca85e948SMichael Tuexen 		sctp_send_shutdown(stcb,
2449ca85e948SMichael Tuexen 		    ((stcb->asoc.alternate) ? stcb->asoc.alternate : stcb->asoc.primary_destination));
2450689e6a5fSMichael Tuexen 		sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED);
2451f8829a4aSRandall Stewart 	} else {
2452f8829a4aSRandall Stewart 		int is_a_gap;
2453f8829a4aSRandall Stewart 
2454f8829a4aSRandall Stewart 		/* is there a gap now ? */
245520b07a4dSMichael Tuexen 		is_a_gap = SCTP_TSN_GT(highest_tsn, stcb->asoc.cumulative_tsn);
2456f8829a4aSRandall Stewart 
2457f8829a4aSRandall Stewart 		/*
2458b5c16493SMichael Tuexen 		 * CMT DAC algorithm: increase number of packets received
2459b5c16493SMichael Tuexen 		 * since last ack
2460f8829a4aSRandall Stewart 		 */
2461f8829a4aSRandall Stewart 		stcb->asoc.cmt_dac_pkts_rcvd++;
2462f8829a4aSRandall Stewart 
246342551e99SRandall Stewart 		if ((stcb->asoc.send_sack == 1) ||	/* We need to send a
246442551e99SRandall Stewart 							 * SACK */
2465f8829a4aSRandall Stewart 		    ((was_a_gap) && (is_a_gap == 0)) ||	/* was a gap, but no
2466f8829a4aSRandall Stewart 							 * longer is one */
2467f8829a4aSRandall Stewart 		    (stcb->asoc.numduptsns) ||	/* we have dup's */
2468f8829a4aSRandall Stewart 		    (is_a_gap) ||	/* is still a gap */
246942551e99SRandall Stewart 		    (stcb->asoc.delayed_ack == 0) ||	/* Delayed sack disabled */
2470*5b495f17SMichael Tuexen 		    (stcb->asoc.data_pkts_seen >= stcb->asoc.sack_freq) /* hit limit of pkts */ ) {
2471f8829a4aSRandall Stewart 
24727c99d56fSMichael Tuexen 			if ((stcb->asoc.sctp_cmt_on_off > 0) &&
2473b3f1ea41SRandall Stewart 			    (SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) &&
247442551e99SRandall Stewart 			    (stcb->asoc.send_sack == 0) &&
2475f8829a4aSRandall Stewart 			    (stcb->asoc.numduptsns == 0) &&
2476f8829a4aSRandall Stewart 			    (stcb->asoc.delayed_ack) &&
2477139bc87fSRandall Stewart 			    (!SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer))) {
2478f8829a4aSRandall Stewart 
2479f8829a4aSRandall Stewart 				/*
2480b5c16493SMichael Tuexen 				 * CMT DAC algorithm: With CMT, delay acks
2481b5c16493SMichael Tuexen 				 * even in the face of
2482f8829a4aSRandall Stewart 				 *
2483*5b495f17SMichael Tuexen 				 * reordering. Therefore, if acks that do
2484*5b495f17SMichael Tuexen 				 * not have to be sent because of the above
2485b5c16493SMichael Tuexen 				 * reasons, will be delayed. That is, acks
2486b5c16493SMichael Tuexen 				 * that would have been sent due to gap
2487b5c16493SMichael Tuexen 				 * reports will be delayed with DAC. Start
2488f8829a4aSRandall Stewart 				 * the delayed ack timer.
2489f8829a4aSRandall Stewart 				 */
2490f8829a4aSRandall Stewart 				sctp_timer_start(SCTP_TIMER_TYPE_RECV,
2491f8829a4aSRandall Stewart 				    stcb->sctp_ep, stcb, NULL);
2492f8829a4aSRandall Stewart 			} else {
2493f8829a4aSRandall Stewart 				/*
2494b5c16493SMichael Tuexen 				 * Ok we must build a SACK since the timer
2495b5c16493SMichael Tuexen 				 * is pending, we got our first packet OR
2496b5c16493SMichael Tuexen 				 * there are gaps or duplicates.
2497f8829a4aSRandall Stewart 				 */
2498ad81507eSRandall Stewart 				(void)SCTP_OS_TIMER_STOP(&stcb->asoc.dack_timer.timer);
2499689e6a5fSMichael Tuexen 				sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED);
2500f8829a4aSRandall Stewart 			}
2501f8829a4aSRandall Stewart 		} else {
250242551e99SRandall Stewart 			if (!SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) {
2503f8829a4aSRandall Stewart 				sctp_timer_start(SCTP_TIMER_TYPE_RECV,
2504f8829a4aSRandall Stewart 				    stcb->sctp_ep, stcb, NULL);
2505f8829a4aSRandall Stewart 			}
2506f8829a4aSRandall Stewart 		}
2507f8829a4aSRandall Stewart 	}
2508f8829a4aSRandall Stewart }
2509f8829a4aSRandall Stewart 
2510f8829a4aSRandall Stewart int
2511f8829a4aSRandall Stewart sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
2512e7e71dd7SMichael Tuexen     struct sctp_inpcb *inp, struct sctp_tcb *stcb,
2513e7e71dd7SMichael Tuexen     struct sctp_nets *net, uint32_t * high_tsn)
2514f8829a4aSRandall Stewart {
251544249214SRandall Stewart 	struct sctp_chunkhdr *ch, chunk_buf;
2516f8829a4aSRandall Stewart 	struct sctp_association *asoc;
2517f8829a4aSRandall Stewart 	int num_chunks = 0;	/* number of control chunks processed */
2518f8829a4aSRandall Stewart 	int stop_proc = 0;
2519f8829a4aSRandall Stewart 	int chk_length, break_flag, last_chunk;
25208f777478SMichael Tuexen 	int abort_flag = 0, was_a_gap;
2521f8829a4aSRandall Stewart 	struct mbuf *m;
25228f777478SMichael Tuexen 	uint32_t highest_tsn;
2523f8829a4aSRandall Stewart 
2524f8829a4aSRandall Stewart 	/* set the rwnd */
2525f8829a4aSRandall Stewart 	sctp_set_rwnd(stcb, &stcb->asoc);
2526f8829a4aSRandall Stewart 
2527f8829a4aSRandall Stewart 	m = *mm;
2528f8829a4aSRandall Stewart 	SCTP_TCB_LOCK_ASSERT(stcb);
2529f8829a4aSRandall Stewart 	asoc = &stcb->asoc;
253020b07a4dSMichael Tuexen 	if (SCTP_TSN_GT(asoc->highest_tsn_inside_nr_map, asoc->highest_tsn_inside_map)) {
25318f777478SMichael Tuexen 		highest_tsn = asoc->highest_tsn_inside_nr_map;
25328f777478SMichael Tuexen 	} else {
25338f777478SMichael Tuexen 		highest_tsn = asoc->highest_tsn_inside_map;
2534f8829a4aSRandall Stewart 	}
253520b07a4dSMichael Tuexen 	was_a_gap = SCTP_TSN_GT(highest_tsn, stcb->asoc.cumulative_tsn);
2536f8829a4aSRandall Stewart 	/*
2537f8829a4aSRandall Stewart 	 * setup where we got the last DATA packet from for any SACK that
2538f8829a4aSRandall Stewart 	 * may need to go out. Don't bump the net. This is done ONLY when a
2539f8829a4aSRandall Stewart 	 * chunk is assigned.
2540f8829a4aSRandall Stewart 	 */
2541f8829a4aSRandall Stewart 	asoc->last_data_chunk_from = net;
2542f8829a4aSRandall Stewart 
2543d06c82f1SRandall Stewart 	/*-
2544f8829a4aSRandall Stewart 	 * Now before we proceed we must figure out if this is a wasted
2545f8829a4aSRandall Stewart 	 * cluster... i.e. it is a small packet sent in and yet the driver
2546f8829a4aSRandall Stewart 	 * underneath allocated a full cluster for it. If so we must copy it
2547f8829a4aSRandall Stewart 	 * to a smaller mbuf and free up the cluster mbuf. This will help
2548d06c82f1SRandall Stewart 	 * with cluster starvation. Note for __Panda__ we don't do this
2549d06c82f1SRandall Stewart 	 * since it has clusters all the way down to 64 bytes.
2550f8829a4aSRandall Stewart 	 */
255144b7479bSRandall Stewart 	if (SCTP_BUF_LEN(m) < (long)MLEN && SCTP_BUF_NEXT(m) == NULL) {
2552f8829a4aSRandall Stewart 		/* we only handle mbufs that are singletons.. not chains */
2553eb1b1807SGleb Smirnoff 		m = sctp_get_mbuf_for_msg(SCTP_BUF_LEN(m), 0, M_NOWAIT, 1, MT_DATA);
2554f8829a4aSRandall Stewart 		if (m) {
2555f8829a4aSRandall Stewart 			/* ok lets see if we can copy the data up */
2556f8829a4aSRandall Stewart 			caddr_t *from, *to;
2557f8829a4aSRandall Stewart 
2558f8829a4aSRandall Stewart 			/* get the pointers and copy */
2559f8829a4aSRandall Stewart 			to = mtod(m, caddr_t *);
2560f8829a4aSRandall Stewart 			from = mtod((*mm), caddr_t *);
2561139bc87fSRandall Stewart 			memcpy(to, from, SCTP_BUF_LEN((*mm)));
2562f8829a4aSRandall Stewart 			/* copy the length and free up the old */
2563139bc87fSRandall Stewart 			SCTP_BUF_LEN(m) = SCTP_BUF_LEN((*mm));
2564f8829a4aSRandall Stewart 			sctp_m_freem(*mm);
2565cd0a4ff6SPedro F. Giffuni 			/* success, back copy */
2566f8829a4aSRandall Stewart 			*mm = m;
2567f8829a4aSRandall Stewart 		} else {
2568f8829a4aSRandall Stewart 			/* We are in trouble in the mbuf world .. yikes */
2569f8829a4aSRandall Stewart 			m = *mm;
2570f8829a4aSRandall Stewart 		}
2571f8829a4aSRandall Stewart 	}
2572f8829a4aSRandall Stewart 	/* get pointer to the first chunk header */
257344249214SRandall Stewart 	ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset,
257444249214SRandall Stewart 	    sizeof(struct sctp_chunkhdr), (uint8_t *) & chunk_buf);
2575f8829a4aSRandall Stewart 	if (ch == NULL) {
2576f8829a4aSRandall Stewart 		return (1);
2577f8829a4aSRandall Stewart 	}
2578f8829a4aSRandall Stewart 	/*
2579f8829a4aSRandall Stewart 	 * process all DATA chunks...
2580f8829a4aSRandall Stewart 	 */
2581f8829a4aSRandall Stewart 	*high_tsn = asoc->cumulative_tsn;
2582f8829a4aSRandall Stewart 	break_flag = 0;
258342551e99SRandall Stewart 	asoc->data_pkts_seen++;
2584f8829a4aSRandall Stewart 	while (stop_proc == 0) {
2585f8829a4aSRandall Stewart 		/* validate chunk length */
258644249214SRandall Stewart 		chk_length = ntohs(ch->chunk_length);
2587f8829a4aSRandall Stewart 		if (length - *offset < chk_length) {
2588f8829a4aSRandall Stewart 			/* all done, mutulated chunk */
2589f8829a4aSRandall Stewart 			stop_proc = 1;
259060990c0cSMichael Tuexen 			continue;
2591f8829a4aSRandall Stewart 		}
259244249214SRandall Stewart 		if ((asoc->idata_supported == 1) &&
259344249214SRandall Stewart 		    (ch->chunk_type == SCTP_DATA)) {
259444249214SRandall Stewart 			struct mbuf *op_err;
259544249214SRandall Stewart 			char msg[SCTP_DIAG_INFO_LEN];
259644249214SRandall Stewart 
2597e7f232a0SMichael Tuexen 			snprintf(msg, sizeof(msg), "%s", "I-DATA chunk received when DATA was negotiated");
259844249214SRandall Stewart 			op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
259944249214SRandall Stewart 			stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_18;
260044249214SRandall Stewart 			sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED);
260144249214SRandall Stewart 			return (2);
260244249214SRandall Stewart 		}
260344249214SRandall Stewart 		if ((asoc->idata_supported == 0) &&
260444249214SRandall Stewart 		    (ch->chunk_type == SCTP_IDATA)) {
260544249214SRandall Stewart 			struct mbuf *op_err;
260644249214SRandall Stewart 			char msg[SCTP_DIAG_INFO_LEN];
260744249214SRandall Stewart 
2608e7f232a0SMichael Tuexen 			snprintf(msg, sizeof(msg), "%s", "DATA chunk received when I-DATA was negotiated");
260944249214SRandall Stewart 			op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
261044249214SRandall Stewart 			stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_19;
261144249214SRandall Stewart 			sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED);
261244249214SRandall Stewart 			return (2);
261344249214SRandall Stewart 		}
261444249214SRandall Stewart 		if ((ch->chunk_type == SCTP_DATA) ||
261544249214SRandall Stewart 		    (ch->chunk_type == SCTP_IDATA)) {
261644249214SRandall Stewart 			int clen;
261744249214SRandall Stewart 
261844249214SRandall Stewart 			if (ch->chunk_type == SCTP_DATA) {
261944249214SRandall Stewart 				clen = sizeof(struct sctp_data_chunk);
262044249214SRandall Stewart 			} else {
262144249214SRandall Stewart 				clen = sizeof(struct sctp_idata_chunk);
262244249214SRandall Stewart 			}
2623f8ee69bfSMichael Tuexen 			if (chk_length < clen) {
2624f8829a4aSRandall Stewart 				/*
2625f8829a4aSRandall Stewart 				 * Need to send an abort since we had a
2626f8829a4aSRandall Stewart 				 * invalid data chunk.
2627f8829a4aSRandall Stewart 				 */
2628f8829a4aSRandall Stewart 				struct mbuf *op_err;
2629ff1ffd74SMichael Tuexen 				char msg[SCTP_DIAG_INFO_LEN];
2630f8829a4aSRandall Stewart 
2631ff1ffd74SMichael Tuexen 				snprintf(msg, sizeof(msg), "DATA chunk of length %d",
2632ff1ffd74SMichael Tuexen 				    chk_length);
2633ff1ffd74SMichael Tuexen 				op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
263444249214SRandall Stewart 				stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_20;
2635e7e71dd7SMichael Tuexen 				sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED);
263632451da4SMichael Tuexen 				return (2);
263732451da4SMichael Tuexen 			}
2638f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED
2639f8829a4aSRandall Stewart 			sctp_audit_log(0xB1, 0);
2640f8829a4aSRandall Stewart #endif
2641f8829a4aSRandall Stewart 			if (SCTP_SIZE32(chk_length) == (length - *offset)) {
2642f8829a4aSRandall Stewart 				last_chunk = 1;
2643f8829a4aSRandall Stewart 			} else {
2644f8829a4aSRandall Stewart 				last_chunk = 0;
2645f8829a4aSRandall Stewart 			}
264644249214SRandall Stewart 			if (sctp_process_a_data_chunk(stcb, asoc, mm, *offset,
2647f8829a4aSRandall Stewart 			    chk_length, net, high_tsn, &abort_flag, &break_flag,
264844249214SRandall Stewart 			    last_chunk, ch->chunk_type)) {
2649f8829a4aSRandall Stewart 				num_chunks++;
2650f8829a4aSRandall Stewart 			}
2651f8829a4aSRandall Stewart 			if (abort_flag)
2652f8829a4aSRandall Stewart 				return (2);
2653f8829a4aSRandall Stewart 
2654f8829a4aSRandall Stewart 			if (break_flag) {
2655f8829a4aSRandall Stewart 				/*
2656f8829a4aSRandall Stewart 				 * Set because of out of rwnd space and no
2657f8829a4aSRandall Stewart 				 * drop rep space left.
2658f8829a4aSRandall Stewart 				 */
2659f8829a4aSRandall Stewart 				stop_proc = 1;
266060990c0cSMichael Tuexen 				continue;
2661f8829a4aSRandall Stewart 			}
2662f8829a4aSRandall Stewart 		} else {
2663f8829a4aSRandall Stewart 			/* not a data chunk in the data region */
266444249214SRandall Stewart 			switch (ch->chunk_type) {
2665f8829a4aSRandall Stewart 			case SCTP_INITIATION:
2666f8829a4aSRandall Stewart 			case SCTP_INITIATION_ACK:
2667f8829a4aSRandall Stewart 			case SCTP_SELECTIVE_ACK:
266860990c0cSMichael Tuexen 			case SCTP_NR_SELECTIVE_ACK:
2669f8829a4aSRandall Stewart 			case SCTP_HEARTBEAT_REQUEST:
2670f8829a4aSRandall Stewart 			case SCTP_HEARTBEAT_ACK:
2671f8829a4aSRandall Stewart 			case SCTP_ABORT_ASSOCIATION:
2672f8829a4aSRandall Stewart 			case SCTP_SHUTDOWN:
2673f8829a4aSRandall Stewart 			case SCTP_SHUTDOWN_ACK:
2674f8829a4aSRandall Stewart 			case SCTP_OPERATION_ERROR:
2675f8829a4aSRandall Stewart 			case SCTP_COOKIE_ECHO:
2676f8829a4aSRandall Stewart 			case SCTP_COOKIE_ACK:
2677f8829a4aSRandall Stewart 			case SCTP_ECN_ECHO:
2678f8829a4aSRandall Stewart 			case SCTP_ECN_CWR:
2679f8829a4aSRandall Stewart 			case SCTP_SHUTDOWN_COMPLETE:
2680f8829a4aSRandall Stewart 			case SCTP_AUTHENTICATION:
2681f8829a4aSRandall Stewart 			case SCTP_ASCONF_ACK:
2682f8829a4aSRandall Stewart 			case SCTP_PACKET_DROPPED:
2683f8829a4aSRandall Stewart 			case SCTP_STREAM_RESET:
2684f8829a4aSRandall Stewart 			case SCTP_FORWARD_CUM_TSN:
2685f8829a4aSRandall Stewart 			case SCTP_ASCONF:
2686fd60718dSMichael Tuexen 				{
2687f8829a4aSRandall Stewart 					/*
2688fd60718dSMichael Tuexen 					 * Now, what do we do with KNOWN
2689fd60718dSMichael Tuexen 					 * chunks that are NOT in the right
2690fd60718dSMichael Tuexen 					 * place?
2691f8829a4aSRandall Stewart 					 *
2692fd60718dSMichael Tuexen 					 * For now, I do nothing but ignore
2693fd60718dSMichael Tuexen 					 * them. We may later want to add
2694fd60718dSMichael Tuexen 					 * sysctl stuff to switch out and do
2695fd60718dSMichael Tuexen 					 * either an ABORT() or possibly
2696fd60718dSMichael Tuexen 					 * process them.
2697f8829a4aSRandall Stewart 					 */
2698f8829a4aSRandall Stewart 					struct mbuf *op_err;
2699267dbe63SMichael Tuexen 					char msg[SCTP_DIAG_INFO_LEN];
2700f8829a4aSRandall Stewart 
27019ae56375SMichael Tuexen 					snprintf(msg, sizeof(msg), "DATA chunk followed by chunk of type %2.2x",
270244249214SRandall Stewart 					    ch->chunk_type);
2703267dbe63SMichael Tuexen 					op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
2704e7e71dd7SMichael Tuexen 					sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED);
2705f8829a4aSRandall Stewart 					return (2);
2706f8829a4aSRandall Stewart 				}
2707f8829a4aSRandall Stewart 			default:
2708f8829a4aSRandall Stewart 				/* unknown chunk type, use bit rules */
270944249214SRandall Stewart 				if (ch->chunk_type & 0x40) {
2710f8829a4aSRandall Stewart 					/* Add a error report to the queue */
271186eda749SMichael Tuexen 					struct mbuf *op_err;
271286eda749SMichael Tuexen 					struct sctp_gen_error_cause *cause;
2713f8829a4aSRandall Stewart 
271486eda749SMichael Tuexen 					op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_gen_error_cause),
271586eda749SMichael Tuexen 					    0, M_NOWAIT, 1, MT_DATA);
271686eda749SMichael Tuexen 					if (op_err != NULL) {
271786eda749SMichael Tuexen 						cause = mtod(op_err, struct sctp_gen_error_cause *);
271886eda749SMichael Tuexen 						cause->code = htons(SCTP_CAUSE_UNRECOG_CHUNK);
27199a8e3088SMichael Tuexen 						cause->length = htons((uint16_t) (chk_length + sizeof(struct sctp_gen_error_cause)));
272086eda749SMichael Tuexen 						SCTP_BUF_LEN(op_err) = sizeof(struct sctp_gen_error_cause);
272186eda749SMichael Tuexen 						SCTP_BUF_NEXT(op_err) = SCTP_M_COPYM(m, *offset, chk_length, M_NOWAIT);
272286eda749SMichael Tuexen 						if (SCTP_BUF_NEXT(op_err) != NULL) {
272386eda749SMichael Tuexen 							sctp_queue_op_err(stcb, op_err);
2724f8829a4aSRandall Stewart 						} else {
272586eda749SMichael Tuexen 							sctp_m_freem(op_err);
2726f8829a4aSRandall Stewart 						}
2727f8829a4aSRandall Stewart 					}
2728f8829a4aSRandall Stewart 				}
272944249214SRandall Stewart 				if ((ch->chunk_type & 0x80) == 0) {
2730f8829a4aSRandall Stewart 					/* discard the rest of this packet */
2731f8829a4aSRandall Stewart 					stop_proc = 1;
2732f8829a4aSRandall Stewart 				}	/* else skip this bad chunk and
2733*5b495f17SMichael Tuexen 				  * continue... */ break;
273460990c0cSMichael Tuexen 			}	/* switch of chunk type */
2735f8829a4aSRandall Stewart 		}
2736f8829a4aSRandall Stewart 		*offset += SCTP_SIZE32(chk_length);
2737f8829a4aSRandall Stewart 		if ((*offset >= length) || stop_proc) {
2738f8829a4aSRandall Stewart 			/* no more data left in the mbuf chain */
2739f8829a4aSRandall Stewart 			stop_proc = 1;
2740f8829a4aSRandall Stewart 			continue;
2741f8829a4aSRandall Stewart 		}
274244249214SRandall Stewart 		ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset,
274344249214SRandall Stewart 		    sizeof(struct sctp_chunkhdr), (uint8_t *) & chunk_buf);
2744f8829a4aSRandall Stewart 		if (ch == NULL) {
2745f8829a4aSRandall Stewart 			*offset = length;
2746f8829a4aSRandall Stewart 			stop_proc = 1;
274760990c0cSMichael Tuexen 			continue;
2748f8829a4aSRandall Stewart 		}
274960990c0cSMichael Tuexen 	}
2750f8829a4aSRandall Stewart 	if (break_flag) {
2751f8829a4aSRandall Stewart 		/*
2752f8829a4aSRandall Stewart 		 * we need to report rwnd overrun drops.
2753f8829a4aSRandall Stewart 		 */
275420cc2188SMichael Tuexen 		sctp_send_packet_dropped(stcb, net, *mm, length, iphlen, 0);
2755f8829a4aSRandall Stewart 	}
2756f8829a4aSRandall Stewart 	if (num_chunks) {
2757f8829a4aSRandall Stewart 		/*
2758ceaad40aSRandall Stewart 		 * Did we get data, if so update the time for auto-close and
2759f8829a4aSRandall Stewart 		 * give peer credit for being alive.
2760f8829a4aSRandall Stewart 		 */
2761f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_recvpktwithdata);
2762b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) {
2763c4739e2fSRandall Stewart 			sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
2764c4739e2fSRandall Stewart 			    stcb->asoc.overall_error_count,
2765c4739e2fSRandall Stewart 			    0,
2766c4739e2fSRandall Stewart 			    SCTP_FROM_SCTP_INDATA,
2767c4739e2fSRandall Stewart 			    __LINE__);
2768c4739e2fSRandall Stewart 		}
2769f8829a4aSRandall Stewart 		stcb->asoc.overall_error_count = 0;
27706e55db54SRandall Stewart 		(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_last_rcvd);
2771f8829a4aSRandall Stewart 	}
2772f8829a4aSRandall Stewart 	/* now service all of the reassm queue if needed */
2773f8829a4aSRandall Stewart 	if (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_SENT) {
277442551e99SRandall Stewart 		/* Assure that we ack right away */
277542551e99SRandall Stewart 		stcb->asoc.send_sack = 1;
2776f8829a4aSRandall Stewart 	}
2777f8829a4aSRandall Stewart 	/* Start a sack timer or QUEUE a SACK for sending */
27787215cc1bSMichael Tuexen 	sctp_sack_check(stcb, was_a_gap);
2779f8829a4aSRandall Stewart 	return (0);
2780f8829a4aSRandall Stewart }
2781f8829a4aSRandall Stewart 
27820fa753b3SRandall Stewart static int
27830fa753b3SRandall Stewart sctp_process_segment_range(struct sctp_tcb *stcb, struct sctp_tmit_chunk **p_tp1, uint32_t last_tsn,
27840fa753b3SRandall Stewart     uint16_t frag_strt, uint16_t frag_end, int nr_sacking,
27850fa753b3SRandall Stewart     int *num_frs,
27860fa753b3SRandall Stewart     uint32_t * biggest_newly_acked_tsn,
27870fa753b3SRandall Stewart     uint32_t * this_sack_lowest_newack,
27887215cc1bSMichael Tuexen     int *rto_ok)
27890fa753b3SRandall Stewart {
27900fa753b3SRandall Stewart 	struct sctp_tmit_chunk *tp1;
27910fa753b3SRandall Stewart 	unsigned int theTSN;
2792b5c16493SMichael Tuexen 	int j, wake_him = 0, circled = 0;
27930fa753b3SRandall Stewart 
27940fa753b3SRandall Stewart 	/* Recover the tp1 we last saw */
27950fa753b3SRandall Stewart 	tp1 = *p_tp1;
27960fa753b3SRandall Stewart 	if (tp1 == NULL) {
27970fa753b3SRandall Stewart 		tp1 = TAILQ_FIRST(&stcb->asoc.sent_queue);
27980fa753b3SRandall Stewart 	}
27990fa753b3SRandall Stewart 	for (j = frag_strt; j <= frag_end; j++) {
28000fa753b3SRandall Stewart 		theTSN = j + last_tsn;
28010fa753b3SRandall Stewart 		while (tp1) {
28020fa753b3SRandall Stewart 			if (tp1->rec.data.doing_fast_retransmit)
28030fa753b3SRandall Stewart 				(*num_frs) += 1;
28040fa753b3SRandall Stewart 
28050fa753b3SRandall Stewart 			/*-
28060fa753b3SRandall Stewart 			 * CMT: CUCv2 algorithm. For each TSN being
28070fa753b3SRandall Stewart 			 * processed from the sent queue, track the
28080fa753b3SRandall Stewart 			 * next expected pseudo-cumack, or
28090fa753b3SRandall Stewart 			 * rtx_pseudo_cumack, if required. Separate
28100fa753b3SRandall Stewart 			 * cumack trackers for first transmissions,
28110fa753b3SRandall Stewart 			 * and retransmissions.
28120fa753b3SRandall Stewart 			 */
28138427b3fdSMichael Tuexen 			if ((tp1->sent < SCTP_DATAGRAM_RESEND) &&
28148427b3fdSMichael Tuexen 			    (tp1->whoTo->find_pseudo_cumack == 1) &&
28150fa753b3SRandall Stewart 			    (tp1->snd_count == 1)) {
28160fa753b3SRandall Stewart 				tp1->whoTo->pseudo_cumack = tp1->rec.data.TSN_seq;
28170fa753b3SRandall Stewart 				tp1->whoTo->find_pseudo_cumack = 0;
28180fa753b3SRandall Stewart 			}
28198427b3fdSMichael Tuexen 			if ((tp1->sent < SCTP_DATAGRAM_RESEND) &&
28208427b3fdSMichael Tuexen 			    (tp1->whoTo->find_rtx_pseudo_cumack == 1) &&
28210fa753b3SRandall Stewart 			    (tp1->snd_count > 1)) {
28220fa753b3SRandall Stewart 				tp1->whoTo->rtx_pseudo_cumack = tp1->rec.data.TSN_seq;
28230fa753b3SRandall Stewart 				tp1->whoTo->find_rtx_pseudo_cumack = 0;
28240fa753b3SRandall Stewart 			}
28250fa753b3SRandall Stewart 			if (tp1->rec.data.TSN_seq == theTSN) {
28260fa753b3SRandall Stewart 				if (tp1->sent != SCTP_DATAGRAM_UNSENT) {
28270fa753b3SRandall Stewart 					/*-
28280fa753b3SRandall Stewart 					 * must be held until
28290fa753b3SRandall Stewart 					 * cum-ack passes
28300fa753b3SRandall Stewart 					 */
28310fa753b3SRandall Stewart 					if (tp1->sent < SCTP_DATAGRAM_RESEND) {
28320fa753b3SRandall Stewart 						/*-
28330fa753b3SRandall Stewart 						 * If it is less than RESEND, it is
28340fa753b3SRandall Stewart 						 * now no-longer in flight.
28350fa753b3SRandall Stewart 						 * Higher values may already be set
28360fa753b3SRandall Stewart 						 * via previous Gap Ack Blocks...
28370fa753b3SRandall Stewart 						 * i.e. ACKED or RESEND.
28380fa753b3SRandall Stewart 						 */
283920b07a4dSMichael Tuexen 						if (SCTP_TSN_GT(tp1->rec.data.TSN_seq,
284020b07a4dSMichael Tuexen 						    *biggest_newly_acked_tsn)) {
28410fa753b3SRandall Stewart 							*biggest_newly_acked_tsn = tp1->rec.data.TSN_seq;
28420fa753b3SRandall Stewart 						}
28430fa753b3SRandall Stewart 						/*-
28440fa753b3SRandall Stewart 						 * CMT: SFR algo (and HTNA) - set
28450fa753b3SRandall Stewart 						 * saw_newack to 1 for dest being
28460fa753b3SRandall Stewart 						 * newly acked. update
28470fa753b3SRandall Stewart 						 * this_sack_highest_newack if
28480fa753b3SRandall Stewart 						 * appropriate.
28490fa753b3SRandall Stewart 						 */
28500fa753b3SRandall Stewart 						if (tp1->rec.data.chunk_was_revoked == 0)
28510fa753b3SRandall Stewart 							tp1->whoTo->saw_newack = 1;
28520fa753b3SRandall Stewart 
285320b07a4dSMichael Tuexen 						if (SCTP_TSN_GT(tp1->rec.data.TSN_seq,
285420b07a4dSMichael Tuexen 						    tp1->whoTo->this_sack_highest_newack)) {
28550fa753b3SRandall Stewart 							tp1->whoTo->this_sack_highest_newack =
28560fa753b3SRandall Stewart 							    tp1->rec.data.TSN_seq;
28570fa753b3SRandall Stewart 						}
28580fa753b3SRandall Stewart 						/*-
28590fa753b3SRandall Stewart 						 * CMT DAC algo: also update
28600fa753b3SRandall Stewart 						 * this_sack_lowest_newack
28610fa753b3SRandall Stewart 						 */
28620fa753b3SRandall Stewart 						if (*this_sack_lowest_newack == 0) {
28630fa753b3SRandall Stewart 							if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) {
28640fa753b3SRandall Stewart 								sctp_log_sack(*this_sack_lowest_newack,
28650fa753b3SRandall Stewart 								    last_tsn,
28660fa753b3SRandall Stewart 								    tp1->rec.data.TSN_seq,
28670fa753b3SRandall Stewart 								    0,
28680fa753b3SRandall Stewart 								    0,
28690fa753b3SRandall Stewart 								    SCTP_LOG_TSN_ACKED);
28700fa753b3SRandall Stewart 							}
28710fa753b3SRandall Stewart 							*this_sack_lowest_newack = tp1->rec.data.TSN_seq;
28720fa753b3SRandall Stewart 						}
28730fa753b3SRandall Stewart 						/*-
28740fa753b3SRandall Stewart 						 * CMT: CUCv2 algorithm. If (rtx-)pseudo-cumack for corresp
28750fa753b3SRandall Stewart 						 * dest is being acked, then we have a new (rtx-)pseudo-cumack. Set
28760fa753b3SRandall Stewart 						 * new_(rtx_)pseudo_cumack to TRUE so that the cwnd for this dest can be
28770fa753b3SRandall Stewart 						 * updated. Also trigger search for the next expected (rtx-)pseudo-cumack.
28780fa753b3SRandall Stewart 						 * Separate pseudo_cumack trackers for first transmissions and
28790fa753b3SRandall Stewart 						 * retransmissions.
28800fa753b3SRandall Stewart 						 */
28810fa753b3SRandall Stewart 						if (tp1->rec.data.TSN_seq == tp1->whoTo->pseudo_cumack) {
28820fa753b3SRandall Stewart 							if (tp1->rec.data.chunk_was_revoked == 0) {
28830fa753b3SRandall Stewart 								tp1->whoTo->new_pseudo_cumack = 1;
28840fa753b3SRandall Stewart 							}
28850fa753b3SRandall Stewart 							tp1->whoTo->find_pseudo_cumack = 1;
28860fa753b3SRandall Stewart 						}
28870fa753b3SRandall Stewart 						if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
28880fa753b3SRandall Stewart 							sctp_log_cwnd(stcb, tp1->whoTo, tp1->rec.data.TSN_seq, SCTP_CWND_LOG_FROM_SACK);
28890fa753b3SRandall Stewart 						}
28900fa753b3SRandall Stewart 						if (tp1->rec.data.TSN_seq == tp1->whoTo->rtx_pseudo_cumack) {
28910fa753b3SRandall Stewart 							if (tp1->rec.data.chunk_was_revoked == 0) {
28920fa753b3SRandall Stewart 								tp1->whoTo->new_pseudo_cumack = 1;
28930fa753b3SRandall Stewart 							}
28940fa753b3SRandall Stewart 							tp1->whoTo->find_rtx_pseudo_cumack = 1;
28950fa753b3SRandall Stewart 						}
28960fa753b3SRandall Stewart 						if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) {
28970fa753b3SRandall Stewart 							sctp_log_sack(*biggest_newly_acked_tsn,
28980fa753b3SRandall Stewart 							    last_tsn,
28990fa753b3SRandall Stewart 							    tp1->rec.data.TSN_seq,
29000fa753b3SRandall Stewart 							    frag_strt,
29010fa753b3SRandall Stewart 							    frag_end,
29020fa753b3SRandall Stewart 							    SCTP_LOG_TSN_ACKED);
29030fa753b3SRandall Stewart 						}
29040fa753b3SRandall Stewart 						if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) {
29050fa753b3SRandall Stewart 							sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_GAP,
29060fa753b3SRandall Stewart 							    tp1->whoTo->flight_size,
29070fa753b3SRandall Stewart 							    tp1->book_size,
29089a8e3088SMichael Tuexen 							    (uint32_t) (uintptr_t) tp1->whoTo,
29090fa753b3SRandall Stewart 							    tp1->rec.data.TSN_seq);
29100fa753b3SRandall Stewart 						}
29110fa753b3SRandall Stewart 						sctp_flight_size_decrease(tp1);
2912299108c5SRandall Stewart 						if (stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) {
2913299108c5SRandall Stewart 							(*stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) (tp1->whoTo,
2914299108c5SRandall Stewart 							    tp1);
2915299108c5SRandall Stewart 						}
29160fa753b3SRandall Stewart 						sctp_total_flight_decrease(stcb, tp1);
29170fa753b3SRandall Stewart 
29180fa753b3SRandall Stewart 						tp1->whoTo->net_ack += tp1->send_size;
29190fa753b3SRandall Stewart 						if (tp1->snd_count < 2) {
29200fa753b3SRandall Stewart 							/*-
29210fa753b3SRandall Stewart 							 * True non-retransmited chunk
29220fa753b3SRandall Stewart 							 */
29230fa753b3SRandall Stewart 							tp1->whoTo->net_ack2 += tp1->send_size;
29240fa753b3SRandall Stewart 
29250fa753b3SRandall Stewart 							/*-
29260fa753b3SRandall Stewart 							 * update RTO too ?
29270fa753b3SRandall Stewart 							 */
29280fa753b3SRandall Stewart 							if (tp1->do_rtt) {
2929f79aab18SRandall Stewart 								if (*rto_ok) {
29300fa753b3SRandall Stewart 									tp1->whoTo->RTO =
29310fa753b3SRandall Stewart 									    sctp_calculate_rto(stcb,
29320fa753b3SRandall Stewart 									    &stcb->asoc,
29330fa753b3SRandall Stewart 									    tp1->whoTo,
29340fa753b3SRandall Stewart 									    &tp1->sent_rcv_time,
2935899288aeSRandall Stewart 									    sctp_align_safe_nocopy,
2936f79aab18SRandall Stewart 									    SCTP_RTT_FROM_DATA);
2937f79aab18SRandall Stewart 									*rto_ok = 0;
2938f79aab18SRandall Stewart 								}
2939f79aab18SRandall Stewart 								if (tp1->whoTo->rto_needed == 0) {
2940f79aab18SRandall Stewart 									tp1->whoTo->rto_needed = 1;
2941f79aab18SRandall Stewart 								}
29420fa753b3SRandall Stewart 								tp1->do_rtt = 0;
29430fa753b3SRandall Stewart 							}
29440fa753b3SRandall Stewart 						}
29450fa753b3SRandall Stewart 					}
29460fa753b3SRandall Stewart 					if (tp1->sent <= SCTP_DATAGRAM_RESEND) {
294720b07a4dSMichael Tuexen 						if (SCTP_TSN_GT(tp1->rec.data.TSN_seq,
294820b07a4dSMichael Tuexen 						    stcb->asoc.this_sack_highest_gap)) {
29490fa753b3SRandall Stewart 							stcb->asoc.this_sack_highest_gap =
29500fa753b3SRandall Stewart 							    tp1->rec.data.TSN_seq;
29510fa753b3SRandall Stewart 						}
29520fa753b3SRandall Stewart 						if (tp1->sent == SCTP_DATAGRAM_RESEND) {
29530fa753b3SRandall Stewart 							sctp_ucount_decr(stcb->asoc.sent_queue_retran_cnt);
29540fa753b3SRandall Stewart #ifdef SCTP_AUDITING_ENABLED
29550fa753b3SRandall Stewart 							sctp_audit_log(0xB2,
29560fa753b3SRandall Stewart 							    (stcb->asoc.sent_queue_retran_cnt & 0x000000ff));
29570fa753b3SRandall Stewart #endif
29580fa753b3SRandall Stewart 						}
29590fa753b3SRandall Stewart 					}
29600fa753b3SRandall Stewart 					/*-
29610fa753b3SRandall Stewart 					 * All chunks NOT UNSENT fall through here and are marked
29620fa753b3SRandall Stewart 					 * (leave PR-SCTP ones that are to skip alone though)
29630fa753b3SRandall Stewart 					 */
29642a498584SMichael Tuexen 					if ((tp1->sent != SCTP_FORWARD_TSN_SKIP) &&
2965325c8c46SMichael Tuexen 					    (tp1->sent != SCTP_DATAGRAM_NR_ACKED)) {
29660fa753b3SRandall Stewart 						tp1->sent = SCTP_DATAGRAM_MARKED;
29672a498584SMichael Tuexen 					}
29680fa753b3SRandall Stewart 					if (tp1->rec.data.chunk_was_revoked) {
29690fa753b3SRandall Stewart 						/* deflate the cwnd */
29700fa753b3SRandall Stewart 						tp1->whoTo->cwnd -= tp1->book_size;
29710fa753b3SRandall Stewart 						tp1->rec.data.chunk_was_revoked = 0;
29720fa753b3SRandall Stewart 					}
29730fa753b3SRandall Stewart 					/* NR Sack code here */
2974325c8c46SMichael Tuexen 					if (nr_sacking &&
2975325c8c46SMichael Tuexen 					    (tp1->sent != SCTP_DATAGRAM_NR_ACKED)) {
2976325c8c46SMichael Tuexen 						if (stcb->asoc.strmout[tp1->rec.data.stream_number].chunks_on_queues > 0) {
2977325c8c46SMichael Tuexen 							stcb->asoc.strmout[tp1->rec.data.stream_number].chunks_on_queues--;
2978325c8c46SMichael Tuexen #ifdef INVARIANTS
2979325c8c46SMichael Tuexen 						} else {
2980325c8c46SMichael Tuexen 							panic("No chunks on the queues for sid %u.", tp1->rec.data.stream_number);
2981325c8c46SMichael Tuexen #endif
2982325c8c46SMichael Tuexen 						}
2983d96bef9cSMichael Tuexen 						if ((stcb->asoc.strmout[tp1->rec.data.stream_number].chunks_on_queues == 0) &&
2984d96bef9cSMichael Tuexen 						    (stcb->asoc.strmout[tp1->rec.data.stream_number].state == SCTP_STREAM_RESET_PENDING) &&
2985d96bef9cSMichael Tuexen 						    TAILQ_EMPTY(&stcb->asoc.strmout[tp1->rec.data.stream_number].outqueue)) {
2986d96bef9cSMichael Tuexen 							stcb->asoc.trigger_reset = 1;
2987d96bef9cSMichael Tuexen 						}
2988325c8c46SMichael Tuexen 						tp1->sent = SCTP_DATAGRAM_NR_ACKED;
29890fa753b3SRandall Stewart 						if (tp1->data) {
2990*5b495f17SMichael Tuexen 							/* sa_ignore
2991*5b495f17SMichael Tuexen 							 * NO_NULL_CHK */
29920fa753b3SRandall Stewart 							sctp_free_bufspace(stcb, &stcb->asoc, tp1, 1);
29930fa753b3SRandall Stewart 							sctp_m_freem(tp1->data);
29940fa753b3SRandall Stewart 							tp1->data = NULL;
2995b5c16493SMichael Tuexen 						}
29960fa753b3SRandall Stewart 						wake_him++;
29970fa753b3SRandall Stewart 					}
29980fa753b3SRandall Stewart 				}
29990fa753b3SRandall Stewart 				break;
3000*5b495f17SMichael Tuexen 			} /* if (tp1->TSN_seq == theTSN) */ if (SCTP_TSN_GT(tp1->rec.data.TSN_seq, theTSN)) {
30010fa753b3SRandall Stewart 				break;
300220b07a4dSMichael Tuexen 			}
30030fa753b3SRandall Stewart 			tp1 = TAILQ_NEXT(tp1, sctp_next);
3004b5c16493SMichael Tuexen 			if ((tp1 == NULL) && (circled == 0)) {
3005b5c16493SMichael Tuexen 				circled++;
30060fa753b3SRandall Stewart 				tp1 = TAILQ_FIRST(&stcb->asoc.sent_queue);
30070fa753b3SRandall Stewart 			}
3008b5c16493SMichael Tuexen 		}		/* end while (tp1) */
3009b5c16493SMichael Tuexen 		if (tp1 == NULL) {
3010b5c16493SMichael Tuexen 			circled = 0;
3011b5c16493SMichael Tuexen 			tp1 = TAILQ_FIRST(&stcb->asoc.sent_queue);
3012b5c16493SMichael Tuexen 		}
3013b5c16493SMichael Tuexen 		/* In case the fragments were not in order we must reset */
30140fa753b3SRandall Stewart 	}			/* end for (j = fragStart */
30150fa753b3SRandall Stewart 	*p_tp1 = tp1;
30160fa753b3SRandall Stewart 	return (wake_him);	/* Return value only used for nr-sack */
30170fa753b3SRandall Stewart }
30180fa753b3SRandall Stewart 
30190fa753b3SRandall Stewart 
3020cd554309SMichael Tuexen static int
3021458303daSRandall Stewart sctp_handle_segments(struct mbuf *m, int *offset, struct sctp_tcb *stcb, struct sctp_association *asoc,
3022cd554309SMichael Tuexen     uint32_t last_tsn, uint32_t * biggest_tsn_acked,
3023139bc87fSRandall Stewart     uint32_t * biggest_newly_acked_tsn, uint32_t * this_sack_lowest_newack,
30247215cc1bSMichael Tuexen     int num_seg, int num_nr_seg, int *rto_ok)
3025f8829a4aSRandall Stewart {
3026458303daSRandall Stewart 	struct sctp_gap_ack_block *frag, block;
3027f8829a4aSRandall Stewart 	struct sctp_tmit_chunk *tp1;
30280fa753b3SRandall Stewart 	int i;
3029f8829a4aSRandall Stewart 	int num_frs = 0;
3030cd554309SMichael Tuexen 	int chunk_freed;
3031cd554309SMichael Tuexen 	int non_revocable;
3032d9c5cfeaSMichael Tuexen 	uint16_t frag_strt, frag_end, prev_frag_end;
3033f8829a4aSRandall Stewart 
3034d9c5cfeaSMichael Tuexen 	tp1 = TAILQ_FIRST(&asoc->sent_queue);
3035d9c5cfeaSMichael Tuexen 	prev_frag_end = 0;
3036cd554309SMichael Tuexen 	chunk_freed = 0;
3037f8829a4aSRandall Stewart 
3038cd554309SMichael Tuexen 	for (i = 0; i < (num_seg + num_nr_seg); i++) {
3039d9c5cfeaSMichael Tuexen 		if (i == num_seg) {
3040d9c5cfeaSMichael Tuexen 			prev_frag_end = 0;
3041d9c5cfeaSMichael Tuexen 			tp1 = TAILQ_FIRST(&asoc->sent_queue);
3042d9c5cfeaSMichael Tuexen 		}
3043458303daSRandall Stewart 		frag = (struct sctp_gap_ack_block *)sctp_m_getptr(m, *offset,
3044458303daSRandall Stewart 		    sizeof(struct sctp_gap_ack_block), (uint8_t *) & block);
3045458303daSRandall Stewart 		*offset += sizeof(block);
3046458303daSRandall Stewart 		if (frag == NULL) {
3047cd554309SMichael Tuexen 			return (chunk_freed);
3048458303daSRandall Stewart 		}
3049f8829a4aSRandall Stewart 		frag_strt = ntohs(frag->start);
3050f8829a4aSRandall Stewart 		frag_end = ntohs(frag->end);
3051d9c5cfeaSMichael Tuexen 
3052f8829a4aSRandall Stewart 		if (frag_strt > frag_end) {
3053d9c5cfeaSMichael Tuexen 			/* This gap report is malformed, skip it. */
3054f8829a4aSRandall Stewart 			continue;
3055f8829a4aSRandall Stewart 		}
3056d9c5cfeaSMichael Tuexen 		if (frag_strt <= prev_frag_end) {
3057d9c5cfeaSMichael Tuexen 			/* This gap report is not in order, so restart. */
3058f8829a4aSRandall Stewart 			tp1 = TAILQ_FIRST(&asoc->sent_queue);
3059f8829a4aSRandall Stewart 		}
306020b07a4dSMichael Tuexen 		if (SCTP_TSN_GT((last_tsn + frag_end), *biggest_tsn_acked)) {
3061d9c5cfeaSMichael Tuexen 			*biggest_tsn_acked = last_tsn + frag_end;
3062f8829a4aSRandall Stewart 		}
3063cd554309SMichael Tuexen 		if (i < num_seg) {
3064cd554309SMichael Tuexen 			non_revocable = 0;
3065cd554309SMichael Tuexen 		} else {
3066cd554309SMichael Tuexen 			non_revocable = 1;
3067cd554309SMichael Tuexen 		}
3068cd554309SMichael Tuexen 		if (sctp_process_segment_range(stcb, &tp1, last_tsn, frag_strt, frag_end,
3069cd554309SMichael Tuexen 		    non_revocable, &num_frs, biggest_newly_acked_tsn,
30707215cc1bSMichael Tuexen 		    this_sack_lowest_newack, rto_ok)) {
3071cd554309SMichael Tuexen 			chunk_freed = 1;
3072458303daSRandall Stewart 		}
3073d9c5cfeaSMichael Tuexen 		prev_frag_end = frag_end;
3074f8829a4aSRandall Stewart 	}
3075b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
307680fefe0aSRandall Stewart 		if (num_frs)
307780fefe0aSRandall Stewart 			sctp_log_fr(*biggest_tsn_acked,
307880fefe0aSRandall Stewart 			    *biggest_newly_acked_tsn,
307980fefe0aSRandall Stewart 			    last_tsn, SCTP_FR_LOG_BIGGEST_TSNS);
308080fefe0aSRandall Stewart 	}
3081cd554309SMichael Tuexen 	return (chunk_freed);
3082f8829a4aSRandall Stewart }
3083f8829a4aSRandall Stewart 
3084f8829a4aSRandall Stewart static void
3085c105859eSRandall Stewart sctp_check_for_revoked(struct sctp_tcb *stcb,
3086c105859eSRandall Stewart     struct sctp_association *asoc, uint32_t cumack,
308763eda93dSMichael Tuexen     uint32_t biggest_tsn_acked)
3088f8829a4aSRandall Stewart {
3089f8829a4aSRandall Stewart 	struct sctp_tmit_chunk *tp1;
3090f8829a4aSRandall Stewart 
30914a9ef3f8SMichael Tuexen 	TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
309220b07a4dSMichael Tuexen 		if (SCTP_TSN_GT(tp1->rec.data.TSN_seq, cumack)) {
3093f8829a4aSRandall Stewart 			/*
3094f8829a4aSRandall Stewart 			 * ok this guy is either ACK or MARKED. If it is
3095f8829a4aSRandall Stewart 			 * ACKED it has been previously acked but not this
3096f8829a4aSRandall Stewart 			 * time i.e. revoked.  If it is MARKED it was ACK'ed
3097f8829a4aSRandall Stewart 			 * again.
3098f8829a4aSRandall Stewart 			 */
309920b07a4dSMichael Tuexen 			if (SCTP_TSN_GT(tp1->rec.data.TSN_seq, biggest_tsn_acked)) {
3100d06c82f1SRandall Stewart 				break;
310120b07a4dSMichael Tuexen 			}
3102f8829a4aSRandall Stewart 			if (tp1->sent == SCTP_DATAGRAM_ACKED) {
3103f8829a4aSRandall Stewart 				/* it has been revoked */
3104f8829a4aSRandall Stewart 				tp1->sent = SCTP_DATAGRAM_SENT;
3105f8829a4aSRandall Stewart 				tp1->rec.data.chunk_was_revoked = 1;
3106a5d547adSRandall Stewart 				/*
310742551e99SRandall Stewart 				 * We must add this stuff back in to assure
310842551e99SRandall Stewart 				 * timers and such get started.
3109a5d547adSRandall Stewart 				 */
3110b3f1ea41SRandall Stewart 				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) {
3111c105859eSRandall Stewart 					sctp_misc_ints(SCTP_FLIGHT_LOG_UP_REVOKE,
3112c105859eSRandall Stewart 					    tp1->whoTo->flight_size,
3113c105859eSRandall Stewart 					    tp1->book_size,
31149a8e3088SMichael Tuexen 					    (uint32_t) (uintptr_t) tp1->whoTo,
3115c105859eSRandall Stewart 					    tp1->rec.data.TSN_seq);
311680fefe0aSRandall Stewart 				}
3117c105859eSRandall Stewart 				sctp_flight_size_increase(tp1);
3118c105859eSRandall Stewart 				sctp_total_flight_increase(stcb, tp1);
311942551e99SRandall Stewart 				/*
312042551e99SRandall Stewart 				 * We inflate the cwnd to compensate for our
312142551e99SRandall Stewart 				 * artificial inflation of the flight_size.
312242551e99SRandall Stewart 				 */
312342551e99SRandall Stewart 				tp1->whoTo->cwnd += tp1->book_size;
3124b3f1ea41SRandall Stewart 				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) {
3125f8829a4aSRandall Stewart 					sctp_log_sack(asoc->last_acked_seq,
3126f8829a4aSRandall Stewart 					    cumack,
3127f8829a4aSRandall Stewart 					    tp1->rec.data.TSN_seq,
3128f8829a4aSRandall Stewart 					    0,
3129f8829a4aSRandall Stewart 					    0,
3130f8829a4aSRandall Stewart 					    SCTP_LOG_TSN_REVOKED);
313180fefe0aSRandall Stewart 				}
3132f8829a4aSRandall Stewart 			} else if (tp1->sent == SCTP_DATAGRAM_MARKED) {
3133f8829a4aSRandall Stewart 				/* it has been re-acked in this SACK */
3134f8829a4aSRandall Stewart 				tp1->sent = SCTP_DATAGRAM_ACKED;
3135f8829a4aSRandall Stewart 			}
3136f8829a4aSRandall Stewart 		}
3137f8829a4aSRandall Stewart 		if (tp1->sent == SCTP_DATAGRAM_UNSENT)
3138f8829a4aSRandall Stewart 			break;
3139f8829a4aSRandall Stewart 	}
3140f8829a4aSRandall Stewart }
3141f8829a4aSRandall Stewart 
3142830d754dSRandall Stewart 
3143f8829a4aSRandall Stewart static void
3144f8829a4aSRandall Stewart sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc,
314563eda93dSMichael Tuexen     uint32_t biggest_tsn_acked, uint32_t biggest_tsn_newly_acked, uint32_t this_sack_lowest_newack, int accum_moved)
3146f8829a4aSRandall Stewart {
3147f8829a4aSRandall Stewart 	struct sctp_tmit_chunk *tp1;
3148f8829a4aSRandall Stewart 	int strike_flag = 0;
3149f8829a4aSRandall Stewart 	struct timeval now;
3150f8829a4aSRandall Stewart 	int tot_retrans = 0;
3151f8829a4aSRandall Stewart 	uint32_t sending_seq;
3152f8829a4aSRandall Stewart 	struct sctp_nets *net;
3153f8829a4aSRandall Stewart 	int num_dests_sacked = 0;
3154f8829a4aSRandall Stewart 
3155f8829a4aSRandall Stewart 	/*
3156f8829a4aSRandall Stewart 	 * select the sending_seq, this is either the next thing ready to be
3157f8829a4aSRandall Stewart 	 * sent but not transmitted, OR, the next seq we assign.
3158f8829a4aSRandall Stewart 	 */
3159f8829a4aSRandall Stewart 	tp1 = TAILQ_FIRST(&stcb->asoc.send_queue);
3160f8829a4aSRandall Stewart 	if (tp1 == NULL) {
3161f8829a4aSRandall Stewart 		sending_seq = asoc->sending_seq;
3162f8829a4aSRandall Stewart 	} else {
3163f8829a4aSRandall Stewart 		sending_seq = tp1->rec.data.TSN_seq;
3164f8829a4aSRandall Stewart 	}
3165f8829a4aSRandall Stewart 
3166f8829a4aSRandall Stewart 	/* CMT DAC algo: finding out if SACK is a mixed SACK */
31677c99d56fSMichael Tuexen 	if ((asoc->sctp_cmt_on_off > 0) &&
316820083c2eSMichael Tuexen 	    SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) {
3169f8829a4aSRandall Stewart 		TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
3170f8829a4aSRandall Stewart 			if (net->saw_newack)
3171f8829a4aSRandall Stewart 				num_dests_sacked++;
3172f8829a4aSRandall Stewart 		}
3173f8829a4aSRandall Stewart 	}
3174dd973b0eSMichael Tuexen 	if (stcb->asoc.prsctp_supported) {
31756e55db54SRandall Stewart 		(void)SCTP_GETTIME_TIMEVAL(&now);
3176f8829a4aSRandall Stewart 	}
31774a9ef3f8SMichael Tuexen 	TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
3178f8829a4aSRandall Stewart 		strike_flag = 0;
3179f8829a4aSRandall Stewart 		if (tp1->no_fr_allowed) {
3180f8829a4aSRandall Stewart 			/* this one had a timeout or something */
3181f8829a4aSRandall Stewart 			continue;
3182f8829a4aSRandall Stewart 		}
3183b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
3184f8829a4aSRandall Stewart 			if (tp1->sent < SCTP_DATAGRAM_RESEND)
3185f8829a4aSRandall Stewart 				sctp_log_fr(biggest_tsn_newly_acked,
3186f8829a4aSRandall Stewart 				    tp1->rec.data.TSN_seq,
3187f8829a4aSRandall Stewart 				    tp1->sent,
3188f8829a4aSRandall Stewart 				    SCTP_FR_LOG_CHECK_STRIKE);
318980fefe0aSRandall Stewart 		}
319020b07a4dSMichael Tuexen 		if (SCTP_TSN_GT(tp1->rec.data.TSN_seq, biggest_tsn_acked) ||
3191f8829a4aSRandall Stewart 		    tp1->sent == SCTP_DATAGRAM_UNSENT) {
3192f8829a4aSRandall Stewart 			/* done */
3193f8829a4aSRandall Stewart 			break;
3194f8829a4aSRandall Stewart 		}
3195dd973b0eSMichael Tuexen 		if (stcb->asoc.prsctp_supported) {
3196f8829a4aSRandall Stewart 			if ((PR_SCTP_TTL_ENABLED(tp1->flags)) && tp1->sent < SCTP_DATAGRAM_ACKED) {
3197f8829a4aSRandall Stewart 				/* Is it expired? */
319899ddc825SMichael Tuexen 				if (timevalcmp(&now, &tp1->rec.data.timetodrop, >)) {
3199f8829a4aSRandall Stewart 					/* Yes so drop it */
3200f8829a4aSRandall Stewart 					if (tp1->data != NULL) {
32011edc9dbaSMichael Tuexen 						(void)sctp_release_pr_sctp_chunk(stcb, tp1, 1,
32020c0982b8SRandall Stewart 						    SCTP_SO_NOT_LOCKED);
3203f8829a4aSRandall Stewart 					}
3204f8829a4aSRandall Stewart 					continue;
3205f8829a4aSRandall Stewart 				}
3206f8829a4aSRandall Stewart 			}
3207f8829a4aSRandall Stewart 		}
320820b07a4dSMichael Tuexen 		if (SCTP_TSN_GT(tp1->rec.data.TSN_seq, asoc->this_sack_highest_gap)) {
3209f8829a4aSRandall Stewart 			/* we are beyond the tsn in the sack  */
3210f8829a4aSRandall Stewart 			break;
3211f8829a4aSRandall Stewart 		}
3212f8829a4aSRandall Stewart 		if (tp1->sent >= SCTP_DATAGRAM_RESEND) {
3213f8829a4aSRandall Stewart 			/* either a RESEND, ACKED, or MARKED */
3214f8829a4aSRandall Stewart 			/* skip */
321544fbe462SRandall Stewart 			if (tp1->sent == SCTP_FORWARD_TSN_SKIP) {
321644fbe462SRandall Stewart 				/* Continue strikin FWD-TSN chunks */
321744fbe462SRandall Stewart 				tp1->rec.data.fwd_tsn_cnt++;
321844fbe462SRandall Stewart 			}
3219f8829a4aSRandall Stewart 			continue;
3220f8829a4aSRandall Stewart 		}
3221f8829a4aSRandall Stewart 		/*
3222f8829a4aSRandall Stewart 		 * CMT : SFR algo (covers part of DAC and HTNA as well)
3223f8829a4aSRandall Stewart 		 */
3224ad81507eSRandall Stewart 		if (tp1->whoTo && tp1->whoTo->saw_newack == 0) {
3225f8829a4aSRandall Stewart 			/*
3226f8829a4aSRandall Stewart 			 * No new acks were receieved for data sent to this
3227f8829a4aSRandall Stewart 			 * dest. Therefore, according to the SFR algo for
3228f8829a4aSRandall Stewart 			 * CMT, no data sent to this dest can be marked for
3229c105859eSRandall Stewart 			 * FR using this SACK.
3230f8829a4aSRandall Stewart 			 */
3231f8829a4aSRandall Stewart 			continue;
323220b07a4dSMichael Tuexen 		} else if (tp1->whoTo && SCTP_TSN_GT(tp1->rec.data.TSN_seq,
323320b07a4dSMichael Tuexen 		    tp1->whoTo->this_sack_highest_newack)) {
3234f8829a4aSRandall Stewart 			/*
3235f8829a4aSRandall Stewart 			 * CMT: New acks were receieved for data sent to
3236f8829a4aSRandall Stewart 			 * this dest. But no new acks were seen for data
3237f8829a4aSRandall Stewart 			 * sent after tp1. Therefore, according to the SFR
3238f8829a4aSRandall Stewart 			 * algo for CMT, tp1 cannot be marked for FR using
3239f8829a4aSRandall Stewart 			 * this SACK. This step covers part of the DAC algo
3240f8829a4aSRandall Stewart 			 * and the HTNA algo as well.
3241f8829a4aSRandall Stewart 			 */
3242f8829a4aSRandall Stewart 			continue;
3243f8829a4aSRandall Stewart 		}
3244f8829a4aSRandall Stewart 		/*
3245f8829a4aSRandall Stewart 		 * Here we check to see if we were have already done a FR
3246f8829a4aSRandall Stewart 		 * and if so we see if the biggest TSN we saw in the sack is
3247f8829a4aSRandall Stewart 		 * smaller than the recovery point. If so we don't strike
3248f8829a4aSRandall Stewart 		 * the tsn... otherwise we CAN strike the TSN.
3249f8829a4aSRandall Stewart 		 */
3250f8829a4aSRandall Stewart 		/*
325142551e99SRandall Stewart 		 * @@@ JRI: Check for CMT if (accum_moved &&
325242551e99SRandall Stewart 		 * asoc->fast_retran_loss_recovery && (sctp_cmt_on_off ==
325342551e99SRandall Stewart 		 * 0)) {
3254f8829a4aSRandall Stewart 		 */
325542551e99SRandall Stewart 		if (accum_moved && asoc->fast_retran_loss_recovery) {
3256f8829a4aSRandall Stewart 			/*
3257f8829a4aSRandall Stewart 			 * Strike the TSN if in fast-recovery and cum-ack
3258f8829a4aSRandall Stewart 			 * moved.
3259f8829a4aSRandall Stewart 			 */
3260b3f1ea41SRandall Stewart 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
3261f8829a4aSRandall Stewart 				sctp_log_fr(biggest_tsn_newly_acked,
3262f8829a4aSRandall Stewart 				    tp1->rec.data.TSN_seq,
3263f8829a4aSRandall Stewart 				    tp1->sent,
3264f8829a4aSRandall Stewart 				    SCTP_FR_LOG_STRIKE_CHUNK);
326580fefe0aSRandall Stewart 			}
32665e54f665SRandall Stewart 			if (tp1->sent < SCTP_DATAGRAM_RESEND) {
3267f8829a4aSRandall Stewart 				tp1->sent++;
32685e54f665SRandall Stewart 			}
32697c99d56fSMichael Tuexen 			if ((asoc->sctp_cmt_on_off > 0) &&
327020083c2eSMichael Tuexen 			    SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) {
3271f8829a4aSRandall Stewart 				/*
3272f8829a4aSRandall Stewart 				 * CMT DAC algorithm: If SACK flag is set to
3273f8829a4aSRandall Stewart 				 * 0, then lowest_newack test will not pass
3274f8829a4aSRandall Stewart 				 * because it would have been set to the
3275f8829a4aSRandall Stewart 				 * cumack earlier. If not already to be
3276f8829a4aSRandall Stewart 				 * rtx'd, If not a mixed sack and if tp1 is
3277f8829a4aSRandall Stewart 				 * not between two sacked TSNs, then mark by
3278c105859eSRandall Stewart 				 * one more. NOTE that we are marking by one
3279c105859eSRandall Stewart 				 * additional time since the SACK DAC flag
3280c105859eSRandall Stewart 				 * indicates that two packets have been
3281c105859eSRandall Stewart 				 * received after this missing TSN.
32825e54f665SRandall Stewart 				 */
32835e54f665SRandall Stewart 				if ((tp1->sent < SCTP_DATAGRAM_RESEND) && (num_dests_sacked == 1) &&
328420b07a4dSMichael Tuexen 				    SCTP_TSN_GT(this_sack_lowest_newack, tp1->rec.data.TSN_seq)) {
3285b3f1ea41SRandall Stewart 					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
3286f8829a4aSRandall Stewart 						sctp_log_fr(16 + num_dests_sacked,
3287f8829a4aSRandall Stewart 						    tp1->rec.data.TSN_seq,
3288f8829a4aSRandall Stewart 						    tp1->sent,
3289f8829a4aSRandall Stewart 						    SCTP_FR_LOG_STRIKE_CHUNK);
329080fefe0aSRandall Stewart 					}
3291f8829a4aSRandall Stewart 					tp1->sent++;
3292f8829a4aSRandall Stewart 				}
3293f8829a4aSRandall Stewart 			}
329420083c2eSMichael Tuexen 		} else if ((tp1->rec.data.doing_fast_retransmit) &&
329520083c2eSMichael Tuexen 		    (asoc->sctp_cmt_on_off == 0)) {
3296f8829a4aSRandall Stewart 			/*
3297f8829a4aSRandall Stewart 			 * For those that have done a FR we must take
3298f8829a4aSRandall Stewart 			 * special consideration if we strike. I.e the
3299f8829a4aSRandall Stewart 			 * biggest_newly_acked must be higher than the
3300f8829a4aSRandall Stewart 			 * sending_seq at the time we did the FR.
3301f8829a4aSRandall Stewart 			 */
33025e54f665SRandall Stewart 			if (
3303f8829a4aSRandall Stewart #ifdef SCTP_FR_TO_ALTERNATE
3304f8829a4aSRandall Stewart 			/*
3305f8829a4aSRandall Stewart 			 * If FR's go to new networks, then we must only do
3306f8829a4aSRandall Stewart 			 * this for singly homed asoc's. However if the FR's
3307f8829a4aSRandall Stewart 			 * go to the same network (Armando's work) then its
3308f8829a4aSRandall Stewart 			 * ok to FR multiple times.
3309f8829a4aSRandall Stewart 			 */
33105e54f665SRandall Stewart 			    (asoc->numnets < 2)
3311f8829a4aSRandall Stewart #else
33125e54f665SRandall Stewart 			    (1)
3313f8829a4aSRandall Stewart #endif
33145e54f665SRandall Stewart 			    ) {
33155e54f665SRandall Stewart 
331620b07a4dSMichael Tuexen 				if (SCTP_TSN_GE(biggest_tsn_newly_acked,
3317f8829a4aSRandall Stewart 				    tp1->rec.data.fast_retran_tsn)) {
3318f8829a4aSRandall Stewart 					/*
3319f8829a4aSRandall Stewart 					 * Strike the TSN, since this ack is
3320f8829a4aSRandall Stewart 					 * beyond where things were when we
3321f8829a4aSRandall Stewart 					 * did a FR.
3322f8829a4aSRandall Stewart 					 */
3323b3f1ea41SRandall Stewart 					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
3324f8829a4aSRandall Stewart 						sctp_log_fr(biggest_tsn_newly_acked,
3325f8829a4aSRandall Stewart 						    tp1->rec.data.TSN_seq,
3326f8829a4aSRandall Stewart 						    tp1->sent,
3327f8829a4aSRandall Stewart 						    SCTP_FR_LOG_STRIKE_CHUNK);
332880fefe0aSRandall Stewart 					}
33295e54f665SRandall Stewart 					if (tp1->sent < SCTP_DATAGRAM_RESEND) {
3330f8829a4aSRandall Stewart 						tp1->sent++;
33315e54f665SRandall Stewart 					}
3332f8829a4aSRandall Stewart 					strike_flag = 1;
33337c99d56fSMichael Tuexen 					if ((asoc->sctp_cmt_on_off > 0) &&
333420083c2eSMichael Tuexen 					    SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) {
3335f8829a4aSRandall Stewart 						/*
3336f8829a4aSRandall Stewart 						 * CMT DAC algorithm: If
3337f8829a4aSRandall Stewart 						 * SACK flag is set to 0,
3338f8829a4aSRandall Stewart 						 * then lowest_newack test
3339f8829a4aSRandall Stewart 						 * will not pass because it
3340f8829a4aSRandall Stewart 						 * would have been set to
3341f8829a4aSRandall Stewart 						 * the cumack earlier. If
3342f8829a4aSRandall Stewart 						 * not already to be rtx'd,
3343f8829a4aSRandall Stewart 						 * If not a mixed sack and
3344f8829a4aSRandall Stewart 						 * if tp1 is not between two
3345f8829a4aSRandall Stewart 						 * sacked TSNs, then mark by
3346c105859eSRandall Stewart 						 * one more. NOTE that we
3347c105859eSRandall Stewart 						 * are marking by one
3348c105859eSRandall Stewart 						 * additional time since the
3349c105859eSRandall Stewart 						 * SACK DAC flag indicates
3350c105859eSRandall Stewart 						 * that two packets have
3351c105859eSRandall Stewart 						 * been received after this
3352c105859eSRandall Stewart 						 * missing TSN.
3353f8829a4aSRandall Stewart 						 */
33545e54f665SRandall Stewart 						if ((tp1->sent < SCTP_DATAGRAM_RESEND) &&
33555e54f665SRandall Stewart 						    (num_dests_sacked == 1) &&
335620b07a4dSMichael Tuexen 						    SCTP_TSN_GT(this_sack_lowest_newack,
335720b07a4dSMichael Tuexen 						    tp1->rec.data.TSN_seq)) {
3358b3f1ea41SRandall Stewart 							if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
3359f8829a4aSRandall Stewart 								sctp_log_fr(32 + num_dests_sacked,
3360f8829a4aSRandall Stewart 								    tp1->rec.data.TSN_seq,
3361f8829a4aSRandall Stewart 								    tp1->sent,
3362f8829a4aSRandall Stewart 								    SCTP_FR_LOG_STRIKE_CHUNK);
336380fefe0aSRandall Stewart 							}
33645e54f665SRandall Stewart 							if (tp1->sent < SCTP_DATAGRAM_RESEND) {
3365f8829a4aSRandall Stewart 								tp1->sent++;
33665e54f665SRandall Stewart 							}
3367f8829a4aSRandall Stewart 						}
3368f8829a4aSRandall Stewart 					}
3369f8829a4aSRandall Stewart 				}
3370f8829a4aSRandall Stewart 			}
3371f8829a4aSRandall Stewart 			/*
337242551e99SRandall Stewart 			 * JRI: TODO: remove code for HTNA algo. CMT's SFR
337342551e99SRandall Stewart 			 * algo covers HTNA.
3374f8829a4aSRandall Stewart 			 */
337520b07a4dSMichael Tuexen 		} else if (SCTP_TSN_GT(tp1->rec.data.TSN_seq,
337620b07a4dSMichael Tuexen 		    biggest_tsn_newly_acked)) {
3377f8829a4aSRandall Stewart 			/*
3378f8829a4aSRandall Stewart 			 * We don't strike these: This is the  HTNA
3379f8829a4aSRandall Stewart 			 * algorithm i.e. we don't strike If our TSN is
3380f8829a4aSRandall Stewart 			 * larger than the Highest TSN Newly Acked.
3381f8829a4aSRandall Stewart 			 */
3382f8829a4aSRandall Stewart 			;
3383f8829a4aSRandall Stewart 		} else {
3384f8829a4aSRandall Stewart 			/* Strike the TSN */
3385b3f1ea41SRandall Stewart 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
3386f8829a4aSRandall Stewart 				sctp_log_fr(biggest_tsn_newly_acked,
3387f8829a4aSRandall Stewart 				    tp1->rec.data.TSN_seq,
3388f8829a4aSRandall Stewart 				    tp1->sent,
3389f8829a4aSRandall Stewart 				    SCTP_FR_LOG_STRIKE_CHUNK);
339080fefe0aSRandall Stewart 			}
33915e54f665SRandall Stewart 			if (tp1->sent < SCTP_DATAGRAM_RESEND) {
3392f8829a4aSRandall Stewart 				tp1->sent++;
33935e54f665SRandall Stewart 			}
33947c99d56fSMichael Tuexen 			if ((asoc->sctp_cmt_on_off > 0) &&
339520083c2eSMichael Tuexen 			    SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) {
3396f8829a4aSRandall Stewart 				/*
3397f8829a4aSRandall Stewart 				 * CMT DAC algorithm: If SACK flag is set to
3398f8829a4aSRandall Stewart 				 * 0, then lowest_newack test will not pass
3399f8829a4aSRandall Stewart 				 * because it would have been set to the
3400f8829a4aSRandall Stewart 				 * cumack earlier. If not already to be
3401f8829a4aSRandall Stewart 				 * rtx'd, If not a mixed sack and if tp1 is
3402f8829a4aSRandall Stewart 				 * not between two sacked TSNs, then mark by
3403c105859eSRandall Stewart 				 * one more. NOTE that we are marking by one
3404c105859eSRandall Stewart 				 * additional time since the SACK DAC flag
3405c105859eSRandall Stewart 				 * indicates that two packets have been
3406c105859eSRandall Stewart 				 * received after this missing TSN.
3407f8829a4aSRandall Stewart 				 */
34085e54f665SRandall Stewart 				if ((tp1->sent < SCTP_DATAGRAM_RESEND) && (num_dests_sacked == 1) &&
340920b07a4dSMichael Tuexen 				    SCTP_TSN_GT(this_sack_lowest_newack, tp1->rec.data.TSN_seq)) {
3410b3f1ea41SRandall Stewart 					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
3411f8829a4aSRandall Stewart 						sctp_log_fr(48 + num_dests_sacked,
3412f8829a4aSRandall Stewart 						    tp1->rec.data.TSN_seq,
3413f8829a4aSRandall Stewart 						    tp1->sent,
3414f8829a4aSRandall Stewart 						    SCTP_FR_LOG_STRIKE_CHUNK);
341580fefe0aSRandall Stewart 					}
3416f8829a4aSRandall Stewart 					tp1->sent++;
3417f8829a4aSRandall Stewart 				}
3418f8829a4aSRandall Stewart 			}
3419f8829a4aSRandall Stewart 		}
3420f8829a4aSRandall Stewart 		if (tp1->sent == SCTP_DATAGRAM_RESEND) {
3421f8829a4aSRandall Stewart 			struct sctp_nets *alt;
3422f8829a4aSRandall Stewart 
3423544e35bdSRandall Stewart 			/* fix counts and things */
3424544e35bdSRandall Stewart 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) {
3425544e35bdSRandall Stewart 				sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_RSND,
3426544e35bdSRandall Stewart 				    (tp1->whoTo ? (tp1->whoTo->flight_size) : 0),
3427544e35bdSRandall Stewart 				    tp1->book_size,
34289a8e3088SMichael Tuexen 				    (uint32_t) (uintptr_t) tp1->whoTo,
3429544e35bdSRandall Stewart 				    tp1->rec.data.TSN_seq);
3430544e35bdSRandall Stewart 			}
3431544e35bdSRandall Stewart 			if (tp1->whoTo) {
3432544e35bdSRandall Stewart 				tp1->whoTo->net_ack++;
3433544e35bdSRandall Stewart 				sctp_flight_size_decrease(tp1);
3434299108c5SRandall Stewart 				if (stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) {
3435299108c5SRandall Stewart 					(*stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) (tp1->whoTo,
3436299108c5SRandall Stewart 					    tp1);
3437299108c5SRandall Stewart 				}
3438544e35bdSRandall Stewart 			}
3439544e35bdSRandall Stewart 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_RWND_ENABLE) {
3440544e35bdSRandall Stewart 				sctp_log_rwnd(SCTP_INCREASE_PEER_RWND,
3441544e35bdSRandall Stewart 				    asoc->peers_rwnd, tp1->send_size, SCTP_BASE_SYSCTL(sctp_peer_chunk_oh));
3442544e35bdSRandall Stewart 			}
3443544e35bdSRandall Stewart 			/* add back to the rwnd */
3444544e35bdSRandall Stewart 			asoc->peers_rwnd += (tp1->send_size + SCTP_BASE_SYSCTL(sctp_peer_chunk_oh));
3445544e35bdSRandall Stewart 
3446544e35bdSRandall Stewart 			/* remove from the total flight */
3447544e35bdSRandall Stewart 			sctp_total_flight_decrease(stcb, tp1);
3448544e35bdSRandall Stewart 
3449dd973b0eSMichael Tuexen 			if ((stcb->asoc.prsctp_supported) &&
3450475d0674SMichael Tuexen 			    (PR_SCTP_RTX_ENABLED(tp1->flags))) {
3451*5b495f17SMichael Tuexen 				/* Has it been retransmitted tv_sec times? -
3452*5b495f17SMichael Tuexen 				 * we store the retran count there. */
3453475d0674SMichael Tuexen 				if (tp1->snd_count > tp1->rec.data.timetodrop.tv_sec) {
3454475d0674SMichael Tuexen 					/* Yes, so drop it */
3455475d0674SMichael Tuexen 					if (tp1->data != NULL) {
34561edc9dbaSMichael Tuexen 						(void)sctp_release_pr_sctp_chunk(stcb, tp1, 1,
3457475d0674SMichael Tuexen 						    SCTP_SO_NOT_LOCKED);
3458475d0674SMichael Tuexen 					}
3459475d0674SMichael Tuexen 					/* Make sure to flag we had a FR */
3460475d0674SMichael Tuexen 					tp1->whoTo->net_ack++;
3461475d0674SMichael Tuexen 					continue;
3462475d0674SMichael Tuexen 				}
3463475d0674SMichael Tuexen 			}
3464*5b495f17SMichael Tuexen 			/* SCTP_PRINTF("OK, we are now ready to FR this
3465*5b495f17SMichael Tuexen 			 * guy\n"); */
3466b3f1ea41SRandall Stewart 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
3467f8829a4aSRandall Stewart 				sctp_log_fr(tp1->rec.data.TSN_seq, tp1->snd_count,
3468f8829a4aSRandall Stewart 				    0, SCTP_FR_MARKED);
346980fefe0aSRandall Stewart 			}
3470f8829a4aSRandall Stewart 			if (strike_flag) {
3471f8829a4aSRandall Stewart 				/* This is a subsequent FR */
3472f8829a4aSRandall Stewart 				SCTP_STAT_INCR(sctps_sendmultfastretrans);
3473f8829a4aSRandall Stewart 			}
34745e54f665SRandall Stewart 			sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
34757c99d56fSMichael Tuexen 			if (asoc->sctp_cmt_on_off > 0) {
3476f8829a4aSRandall Stewart 				/*
3477f8829a4aSRandall Stewart 				 * CMT: Using RTX_SSTHRESH policy for CMT.
3478f8829a4aSRandall Stewart 				 * If CMT is being used, then pick dest with
3479f8829a4aSRandall Stewart 				 * largest ssthresh for any retransmission.
3480f8829a4aSRandall Stewart 				 */
3481f8829a4aSRandall Stewart 				tp1->no_fr_allowed = 1;
3482f8829a4aSRandall Stewart 				alt = tp1->whoTo;
34833c503c28SRandall Stewart 				/* sa_ignore NO_NULL_CHK */
348420083c2eSMichael Tuexen 				if (asoc->sctp_cmt_pf > 0) {
3485*5b495f17SMichael Tuexen 					/* JRS 5/18/07 - If CMT PF is on,
3486b54d3a6cSRandall Stewart 					 * use the PF version of
3487*5b495f17SMichael Tuexen 					 * find_alt_net() */
3488b54d3a6cSRandall Stewart 					alt = sctp_find_alternate_net(stcb, alt, 2);
3489b54d3a6cSRandall Stewart 				} else {
3490*5b495f17SMichael Tuexen 					/* JRS 5/18/07 - If only CMT is on,
3491b54d3a6cSRandall Stewart 					 * use the CMT version of
3492*5b495f17SMichael Tuexen 					 * find_alt_net() */
349352be287eSRandall Stewart 					/* sa_ignore NO_NULL_CHK */
3494f8829a4aSRandall Stewart 					alt = sctp_find_alternate_net(stcb, alt, 1);
3495b54d3a6cSRandall Stewart 				}
3496ad81507eSRandall Stewart 				if (alt == NULL) {
3497ad81507eSRandall Stewart 					alt = tp1->whoTo;
3498ad81507eSRandall Stewart 				}
3499f8829a4aSRandall Stewart 				/*
3500f8829a4aSRandall Stewart 				 * CUCv2: If a different dest is picked for
3501f8829a4aSRandall Stewart 				 * the retransmission, then new
3502f8829a4aSRandall Stewart 				 * (rtx-)pseudo_cumack needs to be tracked
3503f8829a4aSRandall Stewart 				 * for orig dest. Let CUCv2 track new (rtx-)
3504f8829a4aSRandall Stewart 				 * pseudo-cumack always.
3505f8829a4aSRandall Stewart 				 */
3506ad81507eSRandall Stewart 				if (tp1->whoTo) {
3507f8829a4aSRandall Stewart 					tp1->whoTo->find_pseudo_cumack = 1;
3508f8829a4aSRandall Stewart 					tp1->whoTo->find_rtx_pseudo_cumack = 1;
3509ad81507eSRandall Stewart 				}
3510f8829a4aSRandall Stewart 			} else {/* CMT is OFF */
3511f8829a4aSRandall Stewart 
3512f8829a4aSRandall Stewart #ifdef SCTP_FR_TO_ALTERNATE
3513f8829a4aSRandall Stewart 				/* Can we find an alternate? */
3514f8829a4aSRandall Stewart 				alt = sctp_find_alternate_net(stcb, tp1->whoTo, 0);
3515f8829a4aSRandall Stewart #else
3516f8829a4aSRandall Stewart 				/*
3517f8829a4aSRandall Stewart 				 * default behavior is to NOT retransmit
3518f8829a4aSRandall Stewart 				 * FR's to an alternate. Armando Caro's
3519f8829a4aSRandall Stewart 				 * paper details why.
3520f8829a4aSRandall Stewart 				 */
3521f8829a4aSRandall Stewart 				alt = tp1->whoTo;
3522f8829a4aSRandall Stewart #endif
3523f8829a4aSRandall Stewart 			}
3524f8829a4aSRandall Stewart 
3525f8829a4aSRandall Stewart 			tp1->rec.data.doing_fast_retransmit = 1;
3526f8829a4aSRandall Stewart 			tot_retrans++;
3527f8829a4aSRandall Stewart 			/* mark the sending seq for possible subsequent FR's */
3528f8829a4aSRandall Stewart 			/*
3529cd3fd531SMichael Tuexen 			 * SCTP_PRINTF("Marking TSN for FR new value %x\n",
3530f8829a4aSRandall Stewart 			 * (uint32_t)tpi->rec.data.TSN_seq);
3531f8829a4aSRandall Stewart 			 */
3532f8829a4aSRandall Stewart 			if (TAILQ_EMPTY(&asoc->send_queue)) {
3533f8829a4aSRandall Stewart 				/*
3534f8829a4aSRandall Stewart 				 * If the queue of send is empty then its
3535f8829a4aSRandall Stewart 				 * the next sequence number that will be
3536f8829a4aSRandall Stewart 				 * assigned so we subtract one from this to
3537f8829a4aSRandall Stewart 				 * get the one we last sent.
3538f8829a4aSRandall Stewart 				 */
3539f8829a4aSRandall Stewart 				tp1->rec.data.fast_retran_tsn = sending_seq;
3540f8829a4aSRandall Stewart 			} else {
3541f8829a4aSRandall Stewart 				/*
3542f8829a4aSRandall Stewart 				 * If there are chunks on the send queue
3543f8829a4aSRandall Stewart 				 * (unsent data that has made it from the
3544f8829a4aSRandall Stewart 				 * stream queues but not out the door, we
3545f8829a4aSRandall Stewart 				 * take the first one (which will have the
3546f8829a4aSRandall Stewart 				 * lowest TSN) and subtract one to get the
3547f8829a4aSRandall Stewart 				 * one we last sent.
3548f8829a4aSRandall Stewart 				 */
3549f8829a4aSRandall Stewart 				struct sctp_tmit_chunk *ttt;
3550f8829a4aSRandall Stewart 
3551f8829a4aSRandall Stewart 				ttt = TAILQ_FIRST(&asoc->send_queue);
3552f8829a4aSRandall Stewart 				tp1->rec.data.fast_retran_tsn =
3553f8829a4aSRandall Stewart 				    ttt->rec.data.TSN_seq;
3554f8829a4aSRandall Stewart 			}
3555f8829a4aSRandall Stewart 
3556f8829a4aSRandall Stewart 			if (tp1->do_rtt) {
3557f8829a4aSRandall Stewart 				/*
3558f8829a4aSRandall Stewart 				 * this guy had a RTO calculation pending on
3559f8829a4aSRandall Stewart 				 * it, cancel it
3560f8829a4aSRandall Stewart 				 */
356160990c0cSMichael Tuexen 				if ((tp1->whoTo != NULL) &&
356260990c0cSMichael Tuexen 				    (tp1->whoTo->rto_needed == 0)) {
3563f79aab18SRandall Stewart 					tp1->whoTo->rto_needed = 1;
3564f79aab18SRandall Stewart 				}
3565f8829a4aSRandall Stewart 				tp1->do_rtt = 0;
3566f8829a4aSRandall Stewart 			}
3567f8829a4aSRandall Stewart 			if (alt != tp1->whoTo) {
3568f8829a4aSRandall Stewart 				/* yes, there is an alternate. */
3569f8829a4aSRandall Stewart 				sctp_free_remote_addr(tp1->whoTo);
35703c503c28SRandall Stewart 				/* sa_ignore FREED_MEMORY */
3571f8829a4aSRandall Stewart 				tp1->whoTo = alt;
3572f8829a4aSRandall Stewart 				atomic_add_int(&alt->ref_count, 1);
3573f8829a4aSRandall Stewart 			}
3574f8829a4aSRandall Stewart 		}
35754a9ef3f8SMichael Tuexen 	}
3576f8829a4aSRandall Stewart }
3577f8829a4aSRandall Stewart 
3578f8829a4aSRandall Stewart struct sctp_tmit_chunk *
3579f8829a4aSRandall Stewart sctp_try_advance_peer_ack_point(struct sctp_tcb *stcb,
3580f8829a4aSRandall Stewart     struct sctp_association *asoc)
3581f8829a4aSRandall Stewart {
3582f8829a4aSRandall Stewart 	struct sctp_tmit_chunk *tp1, *tp2, *a_adv = NULL;
3583f8829a4aSRandall Stewart 	struct timeval now;
3584f8829a4aSRandall Stewart 	int now_filled = 0;
3585f8829a4aSRandall Stewart 
3586dd973b0eSMichael Tuexen 	if (asoc->prsctp_supported == 0) {
3587f8829a4aSRandall Stewart 		return (NULL);
3588f8829a4aSRandall Stewart 	}
35894a9ef3f8SMichael Tuexen 	TAILQ_FOREACH_SAFE(tp1, &asoc->sent_queue, sctp_next, tp2) {
3590f8829a4aSRandall Stewart 		if (tp1->sent != SCTP_FORWARD_TSN_SKIP &&
359198f2956cSMichael Tuexen 		    tp1->sent != SCTP_DATAGRAM_RESEND &&
3592325c8c46SMichael Tuexen 		    tp1->sent != SCTP_DATAGRAM_NR_ACKED) {
3593f8829a4aSRandall Stewart 			/* no chance to advance, out of here */
3594f8829a4aSRandall Stewart 			break;
3595f8829a4aSRandall Stewart 		}
35960c0982b8SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) {
35972a498584SMichael Tuexen 			if ((tp1->sent == SCTP_FORWARD_TSN_SKIP) ||
3598325c8c46SMichael Tuexen 			    (tp1->sent == SCTP_DATAGRAM_NR_ACKED)) {
35990c0982b8SRandall Stewart 				sctp_misc_ints(SCTP_FWD_TSN_CHECK,
36000c0982b8SRandall Stewart 				    asoc->advanced_peer_ack_point,
36010c0982b8SRandall Stewart 				    tp1->rec.data.TSN_seq, 0, 0);
36020c0982b8SRandall Stewart 			}
36030c0982b8SRandall Stewart 		}
3604f8829a4aSRandall Stewart 		if (!PR_SCTP_ENABLED(tp1->flags)) {
3605f8829a4aSRandall Stewart 			/*
3606f8829a4aSRandall Stewart 			 * We can't fwd-tsn past any that are reliable aka
3607f8829a4aSRandall Stewart 			 * retransmitted until the asoc fails.
3608f8829a4aSRandall Stewart 			 */
3609f8829a4aSRandall Stewart 			break;
3610f8829a4aSRandall Stewart 		}
3611f8829a4aSRandall Stewart 		if (!now_filled) {
36126e55db54SRandall Stewart 			(void)SCTP_GETTIME_TIMEVAL(&now);
3613f8829a4aSRandall Stewart 			now_filled = 1;
3614f8829a4aSRandall Stewart 		}
3615f8829a4aSRandall Stewart 		/*
3616f8829a4aSRandall Stewart 		 * now we got a chunk which is marked for another
3617f8829a4aSRandall Stewart 		 * retransmission to a PR-stream but has run out its chances
3618f8829a4aSRandall Stewart 		 * already maybe OR has been marked to skip now. Can we skip
3619f8829a4aSRandall Stewart 		 * it if its a resend?
3620f8829a4aSRandall Stewart 		 */
3621f8829a4aSRandall Stewart 		if (tp1->sent == SCTP_DATAGRAM_RESEND &&
3622f8829a4aSRandall Stewart 		    (PR_SCTP_TTL_ENABLED(tp1->flags))) {
3623f8829a4aSRandall Stewart 			/*
3624f8829a4aSRandall Stewart 			 * Now is this one marked for resend and its time is
3625f8829a4aSRandall Stewart 			 * now up?
3626f8829a4aSRandall Stewart 			 */
3627f8829a4aSRandall Stewart 			if (timevalcmp(&now, &tp1->rec.data.timetodrop, >)) {
3628f8829a4aSRandall Stewart 				/* Yes so drop it */
3629f8829a4aSRandall Stewart 				if (tp1->data) {
3630ad81507eSRandall Stewart 					(void)sctp_release_pr_sctp_chunk(stcb, tp1,
36311edc9dbaSMichael Tuexen 					    1, SCTP_SO_NOT_LOCKED);
3632f8829a4aSRandall Stewart 				}
3633f8829a4aSRandall Stewart 			} else {
3634f8829a4aSRandall Stewart 				/*
3635f8829a4aSRandall Stewart 				 * No, we are done when hit one for resend
3636f8829a4aSRandall Stewart 				 * whos time as not expired.
3637f8829a4aSRandall Stewart 				 */
3638f8829a4aSRandall Stewart 				break;
3639f8829a4aSRandall Stewart 			}
3640f8829a4aSRandall Stewart 		}
3641f8829a4aSRandall Stewart 		/*
3642f8829a4aSRandall Stewart 		 * Ok now if this chunk is marked to drop it we can clean up
3643f8829a4aSRandall Stewart 		 * the chunk, advance our peer ack point and we can check
3644f8829a4aSRandall Stewart 		 * the next chunk.
3645f8829a4aSRandall Stewart 		 */
364698f2956cSMichael Tuexen 		if ((tp1->sent == SCTP_FORWARD_TSN_SKIP) ||
3647325c8c46SMichael Tuexen 		    (tp1->sent == SCTP_DATAGRAM_NR_ACKED)) {
3648f8829a4aSRandall Stewart 			/* advance PeerAckPoint goes forward */
364920b07a4dSMichael Tuexen 			if (SCTP_TSN_GT(tp1->rec.data.TSN_seq, asoc->advanced_peer_ack_point)) {
3650f8829a4aSRandall Stewart 				asoc->advanced_peer_ack_point = tp1->rec.data.TSN_seq;
3651f8829a4aSRandall Stewart 				a_adv = tp1;
36520c0982b8SRandall Stewart 			} else if (tp1->rec.data.TSN_seq == asoc->advanced_peer_ack_point) {
36530c0982b8SRandall Stewart 				/* No update but we do save the chk */
36540c0982b8SRandall Stewart 				a_adv = tp1;
36550c0982b8SRandall Stewart 			}
3656f8829a4aSRandall Stewart 		} else {
3657f8829a4aSRandall Stewart 			/*
3658f8829a4aSRandall Stewart 			 * If it is still in RESEND we can advance no
3659f8829a4aSRandall Stewart 			 * further
3660f8829a4aSRandall Stewart 			 */
3661f8829a4aSRandall Stewart 			break;
3662f8829a4aSRandall Stewart 		}
3663f8829a4aSRandall Stewart 	}
3664f8829a4aSRandall Stewart 	return (a_adv);
3665f8829a4aSRandall Stewart }
3666f8829a4aSRandall Stewart 
36670c0982b8SRandall Stewart static int
3668c105859eSRandall Stewart sctp_fs_audit(struct sctp_association *asoc)
3669bff64a4dSRandall Stewart {
3670bff64a4dSRandall Stewart 	struct sctp_tmit_chunk *chk;
3671afd67482SMichael Tuexen 	int inflight = 0, resend = 0, inbetween = 0, acked = 0, above = 0;
3672548f47a8SMichael Tuexen 	int ret;
3673548f47a8SMichael Tuexen #ifndef INVARIANTS
3674548f47a8SMichael Tuexen 	int entry_flight, entry_cnt;
3675548f47a8SMichael Tuexen #endif
3676548f47a8SMichael Tuexen 
3677548f47a8SMichael Tuexen 	ret = 0;
3678548f47a8SMichael Tuexen #ifndef INVARIANTS
36790c0982b8SRandall Stewart 	entry_flight = asoc->total_flight;
36800c0982b8SRandall Stewart 	entry_cnt = asoc->total_flight_count;
3681548f47a8SMichael Tuexen #endif
36820c0982b8SRandall Stewart 	if (asoc->pr_sctp_cnt >= asoc->sent_queue_cnt)
36830c0982b8SRandall Stewart 		return (0);
3684bff64a4dSRandall Stewart 
3685bff64a4dSRandall Stewart 	TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) {
3686bff64a4dSRandall Stewart 		if (chk->sent < SCTP_DATAGRAM_RESEND) {
3687cd3fd531SMichael Tuexen 			SCTP_PRINTF("Chk TSN: %u size: %d inflight cnt: %d\n",
36880c0982b8SRandall Stewart 			    chk->rec.data.TSN_seq,
36890c0982b8SRandall Stewart 			    chk->send_size,
3690cd3fd531SMichael Tuexen 			    chk->snd_count);
3691bff64a4dSRandall Stewart 			inflight++;
3692bff64a4dSRandall Stewart 		} else if (chk->sent == SCTP_DATAGRAM_RESEND) {
3693bff64a4dSRandall Stewart 			resend++;
3694bff64a4dSRandall Stewart 		} else if (chk->sent < SCTP_DATAGRAM_ACKED) {
3695bff64a4dSRandall Stewart 			inbetween++;
3696bff64a4dSRandall Stewart 		} else if (chk->sent > SCTP_DATAGRAM_ACKED) {
3697bff64a4dSRandall Stewart 			above++;
3698bff64a4dSRandall Stewart 		} else {
3699bff64a4dSRandall Stewart 			acked++;
3700bff64a4dSRandall Stewart 		}
3701bff64a4dSRandall Stewart 	}
3702f1f73e57SRandall Stewart 
3703c105859eSRandall Stewart 	if ((inflight > 0) || (inbetween > 0)) {
3704f1f73e57SRandall Stewart #ifdef INVARIANTS
3705c105859eSRandall Stewart 		panic("Flight size-express incorrect? \n");
3706f1f73e57SRandall Stewart #else
3707cd3fd531SMichael Tuexen 		SCTP_PRINTF("asoc->total_flight: %d cnt: %d\n",
37080c0982b8SRandall Stewart 		    entry_flight, entry_cnt);
37090c0982b8SRandall Stewart 
37100c0982b8SRandall Stewart 		SCTP_PRINTF("Flight size-express incorrect F: %d I: %d R: %d Ab: %d ACK: %d\n",
37110c0982b8SRandall Stewart 		    inflight, inbetween, resend, above, acked);
37120c0982b8SRandall Stewart 		ret = 1;
3713f1f73e57SRandall Stewart #endif
3714bff64a4dSRandall Stewart 	}
37150c0982b8SRandall Stewart 	return (ret);
3716c105859eSRandall Stewart }
3717c105859eSRandall Stewart 
3718c105859eSRandall Stewart 
3719c105859eSRandall Stewart static void
3720c105859eSRandall Stewart sctp_window_probe_recovery(struct sctp_tcb *stcb,
3721c105859eSRandall Stewart     struct sctp_association *asoc,
3722c105859eSRandall Stewart     struct sctp_tmit_chunk *tp1)
3723c105859eSRandall Stewart {
3724dfb11ef8SRandall Stewart 	tp1->window_probe = 0;
37255171328bSRandall Stewart 	if ((tp1->sent >= SCTP_DATAGRAM_ACKED) || (tp1->data == NULL)) {
3726dfb11ef8SRandall Stewart 		/* TSN's skipped we do NOT move back. */
3727dfb11ef8SRandall Stewart 		sctp_misc_ints(SCTP_FLIGHT_LOG_DWN_WP_FWD,
37288427b3fdSMichael Tuexen 		    tp1->whoTo ? tp1->whoTo->flight_size : 0,
3729dfb11ef8SRandall Stewart 		    tp1->book_size,
37309a8e3088SMichael Tuexen 		    (uint32_t) (uintptr_t) tp1->whoTo,
3731dfb11ef8SRandall Stewart 		    tp1->rec.data.TSN_seq);
3732dfb11ef8SRandall Stewart 		return;
3733dfb11ef8SRandall Stewart 	}
37345171328bSRandall Stewart 	/* First setup this by shrinking flight */
3735299108c5SRandall Stewart 	if (stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) {
3736299108c5SRandall Stewart 		(*stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) (tp1->whoTo,
3737299108c5SRandall Stewart 		    tp1);
3738299108c5SRandall Stewart 	}
37395171328bSRandall Stewart 	sctp_flight_size_decrease(tp1);
37405171328bSRandall Stewart 	sctp_total_flight_decrease(stcb, tp1);
37415171328bSRandall Stewart 	/* Now mark for resend */
37425171328bSRandall Stewart 	tp1->sent = SCTP_DATAGRAM_RESEND;
3743791437b5SRandall Stewart 	sctp_ucount_incr(asoc->sent_queue_retran_cnt);
3744791437b5SRandall Stewart 
3745b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) {
3746c105859eSRandall Stewart 		sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_WP,
3747c105859eSRandall Stewart 		    tp1->whoTo->flight_size,
3748c105859eSRandall Stewart 		    tp1->book_size,
37499a8e3088SMichael Tuexen 		    (uint32_t) (uintptr_t) tp1->whoTo,
3750c105859eSRandall Stewart 		    tp1->rec.data.TSN_seq);
375180fefe0aSRandall Stewart 	}
3752c105859eSRandall Stewart }
3753c105859eSRandall Stewart 
3754f8829a4aSRandall Stewart void
3755f8829a4aSRandall Stewart sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
3756899288aeSRandall Stewart     uint32_t rwnd, int *abort_now, int ecne_seen)
3757f8829a4aSRandall Stewart {
3758f8829a4aSRandall Stewart 	struct sctp_nets *net;
3759f8829a4aSRandall Stewart 	struct sctp_association *asoc;
3760f8829a4aSRandall Stewart 	struct sctp_tmit_chunk *tp1, *tp2;
37615e54f665SRandall Stewart 	uint32_t old_rwnd;
37625e54f665SRandall Stewart 	int win_probe_recovery = 0;
3763c105859eSRandall Stewart 	int win_probe_recovered = 0;
3764d06c82f1SRandall Stewart 	int j, done_once = 0;
3765f79aab18SRandall Stewart 	int rto_ok = 1;
3766fd60718dSMichael Tuexen 	uint32_t send_s;
3767f8829a4aSRandall Stewart 
3768b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_SACK_ARRIVALS_ENABLE) {
3769d06c82f1SRandall Stewart 		sctp_misc_ints(SCTP_SACK_LOG_EXPRESS, cumack,
3770d06c82f1SRandall Stewart 		    rwnd, stcb->asoc.last_acked_seq, stcb->asoc.peers_rwnd);
377180fefe0aSRandall Stewart 	}
3772f8829a4aSRandall Stewart 	SCTP_TCB_LOCK_ASSERT(stcb);
377318e198d3SRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS
377418e198d3SRandall Stewart 	stcb->asoc.cumack_log[stcb->asoc.cumack_log_at] = cumack;
377518e198d3SRandall Stewart 	stcb->asoc.cumack_log_at++;
377618e198d3SRandall Stewart 	if (stcb->asoc.cumack_log_at > SCTP_TSN_LOG_SIZE) {
377718e198d3SRandall Stewart 		stcb->asoc.cumack_log_at = 0;
377818e198d3SRandall Stewart 	}
377918e198d3SRandall Stewart #endif
3780f8829a4aSRandall Stewart 	asoc = &stcb->asoc;
3781d06c82f1SRandall Stewart 	old_rwnd = asoc->peers_rwnd;
378220b07a4dSMichael Tuexen 	if (SCTP_TSN_GT(asoc->last_acked_seq, cumack)) {
37835e54f665SRandall Stewart 		/* old ack */
37845e54f665SRandall Stewart 		return;
3785d06c82f1SRandall Stewart 	} else if (asoc->last_acked_seq == cumack) {
3786d06c82f1SRandall Stewart 		/* Window update sack */
3787d06c82f1SRandall Stewart 		asoc->peers_rwnd = sctp_sbspace_sub(rwnd,
378844fbe462SRandall Stewart 		    (uint32_t) (asoc->total_flight + (asoc->total_flight_count * SCTP_BASE_SYSCTL(sctp_peer_chunk_oh))));
3789d06c82f1SRandall Stewart 		if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) {
3790d06c82f1SRandall Stewart 			/* SWS sender side engages */
3791d06c82f1SRandall Stewart 			asoc->peers_rwnd = 0;
3792d06c82f1SRandall Stewart 		}
3793d06c82f1SRandall Stewart 		if (asoc->peers_rwnd > old_rwnd) {
3794d06c82f1SRandall Stewart 			goto again;
3795d06c82f1SRandall Stewart 		}
3796d06c82f1SRandall Stewart 		return;
37975e54f665SRandall Stewart 	}
3798f8829a4aSRandall Stewart 	/* First setup for CC stuff */
3799f8829a4aSRandall Stewart 	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
3800a21779f0SRandall Stewart 		if (SCTP_TSN_GT(cumack, net->cwr_window_tsn)) {
3801a21779f0SRandall Stewart 			/* Drag along the window_tsn for cwr's */
3802a21779f0SRandall Stewart 			net->cwr_window_tsn = cumack;
3803a21779f0SRandall Stewart 		}
3804f8829a4aSRandall Stewart 		net->prev_cwnd = net->cwnd;
3805f8829a4aSRandall Stewart 		net->net_ack = 0;
3806f8829a4aSRandall Stewart 		net->net_ack2 = 0;
3807132dea7dSRandall Stewart 
3808132dea7dSRandall Stewart 		/*
3809132dea7dSRandall Stewart 		 * CMT: Reset CUC and Fast recovery algo variables before
3810132dea7dSRandall Stewart 		 * SACK processing
3811132dea7dSRandall Stewart 		 */
3812132dea7dSRandall Stewart 		net->new_pseudo_cumack = 0;
3813132dea7dSRandall Stewart 		net->will_exit_fast_recovery = 0;
3814299108c5SRandall Stewart 		if (stcb->asoc.cc_functions.sctp_cwnd_prepare_net_for_sack) {
3815299108c5SRandall Stewart 			(*stcb->asoc.cc_functions.sctp_cwnd_prepare_net_for_sack) (stcb, net);
3816299108c5SRandall Stewart 		}
3817f8829a4aSRandall Stewart 	}
3818c105859eSRandall Stewart 	if (!TAILQ_EMPTY(&asoc->sent_queue)) {
3819c105859eSRandall Stewart 		tp1 = TAILQ_LAST(&asoc->sent_queue,
3820c105859eSRandall Stewart 		    sctpchunk_listhead);
3821c105859eSRandall Stewart 		send_s = tp1->rec.data.TSN_seq + 1;
3822139bc87fSRandall Stewart 	} else {
3823c105859eSRandall Stewart 		send_s = asoc->sending_seq;
3824139bc87fSRandall Stewart 	}
382520b07a4dSMichael Tuexen 	if (SCTP_TSN_GE(cumack, send_s)) {
3826ff1ffd74SMichael Tuexen 		struct mbuf *op_err;
3827ff1ffd74SMichael Tuexen 		char msg[SCTP_DIAG_INFO_LEN];
3828139bc87fSRandall Stewart 
3829139bc87fSRandall Stewart 		*abort_now = 1;
3830139bc87fSRandall Stewart 		/* XXX */
383155f8a4bbSMichael Tuexen 		snprintf(msg, sizeof(msg), "Cum ack %8.8x greater or equal than TSN %8.8x",
3832ff1ffd74SMichael Tuexen 		    cumack, send_s);
3833ff1ffd74SMichael Tuexen 		op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
383444249214SRandall Stewart 		stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_21;
3835ff1ffd74SMichael Tuexen 		sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
3836139bc87fSRandall Stewart 		return;
3837139bc87fSRandall Stewart 	}
3838f8829a4aSRandall Stewart 	asoc->this_sack_highest_gap = cumack;
3839b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) {
3840c4739e2fSRandall Stewart 		sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
3841c4739e2fSRandall Stewart 		    stcb->asoc.overall_error_count,
3842c4739e2fSRandall Stewart 		    0,
3843c4739e2fSRandall Stewart 		    SCTP_FROM_SCTP_INDATA,
3844c4739e2fSRandall Stewart 		    __LINE__);
3845c4739e2fSRandall Stewart 	}
3846f8829a4aSRandall Stewart 	stcb->asoc.overall_error_count = 0;
384720b07a4dSMichael Tuexen 	if (SCTP_TSN_GT(cumack, asoc->last_acked_seq)) {
3848f8829a4aSRandall Stewart 		/* process the new consecutive TSN first */
38494a9ef3f8SMichael Tuexen 		TAILQ_FOREACH_SAFE(tp1, &asoc->sent_queue, sctp_next, tp2) {
385020b07a4dSMichael Tuexen 			if (SCTP_TSN_GE(cumack, tp1->rec.data.TSN_seq)) {
385118e198d3SRandall Stewart 				if (tp1->sent == SCTP_DATAGRAM_UNSENT) {
3852cd3fd531SMichael Tuexen 					SCTP_PRINTF("Warning, an unsent is now acked?\n");
385318e198d3SRandall Stewart 				}
3854f8829a4aSRandall Stewart 				if (tp1->sent < SCTP_DATAGRAM_ACKED) {
3855f8829a4aSRandall Stewart 					/*
385618e198d3SRandall Stewart 					 * If it is less than ACKED, it is
385718e198d3SRandall Stewart 					 * now no-longer in flight. Higher
385818e198d3SRandall Stewart 					 * values may occur during marking
3859f8829a4aSRandall Stewart 					 */
3860c105859eSRandall Stewart 					if (tp1->sent < SCTP_DATAGRAM_RESEND) {
3861b3f1ea41SRandall Stewart 						if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) {
3862c105859eSRandall Stewart 							sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_CA,
3863a5d547adSRandall Stewart 							    tp1->whoTo->flight_size,
3864a5d547adSRandall Stewart 							    tp1->book_size,
38659a8e3088SMichael Tuexen 							    (uint32_t) (uintptr_t) tp1->whoTo,
3866a5d547adSRandall Stewart 							    tp1->rec.data.TSN_seq);
386780fefe0aSRandall Stewart 						}
3868c105859eSRandall Stewart 						sctp_flight_size_decrease(tp1);
3869299108c5SRandall Stewart 						if (stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) {
3870299108c5SRandall Stewart 							(*stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) (tp1->whoTo,
3871299108c5SRandall Stewart 							    tp1);
3872299108c5SRandall Stewart 						}
387304ee05e8SRandall Stewart 						/* sa_ignore NO_NULL_CHK */
3874c105859eSRandall Stewart 						sctp_total_flight_decrease(stcb, tp1);
3875f8829a4aSRandall Stewart 					}
3876f8829a4aSRandall Stewart 					tp1->whoTo->net_ack += tp1->send_size;
3877f8829a4aSRandall Stewart 					if (tp1->snd_count < 2) {
3878f8829a4aSRandall Stewart 						/*
387918e198d3SRandall Stewart 						 * True non-retransmited
3880f8829a4aSRandall Stewart 						 * chunk
3881f8829a4aSRandall Stewart 						 */
3882f8829a4aSRandall Stewart 						tp1->whoTo->net_ack2 +=
3883f8829a4aSRandall Stewart 						    tp1->send_size;
3884f8829a4aSRandall Stewart 
3885f8829a4aSRandall Stewart 						/* update RTO too? */
388662c1ff9cSRandall Stewart 						if (tp1->do_rtt) {
3887f79aab18SRandall Stewart 							if (rto_ok) {
3888f8829a4aSRandall Stewart 								tp1->whoTo->RTO =
388904ee05e8SRandall Stewart 								/*
389004ee05e8SRandall Stewart 								 * sa_ignore
3891*5b495f17SMichael Tuexen 								 * NO_NULL_CHK
389204ee05e8SRandall Stewart 								 */
3893f8829a4aSRandall Stewart 								    sctp_calculate_rto(stcb,
3894f8829a4aSRandall Stewart 								    asoc, tp1->whoTo,
389518e198d3SRandall Stewart 								    &tp1->sent_rcv_time,
3896899288aeSRandall Stewart 								    sctp_align_safe_nocopy,
3897f79aab18SRandall Stewart 								    SCTP_RTT_FROM_DATA);
3898f79aab18SRandall Stewart 								rto_ok = 0;
3899f79aab18SRandall Stewart 							}
3900f79aab18SRandall Stewart 							if (tp1->whoTo->rto_needed == 0) {
3901f79aab18SRandall Stewart 								tp1->whoTo->rto_needed = 1;
3902f79aab18SRandall Stewart 							}
3903f8829a4aSRandall Stewart 							tp1->do_rtt = 0;
3904f8829a4aSRandall Stewart 						}
3905f8829a4aSRandall Stewart 					}
3906132dea7dSRandall Stewart 					/*
390718e198d3SRandall Stewart 					 * CMT: CUCv2 algorithm. From the
390818e198d3SRandall Stewart 					 * cumack'd TSNs, for each TSN being
390918e198d3SRandall Stewart 					 * acked for the first time, set the
391018e198d3SRandall Stewart 					 * following variables for the
391118e198d3SRandall Stewart 					 * corresp destination.
391218e198d3SRandall Stewart 					 * new_pseudo_cumack will trigger a
391318e198d3SRandall Stewart 					 * cwnd update.
391418e198d3SRandall Stewart 					 * find_(rtx_)pseudo_cumack will
391518e198d3SRandall Stewart 					 * trigger search for the next
391618e198d3SRandall Stewart 					 * expected (rtx-)pseudo-cumack.
3917132dea7dSRandall Stewart 					 */
3918132dea7dSRandall Stewart 					tp1->whoTo->new_pseudo_cumack = 1;
3919132dea7dSRandall Stewart 					tp1->whoTo->find_pseudo_cumack = 1;
3920132dea7dSRandall Stewart 					tp1->whoTo->find_rtx_pseudo_cumack = 1;
3921132dea7dSRandall Stewart 
3922b3f1ea41SRandall Stewart 					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
392304ee05e8SRandall Stewart 						/* sa_ignore NO_NULL_CHK */
3924f8829a4aSRandall Stewart 						sctp_log_cwnd(stcb, tp1->whoTo, tp1->rec.data.TSN_seq, SCTP_CWND_LOG_FROM_SACK);
392580fefe0aSRandall Stewart 					}
3926f8829a4aSRandall Stewart 				}
3927f8829a4aSRandall Stewart 				if (tp1->sent == SCTP_DATAGRAM_RESEND) {
3928f8829a4aSRandall Stewart 					sctp_ucount_decr(asoc->sent_queue_retran_cnt);
3929f8829a4aSRandall Stewart 				}
393042551e99SRandall Stewart 				if (tp1->rec.data.chunk_was_revoked) {
393142551e99SRandall Stewart 					/* deflate the cwnd */
393242551e99SRandall Stewart 					tp1->whoTo->cwnd -= tp1->book_size;
393342551e99SRandall Stewart 					tp1->rec.data.chunk_was_revoked = 0;
393442551e99SRandall Stewart 				}
3935325c8c46SMichael Tuexen 				if (tp1->sent != SCTP_DATAGRAM_NR_ACKED) {
3936a7ad6026SMichael Tuexen 					if (asoc->strmout[tp1->rec.data.stream_number].chunks_on_queues > 0) {
3937a7ad6026SMichael Tuexen 						asoc->strmout[tp1->rec.data.stream_number].chunks_on_queues--;
3938a7ad6026SMichael Tuexen #ifdef INVARIANTS
3939a7ad6026SMichael Tuexen 					} else {
3940a7ad6026SMichael Tuexen 						panic("No chunks on the queues for sid %u.", tp1->rec.data.stream_number);
3941a7ad6026SMichael Tuexen #endif
3942a7ad6026SMichael Tuexen 					}
3943a7ad6026SMichael Tuexen 				}
3944d96bef9cSMichael Tuexen 				if ((asoc->strmout[tp1->rec.data.stream_number].chunks_on_queues == 0) &&
3945d96bef9cSMichael Tuexen 				    (asoc->strmout[tp1->rec.data.stream_number].state == SCTP_STREAM_RESET_PENDING) &&
3946d96bef9cSMichael Tuexen 				    TAILQ_EMPTY(&asoc->strmout[tp1->rec.data.stream_number].outqueue)) {
3947d96bef9cSMichael Tuexen 					asoc->trigger_reset = 1;
3948d96bef9cSMichael Tuexen 				}
3949f8829a4aSRandall Stewart 				TAILQ_REMOVE(&asoc->sent_queue, tp1, sctp_next);
3950f8829a4aSRandall Stewart 				if (tp1->data) {
395104ee05e8SRandall Stewart 					/* sa_ignore NO_NULL_CHK */
3952f8829a4aSRandall Stewart 					sctp_free_bufspace(stcb, asoc, tp1, 1);
3953f8829a4aSRandall Stewart 					sctp_m_freem(tp1->data);
39544a9ef3f8SMichael Tuexen 					tp1->data = NULL;
3955f8829a4aSRandall Stewart 				}
3956b3f1ea41SRandall Stewart 				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) {
3957f8829a4aSRandall Stewart 					sctp_log_sack(asoc->last_acked_seq,
3958f8829a4aSRandall Stewart 					    cumack,
3959f8829a4aSRandall Stewart 					    tp1->rec.data.TSN_seq,
3960f8829a4aSRandall Stewart 					    0,
3961f8829a4aSRandall Stewart 					    0,
3962f8829a4aSRandall Stewart 					    SCTP_LOG_FREE_SENT);
396380fefe0aSRandall Stewart 				}
3964f8829a4aSRandall Stewart 				asoc->sent_queue_cnt--;
3965689e6a5fSMichael Tuexen 				sctp_free_a_chunk(stcb, tp1, SCTP_SO_NOT_LOCKED);
396618e198d3SRandall Stewart 			} else {
396718e198d3SRandall Stewart 				break;
3968f8829a4aSRandall Stewart 			}
39695e54f665SRandall Stewart 		}
397018e198d3SRandall Stewart 
397118e198d3SRandall Stewart 	}
397204ee05e8SRandall Stewart 	/* sa_ignore NO_NULL_CHK */
3973f8829a4aSRandall Stewart 	if (stcb->sctp_socket) {
3974ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
3975ceaad40aSRandall Stewart 		struct socket *so;
3976ceaad40aSRandall Stewart 
3977ceaad40aSRandall Stewart #endif
3978f8829a4aSRandall Stewart 		SOCKBUF_LOCK(&stcb->sctp_socket->so_snd);
3979b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_WAKE_LOGGING_ENABLE) {
398004ee05e8SRandall Stewart 			/* sa_ignore NO_NULL_CHK */
39817215cc1bSMichael Tuexen 			sctp_wakeup_log(stcb, 1, SCTP_WAKESND_FROM_SACK);
398280fefe0aSRandall Stewart 		}
3983ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
3984ceaad40aSRandall Stewart 		so = SCTP_INP_SO(stcb->sctp_ep);
3985ceaad40aSRandall Stewart 		atomic_add_int(&stcb->asoc.refcnt, 1);
3986ceaad40aSRandall Stewart 		SCTP_TCB_UNLOCK(stcb);
3987ceaad40aSRandall Stewart 		SCTP_SOCKET_LOCK(so, 1);
3988ceaad40aSRandall Stewart 		SCTP_TCB_LOCK(stcb);
3989ceaad40aSRandall Stewart 		atomic_subtract_int(&stcb->asoc.refcnt, 1);
3990ceaad40aSRandall Stewart 		if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
3991ceaad40aSRandall Stewart 			/* assoc was freed while we were unlocked */
3992ceaad40aSRandall Stewart 			SCTP_SOCKET_UNLOCK(so, 1);
3993ceaad40aSRandall Stewart 			return;
3994ceaad40aSRandall Stewart 		}
3995ceaad40aSRandall Stewart #endif
3996f8829a4aSRandall Stewart 		sctp_sowwakeup_locked(stcb->sctp_ep, stcb->sctp_socket);
3997ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
3998ceaad40aSRandall Stewart 		SCTP_SOCKET_UNLOCK(so, 1);
3999ceaad40aSRandall Stewart #endif
4000f8829a4aSRandall Stewart 	} else {
4001b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_WAKE_LOGGING_ENABLE) {
40027215cc1bSMichael Tuexen 			sctp_wakeup_log(stcb, 1, SCTP_NOWAKE_FROM_SACK);
400380fefe0aSRandall Stewart 		}
4004f8829a4aSRandall Stewart 	}
4005f8829a4aSRandall Stewart 
4006b54d3a6cSRandall Stewart 	/* JRS - Use the congestion control given in the CC module */
4007ca85e948SMichael Tuexen 	if ((asoc->last_acked_seq != cumack) && (ecne_seen == 0)) {
4008ca85e948SMichael Tuexen 		TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
4009ca85e948SMichael Tuexen 			if (net->net_ack2 > 0) {
4010ca85e948SMichael Tuexen 				/*
4011ca85e948SMichael Tuexen 				 * Karn's rule applies to clearing error
4012ca85e948SMichael Tuexen 				 * count, this is optional.
4013ca85e948SMichael Tuexen 				 */
4014ca85e948SMichael Tuexen 				net->error_count = 0;
4015ca85e948SMichael Tuexen 				if (!(net->dest_state & SCTP_ADDR_REACHABLE)) {
4016ca85e948SMichael Tuexen 					/* addr came good */
4017ca85e948SMichael Tuexen 					net->dest_state |= SCTP_ADDR_REACHABLE;
4018ca85e948SMichael Tuexen 					sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb,
40194b1f78e1SMichael Tuexen 					    0, (void *)net, SCTP_SO_NOT_LOCKED);
4020ca85e948SMichael Tuexen 				}
4021ca85e948SMichael Tuexen 				if (net == stcb->asoc.primary_destination) {
4022ca85e948SMichael Tuexen 					if (stcb->asoc.alternate) {
4023*5b495f17SMichael Tuexen 						/* release the alternate,
4024*5b495f17SMichael Tuexen 						 * primary is good */
4025ca85e948SMichael Tuexen 						sctp_free_remote_addr(stcb->asoc.alternate);
4026ca85e948SMichael Tuexen 						stcb->asoc.alternate = NULL;
4027ca85e948SMichael Tuexen 					}
4028ca85e948SMichael Tuexen 				}
4029ca85e948SMichael Tuexen 				if (net->dest_state & SCTP_ADDR_PF) {
4030ca85e948SMichael Tuexen 					net->dest_state &= ~SCTP_ADDR_PF;
4031b7d130beSMichael Tuexen 					sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT,
4032b7d130beSMichael Tuexen 					    stcb->sctp_ep, stcb, net,
403344249214SRandall Stewart 					    SCTP_FROM_SCTP_INDATA + SCTP_LOC_22);
4034ca85e948SMichael Tuexen 					sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
4035ca85e948SMichael Tuexen 					asoc->cc_functions.sctp_cwnd_update_exit_pf(stcb, net);
4036ca85e948SMichael Tuexen 					/* Done with this net */
4037ca85e948SMichael Tuexen 					net->net_ack = 0;
4038ca85e948SMichael Tuexen 				}
4039ca85e948SMichael Tuexen 				/* restore any doubled timers */
4040ca85e948SMichael Tuexen 				net->RTO = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv;
4041ca85e948SMichael Tuexen 				if (net->RTO < stcb->asoc.minrto) {
4042ca85e948SMichael Tuexen 					net->RTO = stcb->asoc.minrto;
4043ca85e948SMichael Tuexen 				}
4044ca85e948SMichael Tuexen 				if (net->RTO > stcb->asoc.maxrto) {
4045ca85e948SMichael Tuexen 					net->RTO = stcb->asoc.maxrto;
4046ca85e948SMichael Tuexen 				}
4047ca85e948SMichael Tuexen 			}
4048ca85e948SMichael Tuexen 		}
4049b54d3a6cSRandall Stewart 		asoc->cc_functions.sctp_cwnd_update_after_sack(stcb, asoc, 1, 0, 0);
4050ca85e948SMichael Tuexen 	}
4051f8829a4aSRandall Stewart 	asoc->last_acked_seq = cumack;
40525e54f665SRandall Stewart 
4053f8829a4aSRandall Stewart 	if (TAILQ_EMPTY(&asoc->sent_queue)) {
4054f8829a4aSRandall Stewart 		/* nothing left in-flight */
4055f8829a4aSRandall Stewart 		TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
4056f8829a4aSRandall Stewart 			net->flight_size = 0;
4057f8829a4aSRandall Stewart 			net->partial_bytes_acked = 0;
4058f8829a4aSRandall Stewart 		}
4059f8829a4aSRandall Stewart 		asoc->total_flight = 0;
4060f8829a4aSRandall Stewart 		asoc->total_flight_count = 0;
4061f8829a4aSRandall Stewart 	}
4062f8829a4aSRandall Stewart 	/* RWND update */
4063f8829a4aSRandall Stewart 	asoc->peers_rwnd = sctp_sbspace_sub(rwnd,
406444fbe462SRandall Stewart 	    (uint32_t) (asoc->total_flight + (asoc->total_flight_count * SCTP_BASE_SYSCTL(sctp_peer_chunk_oh))));
4065f8829a4aSRandall Stewart 	if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) {
4066f8829a4aSRandall Stewart 		/* SWS sender side engages */
4067f8829a4aSRandall Stewart 		asoc->peers_rwnd = 0;
4068f8829a4aSRandall Stewart 	}
40695e54f665SRandall Stewart 	if (asoc->peers_rwnd > old_rwnd) {
40705e54f665SRandall Stewart 		win_probe_recovery = 1;
40715e54f665SRandall Stewart 	}
4072f8829a4aSRandall Stewart 	/* Now assure a timer where data is queued at */
4073a5d547adSRandall Stewart again:
4074a5d547adSRandall Stewart 	j = 0;
4075f8829a4aSRandall Stewart 	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
40765171328bSRandall Stewart 		int to_ticks;
40775171328bSRandall Stewart 
40785e54f665SRandall Stewart 		if (win_probe_recovery && (net->window_probe)) {
4079c105859eSRandall Stewart 			win_probe_recovered = 1;
40805e54f665SRandall Stewart 			/*
40815e54f665SRandall Stewart 			 * Find first chunk that was used with window probe
40825e54f665SRandall Stewart 			 * and clear the sent
40835e54f665SRandall Stewart 			 */
40843c503c28SRandall Stewart 			/* sa_ignore FREED_MEMORY */
40855e54f665SRandall Stewart 			TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
40865e54f665SRandall Stewart 				if (tp1->window_probe) {
4087cd554309SMichael Tuexen 					/* move back to data send queue */
40887215cc1bSMichael Tuexen 					sctp_window_probe_recovery(stcb, asoc, tp1);
40895e54f665SRandall Stewart 					break;
40905e54f665SRandall Stewart 				}
40915e54f665SRandall Stewart 			}
40925e54f665SRandall Stewart 		}
4093f8829a4aSRandall Stewart 		if (net->RTO == 0) {
4094f8829a4aSRandall Stewart 			to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
4095f8829a4aSRandall Stewart 		} else {
4096f8829a4aSRandall Stewart 			to_ticks = MSEC_TO_TICKS(net->RTO);
4097f8829a4aSRandall Stewart 		}
40985171328bSRandall Stewart 		if (net->flight_size) {
4099a5d547adSRandall Stewart 			j++;
4100ad81507eSRandall Stewart 			(void)SCTP_OS_TIMER_START(&net->rxt_timer.timer, to_ticks,
4101f8829a4aSRandall Stewart 			    sctp_timeout_handler, &net->rxt_timer);
41025171328bSRandall Stewart 			if (net->window_probe) {
41035171328bSRandall Stewart 				net->window_probe = 0;
41045171328bSRandall Stewart 			}
4105f8829a4aSRandall Stewart 		} else {
41065171328bSRandall Stewart 			if (net->window_probe) {
4107*5b495f17SMichael Tuexen 				/* In window probes we must assure a timer
4108*5b495f17SMichael Tuexen 				 * is still running there */
41095171328bSRandall Stewart 				net->window_probe = 0;
41105171328bSRandall Stewart 				if (!SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) {
41115171328bSRandall Stewart 					SCTP_OS_TIMER_START(&net->rxt_timer.timer, to_ticks,
41125171328bSRandall Stewart 					    sctp_timeout_handler, &net->rxt_timer);
41135171328bSRandall Stewart 				}
41145171328bSRandall Stewart 			} else if (SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) {
4115f8829a4aSRandall Stewart 				sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
4116a5d547adSRandall Stewart 				    stcb, net,
411744249214SRandall Stewart 				    SCTP_FROM_SCTP_INDATA + SCTP_LOC_23);
4118f8829a4aSRandall Stewart 			}
4119f8829a4aSRandall Stewart 		}
4120f8829a4aSRandall Stewart 	}
4121bff64a4dSRandall Stewart 	if ((j == 0) &&
4122bff64a4dSRandall Stewart 	    (!TAILQ_EMPTY(&asoc->sent_queue)) &&
4123bff64a4dSRandall Stewart 	    (asoc->sent_queue_retran_cnt == 0) &&
4124c105859eSRandall Stewart 	    (win_probe_recovered == 0) &&
4125bff64a4dSRandall Stewart 	    (done_once == 0)) {
41260c0982b8SRandall Stewart 		/*
41270c0982b8SRandall Stewart 		 * huh, this should not happen unless all packets are
41280c0982b8SRandall Stewart 		 * PR-SCTP and marked to skip of course.
41290c0982b8SRandall Stewart 		 */
41300c0982b8SRandall Stewart 		if (sctp_fs_audit(asoc)) {
4131a5d547adSRandall Stewart 			TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
4132a5d547adSRandall Stewart 				net->flight_size = 0;
4133a5d547adSRandall Stewart 			}
4134a5d547adSRandall Stewart 			asoc->total_flight = 0;
4135a5d547adSRandall Stewart 			asoc->total_flight_count = 0;
4136a5d547adSRandall Stewart 			asoc->sent_queue_retran_cnt = 0;
4137a5d547adSRandall Stewart 			TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
4138a5d547adSRandall Stewart 				if (tp1->sent < SCTP_DATAGRAM_RESEND) {
4139c105859eSRandall Stewart 					sctp_flight_size_increase(tp1);
4140c105859eSRandall Stewart 					sctp_total_flight_increase(stcb, tp1);
4141a5d547adSRandall Stewart 				} else if (tp1->sent == SCTP_DATAGRAM_RESEND) {
4142791437b5SRandall Stewart 					sctp_ucount_incr(asoc->sent_queue_retran_cnt);
4143a5d547adSRandall Stewart 				}
4144a5d547adSRandall Stewart 			}
41450c0982b8SRandall Stewart 		}
4146bff64a4dSRandall Stewart 		done_once = 1;
4147a5d547adSRandall Stewart 		goto again;
4148a5d547adSRandall Stewart 	}
4149f8829a4aSRandall Stewart 	/**********************************/
4150f8829a4aSRandall Stewart 	/* Now what about shutdown issues */
4151f8829a4aSRandall Stewart 	/**********************************/
4152f8829a4aSRandall Stewart 	if (TAILQ_EMPTY(&asoc->send_queue) && TAILQ_EMPTY(&asoc->sent_queue)) {
4153f8829a4aSRandall Stewart 		/* nothing left on sendqueue.. consider done */
4154f8829a4aSRandall Stewart 		/* clean up */
4155f8829a4aSRandall Stewart 		if ((asoc->stream_queue_cnt == 1) &&
4156f8829a4aSRandall Stewart 		    ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) ||
4157f8829a4aSRandall Stewart 		    (asoc->state & SCTP_STATE_SHUTDOWN_RECEIVED)) &&
4158d1ea5fa9SMichael Tuexen 		    ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) (stcb, asoc))) {
4159f8829a4aSRandall Stewart 			asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
41602afb3e84SRandall Stewart 		}
4161f8829a4aSRandall Stewart 		if ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) &&
4162f8829a4aSRandall Stewart 		    (asoc->stream_queue_cnt == 0)) {
4163f8829a4aSRandall Stewart 			if (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT) {
4164f8829a4aSRandall Stewart 				/* Need to abort here */
4165ff1ffd74SMichael Tuexen 				struct mbuf *op_err;
4166f8829a4aSRandall Stewart 
4167f8829a4aSRandall Stewart 		abort_out_now:
4168f8829a4aSRandall Stewart 				*abort_now = 1;
4169f8829a4aSRandall Stewart 				/* XXX */
4170ff1ffd74SMichael Tuexen 				op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
417144249214SRandall Stewart 				stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_24;
4172ff1ffd74SMichael Tuexen 				sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
4173fe4a59b3SMichael Tuexen 				return;
4174f8829a4aSRandall Stewart 			} else {
4175ca85e948SMichael Tuexen 				struct sctp_nets *netp;
4176ca85e948SMichael Tuexen 
4177f42a358aSRandall Stewart 				if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
4178f42a358aSRandall Stewart 				    (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
4179f8829a4aSRandall Stewart 					SCTP_STAT_DECR_GAUGE32(sctps_currestab);
4180f42a358aSRandall Stewart 				}
4181c4739e2fSRandall Stewart 				SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
4182b201f536SRandall Stewart 				SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
4183f8829a4aSRandall Stewart 				sctp_stop_timers_for_shutdown(stcb);
4184ca85e948SMichael Tuexen 				if (asoc->alternate) {
4185ca85e948SMichael Tuexen 					netp = asoc->alternate;
4186ca85e948SMichael Tuexen 				} else {
4187ca85e948SMichael Tuexen 					netp = asoc->primary_destination;
4188ca85e948SMichael Tuexen 				}
4189ca85e948SMichael Tuexen 				sctp_send_shutdown(stcb, netp);
4190f8829a4aSRandall Stewart 				sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
4191ca85e948SMichael Tuexen 				    stcb->sctp_ep, stcb, netp);
4192f8829a4aSRandall Stewart 				sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
4193ca85e948SMichael Tuexen 				    stcb->sctp_ep, stcb, netp);
4194f8829a4aSRandall Stewart 			}
4195f8829a4aSRandall Stewart 		} else if ((SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED) &&
4196f8829a4aSRandall Stewart 		    (asoc->stream_queue_cnt == 0)) {
4197ca85e948SMichael Tuexen 			struct sctp_nets *netp;
4198ca85e948SMichael Tuexen 
4199f8829a4aSRandall Stewart 			if (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT) {
4200f8829a4aSRandall Stewart 				goto abort_out_now;
4201f8829a4aSRandall Stewart 			}
4202f8829a4aSRandall Stewart 			SCTP_STAT_DECR_GAUGE32(sctps_currestab);
4203c4739e2fSRandall Stewart 			SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_ACK_SENT);
4204b201f536SRandall Stewart 			SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
420512af6654SMichael Tuexen 			sctp_stop_timers_for_shutdown(stcb);
4206c39cfa1fSMichael Tuexen 			if (asoc->alternate) {
4207c39cfa1fSMichael Tuexen 				netp = asoc->alternate;
4208c39cfa1fSMichael Tuexen 			} else {
4209c39cfa1fSMichael Tuexen 				netp = asoc->primary_destination;
4210c39cfa1fSMichael Tuexen 			}
4211c39cfa1fSMichael Tuexen 			sctp_send_shutdown_ack(stcb, netp);
4212f8829a4aSRandall Stewart 			sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK,
4213ca85e948SMichael Tuexen 			    stcb->sctp_ep, stcb, netp);
4214f8829a4aSRandall Stewart 		}
4215f8829a4aSRandall Stewart 	}
4216dfb11ef8SRandall Stewart 	/*********************************************/
4217dfb11ef8SRandall Stewart 	/* Here we perform PR-SCTP procedures        */
4218dfb11ef8SRandall Stewart 	/* (section 4.2)                             */
4219dfb11ef8SRandall Stewart 	/*********************************************/
4220dfb11ef8SRandall Stewart 	/* C1. update advancedPeerAckPoint */
422120b07a4dSMichael Tuexen 	if (SCTP_TSN_GT(cumack, asoc->advanced_peer_ack_point)) {
4222dfb11ef8SRandall Stewart 		asoc->advanced_peer_ack_point = cumack;
4223dfb11ef8SRandall Stewart 	}
4224830d754dSRandall Stewart 	/* PR-Sctp issues need to be addressed too */
4225dd973b0eSMichael Tuexen 	if ((asoc->prsctp_supported) && (asoc->pr_sctp_cnt > 0)) {
4226830d754dSRandall Stewart 		struct sctp_tmit_chunk *lchk;
4227830d754dSRandall Stewart 		uint32_t old_adv_peer_ack_point;
4228830d754dSRandall Stewart 
4229830d754dSRandall Stewart 		old_adv_peer_ack_point = asoc->advanced_peer_ack_point;
4230830d754dSRandall Stewart 		lchk = sctp_try_advance_peer_ack_point(stcb, asoc);
4231830d754dSRandall Stewart 		/* C3. See if we need to send a Fwd-TSN */
423220b07a4dSMichael Tuexen 		if (SCTP_TSN_GT(asoc->advanced_peer_ack_point, cumack)) {
4233830d754dSRandall Stewart 			/*
4234493d8e5aSRandall Stewart 			 * ISSUE with ECN, see FWD-TSN processing.
4235830d754dSRandall Stewart 			 */
423620b07a4dSMichael Tuexen 			if (SCTP_TSN_GT(asoc->advanced_peer_ack_point, old_adv_peer_ack_point)) {
4237830d754dSRandall Stewart 				send_forward_tsn(stcb, asoc);
42380c0982b8SRandall Stewart 			} else if (lchk) {
42390c0982b8SRandall Stewart 				/* try to FR fwd-tsn's that get lost too */
424044fbe462SRandall Stewart 				if (lchk->rec.data.fwd_tsn_cnt >= 3) {
42410c0982b8SRandall Stewart 					send_forward_tsn(stcb, asoc);
42420c0982b8SRandall Stewart 				}
4243830d754dSRandall Stewart 			}
4244830d754dSRandall Stewart 		}
4245830d754dSRandall Stewart 		if (lchk) {
4246830d754dSRandall Stewart 			/* Assure a timer is up */
4247830d754dSRandall Stewart 			sctp_timer_start(SCTP_TIMER_TYPE_SEND,
4248830d754dSRandall Stewart 			    stcb->sctp_ep, stcb, lchk->whoTo);
4249830d754dSRandall Stewart 		}
4250830d754dSRandall Stewart 	}
4251b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_RWND_LOGGING_ENABLE) {
4252f8829a4aSRandall Stewart 		sctp_misc_ints(SCTP_SACK_RWND_UPDATE,
4253f8829a4aSRandall Stewart 		    rwnd,
4254f8829a4aSRandall Stewart 		    stcb->asoc.peers_rwnd,
4255f8829a4aSRandall Stewart 		    stcb->asoc.total_flight,
4256f8829a4aSRandall Stewart 		    stcb->asoc.total_output_queue_size);
425780fefe0aSRandall Stewart 	}
4258f8829a4aSRandall Stewart }
4259f8829a4aSRandall Stewart 
4260f8829a4aSRandall Stewart void
4261cd554309SMichael Tuexen sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
42627215cc1bSMichael Tuexen     struct sctp_tcb *stcb,
4263cd554309SMichael Tuexen     uint16_t num_seg, uint16_t num_nr_seg, uint16_t num_dup,
4264cd554309SMichael Tuexen     int *abort_now, uint8_t flags,
4265899288aeSRandall Stewart     uint32_t cum_ack, uint32_t rwnd, int ecne_seen)
4266f8829a4aSRandall Stewart {
4267f8829a4aSRandall Stewart 	struct sctp_association *asoc;
4268f8829a4aSRandall Stewart 	struct sctp_tmit_chunk *tp1, *tp2;
4269cd554309SMichael Tuexen 	uint32_t last_tsn, biggest_tsn_acked, biggest_tsn_newly_acked, this_sack_lowest_newack;
4270f8829a4aSRandall Stewart 	uint16_t wake_him = 0;
4271c105859eSRandall Stewart 	uint32_t send_s = 0;
4272f8829a4aSRandall Stewart 	long j;
4273f8829a4aSRandall Stewart 	int accum_moved = 0;
4274f8829a4aSRandall Stewart 	int will_exit_fast_recovery = 0;
42755e54f665SRandall Stewart 	uint32_t a_rwnd, old_rwnd;
42765e54f665SRandall Stewart 	int win_probe_recovery = 0;
4277c105859eSRandall Stewart 	int win_probe_recovered = 0;
4278f8829a4aSRandall Stewart 	struct sctp_nets *net = NULL;
4279bff64a4dSRandall Stewart 	int done_once;
4280f79aab18SRandall Stewart 	int rto_ok = 1;
4281f8829a4aSRandall Stewart 	uint8_t reneged_all = 0;
4282f8829a4aSRandall Stewart 	uint8_t cmt_dac_flag;
4283f8829a4aSRandall Stewart 
4284f8829a4aSRandall Stewart 	/*
4285f8829a4aSRandall Stewart 	 * we take any chance we can to service our queues since we cannot
4286f8829a4aSRandall Stewart 	 * get awoken when the socket is read from :<
4287f8829a4aSRandall Stewart 	 */
4288f8829a4aSRandall Stewart 	/*
4289f8829a4aSRandall Stewart 	 * Now perform the actual SACK handling: 1) Verify that it is not an
4290f8829a4aSRandall Stewart 	 * old sack, if so discard. 2) If there is nothing left in the send
4291f8829a4aSRandall Stewart 	 * queue (cum-ack is equal to last acked) then you have a duplicate
4292f8829a4aSRandall Stewart 	 * too, update any rwnd change and verify no timers are running.
4293f8829a4aSRandall Stewart 	 * then return. 3) Process any new consequtive data i.e. cum-ack
4294f8829a4aSRandall Stewart 	 * moved process these first and note that it moved. 4) Process any
4295f8829a4aSRandall Stewart 	 * sack blocks. 5) Drop any acked from the queue. 6) Check for any
4296f8829a4aSRandall Stewart 	 * revoked blocks and mark. 7) Update the cwnd. 8) Nothing left,
4297f8829a4aSRandall Stewart 	 * sync up flightsizes and things, stop all timers and also check
4298f8829a4aSRandall Stewart 	 * for shutdown_pending state. If so then go ahead and send off the
4299f8829a4aSRandall Stewart 	 * shutdown. If in shutdown recv, send off the shutdown-ack and
4300f8829a4aSRandall Stewart 	 * start that timer, Ret. 9) Strike any non-acked things and do FR
4301f8829a4aSRandall Stewart 	 * procedure if needed being sure to set the FR flag. 10) Do pr-sctp
4302f8829a4aSRandall Stewart 	 * procedures. 11) Apply any FR penalties. 12) Assure we will SACK
4303f8829a4aSRandall Stewart 	 * if in shutdown_recv state.
4304f8829a4aSRandall Stewart 	 */
4305f8829a4aSRandall Stewart 	SCTP_TCB_LOCK_ASSERT(stcb);
4306f8829a4aSRandall Stewart 	/* CMT DAC algo */
4307f8829a4aSRandall Stewart 	this_sack_lowest_newack = 0;
4308f8829a4aSRandall Stewart 	SCTP_STAT_INCR(sctps_slowpath_sack);
4309cd554309SMichael Tuexen 	last_tsn = cum_ack;
4310cd554309SMichael Tuexen 	cmt_dac_flag = flags & SCTP_SACK_CMT_DAC;
431118e198d3SRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS
431218e198d3SRandall Stewart 	stcb->asoc.cumack_log[stcb->asoc.cumack_log_at] = cum_ack;
431318e198d3SRandall Stewart 	stcb->asoc.cumack_log_at++;
431418e198d3SRandall Stewart 	if (stcb->asoc.cumack_log_at > SCTP_TSN_LOG_SIZE) {
431518e198d3SRandall Stewart 		stcb->asoc.cumack_log_at = 0;
431618e198d3SRandall Stewart 	}
431718e198d3SRandall Stewart #endif
4318d06c82f1SRandall Stewart 	a_rwnd = rwnd;
4319f8829a4aSRandall Stewart 
4320cd554309SMichael Tuexen 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_SACK_ARRIVALS_ENABLE) {
4321cd554309SMichael Tuexen 		sctp_misc_ints(SCTP_SACK_LOG_NORMAL, cum_ack,
4322cd554309SMichael Tuexen 		    rwnd, stcb->asoc.last_acked_seq, stcb->asoc.peers_rwnd);
4323cd554309SMichael Tuexen 	}
43245e54f665SRandall Stewart 	old_rwnd = stcb->asoc.peers_rwnd;
4325b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) {
4326c4739e2fSRandall Stewart 		sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
4327c4739e2fSRandall Stewart 		    stcb->asoc.overall_error_count,
4328c4739e2fSRandall Stewart 		    0,
4329c4739e2fSRandall Stewart 		    SCTP_FROM_SCTP_INDATA,
4330c4739e2fSRandall Stewart 		    __LINE__);
4331c4739e2fSRandall Stewart 	}
4332f8829a4aSRandall Stewart 	stcb->asoc.overall_error_count = 0;
4333f8829a4aSRandall Stewart 	asoc = &stcb->asoc;
4334b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) {
4335f8829a4aSRandall Stewart 		sctp_log_sack(asoc->last_acked_seq,
4336f8829a4aSRandall Stewart 		    cum_ack,
4337f8829a4aSRandall Stewart 		    0,
4338f8829a4aSRandall Stewart 		    num_seg,
4339f8829a4aSRandall Stewart 		    num_dup,
4340f8829a4aSRandall Stewart 		    SCTP_LOG_NEW_SACK);
434180fefe0aSRandall Stewart 	}
4342ca85e948SMichael Tuexen 	if ((num_dup) && (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE)) {
4343cd554309SMichael Tuexen 		uint16_t i;
4344458303daSRandall Stewart 		uint32_t *dupdata, dblock;
4345f8829a4aSRandall Stewart 
4346cd554309SMichael Tuexen 		for (i = 0; i < num_dup; i++) {
4347cd554309SMichael Tuexen 			dupdata = (uint32_t *) sctp_m_getptr(m, offset_dup + i * sizeof(uint32_t),
4348458303daSRandall Stewart 			    sizeof(uint32_t), (uint8_t *) & dblock);
4349cd554309SMichael Tuexen 			if (dupdata == NULL) {
4350458303daSRandall Stewart 				break;
4351458303daSRandall Stewart 			}
4352cd554309SMichael Tuexen 			sctp_log_fr(*dupdata, 0, 0, SCTP_FR_DUPED);
4353f8829a4aSRandall Stewart 		}
4354f8829a4aSRandall Stewart 	}
4355c105859eSRandall Stewart 	/* reality check */
4356c105859eSRandall Stewart 	if (!TAILQ_EMPTY(&asoc->sent_queue)) {
4357c105859eSRandall Stewart 		tp1 = TAILQ_LAST(&asoc->sent_queue,
4358c105859eSRandall Stewart 		    sctpchunk_listhead);
4359c105859eSRandall Stewart 		send_s = tp1->rec.data.TSN_seq + 1;
4360c105859eSRandall Stewart 	} else {
4361b5c16493SMichael Tuexen 		tp1 = NULL;
4362c105859eSRandall Stewart 		send_s = asoc->sending_seq;
4363c105859eSRandall Stewart 	}
436420b07a4dSMichael Tuexen 	if (SCTP_TSN_GE(cum_ack, send_s)) {
4365ff1ffd74SMichael Tuexen 		struct mbuf *op_err;
4366ff1ffd74SMichael Tuexen 		char msg[SCTP_DIAG_INFO_LEN];
4367c105859eSRandall Stewart 
4368f8829a4aSRandall Stewart 		/*
4369fd60718dSMichael Tuexen 		 * no way, we have not even sent this TSN out yet. Peer is
4370fd60718dSMichael Tuexen 		 * hopelessly messed up with us.
4371f8829a4aSRandall Stewart 		 */
4372cd3fd531SMichael Tuexen 		SCTP_PRINTF("NEW cum_ack:%x send_s:%x is smaller or equal\n",
4373b5c16493SMichael Tuexen 		    cum_ack, send_s);
4374b5c16493SMichael Tuexen 		if (tp1) {
4375cd3fd531SMichael Tuexen 			SCTP_PRINTF("Got send_s from tsn:%x + 1 of tp1: %p\n",
4376dd294dceSMichael Tuexen 			    tp1->rec.data.TSN_seq, (void *)tp1);
4377b5c16493SMichael Tuexen 		}
4378f8829a4aSRandall Stewart hopeless_peer:
4379f8829a4aSRandall Stewart 		*abort_now = 1;
4380f8829a4aSRandall Stewart 		/* XXX */
438155f8a4bbSMichael Tuexen 		snprintf(msg, sizeof(msg), "Cum ack %8.8x greater or equal than TSN %8.8x",
4382ff1ffd74SMichael Tuexen 		    cum_ack, send_s);
4383ff1ffd74SMichael Tuexen 		op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
438444249214SRandall Stewart 		stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_25;
4385ff1ffd74SMichael Tuexen 		sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
4386f8829a4aSRandall Stewart 		return;
4387f8829a4aSRandall Stewart 	}
4388f8829a4aSRandall Stewart 	/**********************/
4389f8829a4aSRandall Stewart 	/* 1) check the range */
4390f8829a4aSRandall Stewart 	/**********************/
439120b07a4dSMichael Tuexen 	if (SCTP_TSN_GT(asoc->last_acked_seq, last_tsn)) {
4392f8829a4aSRandall Stewart 		/* acking something behind */
4393f8829a4aSRandall Stewart 		return;
4394f8829a4aSRandall Stewart 	}
4395f8829a4aSRandall Stewart 	/* update the Rwnd of the peer */
4396f8829a4aSRandall Stewart 	if (TAILQ_EMPTY(&asoc->sent_queue) &&
4397f8829a4aSRandall Stewart 	    TAILQ_EMPTY(&asoc->send_queue) &&
4398cd554309SMichael Tuexen 	    (asoc->stream_queue_cnt == 0)) {
4399f8829a4aSRandall Stewart 		/* nothing left on send/sent and strmq */
4400b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_RWND_ENABLE) {
4401f8829a4aSRandall Stewart 			sctp_log_rwnd_set(SCTP_SET_PEER_RWND_VIA_SACK,
4402f8829a4aSRandall Stewart 			    asoc->peers_rwnd, 0, 0, a_rwnd);
440380fefe0aSRandall Stewart 		}
4404f8829a4aSRandall Stewart 		asoc->peers_rwnd = a_rwnd;
4405f8829a4aSRandall Stewart 		if (asoc->sent_queue_retran_cnt) {
4406f8829a4aSRandall Stewart 			asoc->sent_queue_retran_cnt = 0;
4407f8829a4aSRandall Stewart 		}
4408f8829a4aSRandall Stewart 		if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) {
4409f8829a4aSRandall Stewart 			/* SWS sender side engages */
4410f8829a4aSRandall Stewart 			asoc->peers_rwnd = 0;
4411f8829a4aSRandall Stewart 		}
4412f8829a4aSRandall Stewart 		/* stop any timers */
4413f8829a4aSRandall Stewart 		TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
4414f8829a4aSRandall Stewart 			sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
441544249214SRandall Stewart 			    stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_26);
4416f8829a4aSRandall Stewart 			net->partial_bytes_acked = 0;
4417f8829a4aSRandall Stewart 			net->flight_size = 0;
4418f8829a4aSRandall Stewart 		}
4419f8829a4aSRandall Stewart 		asoc->total_flight = 0;
4420f8829a4aSRandall Stewart 		asoc->total_flight_count = 0;
4421f8829a4aSRandall Stewart 		return;
4422f8829a4aSRandall Stewart 	}
4423f8829a4aSRandall Stewart 	/*
4424f8829a4aSRandall Stewart 	 * We init netAckSz and netAckSz2 to 0. These are used to track 2
4425f8829a4aSRandall Stewart 	 * things. The total byte count acked is tracked in netAckSz AND
4426f8829a4aSRandall Stewart 	 * netAck2 is used to track the total bytes acked that are un-
4427f8829a4aSRandall Stewart 	 * amibguious and were never retransmitted. We track these on a per
4428f8829a4aSRandall Stewart 	 * destination address basis.
4429f8829a4aSRandall Stewart 	 */
4430f8829a4aSRandall Stewart 	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
4431a21779f0SRandall Stewart 		if (SCTP_TSN_GT(cum_ack, net->cwr_window_tsn)) {
4432a21779f0SRandall Stewart 			/* Drag along the window_tsn for cwr's */
4433a21779f0SRandall Stewart 			net->cwr_window_tsn = cum_ack;
4434a21779f0SRandall Stewart 		}
4435f8829a4aSRandall Stewart 		net->prev_cwnd = net->cwnd;
4436f8829a4aSRandall Stewart 		net->net_ack = 0;
4437f8829a4aSRandall Stewart 		net->net_ack2 = 0;
4438f8829a4aSRandall Stewart 
4439f8829a4aSRandall Stewart 		/*
444042551e99SRandall Stewart 		 * CMT: Reset CUC and Fast recovery algo variables before
444142551e99SRandall Stewart 		 * SACK processing
4442f8829a4aSRandall Stewart 		 */
4443f8829a4aSRandall Stewart 		net->new_pseudo_cumack = 0;
4444f8829a4aSRandall Stewart 		net->will_exit_fast_recovery = 0;
4445299108c5SRandall Stewart 		if (stcb->asoc.cc_functions.sctp_cwnd_prepare_net_for_sack) {
4446299108c5SRandall Stewart 			(*stcb->asoc.cc_functions.sctp_cwnd_prepare_net_for_sack) (stcb, net);
4447299108c5SRandall Stewart 		}
4448f8829a4aSRandall Stewart 	}
4449f8829a4aSRandall Stewart 	/* process the new consecutive TSN first */
44504a9ef3f8SMichael Tuexen 	TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
445120b07a4dSMichael Tuexen 		if (SCTP_TSN_GE(last_tsn, tp1->rec.data.TSN_seq)) {
4452f8829a4aSRandall Stewart 			if (tp1->sent != SCTP_DATAGRAM_UNSENT) {
4453f8829a4aSRandall Stewart 				accum_moved = 1;
4454f8829a4aSRandall Stewart 				if (tp1->sent < SCTP_DATAGRAM_ACKED) {
4455f8829a4aSRandall Stewart 					/*
4456f8829a4aSRandall Stewart 					 * If it is less than ACKED, it is
4457f8829a4aSRandall Stewart 					 * now no-longer in flight. Higher
4458f8829a4aSRandall Stewart 					 * values may occur during marking
4459f8829a4aSRandall Stewart 					 */
4460f8829a4aSRandall Stewart 					if ((tp1->whoTo->dest_state &
4461f8829a4aSRandall Stewart 					    SCTP_ADDR_UNCONFIRMED) &&
4462f8829a4aSRandall Stewart 					    (tp1->snd_count < 2)) {
4463f8829a4aSRandall Stewart 						/*
4464f8829a4aSRandall Stewart 						 * If there was no retran
4465f8829a4aSRandall Stewart 						 * and the address is
4466f8829a4aSRandall Stewart 						 * un-confirmed and we sent
4467f8829a4aSRandall Stewart 						 * there and are now
4468f8829a4aSRandall Stewart 						 * sacked.. its confirmed,
4469f8829a4aSRandall Stewart 						 * mark it so.
4470f8829a4aSRandall Stewart 						 */
4471f8829a4aSRandall Stewart 						tp1->whoTo->dest_state &=
4472f8829a4aSRandall Stewart 						    ~SCTP_ADDR_UNCONFIRMED;
4473f8829a4aSRandall Stewart 					}
4474c105859eSRandall Stewart 					if (tp1->sent < SCTP_DATAGRAM_RESEND) {
4475b3f1ea41SRandall Stewart 						if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) {
4476c105859eSRandall Stewart 							sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_CA,
4477a5d547adSRandall Stewart 							    tp1->whoTo->flight_size,
4478a5d547adSRandall Stewart 							    tp1->book_size,
44799a8e3088SMichael Tuexen 							    (uint32_t) (uintptr_t) tp1->whoTo,
4480a5d547adSRandall Stewart 							    tp1->rec.data.TSN_seq);
448180fefe0aSRandall Stewart 						}
4482c105859eSRandall Stewart 						sctp_flight_size_decrease(tp1);
4483c105859eSRandall Stewart 						sctp_total_flight_decrease(stcb, tp1);
4484299108c5SRandall Stewart 						if (stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) {
4485299108c5SRandall Stewart 							(*stcb->asoc.cc_functions.sctp_cwnd_update_tsn_acknowledged) (tp1->whoTo,
4486299108c5SRandall Stewart 							    tp1);
4487299108c5SRandall Stewart 						}
4488f8829a4aSRandall Stewart 					}
4489f8829a4aSRandall Stewart 					tp1->whoTo->net_ack += tp1->send_size;
4490f8829a4aSRandall Stewart 
4491f8829a4aSRandall Stewart 					/* CMT SFR and DAC algos */
4492f8829a4aSRandall Stewart 					this_sack_lowest_newack = tp1->rec.data.TSN_seq;
4493f8829a4aSRandall Stewart 					tp1->whoTo->saw_newack = 1;
4494f8829a4aSRandall Stewart 
4495f8829a4aSRandall Stewart 					if (tp1->snd_count < 2) {
4496f8829a4aSRandall Stewart 						/*
4497f8829a4aSRandall Stewart 						 * True non-retransmited
4498f8829a4aSRandall Stewart 						 * chunk
4499f8829a4aSRandall Stewart 						 */
4500f8829a4aSRandall Stewart 						tp1->whoTo->net_ack2 +=
4501f8829a4aSRandall Stewart 						    tp1->send_size;
4502f8829a4aSRandall Stewart 
4503f8829a4aSRandall Stewart 						/* update RTO too? */
4504f8829a4aSRandall Stewart 						if (tp1->do_rtt) {
4505f79aab18SRandall Stewart 							if (rto_ok) {
4506f8829a4aSRandall Stewart 								tp1->whoTo->RTO =
4507f8829a4aSRandall Stewart 								    sctp_calculate_rto(stcb,
4508f8829a4aSRandall Stewart 								    asoc, tp1->whoTo,
450918e198d3SRandall Stewart 								    &tp1->sent_rcv_time,
4510899288aeSRandall Stewart 								    sctp_align_safe_nocopy,
4511f79aab18SRandall Stewart 								    SCTP_RTT_FROM_DATA);
4512f79aab18SRandall Stewart 								rto_ok = 0;
4513f79aab18SRandall Stewart 							}
4514f79aab18SRandall Stewart 							if (tp1->whoTo->rto_needed == 0) {
4515f79aab18SRandall Stewart 								tp1->whoTo->rto_needed = 1;
4516f79aab18SRandall Stewart 							}
4517f8829a4aSRandall Stewart 							tp1->do_rtt = 0;
4518f8829a4aSRandall Stewart 						}
4519f8829a4aSRandall Stewart 					}
4520f8829a4aSRandall Stewart 					/*
4521f8829a4aSRandall Stewart 					 * CMT: CUCv2 algorithm. From the
4522f8829a4aSRandall Stewart 					 * cumack'd TSNs, for each TSN being
4523f8829a4aSRandall Stewart 					 * acked for the first time, set the
4524f8829a4aSRandall Stewart 					 * following variables for the
4525f8829a4aSRandall Stewart 					 * corresp destination.
4526f8829a4aSRandall Stewart 					 * new_pseudo_cumack will trigger a
4527f8829a4aSRandall Stewart 					 * cwnd update.
4528f8829a4aSRandall Stewart 					 * find_(rtx_)pseudo_cumack will
4529f8829a4aSRandall Stewart 					 * trigger search for the next
4530f8829a4aSRandall Stewart 					 * expected (rtx-)pseudo-cumack.
4531f8829a4aSRandall Stewart 					 */
4532f8829a4aSRandall Stewart 					tp1->whoTo->new_pseudo_cumack = 1;
4533f8829a4aSRandall Stewart 					tp1->whoTo->find_pseudo_cumack = 1;
4534f8829a4aSRandall Stewart 					tp1->whoTo->find_rtx_pseudo_cumack = 1;
4535f8829a4aSRandall Stewart 
4536f8829a4aSRandall Stewart 
4537b3f1ea41SRandall Stewart 					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) {
4538f8829a4aSRandall Stewart 						sctp_log_sack(asoc->last_acked_seq,
4539f8829a4aSRandall Stewart 						    cum_ack,
4540f8829a4aSRandall Stewart 						    tp1->rec.data.TSN_seq,
4541f8829a4aSRandall Stewart 						    0,
4542f8829a4aSRandall Stewart 						    0,
4543f8829a4aSRandall Stewart 						    SCTP_LOG_TSN_ACKED);
454480fefe0aSRandall Stewart 					}
4545b3f1ea41SRandall Stewart 					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
4546f8829a4aSRandall Stewart 						sctp_log_cwnd(stcb, tp1->whoTo, tp1->rec.data.TSN_seq, SCTP_CWND_LOG_FROM_SACK);
454780fefe0aSRandall Stewart 					}
4548f8829a4aSRandall Stewart 				}
4549f8829a4aSRandall Stewart 				if (tp1->sent == SCTP_DATAGRAM_RESEND) {
4550f8829a4aSRandall Stewart 					sctp_ucount_decr(asoc->sent_queue_retran_cnt);
4551f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED
4552f8829a4aSRandall Stewart 					sctp_audit_log(0xB3,
4553f8829a4aSRandall Stewart 					    (asoc->sent_queue_retran_cnt & 0x000000ff));
4554f8829a4aSRandall Stewart #endif
4555f8829a4aSRandall Stewart 				}
455642551e99SRandall Stewart 				if (tp1->rec.data.chunk_was_revoked) {
455742551e99SRandall Stewart 					/* deflate the cwnd */
455842551e99SRandall Stewart 					tp1->whoTo->cwnd -= tp1->book_size;
455942551e99SRandall Stewart 					tp1->rec.data.chunk_was_revoked = 0;
456042551e99SRandall Stewart 				}
4561325c8c46SMichael Tuexen 				if (tp1->sent != SCTP_DATAGRAM_NR_ACKED) {
4562f8829a4aSRandall Stewart 					tp1->sent = SCTP_DATAGRAM_ACKED;
4563f8829a4aSRandall Stewart 				}
4564325c8c46SMichael Tuexen 			}
4565f8829a4aSRandall Stewart 		} else {
4566f8829a4aSRandall Stewart 			break;
4567f8829a4aSRandall Stewart 		}
4568f8829a4aSRandall Stewart 	}
4569f8829a4aSRandall Stewart 	biggest_tsn_newly_acked = biggest_tsn_acked = last_tsn;
4570f8829a4aSRandall Stewart 	/* always set this up to cum-ack */
4571f8829a4aSRandall Stewart 	asoc->this_sack_highest_gap = last_tsn;
4572f8829a4aSRandall Stewart 
4573cd554309SMichael Tuexen 	if ((num_seg > 0) || (num_nr_seg > 0)) {
4574f8829a4aSRandall Stewart 
4575f8829a4aSRandall Stewart 		/*
4576f8829a4aSRandall Stewart 		 * CMT: SFR algo (and HTNA) - this_sack_highest_newack has
4577f8829a4aSRandall Stewart 		 * to be greater than the cumack. Also reset saw_newack to 0
4578f8829a4aSRandall Stewart 		 * for all dests.
4579f8829a4aSRandall Stewart 		 */
4580f8829a4aSRandall Stewart 		TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
4581f8829a4aSRandall Stewart 			net->saw_newack = 0;
4582f8829a4aSRandall Stewart 			net->this_sack_highest_newack = last_tsn;
4583f8829a4aSRandall Stewart 		}
4584f8829a4aSRandall Stewart 
4585f8829a4aSRandall Stewart 		/*
4586f8829a4aSRandall Stewart 		 * thisSackHighestGap will increase while handling NEW
4587f8829a4aSRandall Stewart 		 * segments this_sack_highest_newack will increase while
4588f8829a4aSRandall Stewart 		 * handling NEWLY ACKED chunks. this_sack_lowest_newack is
4589f8829a4aSRandall Stewart 		 * used for CMT DAC algo. saw_newack will also change.
4590f8829a4aSRandall Stewart 		 */
4591cd554309SMichael Tuexen 		if (sctp_handle_segments(m, &offset_seg, stcb, asoc, last_tsn, &biggest_tsn_acked,
4592cd554309SMichael Tuexen 		    &biggest_tsn_newly_acked, &this_sack_lowest_newack,
45937215cc1bSMichael Tuexen 		    num_seg, num_nr_seg, &rto_ok)) {
4594cd554309SMichael Tuexen 			wake_him++;
4595cd554309SMichael Tuexen 		}
4596f8829a4aSRandall Stewart 		/*
4597fd60718dSMichael Tuexen 		 * validate the biggest_tsn_acked in the gap acks if strict
4598fd60718dSMichael Tuexen 		 * adherence is wanted.
4599f8829a4aSRandall Stewart 		 */
460020b07a4dSMichael Tuexen 		if (SCTP_TSN_GE(biggest_tsn_acked, send_s)) {
4601f8829a4aSRandall Stewart 			/*
4602fd60718dSMichael Tuexen 			 * peer is either confused or we are under attack.
4603fd60718dSMichael Tuexen 			 * We must abort.
4604f8829a4aSRandall Stewart 			 */
4605cd3fd531SMichael Tuexen 			SCTP_PRINTF("Hopeless peer! biggest_tsn_acked:%x largest seq:%x\n",
4606cd3fd531SMichael Tuexen 			    biggest_tsn_acked, send_s);
4607f8829a4aSRandall Stewart 			goto hopeless_peer;
4608f8829a4aSRandall Stewart 		}
4609f8829a4aSRandall Stewart 	}
4610f8829a4aSRandall Stewart 	/*******************************************/
4611f8829a4aSRandall Stewart 	/* cancel ALL T3-send timer if accum moved */
4612f8829a4aSRandall Stewart 	/*******************************************/
46137c99d56fSMichael Tuexen 	if (asoc->sctp_cmt_on_off > 0) {
4614f8829a4aSRandall Stewart 		TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
4615f8829a4aSRandall Stewart 			if (net->new_pseudo_cumack)
4616f8829a4aSRandall Stewart 				sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
4617a5d547adSRandall Stewart 				    stcb, net,
461844249214SRandall Stewart 				    SCTP_FROM_SCTP_INDATA + SCTP_LOC_27);
4619f8829a4aSRandall Stewart 
4620f8829a4aSRandall Stewart 		}
4621f8829a4aSRandall Stewart 	} else {
4622f8829a4aSRandall Stewart 		if (accum_moved) {
4623f8829a4aSRandall Stewart 			TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
4624f8829a4aSRandall Stewart 				sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
462544249214SRandall Stewart 				    stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_28);
4626f8829a4aSRandall Stewart 			}
4627f8829a4aSRandall Stewart 		}
4628f8829a4aSRandall Stewart 	}
4629f8829a4aSRandall Stewart 	/********************************************/
4630d9c5cfeaSMichael Tuexen 	/* drop the acked chunks from the sentqueue */
4631f8829a4aSRandall Stewart 	/********************************************/
4632f8829a4aSRandall Stewart 	asoc->last_acked_seq = cum_ack;
4633f8829a4aSRandall Stewart 
46347c99d56fSMichael Tuexen 	TAILQ_FOREACH_SAFE(tp1, &asoc->sent_queue, sctp_next, tp2) {
463520b07a4dSMichael Tuexen 		if (SCTP_TSN_GT(tp1->rec.data.TSN_seq, cum_ack)) {
4636f8829a4aSRandall Stewart 			break;
4637f8829a4aSRandall Stewart 		}
4638325c8c46SMichael Tuexen 		if (tp1->sent != SCTP_DATAGRAM_NR_ACKED) {
4639a7ad6026SMichael Tuexen 			if (asoc->strmout[tp1->rec.data.stream_number].chunks_on_queues > 0) {
4640a7ad6026SMichael Tuexen 				asoc->strmout[tp1->rec.data.stream_number].chunks_on_queues--;
4641a7ad6026SMichael Tuexen #ifdef INVARIANTS
4642a7ad6026SMichael Tuexen 			} else {
4643a7ad6026SMichael Tuexen 				panic("No chunks on the queues for sid %u.", tp1->rec.data.stream_number);
4644a7ad6026SMichael Tuexen #endif
4645a7ad6026SMichael Tuexen 			}
4646f8829a4aSRandall Stewart 		}
4647d96bef9cSMichael Tuexen 		if ((asoc->strmout[tp1->rec.data.stream_number].chunks_on_queues == 0) &&
4648d96bef9cSMichael Tuexen 		    (asoc->strmout[tp1->rec.data.stream_number].state == SCTP_STREAM_RESET_PENDING) &&
4649d96bef9cSMichael Tuexen 		    TAILQ_EMPTY(&asoc->strmout[tp1->rec.data.stream_number].outqueue)) {
4650d96bef9cSMichael Tuexen 			asoc->trigger_reset = 1;
4651d96bef9cSMichael Tuexen 		}
4652f8829a4aSRandall Stewart 		TAILQ_REMOVE(&asoc->sent_queue, tp1, sctp_next);
46530ddb4299SMichael Tuexen 		if (PR_SCTP_ENABLED(tp1->flags)) {
4654f8829a4aSRandall Stewart 			if (asoc->pr_sctp_cnt != 0)
4655f8829a4aSRandall Stewart 				asoc->pr_sctp_cnt--;
4656f8829a4aSRandall Stewart 		}
46577c99d56fSMichael Tuexen 		asoc->sent_queue_cnt--;
4658f8829a4aSRandall Stewart 		if (tp1->data) {
465904ee05e8SRandall Stewart 			/* sa_ignore NO_NULL_CHK */
4660f8829a4aSRandall Stewart 			sctp_free_bufspace(stcb, asoc, tp1, 1);
4661f8829a4aSRandall Stewart 			sctp_m_freem(tp1->data);
46627c99d56fSMichael Tuexen 			tp1->data = NULL;
4663dd973b0eSMichael Tuexen 			if (asoc->prsctp_supported && PR_SCTP_BUF_ENABLED(tp1->flags)) {
4664f8829a4aSRandall Stewart 				asoc->sent_queue_cnt_removeable--;
4665f8829a4aSRandall Stewart 			}
4666f8829a4aSRandall Stewart 		}
4667b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_LOGGING_ENABLE) {
4668f8829a4aSRandall Stewart 			sctp_log_sack(asoc->last_acked_seq,
4669f8829a4aSRandall Stewart 			    cum_ack,
4670f8829a4aSRandall Stewart 			    tp1->rec.data.TSN_seq,
4671f8829a4aSRandall Stewart 			    0,
4672f8829a4aSRandall Stewart 			    0,
4673f8829a4aSRandall Stewart 			    SCTP_LOG_FREE_SENT);
467480fefe0aSRandall Stewart 		}
4675689e6a5fSMichael Tuexen 		sctp_free_a_chunk(stcb, tp1, SCTP_SO_NOT_LOCKED);
4676f8829a4aSRandall Stewart 		wake_him++;
46777c99d56fSMichael Tuexen 	}
46787c99d56fSMichael Tuexen 	if (TAILQ_EMPTY(&asoc->sent_queue) && (asoc->total_flight > 0)) {
46797c99d56fSMichael Tuexen #ifdef INVARIANTS
4680cd0a4ff6SPedro F. Giffuni 		panic("Warning flight size is positive and should be 0");
46817c99d56fSMichael Tuexen #else
46827c99d56fSMichael Tuexen 		SCTP_PRINTF("Warning flight size incorrect should be 0 is %d\n",
46837c99d56fSMichael Tuexen 		    asoc->total_flight);
46847c99d56fSMichael Tuexen #endif
46857c99d56fSMichael Tuexen 		asoc->total_flight = 0;
46867c99d56fSMichael Tuexen 	}
468704ee05e8SRandall Stewart 	/* sa_ignore NO_NULL_CHK */
4688f8829a4aSRandall Stewart 	if ((wake_him) && (stcb->sctp_socket)) {
4689ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
4690ceaad40aSRandall Stewart 		struct socket *so;
4691ceaad40aSRandall Stewart 
4692ceaad40aSRandall Stewart #endif
4693f8829a4aSRandall Stewart 		SOCKBUF_LOCK(&stcb->sctp_socket->so_snd);
4694b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_WAKE_LOGGING_ENABLE) {
46957215cc1bSMichael Tuexen 			sctp_wakeup_log(stcb, wake_him, SCTP_WAKESND_FROM_SACK);
469680fefe0aSRandall Stewart 		}
4697ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
4698ceaad40aSRandall Stewart 		so = SCTP_INP_SO(stcb->sctp_ep);
4699ceaad40aSRandall Stewart 		atomic_add_int(&stcb->asoc.refcnt, 1);
4700ceaad40aSRandall Stewart 		SCTP_TCB_UNLOCK(stcb);
4701ceaad40aSRandall Stewart 		SCTP_SOCKET_LOCK(so, 1);
4702ceaad40aSRandall Stewart 		SCTP_TCB_LOCK(stcb);
4703ceaad40aSRandall Stewart 		atomic_subtract_int(&stcb->asoc.refcnt, 1);
4704ceaad40aSRandall Stewart 		if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
4705ceaad40aSRandall Stewart 			/* assoc was freed while we were unlocked */
4706ceaad40aSRandall Stewart 			SCTP_SOCKET_UNLOCK(so, 1);
4707ceaad40aSRandall Stewart 			return;
4708ceaad40aSRandall Stewart 		}
4709ceaad40aSRandall Stewart #endif
4710f8829a4aSRandall Stewart 		sctp_sowwakeup_locked(stcb->sctp_ep, stcb->sctp_socket);
4711ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
4712ceaad40aSRandall Stewart 		SCTP_SOCKET_UNLOCK(so, 1);
4713ceaad40aSRandall Stewart #endif
4714f8829a4aSRandall Stewart 	} else {
4715b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_WAKE_LOGGING_ENABLE) {
47167215cc1bSMichael Tuexen 			sctp_wakeup_log(stcb, wake_him, SCTP_NOWAKE_FROM_SACK);
471780fefe0aSRandall Stewart 		}
4718f8829a4aSRandall Stewart 	}
4719f8829a4aSRandall Stewart 
472042551e99SRandall Stewart 	if (asoc->fast_retran_loss_recovery && accum_moved) {
472120b07a4dSMichael Tuexen 		if (SCTP_TSN_GE(asoc->last_acked_seq, asoc->fast_recovery_tsn)) {
4722f8829a4aSRandall Stewart 			/* Setup so we will exit RFC2582 fast recovery */
4723f8829a4aSRandall Stewart 			will_exit_fast_recovery = 1;
4724f8829a4aSRandall Stewart 		}
4725f8829a4aSRandall Stewart 	}
4726f8829a4aSRandall Stewart 	/*
4727f8829a4aSRandall Stewart 	 * Check for revoked fragments:
4728f8829a4aSRandall Stewart 	 *
4729f8829a4aSRandall Stewart 	 * if Previous sack - Had no frags then we can't have any revoked if
4730f8829a4aSRandall Stewart 	 * Previous sack - Had frag's then - If we now have frags aka
4731f8829a4aSRandall Stewart 	 * num_seg > 0 call sctp_check_for_revoked() to tell if peer revoked
4732f8829a4aSRandall Stewart 	 * some of them. else - The peer revoked all ACKED fragments, since
4733f8829a4aSRandall Stewart 	 * we had some before and now we have NONE.
4734f8829a4aSRandall Stewart 	 */
4735f8829a4aSRandall Stewart 
4736d9c5cfeaSMichael Tuexen 	if (num_seg) {
4737c105859eSRandall Stewart 		sctp_check_for_revoked(stcb, asoc, cum_ack, biggest_tsn_acked);
4738d9c5cfeaSMichael Tuexen 		asoc->saw_sack_with_frags = 1;
4739d9c5cfeaSMichael Tuexen 	} else if (asoc->saw_sack_with_frags) {
4740f8829a4aSRandall Stewart 		int cnt_revoked = 0;
4741f8829a4aSRandall Stewart 
4742f8829a4aSRandall Stewart 		/* Peer revoked all dg's marked or acked */
4743f8829a4aSRandall Stewart 		TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
4744b5c16493SMichael Tuexen 			if (tp1->sent == SCTP_DATAGRAM_ACKED) {
4745f8829a4aSRandall Stewart 				tp1->sent = SCTP_DATAGRAM_SENT;
4746b3f1ea41SRandall Stewart 				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) {
4747c105859eSRandall Stewart 					sctp_misc_ints(SCTP_FLIGHT_LOG_UP_REVOKE,
4748c105859eSRandall Stewart 					    tp1->whoTo->flight_size,
4749c105859eSRandall Stewart 					    tp1->book_size,
47509a8e3088SMichael Tuexen 					    (uint32_t) (uintptr_t) tp1->whoTo,
4751c105859eSRandall Stewart 					    tp1->rec.data.TSN_seq);
475280fefe0aSRandall Stewart 				}
4753c105859eSRandall Stewart 				sctp_flight_size_increase(tp1);
4754c105859eSRandall Stewart 				sctp_total_flight_increase(stcb, tp1);
4755a5d547adSRandall Stewart 				tp1->rec.data.chunk_was_revoked = 1;
475642551e99SRandall Stewart 				/*
475742551e99SRandall Stewart 				 * To ensure that this increase in
47584a9ef3f8SMichael Tuexen 				 * flightsize, which is artificial, does not
47594a9ef3f8SMichael Tuexen 				 * throttle the sender, we also increase the
47604a9ef3f8SMichael Tuexen 				 * cwnd artificially.
476142551e99SRandall Stewart 				 */
476242551e99SRandall Stewart 				tp1->whoTo->cwnd += tp1->book_size;
4763f8829a4aSRandall Stewart 				cnt_revoked++;
4764f8829a4aSRandall Stewart 			}
4765f8829a4aSRandall Stewart 		}
4766f8829a4aSRandall Stewart 		if (cnt_revoked) {
4767f8829a4aSRandall Stewart 			reneged_all = 1;
4768f8829a4aSRandall Stewart 		}
4769f8829a4aSRandall Stewart 		asoc->saw_sack_with_frags = 0;
4770f8829a4aSRandall Stewart 	}
4771d9c5cfeaSMichael Tuexen 	if (num_nr_seg > 0)
4772d9c5cfeaSMichael Tuexen 		asoc->saw_sack_with_nr_frags = 1;
4773f8829a4aSRandall Stewart 	else
4774d9c5cfeaSMichael Tuexen 		asoc->saw_sack_with_nr_frags = 0;
4775f8829a4aSRandall Stewart 
4776b54d3a6cSRandall Stewart 	/* JRS - Use the congestion control given in the CC module */
4777ca85e948SMichael Tuexen 	if (ecne_seen == 0) {
4778ca85e948SMichael Tuexen 		TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
4779ca85e948SMichael Tuexen 			if (net->net_ack2 > 0) {
4780ca85e948SMichael Tuexen 				/*
4781ca85e948SMichael Tuexen 				 * Karn's rule applies to clearing error
4782ca85e948SMichael Tuexen 				 * count, this is optional.
4783ca85e948SMichael Tuexen 				 */
4784ca85e948SMichael Tuexen 				net->error_count = 0;
4785ca85e948SMichael Tuexen 				if (!(net->dest_state & SCTP_ADDR_REACHABLE)) {
4786ca85e948SMichael Tuexen 					/* addr came good */
4787ca85e948SMichael Tuexen 					net->dest_state |= SCTP_ADDR_REACHABLE;
4788ca85e948SMichael Tuexen 					sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb,
47894b1f78e1SMichael Tuexen 					    0, (void *)net, SCTP_SO_NOT_LOCKED);
4790ca85e948SMichael Tuexen 				}
4791ca85e948SMichael Tuexen 				if (net == stcb->asoc.primary_destination) {
4792ca85e948SMichael Tuexen 					if (stcb->asoc.alternate) {
4793*5b495f17SMichael Tuexen 						/* release the alternate,
4794*5b495f17SMichael Tuexen 						 * primary is good */
4795ca85e948SMichael Tuexen 						sctp_free_remote_addr(stcb->asoc.alternate);
4796ca85e948SMichael Tuexen 						stcb->asoc.alternate = NULL;
4797ca85e948SMichael Tuexen 					}
4798ca85e948SMichael Tuexen 				}
4799ca85e948SMichael Tuexen 				if (net->dest_state & SCTP_ADDR_PF) {
4800ca85e948SMichael Tuexen 					net->dest_state &= ~SCTP_ADDR_PF;
4801b7d130beSMichael Tuexen 					sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT,
4802b7d130beSMichael Tuexen 					    stcb->sctp_ep, stcb, net,
480344249214SRandall Stewart 					    SCTP_FROM_SCTP_INDATA + SCTP_LOC_29);
4804ca85e948SMichael Tuexen 					sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
4805ca85e948SMichael Tuexen 					asoc->cc_functions.sctp_cwnd_update_exit_pf(stcb, net);
4806ca85e948SMichael Tuexen 					/* Done with this net */
4807ca85e948SMichael Tuexen 					net->net_ack = 0;
4808ca85e948SMichael Tuexen 				}
4809ca85e948SMichael Tuexen 				/* restore any doubled timers */
4810ca85e948SMichael Tuexen 				net->RTO = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv;
4811ca85e948SMichael Tuexen 				if (net->RTO < stcb->asoc.minrto) {
4812ca85e948SMichael Tuexen 					net->RTO = stcb->asoc.minrto;
4813ca85e948SMichael Tuexen 				}
4814ca85e948SMichael Tuexen 				if (net->RTO > stcb->asoc.maxrto) {
4815ca85e948SMichael Tuexen 					net->RTO = stcb->asoc.maxrto;
4816ca85e948SMichael Tuexen 				}
4817ca85e948SMichael Tuexen 			}
4818ca85e948SMichael Tuexen 		}
4819b54d3a6cSRandall Stewart 		asoc->cc_functions.sctp_cwnd_update_after_sack(stcb, asoc, accum_moved, reneged_all, will_exit_fast_recovery);
4820ca85e948SMichael Tuexen 	}
4821f8829a4aSRandall Stewart 	if (TAILQ_EMPTY(&asoc->sent_queue)) {
4822f8829a4aSRandall Stewart 		/* nothing left in-flight */
4823f8829a4aSRandall Stewart 		TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
4824f8829a4aSRandall Stewart 			/* stop all timers */
4825f8829a4aSRandall Stewart 			sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
4826b7d130beSMichael Tuexen 			    stcb, net,
482744249214SRandall Stewart 			    SCTP_FROM_SCTP_INDATA + SCTP_LOC_30);
4828f8829a4aSRandall Stewart 			net->flight_size = 0;
4829f8829a4aSRandall Stewart 			net->partial_bytes_acked = 0;
4830f8829a4aSRandall Stewart 		}
4831f8829a4aSRandall Stewart 		asoc->total_flight = 0;
4832f8829a4aSRandall Stewart 		asoc->total_flight_count = 0;
4833f8829a4aSRandall Stewart 	}
4834f8829a4aSRandall Stewart 	/**********************************/
4835f8829a4aSRandall Stewart 	/* Now what about shutdown issues */
4836f8829a4aSRandall Stewart 	/**********************************/
4837f8829a4aSRandall Stewart 	if (TAILQ_EMPTY(&asoc->send_queue) && TAILQ_EMPTY(&asoc->sent_queue)) {
4838f8829a4aSRandall Stewart 		/* nothing left on sendqueue.. consider done */
4839b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_RWND_ENABLE) {
4840f8829a4aSRandall Stewart 			sctp_log_rwnd_set(SCTP_SET_PEER_RWND_VIA_SACK,
4841f8829a4aSRandall Stewart 			    asoc->peers_rwnd, 0, 0, a_rwnd);
484280fefe0aSRandall Stewart 		}
4843f8829a4aSRandall Stewart 		asoc->peers_rwnd = a_rwnd;
4844f8829a4aSRandall Stewart 		if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) {
4845f8829a4aSRandall Stewart 			/* SWS sender side engages */
4846f8829a4aSRandall Stewart 			asoc->peers_rwnd = 0;
4847f8829a4aSRandall Stewart 		}
4848f8829a4aSRandall Stewart 		/* clean up */
4849f8829a4aSRandall Stewart 		if ((asoc->stream_queue_cnt == 1) &&
4850f8829a4aSRandall Stewart 		    ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) ||
4851f8829a4aSRandall Stewart 		    (asoc->state & SCTP_STATE_SHUTDOWN_RECEIVED)) &&
4852d1ea5fa9SMichael Tuexen 		    ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) (stcb, asoc))) {
48532afb3e84SRandall Stewart 			asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
4854f8829a4aSRandall Stewart 		}
4855f8829a4aSRandall Stewart 		if ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) &&
4856f8829a4aSRandall Stewart 		    (asoc->stream_queue_cnt == 0)) {
4857f8829a4aSRandall Stewart 			if (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT) {
4858f8829a4aSRandall Stewart 				/* Need to abort here */
4859ff1ffd74SMichael Tuexen 				struct mbuf *op_err;
4860f8829a4aSRandall Stewart 
4861f8829a4aSRandall Stewart 		abort_out_now:
4862f8829a4aSRandall Stewart 				*abort_now = 1;
4863f8829a4aSRandall Stewart 				/* XXX */
4864ff1ffd74SMichael Tuexen 				op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
486544249214SRandall Stewart 				stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_31;
4866ff1ffd74SMichael Tuexen 				sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
4867f8829a4aSRandall Stewart 				return;
4868f8829a4aSRandall Stewart 			} else {
4869ca85e948SMichael Tuexen 				struct sctp_nets *netp;
4870ca85e948SMichael Tuexen 
4871f42a358aSRandall Stewart 				if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
4872f42a358aSRandall Stewart 				    (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
4873f8829a4aSRandall Stewart 					SCTP_STAT_DECR_GAUGE32(sctps_currestab);
4874f42a358aSRandall Stewart 				}
4875c4739e2fSRandall Stewart 				SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
4876b201f536SRandall Stewart 				SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
4877f8829a4aSRandall Stewart 				sctp_stop_timers_for_shutdown(stcb);
4878c39cfa1fSMichael Tuexen 				if (asoc->alternate) {
4879c39cfa1fSMichael Tuexen 					netp = asoc->alternate;
4880c39cfa1fSMichael Tuexen 				} else {
4881c39cfa1fSMichael Tuexen 					netp = asoc->primary_destination;
4882c39cfa1fSMichael Tuexen 				}
4883ca85e948SMichael Tuexen 				sctp_send_shutdown(stcb, netp);
4884f8829a4aSRandall Stewart 				sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
4885ca85e948SMichael Tuexen 				    stcb->sctp_ep, stcb, netp);
4886f8829a4aSRandall Stewart 				sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
4887ca85e948SMichael Tuexen 				    stcb->sctp_ep, stcb, netp);
4888f8829a4aSRandall Stewart 			}
4889f8829a4aSRandall Stewart 			return;
4890f8829a4aSRandall Stewart 		} else if ((SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED) &&
4891f8829a4aSRandall Stewart 		    (asoc->stream_queue_cnt == 0)) {
4892ca85e948SMichael Tuexen 			struct sctp_nets *netp;
4893ca85e948SMichael Tuexen 
4894f8829a4aSRandall Stewart 			if (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT) {
4895f8829a4aSRandall Stewart 				goto abort_out_now;
4896f8829a4aSRandall Stewart 			}
4897f8829a4aSRandall Stewart 			SCTP_STAT_DECR_GAUGE32(sctps_currestab);
4898c4739e2fSRandall Stewart 			SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_ACK_SENT);
4899b201f536SRandall Stewart 			SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
490012af6654SMichael Tuexen 			sctp_stop_timers_for_shutdown(stcb);
4901c39cfa1fSMichael Tuexen 			if (asoc->alternate) {
4902c39cfa1fSMichael Tuexen 				netp = asoc->alternate;
4903c39cfa1fSMichael Tuexen 			} else {
4904c39cfa1fSMichael Tuexen 				netp = asoc->primary_destination;
4905c39cfa1fSMichael Tuexen 			}
4906c39cfa1fSMichael Tuexen 			sctp_send_shutdown_ack(stcb, netp);
4907f8829a4aSRandall Stewart 			sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK,
4908ca85e948SMichael Tuexen 			    stcb->sctp_ep, stcb, netp);
4909f8829a4aSRandall Stewart 			return;
4910f8829a4aSRandall Stewart 		}
4911f8829a4aSRandall Stewart 	}
4912f8829a4aSRandall Stewart 	/*
4913f8829a4aSRandall Stewart 	 * Now here we are going to recycle net_ack for a different use...
4914f8829a4aSRandall Stewart 	 * HEADS UP.
4915f8829a4aSRandall Stewart 	 */
4916f8829a4aSRandall Stewart 	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
4917f8829a4aSRandall Stewart 		net->net_ack = 0;
4918f8829a4aSRandall Stewart 	}
4919f8829a4aSRandall Stewart 
4920f8829a4aSRandall Stewart 	/*
4921f8829a4aSRandall Stewart 	 * CMT DAC algorithm: If SACK DAC flag was 0, then no extra marking
4922f8829a4aSRandall Stewart 	 * to be done. Setting this_sack_lowest_newack to the cum_ack will
4923f8829a4aSRandall Stewart 	 * automatically ensure that.
4924f8829a4aSRandall Stewart 	 */
49257c99d56fSMichael Tuexen 	if ((asoc->sctp_cmt_on_off > 0) &&
492620083c2eSMichael Tuexen 	    SCTP_BASE_SYSCTL(sctp_cmt_use_dac) &&
492720083c2eSMichael Tuexen 	    (cmt_dac_flag == 0)) {
4928f8829a4aSRandall Stewart 		this_sack_lowest_newack = cum_ack;
4929f8829a4aSRandall Stewart 	}
4930cd554309SMichael Tuexen 	if ((num_seg > 0) || (num_nr_seg > 0)) {
4931f8829a4aSRandall Stewart 		sctp_strike_gap_ack_chunks(stcb, asoc, biggest_tsn_acked,
4932f8829a4aSRandall Stewart 		    biggest_tsn_newly_acked, this_sack_lowest_newack, accum_moved);
4933f8829a4aSRandall Stewart 	}
4934b54d3a6cSRandall Stewart 	/* JRS - Use the congestion control given in the CC module */
4935b54d3a6cSRandall Stewart 	asoc->cc_functions.sctp_cwnd_update_after_fr(stcb, asoc);
4936f8829a4aSRandall Stewart 
4937f8829a4aSRandall Stewart 	/* Now are we exiting loss recovery ? */
4938f8829a4aSRandall Stewart 	if (will_exit_fast_recovery) {
4939f8829a4aSRandall Stewart 		/* Ok, we must exit fast recovery */
4940f8829a4aSRandall Stewart 		asoc->fast_retran_loss_recovery = 0;
4941f8829a4aSRandall Stewart 	}
4942f8829a4aSRandall Stewart 	if ((asoc->sat_t3_loss_recovery) &&
494320b07a4dSMichael Tuexen 	    SCTP_TSN_GE(asoc->last_acked_seq, asoc->sat_t3_recovery_tsn)) {
4944f8829a4aSRandall Stewart 		/* end satellite t3 loss recovery */
4945f8829a4aSRandall Stewart 		asoc->sat_t3_loss_recovery = 0;
4946f8829a4aSRandall Stewart 	}
494742551e99SRandall Stewart 	/*
494842551e99SRandall Stewart 	 * CMT Fast recovery
494942551e99SRandall Stewart 	 */
4950f8829a4aSRandall Stewart 	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
4951f8829a4aSRandall Stewart 		if (net->will_exit_fast_recovery) {
4952f8829a4aSRandall Stewart 			/* Ok, we must exit fast recovery */
4953f8829a4aSRandall Stewart 			net->fast_retran_loss_recovery = 0;
4954f8829a4aSRandall Stewart 		}
4955f8829a4aSRandall Stewart 	}
4956f8829a4aSRandall Stewart 
4957f8829a4aSRandall Stewart 	/* Adjust and set the new rwnd value */
4958b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_RWND_ENABLE) {
4959f8829a4aSRandall Stewart 		sctp_log_rwnd_set(SCTP_SET_PEER_RWND_VIA_SACK,
496044fbe462SRandall Stewart 		    asoc->peers_rwnd, asoc->total_flight, (asoc->total_flight_count * SCTP_BASE_SYSCTL(sctp_peer_chunk_oh)), a_rwnd);
496180fefe0aSRandall Stewart 	}
4962f8829a4aSRandall Stewart 	asoc->peers_rwnd = sctp_sbspace_sub(a_rwnd,
496344fbe462SRandall Stewart 	    (uint32_t) (asoc->total_flight + (asoc->total_flight_count * SCTP_BASE_SYSCTL(sctp_peer_chunk_oh))));
4964f8829a4aSRandall Stewart 	if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) {
4965f8829a4aSRandall Stewart 		/* SWS sender side engages */
4966f8829a4aSRandall Stewart 		asoc->peers_rwnd = 0;
4967f8829a4aSRandall Stewart 	}
49685e54f665SRandall Stewart 	if (asoc->peers_rwnd > old_rwnd) {
49695e54f665SRandall Stewart 		win_probe_recovery = 1;
49705e54f665SRandall Stewart 	}
4971f8829a4aSRandall Stewart 	/*
4972f8829a4aSRandall Stewart 	 * Now we must setup so we have a timer up for anyone with
4973f8829a4aSRandall Stewart 	 * outstanding data.
4974f8829a4aSRandall Stewart 	 */
4975bff64a4dSRandall Stewart 	done_once = 0;
4976a5d547adSRandall Stewart again:
4977a5d547adSRandall Stewart 	j = 0;
4978f8829a4aSRandall Stewart 	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
49795e54f665SRandall Stewart 		if (win_probe_recovery && (net->window_probe)) {
4980c105859eSRandall Stewart 			win_probe_recovered = 1;
49815e54f665SRandall Stewart 			/*-
49825e54f665SRandall Stewart 			 * Find first chunk that was used with
49835e54f665SRandall Stewart 			 * window probe and clear the event. Put
49845e54f665SRandall Stewart 			 * it back into the send queue as if has
49855e54f665SRandall Stewart 			 * not been sent.
49865e54f665SRandall Stewart 			 */
49875e54f665SRandall Stewart 			TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
49885e54f665SRandall Stewart 				if (tp1->window_probe) {
49897215cc1bSMichael Tuexen 					sctp_window_probe_recovery(stcb, asoc, tp1);
49905e54f665SRandall Stewart 					break;
49915e54f665SRandall Stewart 				}
49925e54f665SRandall Stewart 			}
49935e54f665SRandall Stewart 		}
4994f8829a4aSRandall Stewart 		if (net->flight_size) {
4995a5d547adSRandall Stewart 			j++;
4996cd554309SMichael Tuexen 			if (!SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) {
4997f8829a4aSRandall Stewart 				sctp_timer_start(SCTP_TIMER_TYPE_SEND,
4998f8829a4aSRandall Stewart 				    stcb->sctp_ep, stcb, net);
4999cd554309SMichael Tuexen 			}
50005171328bSRandall Stewart 			if (net->window_probe) {
5001cd554309SMichael Tuexen 				net->window_probe = 0;
50025171328bSRandall Stewart 			}
5003c105859eSRandall Stewart 		} else {
50045171328bSRandall Stewart 			if (net->window_probe) {
5005*5b495f17SMichael Tuexen 				/* In window probes we must assure a timer
5006*5b495f17SMichael Tuexen 				 * is still running there */
50075171328bSRandall Stewart 				if (!SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) {
50085171328bSRandall Stewart 					sctp_timer_start(SCTP_TIMER_TYPE_SEND,
50095171328bSRandall Stewart 					    stcb->sctp_ep, stcb, net);
50105171328bSRandall Stewart 
50115171328bSRandall Stewart 				}
50125171328bSRandall Stewart 			} else if (SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) {
5013c105859eSRandall Stewart 				sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
5014c105859eSRandall Stewart 				    stcb, net,
501544249214SRandall Stewart 				    SCTP_FROM_SCTP_INDATA + SCTP_LOC_32);
5016c105859eSRandall Stewart 			}
5017f8829a4aSRandall Stewart 		}
5018f8829a4aSRandall Stewart 	}
5019bff64a4dSRandall Stewart 	if ((j == 0) &&
5020bff64a4dSRandall Stewart 	    (!TAILQ_EMPTY(&asoc->sent_queue)) &&
5021bff64a4dSRandall Stewart 	    (asoc->sent_queue_retran_cnt == 0) &&
5022c105859eSRandall Stewart 	    (win_probe_recovered == 0) &&
5023bff64a4dSRandall Stewart 	    (done_once == 0)) {
50240c0982b8SRandall Stewart 		/*
50250c0982b8SRandall Stewart 		 * huh, this should not happen unless all packets are
50260c0982b8SRandall Stewart 		 * PR-SCTP and marked to skip of course.
50270c0982b8SRandall Stewart 		 */
50280c0982b8SRandall Stewart 		if (sctp_fs_audit(asoc)) {
5029a5d547adSRandall Stewart 			TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
5030a5d547adSRandall Stewart 				net->flight_size = 0;
5031a5d547adSRandall Stewart 			}
5032a5d547adSRandall Stewart 			asoc->total_flight = 0;
5033a5d547adSRandall Stewart 			asoc->total_flight_count = 0;
5034a5d547adSRandall Stewart 			asoc->sent_queue_retran_cnt = 0;
5035a5d547adSRandall Stewart 			TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
5036a5d547adSRandall Stewart 				if (tp1->sent < SCTP_DATAGRAM_RESEND) {
5037c105859eSRandall Stewart 					sctp_flight_size_increase(tp1);
5038c105859eSRandall Stewart 					sctp_total_flight_increase(stcb, tp1);
5039a5d547adSRandall Stewart 				} else if (tp1->sent == SCTP_DATAGRAM_RESEND) {
5040791437b5SRandall Stewart 					sctp_ucount_incr(asoc->sent_queue_retran_cnt);
5041a5d547adSRandall Stewart 				}
5042a5d547adSRandall Stewart 			}
50430c0982b8SRandall Stewart 		}
5044bff64a4dSRandall Stewart 		done_once = 1;
5045a5d547adSRandall Stewart 		goto again;
5046a5d547adSRandall Stewart 	}
5047cd554309SMichael Tuexen 	/*********************************************/
5048cd554309SMichael Tuexen 	/* Here we perform PR-SCTP procedures        */
5049cd554309SMichael Tuexen 	/* (section 4.2)                             */
5050cd554309SMichael Tuexen 	/*********************************************/
5051cd554309SMichael Tuexen 	/* C1. update advancedPeerAckPoint */
505220b07a4dSMichael Tuexen 	if (SCTP_TSN_GT(cum_ack, asoc->advanced_peer_ack_point)) {
5053dfb11ef8SRandall Stewart 		asoc->advanced_peer_ack_point = cum_ack;
5054dfb11ef8SRandall Stewart 	}
5055830d754dSRandall Stewart 	/* C2. try to further move advancedPeerAckPoint ahead */
5056dd973b0eSMichael Tuexen 	if ((asoc->prsctp_supported) && (asoc->pr_sctp_cnt > 0)) {
5057830d754dSRandall Stewart 		struct sctp_tmit_chunk *lchk;
5058830d754dSRandall Stewart 		uint32_t old_adv_peer_ack_point;
5059830d754dSRandall Stewart 
5060830d754dSRandall Stewart 		old_adv_peer_ack_point = asoc->advanced_peer_ack_point;
5061830d754dSRandall Stewart 		lchk = sctp_try_advance_peer_ack_point(stcb, asoc);
5062830d754dSRandall Stewart 		/* C3. See if we need to send a Fwd-TSN */
506320b07a4dSMichael Tuexen 		if (SCTP_TSN_GT(asoc->advanced_peer_ack_point, cum_ack)) {
5064830d754dSRandall Stewart 			/*
5065493d8e5aSRandall Stewart 			 * ISSUE with ECN, see FWD-TSN processing.
5066830d754dSRandall Stewart 			 */
50670c0982b8SRandall Stewart 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) {
50680c0982b8SRandall Stewart 				sctp_misc_ints(SCTP_FWD_TSN_CHECK,
50690c0982b8SRandall Stewart 				    0xee, cum_ack, asoc->advanced_peer_ack_point,
50700c0982b8SRandall Stewart 				    old_adv_peer_ack_point);
50710c0982b8SRandall Stewart 			}
507220b07a4dSMichael Tuexen 			if (SCTP_TSN_GT(asoc->advanced_peer_ack_point, old_adv_peer_ack_point)) {
5073830d754dSRandall Stewart 				send_forward_tsn(stcb, asoc);
50740c0982b8SRandall Stewart 			} else if (lchk) {
50750c0982b8SRandall Stewart 				/* try to FR fwd-tsn's that get lost too */
507644fbe462SRandall Stewart 				if (lchk->rec.data.fwd_tsn_cnt >= 3) {
50770c0982b8SRandall Stewart 					send_forward_tsn(stcb, asoc);
50780c0982b8SRandall Stewart 				}
5079830d754dSRandall Stewart 			}
5080830d754dSRandall Stewart 		}
5081830d754dSRandall Stewart 		if (lchk) {
5082830d754dSRandall Stewart 			/* Assure a timer is up */
5083830d754dSRandall Stewart 			sctp_timer_start(SCTP_TIMER_TYPE_SEND,
5084830d754dSRandall Stewart 			    stcb->sctp_ep, stcb, lchk->whoTo);
5085830d754dSRandall Stewart 		}
5086830d754dSRandall Stewart 	}
5087b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SACK_RWND_LOGGING_ENABLE) {
5088f8829a4aSRandall Stewart 		sctp_misc_ints(SCTP_SACK_RWND_UPDATE,
5089f8829a4aSRandall Stewart 		    a_rwnd,
5090f8829a4aSRandall Stewart 		    stcb->asoc.peers_rwnd,
5091f8829a4aSRandall Stewart 		    stcb->asoc.total_flight,
5092f8829a4aSRandall Stewart 		    stcb->asoc.total_output_queue_size);
509380fefe0aSRandall Stewart 	}
5094f8829a4aSRandall Stewart }
5095f8829a4aSRandall Stewart 
5096f8829a4aSRandall Stewart void
50977215cc1bSMichael Tuexen sctp_update_acked(struct sctp_tcb *stcb, struct sctp_shutdown_chunk *cp, int *abort_flag)
5098f8829a4aSRandall Stewart {
5099f8829a4aSRandall Stewart 	/* Copy cum-ack */
5100f8829a4aSRandall Stewart 	uint32_t cum_ack, a_rwnd;
5101f8829a4aSRandall Stewart 
5102f8829a4aSRandall Stewart 	cum_ack = ntohl(cp->cumulative_tsn_ack);
5103f8829a4aSRandall Stewart 	/* Arrange so a_rwnd does NOT change */
5104f8829a4aSRandall Stewart 	a_rwnd = stcb->asoc.peers_rwnd + stcb->asoc.total_flight;
5105f8829a4aSRandall Stewart 
5106f8829a4aSRandall Stewart 	/* Now call the express sack handling */
5107899288aeSRandall Stewart 	sctp_express_handle_sack(stcb, cum_ack, a_rwnd, abort_flag, 0);
5108f8829a4aSRandall Stewart }
5109f8829a4aSRandall Stewart 
5110f8829a4aSRandall Stewart static void
5111f8829a4aSRandall Stewart sctp_kick_prsctp_reorder_queue(struct sctp_tcb *stcb,
5112f8829a4aSRandall Stewart     struct sctp_stream_in *strmin)
5113f8829a4aSRandall Stewart {
5114f8829a4aSRandall Stewart 	struct sctp_queued_to_read *ctl, *nctl;
5115f8829a4aSRandall Stewart 	struct sctp_association *asoc;
511644249214SRandall Stewart 	uint32_t tt;
511744249214SRandall Stewart 	int need_reasm_check = 0, old;
5118f8829a4aSRandall Stewart 
5119f8829a4aSRandall Stewart 	asoc = &stcb->asoc;
5120f8829a4aSRandall Stewart 	tt = strmin->last_sequence_delivered;
512144249214SRandall Stewart 	if (asoc->idata_supported) {
512244249214SRandall Stewart 		old = 0;
512344249214SRandall Stewart 	} else {
512444249214SRandall Stewart 		old = 1;
512544249214SRandall Stewart 	}
5126f8829a4aSRandall Stewart 	/*
5127f8829a4aSRandall Stewart 	 * First deliver anything prior to and including the stream no that
512844249214SRandall Stewart 	 * came in.
5129f8829a4aSRandall Stewart 	 */
513044249214SRandall Stewart 	TAILQ_FOREACH_SAFE(ctl, &strmin->inqueue, next_instrm, nctl) {
513144249214SRandall Stewart 		if (SCTP_MSGID_GE(old, tt, ctl->sinfo_ssn)) {
5132f8829a4aSRandall Stewart 			/* this is deliverable now */
513344249214SRandall Stewart 			if (((ctl->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) {
513444249214SRandall Stewart 				if (ctl->on_strm_q) {
513544249214SRandall Stewart 					if (ctl->on_strm_q == SCTP_ON_ORDERED) {
513644249214SRandall Stewart 						TAILQ_REMOVE(&strmin->inqueue, ctl, next_instrm);
513744249214SRandall Stewart 					} else if (ctl->on_strm_q == SCTP_ON_UNORDERED) {
513844249214SRandall Stewart 						TAILQ_REMOVE(&strmin->uno_inqueue, ctl, next_instrm);
513998d5fd97SMichael Tuexen #ifdef INVARIANTS
514044249214SRandall Stewart 					} else {
514144249214SRandall Stewart 						panic("strmin: %p ctl: %p unknown %d",
514244249214SRandall Stewart 						    strmin, ctl, ctl->on_strm_q);
514398d5fd97SMichael Tuexen #endif
514444249214SRandall Stewart 					}
514544249214SRandall Stewart 					ctl->on_strm_q = 0;
514644249214SRandall Stewart 				}
5147f8829a4aSRandall Stewart 				/* subtract pending on streams */
5148f8829a4aSRandall Stewart 				asoc->size_on_all_streams -= ctl->length;
5149f8829a4aSRandall Stewart 				sctp_ucount_decr(asoc->cnt_on_all_streams);
5150f8829a4aSRandall Stewart 				/* deliver it to at least the delivery-q */
5151f8829a4aSRandall Stewart 				if (stcb->sctp_socket) {
5152b5c16493SMichael Tuexen 					sctp_mark_non_revokable(asoc, ctl->sinfo_tsn);
5153f8829a4aSRandall Stewart 					sctp_add_to_readq(stcb->sctp_ep, stcb,
5154f8829a4aSRandall Stewart 					    ctl,
515544249214SRandall Stewart 					    &stcb->sctp_socket->so_rcv,
515644249214SRandall Stewart 					    1, SCTP_READ_LOCK_HELD,
515744249214SRandall Stewart 					    SCTP_SO_NOT_LOCKED);
515844249214SRandall Stewart 				}
515944249214SRandall Stewart 			} else {
516044249214SRandall Stewart 				/* Its a fragmented message */
516144249214SRandall Stewart 				if (ctl->first_frag_seen) {
5162*5b495f17SMichael Tuexen 					/* Make it so this is next to
5163*5b495f17SMichael Tuexen 					 * deliver, we restore later */
516444249214SRandall Stewart 					strmin->last_sequence_delivered = ctl->sinfo_ssn - 1;
516544249214SRandall Stewart 					need_reasm_check = 1;
516644249214SRandall Stewart 					break;
516744249214SRandall Stewart 				}
5168f8829a4aSRandall Stewart 			}
5169f8829a4aSRandall Stewart 		} else {
5170f8829a4aSRandall Stewart 			/* no more delivery now. */
5171f8829a4aSRandall Stewart 			break;
5172f8829a4aSRandall Stewart 		}
5173f8829a4aSRandall Stewart 	}
517444249214SRandall Stewart 	if (need_reasm_check) {
517544249214SRandall Stewart 		int ret;
517644249214SRandall Stewart 
5177d1ea5fa9SMichael Tuexen 		ret = sctp_deliver_reasm_check(stcb, &stcb->asoc, strmin, SCTP_READ_LOCK_HELD);
517844249214SRandall Stewart 		if (SCTP_MSGID_GT(old, tt, strmin->last_sequence_delivered)) {
517944249214SRandall Stewart 			/* Restore the next to deliver unless we are ahead */
518044249214SRandall Stewart 			strmin->last_sequence_delivered = tt;
518144249214SRandall Stewart 		}
518244249214SRandall Stewart 		if (ret == 0) {
518344249214SRandall Stewart 			/* Left the front Partial one on */
518444249214SRandall Stewart 			return;
518544249214SRandall Stewart 		}
518644249214SRandall Stewart 		need_reasm_check = 0;
518744249214SRandall Stewart 	}
5188f8829a4aSRandall Stewart 	/*
5189f8829a4aSRandall Stewart 	 * now we must deliver things in queue the normal way  if any are
5190f8829a4aSRandall Stewart 	 * now ready.
5191f8829a4aSRandall Stewart 	 */
5192f8829a4aSRandall Stewart 	tt = strmin->last_sequence_delivered + 1;
519344249214SRandall Stewart 	TAILQ_FOREACH_SAFE(ctl, &strmin->inqueue, next_instrm, nctl) {
5194f8829a4aSRandall Stewart 		if (tt == ctl->sinfo_ssn) {
519544249214SRandall Stewart 			if (((ctl->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) {
5196f8829a4aSRandall Stewart 				/* this is deliverable now */
519744249214SRandall Stewart 				if (ctl->on_strm_q) {
519844249214SRandall Stewart 					if (ctl->on_strm_q == SCTP_ON_ORDERED) {
519944249214SRandall Stewart 						TAILQ_REMOVE(&strmin->inqueue, ctl, next_instrm);
520044249214SRandall Stewart 					} else if (ctl->on_strm_q == SCTP_ON_UNORDERED) {
520144249214SRandall Stewart 						TAILQ_REMOVE(&strmin->uno_inqueue, ctl, next_instrm);
520298d5fd97SMichael Tuexen #ifdef INVARIANTS
520344249214SRandall Stewart 					} else {
520444249214SRandall Stewart 						panic("strmin: %p ctl: %p unknown %d",
520544249214SRandall Stewart 						    strmin, ctl, ctl->on_strm_q);
520698d5fd97SMichael Tuexen #endif
520744249214SRandall Stewart 					}
520844249214SRandall Stewart 					ctl->on_strm_q = 0;
520944249214SRandall Stewart 				}
5210f8829a4aSRandall Stewart 				/* subtract pending on streams */
5211f8829a4aSRandall Stewart 				asoc->size_on_all_streams -= ctl->length;
5212f8829a4aSRandall Stewart 				sctp_ucount_decr(asoc->cnt_on_all_streams);
5213f8829a4aSRandall Stewart 				/* deliver it to at least the delivery-q */
5214f8829a4aSRandall Stewart 				strmin->last_sequence_delivered = ctl->sinfo_ssn;
5215f8829a4aSRandall Stewart 				if (stcb->sctp_socket) {
5216b5c16493SMichael Tuexen 					sctp_mark_non_revokable(asoc, ctl->sinfo_tsn);
5217f8829a4aSRandall Stewart 					sctp_add_to_readq(stcb->sctp_ep, stcb,
5218f8829a4aSRandall Stewart 					    ctl,
521944249214SRandall Stewart 					    &stcb->sctp_socket->so_rcv, 1,
522044249214SRandall Stewart 					    SCTP_READ_LOCK_HELD, SCTP_SO_NOT_LOCKED);
522177acdc25SRandall Stewart 
5222f8829a4aSRandall Stewart 				}
5223f8829a4aSRandall Stewart 				tt = strmin->last_sequence_delivered + 1;
5224f8829a4aSRandall Stewart 			} else {
522544249214SRandall Stewart 				/* Its a fragmented message */
522644249214SRandall Stewart 				if (ctl->first_frag_seen) {
5227*5b495f17SMichael Tuexen 					/* Make it so this is next to
5228*5b495f17SMichael Tuexen 					 * deliver */
522944249214SRandall Stewart 					strmin->last_sequence_delivered = ctl->sinfo_ssn - 1;
523044249214SRandall Stewart 					need_reasm_check = 1;
5231f8829a4aSRandall Stewart 					break;
5232f8829a4aSRandall Stewart 				}
5233f8829a4aSRandall Stewart 			}
523444249214SRandall Stewart 		} else {
523544249214SRandall Stewart 			break;
523644249214SRandall Stewart 		}
523744249214SRandall Stewart 	}
523844249214SRandall Stewart 	if (need_reasm_check) {
5239d1ea5fa9SMichael Tuexen 		(void)sctp_deliver_reasm_check(stcb, &stcb->asoc, strmin, SCTP_READ_LOCK_HELD);
524044249214SRandall Stewart 	}
5241f8829a4aSRandall Stewart }
5242f8829a4aSRandall Stewart 
52438e1b295fSMichael Tuexen 
5244d1ea5fa9SMichael Tuexen 
52458933fa13SRandall Stewart static void
52468933fa13SRandall Stewart sctp_flush_reassm_for_str_seq(struct sctp_tcb *stcb,
52478933fa13SRandall Stewart     struct sctp_association *asoc,
5248d1ea5fa9SMichael Tuexen     uint16_t stream, uint32_t seq, int ordered, int old, uint32_t cumtsn)
52498933fa13SRandall Stewart {
525044249214SRandall Stewart 	struct sctp_queued_to_read *control;
525144249214SRandall Stewart 	struct sctp_stream_in *strm;
52524a9ef3f8SMichael Tuexen 	struct sctp_tmit_chunk *chk, *nchk;
5253d1ea5fa9SMichael Tuexen 	int cnt_removed = 0;
52548933fa13SRandall Stewart 
52558933fa13SRandall Stewart 	/*
525644249214SRandall Stewart 	 * For now large messages held on the stream reasm that are complete
52574a9ef3f8SMichael Tuexen 	 * will be tossed too. We could in theory do more work to spin
52584a9ef3f8SMichael Tuexen 	 * through and stop after dumping one msg aka seeing the start of a
52594a9ef3f8SMichael Tuexen 	 * new msg at the head, and call the delivery function... to see if
52604a9ef3f8SMichael Tuexen 	 * it can be delivered... But for now we just dump everything on the
52614a9ef3f8SMichael Tuexen 	 * queue.
52628933fa13SRandall Stewart 	 */
526344249214SRandall Stewart 	strm = &asoc->strmin[stream];
5264d1ea5fa9SMichael Tuexen 	control = sctp_find_reasm_entry(strm, (uint32_t) seq, ordered, old);
526544249214SRandall Stewart 	if (control == NULL) {
526644249214SRandall Stewart 		/* Not found */
526744249214SRandall Stewart 		return;
52688933fa13SRandall Stewart 	}
52695cb91655SMichael Tuexen 	if (old && !ordered && SCTP_TSN_GT(control->fsn_included, cumtsn)) {
52705cb91655SMichael Tuexen 		return;
52715cb91655SMichael Tuexen 	}
527244249214SRandall Stewart 	TAILQ_FOREACH_SAFE(chk, &control->reasm, sctp_next, nchk) {
527344249214SRandall Stewart 		/* Purge hanging chunks */
5274d1ea5fa9SMichael Tuexen 		if (old && (ordered == 0)) {
5275d1ea5fa9SMichael Tuexen 			if (SCTP_TSN_GT(chk->rec.data.TSN_seq, cumtsn)) {
5276d1ea5fa9SMichael Tuexen 				break;
5277d1ea5fa9SMichael Tuexen 			}
5278d1ea5fa9SMichael Tuexen 		}
5279d1ea5fa9SMichael Tuexen 		cnt_removed++;
528044249214SRandall Stewart 		TAILQ_REMOVE(&control->reasm, chk, sctp_next);
52818933fa13SRandall Stewart 		asoc->size_on_reasm_queue -= chk->send_size;
52828933fa13SRandall Stewart 		sctp_ucount_decr(asoc->cnt_on_reasm_queue);
52838933fa13SRandall Stewart 		if (chk->data) {
52848933fa13SRandall Stewart 			sctp_m_freem(chk->data);
52858933fa13SRandall Stewart 			chk->data = NULL;
52868933fa13SRandall Stewart 		}
5287689e6a5fSMichael Tuexen 		sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
52888933fa13SRandall Stewart 	}
5289d1ea5fa9SMichael Tuexen 	if (!TAILQ_EMPTY(&control->reasm)) {
5290d1ea5fa9SMichael Tuexen 		/* This has to be old data, unordered */
5291d1ea5fa9SMichael Tuexen 		if (control->data) {
5292d1ea5fa9SMichael Tuexen 			sctp_m_freem(control->data);
5293d1ea5fa9SMichael Tuexen 			control->data = NULL;
5294d1ea5fa9SMichael Tuexen 		}
5295d1ea5fa9SMichael Tuexen 		sctp_reset_a_control(control, stcb->sctp_ep, cumtsn);
5296d1ea5fa9SMichael Tuexen 		chk = TAILQ_FIRST(&control->reasm);
5297d1ea5fa9SMichael Tuexen 		if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) {
5298d1ea5fa9SMichael Tuexen 			TAILQ_REMOVE(&control->reasm, chk, sctp_next);
5299d1ea5fa9SMichael Tuexen 			sctp_add_chk_to_control(control, strm, stcb, asoc,
5300d1ea5fa9SMichael Tuexen 			    chk, SCTP_READ_LOCK_HELD);
5301d1ea5fa9SMichael Tuexen 		}
5302d1ea5fa9SMichael Tuexen 		sctp_deliver_reasm_check(stcb, asoc, strm, SCTP_READ_LOCK_HELD);
5303d1ea5fa9SMichael Tuexen 		return;
5304d1ea5fa9SMichael Tuexen 	}
5305d1ea5fa9SMichael Tuexen 	if (control->on_strm_q == SCTP_ON_ORDERED) {
530644249214SRandall Stewart 		TAILQ_REMOVE(&strm->inqueue, control, next_instrm);
5307d1ea5fa9SMichael Tuexen 		control->on_strm_q = 0;
5308d1ea5fa9SMichael Tuexen 	} else if (control->on_strm_q == SCTP_ON_UNORDERED) {
5309d1ea5fa9SMichael Tuexen 		TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm);
5310d1ea5fa9SMichael Tuexen 		control->on_strm_q = 0;
5311d1ea5fa9SMichael Tuexen #ifdef INVARIANTS
5312d1ea5fa9SMichael Tuexen 	} else if (control->on_strm_q) {
5313d1ea5fa9SMichael Tuexen 		panic("strm: %p ctl: %p unknown %d",
5314d1ea5fa9SMichael Tuexen 		    strm, control, control->on_strm_q);
5315d1ea5fa9SMichael Tuexen #endif
5316d1ea5fa9SMichael Tuexen 	}
5317d1ea5fa9SMichael Tuexen 	control->on_strm_q = 0;
531844249214SRandall Stewart 	if (control->on_read_q == 0) {
531944249214SRandall Stewart 		sctp_free_remote_addr(control->whoFrom);
532044249214SRandall Stewart 		if (control->data) {
532144249214SRandall Stewart 			sctp_m_freem(control->data);
532244249214SRandall Stewart 			control->data = NULL;
532344249214SRandall Stewart 		}
532444249214SRandall Stewart 		sctp_free_a_readq(stcb, control);
53258933fa13SRandall Stewart 	}
53268933fa13SRandall Stewart }
53278933fa13SRandall Stewart 
5328f8829a4aSRandall Stewart void
5329f8829a4aSRandall Stewart sctp_handle_forward_tsn(struct sctp_tcb *stcb,
5330b5c16493SMichael Tuexen     struct sctp_forward_tsn_chunk *fwd,
5331b5c16493SMichael Tuexen     int *abort_flag, struct mbuf *m, int offset)
5332f8829a4aSRandall Stewart {
5333f8829a4aSRandall Stewart 	/* The pr-sctp fwd tsn */
5334f8829a4aSRandall Stewart 	/*
5335f8829a4aSRandall Stewart 	 * here we will perform all the data receiver side steps for
5336f8829a4aSRandall Stewart 	 * processing FwdTSN, as required in by pr-sctp draft:
5337f8829a4aSRandall Stewart 	 *
5338f8829a4aSRandall Stewart 	 * Assume we get FwdTSN(x):
5339f8829a4aSRandall Stewart 	 *
5340*5b495f17SMichael Tuexen 	 * 1) update local cumTSN to x 2) try to further advance cumTSN to x
5341*5b495f17SMichael Tuexen 	 * + others we have 3) examine and update re-ordering queue on
5342f8829a4aSRandall Stewart 	 * pr-in-streams 4) clean up re-assembly queue 5) Send a sack to
5343f8829a4aSRandall Stewart 	 * report where we are.
5344f8829a4aSRandall Stewart 	 */
5345f8829a4aSRandall Stewart 	struct sctp_association *asoc;
53467898f408SRandall Stewart 	uint32_t new_cum_tsn, gap;
53477215cc1bSMichael Tuexen 	unsigned int i, fwd_sz, m_size;
53488933fa13SRandall Stewart 	uint32_t str_seq;
5349f8829a4aSRandall Stewart 	struct sctp_stream_in *strm;
53508933fa13SRandall Stewart 	struct sctp_queued_to_read *ctl, *sv;
5351f8829a4aSRandall Stewart 
5352f8829a4aSRandall Stewart 	asoc = &stcb->asoc;
5353f8829a4aSRandall Stewart 	if ((fwd_sz = ntohs(fwd->ch.chunk_length)) < sizeof(struct sctp_forward_tsn_chunk)) {
5354ad81507eSRandall Stewart 		SCTPDBG(SCTP_DEBUG_INDATA1,
5355ad81507eSRandall Stewart 		    "Bad size too small/big fwd-tsn\n");
5356f8829a4aSRandall Stewart 		return;
5357f8829a4aSRandall Stewart 	}
5358f8829a4aSRandall Stewart 	m_size = (stcb->asoc.mapping_array_size << 3);
5359f8829a4aSRandall Stewart 	/*************************************************************/
5360f8829a4aSRandall Stewart 	/* 1. Here we update local cumTSN and shift the bitmap array */
5361f8829a4aSRandall Stewart 	/*************************************************************/
5362f8829a4aSRandall Stewart 	new_cum_tsn = ntohl(fwd->new_cumulative_tsn);
5363f8829a4aSRandall Stewart 
536420b07a4dSMichael Tuexen 	if (SCTP_TSN_GE(asoc->cumulative_tsn, new_cum_tsn)) {
5365f8829a4aSRandall Stewart 		/* Already got there ... */
5366f8829a4aSRandall Stewart 		return;
5367f8829a4aSRandall Stewart 	}
5368f8829a4aSRandall Stewart 	/*
5369f8829a4aSRandall Stewart 	 * now we know the new TSN is more advanced, let's find the actual
5370f8829a4aSRandall Stewart 	 * gap
5371f8829a4aSRandall Stewart 	 */
5372b5c16493SMichael Tuexen 	SCTP_CALC_TSN_TO_GAP(gap, new_cum_tsn, asoc->mapping_array_base_tsn);
537377acdc25SRandall Stewart 	asoc->cumulative_tsn = new_cum_tsn;
53742afb3e84SRandall Stewart 	if (gap >= m_size) {
5375f8829a4aSRandall Stewart 		if ((long)gap > sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv)) {
5376ff1ffd74SMichael Tuexen 			struct mbuf *op_err;
5377ff1ffd74SMichael Tuexen 			char msg[SCTP_DIAG_INFO_LEN];
537817205eccSRandall Stewart 
5379f8829a4aSRandall Stewart 			/*
5380f8829a4aSRandall Stewart 			 * out of range (of single byte chunks in the rwnd I
538117205eccSRandall Stewart 			 * give out). This must be an attacker.
5382f8829a4aSRandall Stewart 			 */
538317205eccSRandall Stewart 			*abort_flag = 1;
5384ff1ffd74SMichael Tuexen 			snprintf(msg, sizeof(msg),
5385ff1ffd74SMichael Tuexen 			    "New cum ack %8.8x too high, highest TSN %8.8x",
5386ff1ffd74SMichael Tuexen 			    new_cum_tsn, asoc->highest_tsn_inside_map);
5387ff1ffd74SMichael Tuexen 			op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
538844249214SRandall Stewart 			stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_33;
5389ff1ffd74SMichael Tuexen 			sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
5390f8829a4aSRandall Stewart 			return;
5391f8829a4aSRandall Stewart 		}
5392207304d4SRandall Stewart 		SCTP_STAT_INCR(sctps_fwdtsn_map_over);
539377acdc25SRandall Stewart 
53942afb3e84SRandall Stewart 		memset(stcb->asoc.mapping_array, 0, stcb->asoc.mapping_array_size);
53952afb3e84SRandall Stewart 		asoc->mapping_array_base_tsn = new_cum_tsn + 1;
539677acdc25SRandall Stewart 		asoc->highest_tsn_inside_map = new_cum_tsn;
539777acdc25SRandall Stewart 
5398b5c16493SMichael Tuexen 		memset(stcb->asoc.nr_mapping_array, 0, stcb->asoc.mapping_array_size);
5399830d754dSRandall Stewart 		asoc->highest_tsn_inside_nr_map = new_cum_tsn;
540077acdc25SRandall Stewart 
5401b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
5402f8829a4aSRandall Stewart 			sctp_log_map(0, 3, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT);
540380fefe0aSRandall Stewart 		}
54042afb3e84SRandall Stewart 	} else {
54052afb3e84SRandall Stewart 		SCTP_TCB_LOCK_ASSERT(stcb);
54062afb3e84SRandall Stewart 		for (i = 0; i <= gap; i++) {
54077898f408SRandall Stewart 			if (!SCTP_IS_TSN_PRESENT(asoc->mapping_array, i) &&
54087898f408SRandall Stewart 			    !SCTP_IS_TSN_PRESENT(asoc->nr_mapping_array, i)) {
54098933fa13SRandall Stewart 				SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, i);
541020b07a4dSMichael Tuexen 				if (SCTP_TSN_GT(asoc->mapping_array_base_tsn + i, asoc->highest_tsn_inside_nr_map)) {
54117898f408SRandall Stewart 					asoc->highest_tsn_inside_nr_map = asoc->mapping_array_base_tsn + i;
5412b5c16493SMichael Tuexen 				}
5413b5c16493SMichael Tuexen 			}
5414b5c16493SMichael Tuexen 		}
5415f8829a4aSRandall Stewart 	}
5416f8829a4aSRandall Stewart 	/*************************************************************/
5417f8829a4aSRandall Stewart 	/* 2. Clear up re-assembly queue                             */
5418f8829a4aSRandall Stewart 	/*************************************************************/
5419f8829a4aSRandall Stewart 
542044249214SRandall Stewart 	/* This is now done as part of clearing up the stream/seq */
5421d1ea5fa9SMichael Tuexen 	if (asoc->idata_supported == 0) {
5422d1ea5fa9SMichael Tuexen 		uint16_t sid;
542344249214SRandall Stewart 
5424d1ea5fa9SMichael Tuexen 		/* Flush all the un-ordered data based on cum-tsn */
5425d1ea5fa9SMichael Tuexen 		SCTP_INP_READ_LOCK(stcb->sctp_ep);
5426d1ea5fa9SMichael Tuexen 		for (sid = 0; sid < asoc->streamincnt; sid++) {
5427d1ea5fa9SMichael Tuexen 			sctp_flush_reassm_for_str_seq(stcb, asoc, sid, 0, 0, 1, new_cum_tsn);
5428d1ea5fa9SMichael Tuexen 		}
5429d1ea5fa9SMichael Tuexen 		SCTP_INP_READ_UNLOCK(stcb->sctp_ep);
5430d1ea5fa9SMichael Tuexen 	}
54318933fa13SRandall Stewart 	/*******************************************************/
54328933fa13SRandall Stewart 	/* 3. Update the PR-stream re-ordering queues and fix  */
54338933fa13SRandall Stewart 	/* delivery issues as needed.                       */
54348933fa13SRandall Stewart 	/*******************************************************/
5435f8829a4aSRandall Stewart 	fwd_sz -= sizeof(*fwd);
5436671d309cSRandall Stewart 	if (m && fwd_sz) {
5437f8829a4aSRandall Stewart 		/* New method. */
5438d61a0ae0SRandall Stewart 		unsigned int num_str;
543944249214SRandall Stewart 		uint32_t sequence;
544044249214SRandall Stewart 		uint16_t stream;
54418e1b295fSMichael Tuexen 		uint16_t ordered, flags;
544244249214SRandall Stewart 		int old;
5443671d309cSRandall Stewart 		struct sctp_strseq *stseq, strseqbuf;
544444249214SRandall Stewart 		struct sctp_strseq_mid *stseq_m, strseqbuf_m;
5445671d309cSRandall Stewart 
5446671d309cSRandall Stewart 		offset += sizeof(*fwd);
5447f8829a4aSRandall Stewart 
54488933fa13SRandall Stewart 		SCTP_INP_READ_LOCK(stcb->sctp_ep);
544944249214SRandall Stewart 		if (asoc->idata_supported) {
545044249214SRandall Stewart 			num_str = fwd_sz / sizeof(struct sctp_strseq_mid);
545144249214SRandall Stewart 			old = 0;
545244249214SRandall Stewart 		} else {
5453f8829a4aSRandall Stewart 			num_str = fwd_sz / sizeof(struct sctp_strseq);
545444249214SRandall Stewart 			old = 1;
545544249214SRandall Stewart 		}
5456f8829a4aSRandall Stewart 		for (i = 0; i < num_str; i++) {
545744249214SRandall Stewart 			if (asoc->idata_supported) {
545844249214SRandall Stewart 				stseq_m = (struct sctp_strseq_mid *)sctp_m_getptr(m, offset,
545944249214SRandall Stewart 				    sizeof(struct sctp_strseq_mid),
546044249214SRandall Stewart 				    (uint8_t *) & strseqbuf_m);
546144249214SRandall Stewart 				offset += sizeof(struct sctp_strseq_mid);
546244249214SRandall Stewart 				if (stseq_m == NULL) {
546344249214SRandall Stewart 					break;
546444249214SRandall Stewart 				}
546544249214SRandall Stewart 				stream = ntohs(stseq_m->stream);
546644249214SRandall Stewart 				sequence = ntohl(stseq_m->msg_id);
54678e1b295fSMichael Tuexen 				flags = ntohs(stseq_m->flags);
54688e1b295fSMichael Tuexen 				if (flags & PR_SCTP_UNORDERED_FLAG) {
54698e1b295fSMichael Tuexen 					ordered = 0;
54708e1b295fSMichael Tuexen 				} else {
54718e1b295fSMichael Tuexen 					ordered = 1;
54728e1b295fSMichael Tuexen 				}
547344249214SRandall Stewart 			} else {
5474671d309cSRandall Stewart 				stseq = (struct sctp_strseq *)sctp_m_getptr(m, offset,
5475671d309cSRandall Stewart 				    sizeof(struct sctp_strseq),
5476671d309cSRandall Stewart 				    (uint8_t *) & strseqbuf);
5477671d309cSRandall Stewart 				offset += sizeof(struct sctp_strseq);
54782afb3e84SRandall Stewart 				if (stseq == NULL) {
5479671d309cSRandall Stewart 					break;
54802afb3e84SRandall Stewart 				}
548144249214SRandall Stewart 				stream = ntohs(stseq->stream);
548244249214SRandall Stewart 				sequence = (uint32_t) ntohs(stseq->sequence);
54838e1b295fSMichael Tuexen 				ordered = 1;
548444249214SRandall Stewart 			}
5485f8829a4aSRandall Stewart 			/* Convert */
54868933fa13SRandall Stewart 
5487f8829a4aSRandall Stewart 			/* now process */
54888933fa13SRandall Stewart 
54898933fa13SRandall Stewart 			/*
54908933fa13SRandall Stewart 			 * Ok we now look for the stream/seq on the read
54918933fa13SRandall Stewart 			 * queue where its not all delivered. If we find it
54928933fa13SRandall Stewart 			 * we transmute the read entry into a PDI_ABORTED.
54938933fa13SRandall Stewart 			 */
549444249214SRandall Stewart 			if (stream >= asoc->streamincnt) {
54952afb3e84SRandall Stewart 				/* screwed up streams, stop!  */
54962afb3e84SRandall Stewart 				break;
5497f8829a4aSRandall Stewart 			}
549844249214SRandall Stewart 			if ((asoc->str_of_pdapi == stream) &&
549944249214SRandall Stewart 			    (asoc->ssn_of_pdapi == sequence)) {
55008933fa13SRandall Stewart 				/*
55018933fa13SRandall Stewart 				 * If this is the one we were partially
55028933fa13SRandall Stewart 				 * delivering now then we no longer are.
55038933fa13SRandall Stewart 				 * Note this will change with the reassembly
55048933fa13SRandall Stewart 				 * re-write.
55058933fa13SRandall Stewart 				 */
55068933fa13SRandall Stewart 				asoc->fragmented_delivery_inprogress = 0;
55078933fa13SRandall Stewart 			}
550844249214SRandall Stewart 			strm = &asoc->strmin[stream];
5509d1ea5fa9SMichael Tuexen 			if (asoc->idata_supported == 0) {
5510d1ea5fa9SMichael Tuexen 				uint16_t strm_at;
5511d1ea5fa9SMichael Tuexen 
5512d1ea5fa9SMichael Tuexen 				for (strm_at = strm->last_sequence_delivered; SCTP_MSGID_GE(1, sequence, strm_at); strm_at++) {
5513d1ea5fa9SMichael Tuexen 					sctp_flush_reassm_for_str_seq(stcb, asoc, stream, strm_at, ordered, old, new_cum_tsn);
5514d1ea5fa9SMichael Tuexen 				}
5515d1ea5fa9SMichael Tuexen 			} else {
5516d1ea5fa9SMichael Tuexen 				uint32_t strm_at;
5517d1ea5fa9SMichael Tuexen 
5518d1ea5fa9SMichael Tuexen 				for (strm_at = strm->last_sequence_delivered; SCTP_MSGID_GE(0, sequence, strm_at); strm_at++) {
5519d1ea5fa9SMichael Tuexen 					sctp_flush_reassm_for_str_seq(stcb, asoc, stream, strm_at, ordered, old, new_cum_tsn);
5520d1ea5fa9SMichael Tuexen 				}
5521d1ea5fa9SMichael Tuexen 			}
55228933fa13SRandall Stewart 			TAILQ_FOREACH(ctl, &stcb->sctp_ep->read_queue, next) {
552344249214SRandall Stewart 				if ((ctl->sinfo_stream == stream) &&
552444249214SRandall Stewart 				    (ctl->sinfo_ssn == sequence)) {
552544249214SRandall Stewart 					str_seq = (stream << 16) | (0x0000ffff & sequence);
55268933fa13SRandall Stewart 					ctl->pdapi_aborted = 1;
55278933fa13SRandall Stewart 					sv = stcb->asoc.control_pdapi;
552844249214SRandall Stewart 					ctl->end_added = 1;
552944249214SRandall Stewart 					if (ctl->on_strm_q == SCTP_ON_ORDERED) {
553044249214SRandall Stewart 						TAILQ_REMOVE(&strm->inqueue, ctl, next_instrm);
553144249214SRandall Stewart 					} else if (ctl->on_strm_q == SCTP_ON_UNORDERED) {
553244249214SRandall Stewart 						TAILQ_REMOVE(&strm->uno_inqueue, ctl, next_instrm);
553398d5fd97SMichael Tuexen #ifdef INVARIANTS
553444249214SRandall Stewart 					} else if (ctl->on_strm_q) {
553544249214SRandall Stewart 						panic("strm: %p ctl: %p unknown %d",
553644249214SRandall Stewart 						    strm, ctl, ctl->on_strm_q);
553798d5fd97SMichael Tuexen #endif
553844249214SRandall Stewart 					}
553944249214SRandall Stewart 					ctl->on_strm_q = 0;
55408933fa13SRandall Stewart 					stcb->asoc.control_pdapi = ctl;
5541810ec536SMichael Tuexen 					sctp_ulp_notify(SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION,
5542810ec536SMichael Tuexen 					    stcb,
55438933fa13SRandall Stewart 					    SCTP_PARTIAL_DELIVERY_ABORTED,
5544810ec536SMichael Tuexen 					    (void *)&str_seq,
5545810ec536SMichael Tuexen 					    SCTP_SO_NOT_LOCKED);
55468933fa13SRandall Stewart 					stcb->asoc.control_pdapi = sv;
55478933fa13SRandall Stewart 					break;
554844249214SRandall Stewart 				} else if ((ctl->sinfo_stream == stream) &&
554944249214SRandall Stewart 				    SCTP_MSGID_GT(old, ctl->sinfo_ssn, sequence)) {
55508933fa13SRandall Stewart 					/* We are past our victim SSN */
55518933fa13SRandall Stewart 					break;
55528933fa13SRandall Stewart 				}
55538933fa13SRandall Stewart 			}
555444249214SRandall Stewart 			if (SCTP_MSGID_GT(old, sequence, strm->last_sequence_delivered)) {
5555f8829a4aSRandall Stewart 				/* Update the sequence number */
555644249214SRandall Stewart 				strm->last_sequence_delivered = sequence;
5557f8829a4aSRandall Stewart 			}
5558f8829a4aSRandall Stewart 			/* now kick the stream the new way */
555904ee05e8SRandall Stewart 			/* sa_ignore NO_NULL_CHK */
5560f8829a4aSRandall Stewart 			sctp_kick_prsctp_reorder_queue(stcb, strm);
5561f8829a4aSRandall Stewart 		}
55628933fa13SRandall Stewart 		SCTP_INP_READ_UNLOCK(stcb->sctp_ep);
5563f8829a4aSRandall Stewart 	}
55647898f408SRandall Stewart 	/*
55657898f408SRandall Stewart 	 * Now slide thing forward.
55667898f408SRandall Stewart 	 */
55677898f408SRandall Stewart 	sctp_slide_mapping_arrays(stcb);
5568f8829a4aSRandall Stewart }
5569